netlogon_creds_cli: Simplify netlogon_creds_cli_delete
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blobf95c97bafb79a103bb13f39864be8eec6afd93b6
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 const char *dns_domain;
58 uint32_t cached_flags;
59 bool try_validation6;
60 bool try_logon_ex;
61 bool try_logon_with;
62 } server;
64 struct {
65 const char *key_name;
66 TDB_DATA key_data;
67 struct db_context *ctx;
68 struct g_lock_ctx *g_ctx;
69 struct netlogon_creds_cli_locked_state *locked_state;
70 } db;
73 struct netlogon_creds_cli_locked_state {
74 struct netlogon_creds_cli_context *context;
75 bool is_glocked;
76 struct netlogon_creds_CredentialState *creds;
79 static int netlogon_creds_cli_locked_state_destructor(
80 struct netlogon_creds_cli_locked_state *state)
82 struct netlogon_creds_cli_context *context = state->context;
84 if (context == NULL) {
85 return 0;
88 if (context->db.locked_state == state) {
89 context->db.locked_state = NULL;
92 if (state->is_glocked) {
93 g_lock_unlock(context->db.g_ctx,
94 context->db.key_name);
97 return 0;
100 static NTSTATUS netlogon_creds_cli_context_common(
101 const char *client_computer,
102 const char *client_account,
103 enum netr_SchannelType type,
104 enum dcerpc_AuthLevel auth_level,
105 uint32_t proposed_flags,
106 uint32_t required_flags,
107 const char *server_computer,
108 const char *server_netbios_domain,
109 const char *server_dns_domain,
110 TALLOC_CTX *mem_ctx,
111 struct netlogon_creds_cli_context **_context)
113 struct netlogon_creds_cli_context *context = NULL;
114 char *_key_name = NULL;
115 size_t server_netbios_name_len;
116 char *p = NULL;
118 *_context = NULL;
120 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
121 if (context == NULL) {
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 return NT_STATUS_NO_MEMORY;
131 context->client.account = talloc_strdup(context, client_account);
132 if (context->client.account == NULL) {
133 TALLOC_FREE(context);
134 return NT_STATUS_NO_MEMORY;
137 context->client.proposed_flags = proposed_flags;
138 context->client.required_flags = required_flags;
139 context->client.type = type;
140 context->client.auth_level = auth_level;
142 context->server.computer = talloc_strdup(context, server_computer);
143 if (context->server.computer == NULL) {
144 TALLOC_FREE(context);
145 return NT_STATUS_NO_MEMORY;
148 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
149 if (context->server.netbios_domain == NULL) {
150 TALLOC_FREE(context);
151 return NT_STATUS_NO_MEMORY;
154 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
155 if (context->server.dns_domain == NULL) {
156 TALLOC_FREE(context);
157 return NT_STATUS_NO_MEMORY;
161 * TODO:
162 * Force the callers to provide a unique
163 * value for server_computer and use this directly.
165 * For now we have to deal with
166 * "HOSTNAME" vs. "hostname.example.com".
169 p = strchr(server_computer, '.');
170 if (p != NULL) {
171 server_netbios_name_len = p-server_computer;
172 } else {
173 server_netbios_name_len = strlen(server_computer);
176 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
177 client_computer,
178 client_account,
179 (int)server_netbios_name_len,
180 server_computer,
181 server_netbios_domain);
182 if (_key_name == NULL) {
183 TALLOC_FREE(context);
184 return NT_STATUS_NO_MEMORY;
187 context->db.key_name = talloc_strdup_upper(context, _key_name);
188 TALLOC_FREE(_key_name);
189 if (context->db.key_name == NULL) {
190 TALLOC_FREE(context);
191 return NT_STATUS_NO_MEMORY;
194 context->db.key_data = string_term_tdb_data(context->db.key_name);
196 *_context = context;
197 return NT_STATUS_OK;
200 static struct db_context *netlogon_creds_cli_global_db;
202 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
204 if (netlogon_creds_cli_global_db != NULL) {
205 return NT_STATUS_INVALID_PARAMETER_MIX;
208 netlogon_creds_cli_global_db = talloc_move(NULL, db);
209 return NT_STATUS_OK;
212 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
214 char *fname;
215 struct db_context *global_db;
217 if (netlogon_creds_cli_global_db != NULL) {
218 return NT_STATUS_OK;
221 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
222 if (fname == NULL) {
223 return NT_STATUS_NO_MEMORY;
226 global_db = dbwrap_local_open(NULL, lp_ctx,
227 fname, 0,
228 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
229 O_RDWR|O_CREAT,
230 0600, DBWRAP_LOCK_ORDER_2,
231 DBWRAP_FLAG_NONE);
232 if (global_db == NULL) {
233 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
234 fname, strerror(errno)));
235 talloc_free(fname);
236 return NT_STATUS_NO_MEMORY;
238 TALLOC_FREE(fname);
240 netlogon_creds_cli_global_db = global_db;
241 return NT_STATUS_OK;
244 void netlogon_creds_cli_close_global_db(void)
246 TALLOC_FREE(netlogon_creds_cli_global_db);
249 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
250 struct messaging_context *msg_ctx,
251 const char *client_account,
252 enum netr_SchannelType type,
253 const char *server_computer,
254 const char *server_netbios_domain,
255 const char *server_dns_domain,
256 TALLOC_CTX *mem_ctx,
257 struct netlogon_creds_cli_context **_context)
259 TALLOC_CTX *frame = talloc_stackframe();
260 NTSTATUS status;
261 struct netlogon_creds_cli_context *context = NULL;
262 const char *client_computer;
263 uint32_t proposed_flags;
264 uint32_t required_flags = 0;
265 bool reject_md5_servers = false;
266 bool require_strong_key = false;
267 int require_sign_or_seal = true;
268 bool seal_secure_channel = true;
269 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
270 bool neutralize_nt4_emulation = false;
272 *_context = NULL;
274 if (msg_ctx == NULL) {
275 TALLOC_FREE(frame);
276 return NT_STATUS_INVALID_PARAMETER_MIX;
279 client_computer = lpcfg_netbios_name(lp_ctx);
280 if (strlen(client_computer) > 15) {
281 TALLOC_FREE(frame);
282 return NT_STATUS_INVALID_PARAMETER_MIX;
286 * allow overwrite per domain
287 * reject md5 servers:<netbios_domain>
289 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
290 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
291 "reject md5 servers",
292 server_netbios_domain,
293 reject_md5_servers);
296 * allow overwrite per domain
297 * require strong key:<netbios_domain>
299 require_strong_key = lpcfg_require_strong_key(lp_ctx);
300 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
301 "require strong key",
302 server_netbios_domain,
303 require_strong_key);
306 * allow overwrite per domain
307 * client schannel:<netbios_domain>
309 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
310 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
311 "client schannel",
312 server_netbios_domain,
313 require_sign_or_seal);
316 * allow overwrite per domain
317 * winbind sealed pipes:<netbios_domain>
319 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
320 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
321 "winbind sealed pipes",
322 server_netbios_domain,
323 seal_secure_channel);
326 * allow overwrite per domain
327 * neutralize nt4 emulation:<netbios_domain>
329 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
330 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
331 "neutralize nt4 emulation",
332 server_netbios_domain,
333 neutralize_nt4_emulation);
335 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
336 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
338 switch (type) {
339 case SEC_CHAN_WKSTA:
340 if (lpcfg_security(lp_ctx) == SEC_ADS) {
342 * AD domains should be secure
344 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
345 require_sign_or_seal = true;
346 require_strong_key = true;
348 break;
350 case SEC_CHAN_DOMAIN:
351 break;
353 case SEC_CHAN_DNS_DOMAIN:
355 * AD domains should be secure
357 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
358 require_sign_or_seal = true;
359 require_strong_key = true;
360 neutralize_nt4_emulation = true;
361 break;
363 case SEC_CHAN_BDC:
364 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
365 require_sign_or_seal = true;
366 require_strong_key = true;
367 break;
369 case SEC_CHAN_RODC:
370 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
371 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
372 require_sign_or_seal = true;
373 require_strong_key = true;
374 neutralize_nt4_emulation = true;
375 break;
377 default:
378 TALLOC_FREE(frame);
379 return NT_STATUS_INVALID_PARAMETER;
382 if (neutralize_nt4_emulation) {
383 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
386 if (require_sign_or_seal) {
387 required_flags |= NETLOGON_NEG_ARCFOUR;
388 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
389 } else {
390 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
393 if (reject_md5_servers) {
394 required_flags |= NETLOGON_NEG_ARCFOUR;
395 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
396 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
397 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
400 if (require_strong_key) {
401 required_flags |= NETLOGON_NEG_ARCFOUR;
402 required_flags |= NETLOGON_NEG_STRONG_KEYS;
403 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
406 proposed_flags |= required_flags;
408 if (seal_secure_channel) {
409 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
410 } else {
411 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
414 status = netlogon_creds_cli_context_common(client_computer,
415 client_account,
416 type,
417 auth_level,
418 proposed_flags,
419 required_flags,
420 server_computer,
421 server_netbios_domain,
423 mem_ctx,
424 &context);
425 if (!NT_STATUS_IS_OK(status)) {
426 TALLOC_FREE(frame);
427 return status;
430 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
431 if (context->db.g_ctx == NULL) {
432 TALLOC_FREE(context);
433 TALLOC_FREE(frame);
434 return NT_STATUS_NO_MEMORY;
437 status = netlogon_creds_cli_open_global_db(lp_ctx);
438 if (!NT_STATUS_IS_OK(status)) {
439 TALLOC_FREE(context);
440 TALLOC_FREE(frame);
441 return NT_STATUS_NO_MEMORY;
444 context->db.ctx = netlogon_creds_cli_global_db;
445 *_context = context;
446 TALLOC_FREE(frame);
447 return NT_STATUS_OK;
450 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
451 const char *client_account,
452 enum netr_SchannelType type,
453 uint32_t proposed_flags,
454 uint32_t required_flags,
455 enum dcerpc_AuthLevel auth_level,
456 const char *server_computer,
457 const char *server_netbios_domain,
458 TALLOC_CTX *mem_ctx,
459 struct netlogon_creds_cli_context **_context)
461 NTSTATUS status;
462 struct netlogon_creds_cli_context *context = NULL;
464 *_context = NULL;
466 status = netlogon_creds_cli_context_common(client_computer,
467 client_account,
468 type,
469 auth_level,
470 proposed_flags,
471 required_flags,
472 server_computer,
473 server_netbios_domain,
475 mem_ctx,
476 &context);
477 if (!NT_STATUS_IS_OK(status)) {
478 return status;
481 context->db.ctx = db_open_rbt(context);
482 if (context->db.ctx == NULL) {
483 talloc_free(context);
484 return NT_STATUS_NO_MEMORY;
487 *_context = context;
488 return NT_STATUS_OK;
491 char *netlogon_creds_cli_debug_string(
492 const struct netlogon_creds_cli_context *context,
493 TALLOC_CTX *mem_ctx)
495 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
496 context->db.key_name);
499 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
500 struct netlogon_creds_cli_context *context)
502 return context->client.auth_level;
505 struct netlogon_creds_cli_fetch_state {
506 TALLOC_CTX *mem_ctx;
507 struct netlogon_creds_CredentialState *creds;
508 uint32_t required_flags;
509 NTSTATUS status;
512 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
513 void *private_data)
515 struct netlogon_creds_cli_fetch_state *state =
516 (struct netlogon_creds_cli_fetch_state *)private_data;
517 enum ndr_err_code ndr_err;
518 DATA_BLOB blob;
519 uint32_t tmp_flags;
521 state->creds = talloc_zero(state->mem_ctx,
522 struct netlogon_creds_CredentialState);
523 if (state->creds == NULL) {
524 state->status = NT_STATUS_NO_MEMORY;
525 return;
528 blob.data = data.dptr;
529 blob.length = data.dsize;
531 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
532 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
533 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
534 TALLOC_FREE(state->creds);
535 state->status = ndr_map_error2ntstatus(ndr_err);
536 return;
539 tmp_flags = state->creds->negotiate_flags;
540 tmp_flags &= state->required_flags;
541 if (tmp_flags != state->required_flags) {
542 TALLOC_FREE(state->creds);
543 state->status = NT_STATUS_DOWNGRADE_DETECTED;
544 return;
547 state->status = NT_STATUS_OK;
550 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
551 TALLOC_CTX *mem_ctx,
552 struct netlogon_creds_CredentialState **_creds)
554 NTSTATUS status;
555 struct netlogon_creds_cli_fetch_state fstate = {
556 .mem_ctx = mem_ctx,
557 .status = NT_STATUS_INTERNAL_ERROR,
558 .required_flags = context->client.required_flags,
561 *_creds = NULL;
563 status = dbwrap_parse_record(context->db.ctx,
564 context->db.key_data,
565 netlogon_creds_cli_fetch_parser,
566 &fstate);
567 if (!NT_STATUS_IS_OK(status)) {
568 return status;
570 status = fstate.status;
571 if (!NT_STATUS_IS_OK(status)) {
572 return status;
576 * mark it as invalid for step operations.
578 fstate.creds->sequence = 0;
579 fstate.creds->seed = (struct netr_Credential) {{0}};
580 fstate.creds->client = (struct netr_Credential) {{0}};
581 fstate.creds->server = (struct netr_Credential) {{0}};
583 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
584 *_creds = fstate.creds;
585 return NT_STATUS_OK;
589 * It is really important to try SamLogonEx here,
590 * because multiple processes can talk to the same
591 * domain controller, without using the credential
592 * chain.
594 * With a normal SamLogon call, we must keep the
595 * credentials chain updated and intact between all
596 * users of the machine account (which would imply
597 * cross-node communication for every NTLM logon).
599 * The credentials chain is not per NETLOGON pipe
600 * connection, but globally on the server/client pair
601 * by computer name.
603 * It's also important to use NetlogonValidationSamInfo4 (6),
604 * because it relies on the rpc transport encryption
605 * and avoids using the global netlogon schannel
606 * session key to en/decrypt secret information
607 * like the user_session_key for network logons.
609 * [MS-APDS] 3.1.5.2 NTLM Network Logon
610 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
611 * NETLOGON_NEG_AUTHENTICATED_RPC set together
612 * are the indication that the server supports
613 * NetlogonValidationSamInfo4 (6). And it must only
614 * be used if "SealSecureChannel" is used.
616 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
617 * check is done in netlogon_creds_cli_LogonSamLogon*().
619 context->server.cached_flags = fstate.creds->negotiate_flags;
620 context->server.try_validation6 = true;
621 context->server.try_logon_ex = true;
622 context->server.try_logon_with = true;
624 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
625 context->server.try_validation6 = false;
626 context->server.try_logon_ex = false;
628 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
629 context->server.try_validation6 = false;
632 *_creds = fstate.creds;
633 return NT_STATUS_OK;
636 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
637 const struct netlogon_creds_CredentialState *creds1)
639 TALLOC_CTX *frame = talloc_stackframe();
640 struct netlogon_creds_CredentialState *creds2;
641 DATA_BLOB blob1;
642 DATA_BLOB blob2;
643 NTSTATUS status;
644 enum ndr_err_code ndr_err;
645 int cmp;
647 status = netlogon_creds_cli_get(context, frame, &creds2);
648 if (!NT_STATUS_IS_OK(status)) {
649 TALLOC_FREE(frame);
650 return false;
653 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
654 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
655 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
656 TALLOC_FREE(frame);
657 return false;
660 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
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 cmp = data_blob_cmp(&blob1, &blob2);
669 TALLOC_FREE(frame);
671 return (cmp == 0);
674 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
675 struct netlogon_creds_CredentialState *creds)
677 NTSTATUS status;
678 enum ndr_err_code ndr_err;
679 DATA_BLOB blob;
680 TDB_DATA data;
682 if (context->db.locked_state == NULL) {
684 * this was not the result of netlogon_creds_cli_lock*()
686 return NT_STATUS_INVALID_PAGE_PROTECTION;
689 if (context->db.locked_state->creds != creds) {
691 * this was not the result of netlogon_creds_cli_lock*()
693 return NT_STATUS_INVALID_PAGE_PROTECTION;
696 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
697 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
698 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
699 status = ndr_map_error2ntstatus(ndr_err);
700 return status;
703 data.dptr = blob.data;
704 data.dsize = blob.length;
706 status = dbwrap_store(context->db.ctx,
707 context->db.key_data,
708 data, TDB_REPLACE);
709 TALLOC_FREE(data.dptr);
710 if (!NT_STATUS_IS_OK(status)) {
711 return status;
714 return NT_STATUS_OK;
717 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
718 struct netlogon_creds_CredentialState *creds)
720 NTSTATUS status;
722 if (context->db.locked_state == NULL) {
724 * this was not the result of netlogon_creds_cli_lock*()
726 return NT_STATUS_INVALID_PAGE_PROTECTION;
729 if (context->db.locked_state->creds != creds) {
731 * this was not the result of netlogon_creds_cli_lock*()
733 return NT_STATUS_INVALID_PAGE_PROTECTION;
736 status = dbwrap_delete(context->db.ctx,
737 context->db.key_data);
738 if (!NT_STATUS_IS_OK(status)) {
739 return status;
742 return NT_STATUS_OK;
745 struct netlogon_creds_cli_lock_state {
746 struct netlogon_creds_cli_locked_state *locked_state;
747 struct netlogon_creds_CredentialState *creds;
750 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
751 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
753 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
754 struct tevent_context *ev,
755 struct netlogon_creds_cli_context *context)
757 struct tevent_req *req;
758 struct netlogon_creds_cli_lock_state *state;
759 struct netlogon_creds_cli_locked_state *locked_state;
760 struct tevent_req *subreq;
762 req = tevent_req_create(mem_ctx, &state,
763 struct netlogon_creds_cli_lock_state);
764 if (req == NULL) {
765 return NULL;
768 if (context->db.locked_state != NULL) {
769 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
770 return tevent_req_post(req, ev);
773 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
774 if (tevent_req_nomem(locked_state, req)) {
775 return tevent_req_post(req, ev);
777 talloc_set_destructor(locked_state,
778 netlogon_creds_cli_locked_state_destructor);
779 locked_state->context = context;
781 context->db.locked_state = locked_state;
782 state->locked_state = locked_state;
784 if (context->db.g_ctx == NULL) {
785 netlogon_creds_cli_lock_fetch(req);
786 if (!tevent_req_is_in_progress(req)) {
787 return tevent_req_post(req, ev);
790 return req;
793 subreq = g_lock_lock_send(state, ev,
794 context->db.g_ctx,
795 context->db.key_name,
796 G_LOCK_WRITE);
797 if (tevent_req_nomem(subreq, req)) {
798 return tevent_req_post(req, ev);
800 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
802 return req;
805 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
807 struct tevent_req *req =
808 tevent_req_callback_data(subreq,
809 struct tevent_req);
810 struct netlogon_creds_cli_lock_state *state =
811 tevent_req_data(req,
812 struct netlogon_creds_cli_lock_state);
813 NTSTATUS status;
815 status = g_lock_lock_recv(subreq);
816 TALLOC_FREE(subreq);
817 if (tevent_req_nterror(req, status)) {
818 return;
820 state->locked_state->is_glocked = true;
822 netlogon_creds_cli_lock_fetch(req);
825 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
827 struct netlogon_creds_cli_lock_state *state =
828 tevent_req_data(req,
829 struct netlogon_creds_cli_lock_state);
830 struct netlogon_creds_cli_context *context = state->locked_state->context;
831 struct netlogon_creds_cli_fetch_state fstate = {
832 .status = NT_STATUS_INTERNAL_ERROR,
833 .required_flags = context->client.required_flags,
835 NTSTATUS status;
837 fstate.mem_ctx = state;
838 status = dbwrap_parse_record(context->db.ctx,
839 context->db.key_data,
840 netlogon_creds_cli_fetch_parser,
841 &fstate);
842 if (tevent_req_nterror(req, status)) {
843 return;
845 status = fstate.status;
846 if (tevent_req_nterror(req, status)) {
847 return;
850 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
851 state->creds = fstate.creds;
852 tevent_req_done(req);
853 return;
856 context->server.cached_flags = fstate.creds->negotiate_flags;
857 context->server.try_validation6 = true;
858 context->server.try_logon_ex = true;
859 context->server.try_logon_with = true;
861 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
862 context->server.try_validation6 = false;
863 context->server.try_logon_ex = false;
865 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
866 context->server.try_validation6 = false;
869 state->creds = fstate.creds;
870 tevent_req_done(req);
871 return;
874 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
875 TALLOC_CTX *mem_ctx,
876 struct netlogon_creds_CredentialState **creds)
878 struct netlogon_creds_cli_lock_state *state =
879 tevent_req_data(req,
880 struct netlogon_creds_cli_lock_state);
881 NTSTATUS status;
883 if (tevent_req_is_nterror(req, &status)) {
884 tevent_req_received(req);
885 return status;
888 talloc_steal(state->creds, state->locked_state);
889 state->locked_state->creds = state->creds;
890 *creds = talloc_move(mem_ctx, &state->creds);
891 tevent_req_received(req);
892 return NT_STATUS_OK;
895 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
896 TALLOC_CTX *mem_ctx,
897 struct netlogon_creds_CredentialState **creds)
899 TALLOC_CTX *frame = talloc_stackframe();
900 struct tevent_context *ev;
901 struct tevent_req *req;
902 NTSTATUS status = NT_STATUS_NO_MEMORY;
904 ev = samba_tevent_context_init(frame);
905 if (ev == NULL) {
906 goto fail;
908 req = netlogon_creds_cli_lock_send(frame, ev, context);
909 if (req == NULL) {
910 goto fail;
912 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
913 goto fail;
915 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
916 fail:
917 TALLOC_FREE(frame);
918 return status;
921 struct netlogon_creds_cli_auth_state {
922 struct tevent_context *ev;
923 struct netlogon_creds_cli_context *context;
924 struct dcerpc_binding_handle *binding_handle;
925 uint8_t num_nt_hashes;
926 uint8_t idx_nt_hashes;
927 const struct samr_Password * const *nt_hashes;
928 const struct samr_Password *used_nt_hash;
929 char *srv_name_slash;
930 uint32_t current_flags;
931 struct netr_Credential client_challenge;
932 struct netr_Credential server_challenge;
933 struct netlogon_creds_CredentialState *creds;
934 struct netr_Credential client_credential;
935 struct netr_Credential server_credential;
936 uint32_t rid;
937 bool try_auth3;
938 bool try_auth2;
939 bool require_auth2;
940 struct netlogon_creds_cli_locked_state *locked_state;
943 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
944 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
946 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
947 struct tevent_context *ev,
948 struct netlogon_creds_cli_context *context,
949 struct dcerpc_binding_handle *b,
950 uint8_t num_nt_hashes,
951 const struct samr_Password * const *nt_hashes)
953 struct tevent_req *req;
954 struct netlogon_creds_cli_auth_state *state;
955 struct netlogon_creds_cli_locked_state *locked_state;
956 NTSTATUS status;
958 req = tevent_req_create(mem_ctx, &state,
959 struct netlogon_creds_cli_auth_state);
960 if (req == NULL) {
961 return NULL;
964 state->ev = ev;
965 state->context = context;
966 state->binding_handle = b;
967 if (num_nt_hashes < 1) {
968 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
969 return tevent_req_post(req, ev);
971 if (num_nt_hashes > 4) {
972 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
973 return tevent_req_post(req, ev);
976 state->num_nt_hashes = num_nt_hashes;
977 state->idx_nt_hashes = 0;
978 state->nt_hashes = nt_hashes;
980 if (context->db.locked_state != NULL) {
981 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
982 return tevent_req_post(req, ev);
985 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
986 if (tevent_req_nomem(locked_state, req)) {
987 return tevent_req_post(req, ev);
989 talloc_set_destructor(locked_state,
990 netlogon_creds_cli_locked_state_destructor);
991 locked_state->context = context;
993 context->db.locked_state = locked_state;
994 state->locked_state = locked_state;
996 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
997 context->server.computer);
998 if (tevent_req_nomem(state->srv_name_slash, req)) {
999 return tevent_req_post(req, ev);
1002 state->try_auth3 = true;
1003 state->try_auth2 = true;
1005 if (context->client.required_flags != 0) {
1006 state->require_auth2 = true;
1009 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1010 state->current_flags = context->client.proposed_flags;
1012 if (context->db.g_ctx != NULL) {
1013 struct tevent_req *subreq;
1015 subreq = g_lock_lock_send(state, ev,
1016 context->db.g_ctx,
1017 context->db.key_name,
1018 G_LOCK_WRITE);
1019 if (tevent_req_nomem(subreq, req)) {
1020 return tevent_req_post(req, ev);
1022 tevent_req_set_callback(subreq,
1023 netlogon_creds_cli_auth_locked,
1024 req);
1026 return req;
1029 status = dbwrap_purge(state->context->db.ctx,
1030 state->context->db.key_data);
1031 if (tevent_req_nterror(req, status)) {
1032 return tevent_req_post(req, ev);
1035 netlogon_creds_cli_auth_challenge_start(req);
1036 if (!tevent_req_is_in_progress(req)) {
1037 return tevent_req_post(req, ev);
1040 return req;
1043 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1045 struct tevent_req *req =
1046 tevent_req_callback_data(subreq,
1047 struct tevent_req);
1048 struct netlogon_creds_cli_auth_state *state =
1049 tevent_req_data(req,
1050 struct netlogon_creds_cli_auth_state);
1051 NTSTATUS status;
1053 status = g_lock_lock_recv(subreq);
1054 TALLOC_FREE(subreq);
1055 if (tevent_req_nterror(req, status)) {
1056 return;
1058 state->locked_state->is_glocked = true;
1060 status = dbwrap_purge(state->context->db.ctx,
1061 state->context->db.key_data);
1062 if (tevent_req_nterror(req, status)) {
1063 return;
1066 netlogon_creds_cli_auth_challenge_start(req);
1069 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1071 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1073 struct netlogon_creds_cli_auth_state *state =
1074 tevent_req_data(req,
1075 struct netlogon_creds_cli_auth_state);
1076 struct tevent_req *subreq;
1078 TALLOC_FREE(state->creds);
1080 generate_random_buffer(state->client_challenge.data,
1081 sizeof(state->client_challenge.data));
1083 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1084 state->binding_handle,
1085 state->srv_name_slash,
1086 state->context->client.computer,
1087 &state->client_challenge,
1088 &state->server_challenge);
1089 if (tevent_req_nomem(subreq, req)) {
1090 return;
1092 tevent_req_set_callback(subreq,
1093 netlogon_creds_cli_auth_challenge_done,
1094 req);
1097 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1099 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1101 struct tevent_req *req =
1102 tevent_req_callback_data(subreq,
1103 struct tevent_req);
1104 struct netlogon_creds_cli_auth_state *state =
1105 tevent_req_data(req,
1106 struct netlogon_creds_cli_auth_state);
1107 NTSTATUS status;
1108 NTSTATUS result;
1110 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1111 TALLOC_FREE(subreq);
1112 if (tevent_req_nterror(req, status)) {
1113 return;
1115 if (tevent_req_nterror(req, result)) {
1116 return;
1119 if (!state->try_auth3 && !state->try_auth2) {
1120 state->current_flags = 0;
1123 /* Calculate the session key and client credentials */
1125 state->creds = netlogon_creds_client_init(state,
1126 state->context->client.account,
1127 state->context->client.computer,
1128 state->context->client.type,
1129 &state->client_challenge,
1130 &state->server_challenge,
1131 state->used_nt_hash,
1132 &state->client_credential,
1133 state->current_flags);
1134 if (tevent_req_nomem(state->creds, req)) {
1135 return;
1138 if (state->try_auth3) {
1139 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1140 state->binding_handle,
1141 state->srv_name_slash,
1142 state->context->client.account,
1143 state->context->client.type,
1144 state->context->client.computer,
1145 &state->client_credential,
1146 &state->server_credential,
1147 &state->creds->negotiate_flags,
1148 &state->rid);
1149 if (tevent_req_nomem(subreq, req)) {
1150 return;
1152 } else if (state->try_auth2) {
1153 state->rid = 0;
1155 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1156 state->binding_handle,
1157 state->srv_name_slash,
1158 state->context->client.account,
1159 state->context->client.type,
1160 state->context->client.computer,
1161 &state->client_credential,
1162 &state->server_credential,
1163 &state->creds->negotiate_flags);
1164 if (tevent_req_nomem(subreq, req)) {
1165 return;
1167 } else {
1168 state->rid = 0;
1170 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1171 state->binding_handle,
1172 state->srv_name_slash,
1173 state->context->client.account,
1174 state->context->client.type,
1175 state->context->client.computer,
1176 &state->client_credential,
1177 &state->server_credential);
1178 if (tevent_req_nomem(subreq, req)) {
1179 return;
1182 tevent_req_set_callback(subreq,
1183 netlogon_creds_cli_auth_srvauth_done,
1184 req);
1187 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1189 struct tevent_req *req =
1190 tevent_req_callback_data(subreq,
1191 struct tevent_req);
1192 struct netlogon_creds_cli_auth_state *state =
1193 tevent_req_data(req,
1194 struct netlogon_creds_cli_auth_state);
1195 NTSTATUS status;
1196 NTSTATUS result;
1197 bool ok;
1198 enum ndr_err_code ndr_err;
1199 DATA_BLOB blob;
1200 TDB_DATA data;
1201 uint32_t tmp_flags;
1203 if (state->try_auth3) {
1204 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1205 &result);
1206 TALLOC_FREE(subreq);
1207 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1208 state->try_auth3 = false;
1209 netlogon_creds_cli_auth_challenge_start(req);
1210 return;
1212 if (tevent_req_nterror(req, status)) {
1213 return;
1215 } else if (state->try_auth2) {
1216 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1217 &result);
1218 TALLOC_FREE(subreq);
1219 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1220 state->try_auth2 = false;
1221 if (state->require_auth2) {
1222 status = NT_STATUS_DOWNGRADE_DETECTED;
1223 tevent_req_nterror(req, status);
1224 return;
1226 netlogon_creds_cli_auth_challenge_start(req);
1227 return;
1229 if (tevent_req_nterror(req, status)) {
1230 return;
1232 } else {
1233 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1234 &result);
1235 TALLOC_FREE(subreq);
1236 if (tevent_req_nterror(req, status)) {
1237 return;
1241 if (!NT_STATUS_IS_OK(result) &&
1242 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1244 tevent_req_nterror(req, result);
1245 return;
1248 tmp_flags = state->creds->negotiate_flags;
1249 tmp_flags &= state->context->client.required_flags;
1250 if (tmp_flags != state->context->client.required_flags) {
1251 if (NT_STATUS_IS_OK(result)) {
1252 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1253 return;
1255 tevent_req_nterror(req, result);
1256 return;
1259 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1261 tmp_flags = state->context->client.proposed_flags;
1262 if ((state->current_flags == tmp_flags) &&
1263 (state->creds->negotiate_flags != tmp_flags))
1266 * lets retry with the negotiated flags
1268 state->current_flags = state->creds->negotiate_flags;
1269 netlogon_creds_cli_auth_challenge_start(req);
1270 return;
1273 state->idx_nt_hashes += 1;
1274 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1276 * we already retried, giving up...
1278 tevent_req_nterror(req, result);
1279 return;
1283 * lets retry with the old nt hash.
1285 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1286 state->current_flags = state->context->client.proposed_flags;
1287 netlogon_creds_cli_auth_challenge_start(req);
1288 return;
1291 ok = netlogon_creds_client_check(state->creds,
1292 &state->server_credential);
1293 if (!ok) {
1294 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1295 return;
1298 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1299 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1300 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1301 status = ndr_map_error2ntstatus(ndr_err);
1302 tevent_req_nterror(req, status);
1303 return;
1306 data.dptr = blob.data;
1307 data.dsize = blob.length;
1309 status = dbwrap_store(state->context->db.ctx,
1310 state->context->db.key_data,
1311 data, TDB_REPLACE);
1312 TALLOC_FREE(state->locked_state);
1313 if (tevent_req_nterror(req, status)) {
1314 return;
1317 tevent_req_done(req);
1320 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1321 uint8_t *idx_nt_hashes)
1323 struct netlogon_creds_cli_auth_state *state =
1324 tevent_req_data(req,
1325 struct netlogon_creds_cli_auth_state);
1326 NTSTATUS status;
1328 *idx_nt_hashes = 0;
1330 if (tevent_req_is_nterror(req, &status)) {
1331 tevent_req_received(req);
1332 return status;
1335 *idx_nt_hashes = state->idx_nt_hashes;
1336 tevent_req_received(req);
1337 return NT_STATUS_OK;
1340 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1341 struct dcerpc_binding_handle *b,
1342 uint8_t num_nt_hashes,
1343 const struct samr_Password * const *nt_hashes,
1344 uint8_t *idx_nt_hashes)
1346 TALLOC_CTX *frame = talloc_stackframe();
1347 struct tevent_context *ev;
1348 struct tevent_req *req;
1349 NTSTATUS status = NT_STATUS_NO_MEMORY;
1351 *idx_nt_hashes = 0;
1353 ev = samba_tevent_context_init(frame);
1354 if (ev == NULL) {
1355 goto fail;
1357 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1358 num_nt_hashes, nt_hashes);
1359 if (req == NULL) {
1360 goto fail;
1362 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1363 goto fail;
1365 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1366 fail:
1367 TALLOC_FREE(frame);
1368 return status;
1371 struct netlogon_creds_cli_check_state {
1372 struct tevent_context *ev;
1373 struct netlogon_creds_cli_context *context;
1374 struct dcerpc_binding_handle *binding_handle;
1376 char *srv_name_slash;
1378 union netr_Capabilities caps;
1380 struct netlogon_creds_CredentialState *creds;
1381 struct netlogon_creds_CredentialState tmp_creds;
1382 struct netr_Authenticator req_auth;
1383 struct netr_Authenticator rep_auth;
1386 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1387 NTSTATUS status);
1388 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1390 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1391 struct tevent_context *ev,
1392 struct netlogon_creds_cli_context *context,
1393 struct dcerpc_binding_handle *b)
1395 struct tevent_req *req;
1396 struct netlogon_creds_cli_check_state *state;
1397 struct tevent_req *subreq;
1398 enum dcerpc_AuthType auth_type;
1399 enum dcerpc_AuthLevel auth_level;
1401 req = tevent_req_create(mem_ctx, &state,
1402 struct netlogon_creds_cli_check_state);
1403 if (req == NULL) {
1404 return NULL;
1407 state->ev = ev;
1408 state->context = context;
1409 state->binding_handle = b;
1411 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1412 context->server.computer);
1413 if (tevent_req_nomem(state->srv_name_slash, req)) {
1414 return tevent_req_post(req, ev);
1417 dcerpc_binding_handle_auth_info(state->binding_handle,
1418 &auth_type, &auth_level);
1420 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1421 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1422 return tevent_req_post(req, ev);
1425 switch (auth_level) {
1426 case DCERPC_AUTH_LEVEL_INTEGRITY:
1427 case DCERPC_AUTH_LEVEL_PRIVACY:
1428 break;
1429 default:
1430 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1431 return tevent_req_post(req, ev);
1434 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1435 state->context);
1436 if (tevent_req_nomem(subreq, req)) {
1437 return tevent_req_post(req, ev);
1440 tevent_req_set_callback(subreq,
1441 netlogon_creds_cli_check_locked,
1442 req);
1444 return req;
1447 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1448 NTSTATUS status)
1450 struct netlogon_creds_cli_check_state *state =
1451 tevent_req_data(req,
1452 struct netlogon_creds_cli_check_state);
1454 if (state->creds == NULL) {
1455 return;
1458 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1459 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1460 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1461 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1462 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1463 TALLOC_FREE(state->creds);
1464 return;
1467 netlogon_creds_cli_delete(state->context, state->creds);
1468 TALLOC_FREE(state->creds);
1471 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1473 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1475 struct tevent_req *req =
1476 tevent_req_callback_data(subreq,
1477 struct tevent_req);
1478 struct netlogon_creds_cli_check_state *state =
1479 tevent_req_data(req,
1480 struct netlogon_creds_cli_check_state);
1481 NTSTATUS status;
1483 status = netlogon_creds_cli_lock_recv(subreq, state,
1484 &state->creds);
1485 TALLOC_FREE(subreq);
1486 if (tevent_req_nterror(req, status)) {
1487 return;
1491 * we defer all callbacks in order to cleanup
1492 * the database record.
1494 tevent_req_defer_callback(req, state->ev);
1496 state->tmp_creds = *state->creds;
1497 netlogon_creds_client_authenticator(&state->tmp_creds,
1498 &state->req_auth);
1499 ZERO_STRUCT(state->rep_auth);
1501 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1502 state->binding_handle,
1503 state->srv_name_slash,
1504 state->context->client.computer,
1505 &state->req_auth,
1506 &state->rep_auth,
1508 &state->caps);
1509 if (tevent_req_nomem(subreq, req)) {
1510 status = NT_STATUS_NO_MEMORY;
1511 netlogon_creds_cli_check_cleanup(req, status);
1512 return;
1514 tevent_req_set_callback(subreq,
1515 netlogon_creds_cli_check_caps,
1516 req);
1519 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1521 struct tevent_req *req =
1522 tevent_req_callback_data(subreq,
1523 struct tevent_req);
1524 struct netlogon_creds_cli_check_state *state =
1525 tevent_req_data(req,
1526 struct netlogon_creds_cli_check_state);
1527 NTSTATUS status;
1528 NTSTATUS result;
1529 bool ok;
1531 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1532 &result);
1533 TALLOC_FREE(subreq);
1534 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1536 * Note that the negotiated flags are already checked
1537 * for our required flags after the ServerAuthenticate3/2 call.
1539 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1541 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1543 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1544 * already, we expect this to work!
1546 status = NT_STATUS_DOWNGRADE_DETECTED;
1547 tevent_req_nterror(req, status);
1548 netlogon_creds_cli_check_cleanup(req, status);
1549 return;
1552 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1554 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1555 * we expect this to work at least as far as the
1556 * NOT_SUPPORTED error handled below!
1558 * NT 4.0 and Old Samba servers are not
1559 * allowed without "require strong key = no"
1561 status = NT_STATUS_DOWNGRADE_DETECTED;
1562 tevent_req_nterror(req, status);
1563 netlogon_creds_cli_check_cleanup(req, status);
1564 return;
1568 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1569 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1570 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1572 * This is needed against NT 4.0 and old Samba servers.
1574 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1575 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1576 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1577 * with the next request as the sequence number processing
1578 * gets out of sync.
1580 netlogon_creds_cli_check_cleanup(req, status);
1581 tevent_req_done(req);
1582 return;
1584 if (tevent_req_nterror(req, status)) {
1585 netlogon_creds_cli_check_cleanup(req, status);
1586 return;
1589 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1591 * Note that the negotiated flags are already checked
1592 * for our required flags after the ServerAuthenticate3/2 call.
1594 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1596 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1598 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1599 * already, we expect this to work!
1601 status = NT_STATUS_DOWNGRADE_DETECTED;
1602 tevent_req_nterror(req, status);
1603 netlogon_creds_cli_check_cleanup(req, status);
1604 return;
1608 * This is ok, the server does not support
1609 * NETLOGON_NEG_SUPPORTS_AES.
1611 * netr_LogonGetCapabilities() was
1612 * netr_LogonDummyRoutine1() before
1613 * NETLOGON_NEG_SUPPORTS_AES was invented.
1615 netlogon_creds_cli_check_cleanup(req, result);
1616 tevent_req_done(req);
1617 return;
1620 ok = netlogon_creds_client_check(&state->tmp_creds,
1621 &state->rep_auth.cred);
1622 if (!ok) {
1623 status = NT_STATUS_ACCESS_DENIED;
1624 tevent_req_nterror(req, status);
1625 netlogon_creds_cli_check_cleanup(req, status);
1626 return;
1629 if (tevent_req_nterror(req, result)) {
1630 netlogon_creds_cli_check_cleanup(req, result);
1631 return;
1634 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1635 status = NT_STATUS_DOWNGRADE_DETECTED;
1636 tevent_req_nterror(req, status);
1637 netlogon_creds_cli_check_cleanup(req, status);
1638 return;
1642 * This is the key check that makes this check secure. If we
1643 * get OK here (rather than NOT_SUPPORTED), then the server
1644 * did support AES. If the server only proposed STRONG_KEYS
1645 * and not AES, then it should have failed with
1646 * NOT_IMPLEMENTED. We always send AES as a client, so the
1647 * server should always have returned it.
1649 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1650 status = NT_STATUS_DOWNGRADE_DETECTED;
1651 tevent_req_nterror(req, status);
1652 netlogon_creds_cli_check_cleanup(req, status);
1653 return;
1656 *state->creds = state->tmp_creds;
1657 status = netlogon_creds_cli_store(state->context,
1658 state->creds);
1659 TALLOC_FREE(state->creds);
1660 if (tevent_req_nterror(req, status)) {
1661 return;
1664 tevent_req_done(req);
1667 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1669 NTSTATUS status;
1671 if (tevent_req_is_nterror(req, &status)) {
1672 netlogon_creds_cli_check_cleanup(req, status);
1673 tevent_req_received(req);
1674 return status;
1677 tevent_req_received(req);
1678 return NT_STATUS_OK;
1681 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1682 struct dcerpc_binding_handle *b)
1684 TALLOC_CTX *frame = talloc_stackframe();
1685 struct tevent_context *ev;
1686 struct tevent_req *req;
1687 NTSTATUS status = NT_STATUS_NO_MEMORY;
1689 ev = samba_tevent_context_init(frame);
1690 if (ev == NULL) {
1691 goto fail;
1693 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1694 if (req == NULL) {
1695 goto fail;
1697 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1698 goto fail;
1700 status = netlogon_creds_cli_check_recv(req);
1701 fail:
1702 TALLOC_FREE(frame);
1703 return status;
1706 struct netlogon_creds_cli_ServerPasswordSet_state {
1707 struct tevent_context *ev;
1708 struct netlogon_creds_cli_context *context;
1709 struct dcerpc_binding_handle *binding_handle;
1710 uint32_t old_timeout;
1712 char *srv_name_slash;
1713 enum dcerpc_AuthType auth_type;
1714 enum dcerpc_AuthLevel auth_level;
1716 struct samr_CryptPassword samr_crypt_password;
1717 struct netr_CryptPassword netr_crypt_password;
1718 struct samr_Password samr_password;
1720 struct netlogon_creds_CredentialState *creds;
1721 struct netlogon_creds_CredentialState tmp_creds;
1722 struct netr_Authenticator req_auth;
1723 struct netr_Authenticator rep_auth;
1726 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1727 NTSTATUS status);
1728 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1730 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1731 struct tevent_context *ev,
1732 struct netlogon_creds_cli_context *context,
1733 struct dcerpc_binding_handle *b,
1734 const DATA_BLOB *new_password,
1735 const uint32_t *new_version)
1737 struct tevent_req *req;
1738 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1739 struct tevent_req *subreq;
1740 bool ok;
1742 req = tevent_req_create(mem_ctx, &state,
1743 struct netlogon_creds_cli_ServerPasswordSet_state);
1744 if (req == NULL) {
1745 return NULL;
1748 state->ev = ev;
1749 state->context = context;
1750 state->binding_handle = b;
1752 if (new_password->length < 14) {
1753 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1754 return tevent_req_post(req, ev);
1758 * netr_ServerPasswordSet
1760 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1763 * netr_ServerPasswordSet2
1765 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1766 new_password);
1767 if (!ok) {
1768 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1769 return tevent_req_post(req, ev);
1772 if (new_version != NULL) {
1773 struct NL_PASSWORD_VERSION version;
1774 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1775 uint32_t ofs = 512 - len;
1776 uint8_t *p;
1778 if (len > 500) {
1779 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1780 return tevent_req_post(req, ev);
1782 ofs -= 12;
1784 version.ReservedField = 0;
1785 version.PasswordVersionNumber = *new_version;
1786 version.PasswordVersionPresent =
1787 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1789 p = state->samr_crypt_password.data + ofs;
1790 SIVAL(p, 0, version.ReservedField);
1791 SIVAL(p, 4, version.PasswordVersionNumber);
1792 SIVAL(p, 8, version.PasswordVersionPresent);
1795 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1796 context->server.computer);
1797 if (tevent_req_nomem(state->srv_name_slash, req)) {
1798 return tevent_req_post(req, ev);
1801 dcerpc_binding_handle_auth_info(state->binding_handle,
1802 &state->auth_type,
1803 &state->auth_level);
1805 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1806 state->context);
1807 if (tevent_req_nomem(subreq, req)) {
1808 return tevent_req_post(req, ev);
1811 tevent_req_set_callback(subreq,
1812 netlogon_creds_cli_ServerPasswordSet_locked,
1813 req);
1815 return req;
1818 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1819 NTSTATUS status)
1821 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1822 tevent_req_data(req,
1823 struct netlogon_creds_cli_ServerPasswordSet_state);
1825 if (state->creds == NULL) {
1826 return;
1829 dcerpc_binding_handle_set_timeout(state->binding_handle,
1830 state->old_timeout);
1832 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1833 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1834 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1835 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1836 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1837 TALLOC_FREE(state->creds);
1838 return;
1841 netlogon_creds_cli_delete(state->context, state->creds);
1842 TALLOC_FREE(state->creds);
1845 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1847 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1849 struct tevent_req *req =
1850 tevent_req_callback_data(subreq,
1851 struct tevent_req);
1852 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1853 tevent_req_data(req,
1854 struct netlogon_creds_cli_ServerPasswordSet_state);
1855 NTSTATUS status;
1857 status = netlogon_creds_cli_lock_recv(subreq, state,
1858 &state->creds);
1859 TALLOC_FREE(subreq);
1860 if (tevent_req_nterror(req, status)) {
1861 return;
1864 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1865 switch (state->auth_level) {
1866 case DCERPC_AUTH_LEVEL_INTEGRITY:
1867 case DCERPC_AUTH_LEVEL_PRIVACY:
1868 break;
1869 default:
1870 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1871 return;
1873 } else {
1874 uint32_t tmp = state->creds->negotiate_flags;
1876 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1878 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1879 * it should be used, which means
1880 * we had a chance to verify no downgrade
1881 * happened.
1883 * This relies on netlogon_creds_cli_check*
1884 * being called before, as first request after
1885 * the DCERPC bind.
1887 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1888 return;
1892 state->old_timeout = dcerpc_binding_handle_set_timeout(
1893 state->binding_handle, 600000);
1896 * we defer all callbacks in order to cleanup
1897 * the database record.
1899 tevent_req_defer_callback(req, state->ev);
1901 state->tmp_creds = *state->creds;
1902 netlogon_creds_client_authenticator(&state->tmp_creds,
1903 &state->req_auth);
1904 ZERO_STRUCT(state->rep_auth);
1906 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1908 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1909 netlogon_creds_aes_encrypt(&state->tmp_creds,
1910 state->samr_crypt_password.data,
1911 516);
1912 } else {
1913 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1914 state->samr_crypt_password.data,
1915 516);
1918 memcpy(state->netr_crypt_password.data,
1919 state->samr_crypt_password.data, 512);
1920 state->netr_crypt_password.length =
1921 IVAL(state->samr_crypt_password.data, 512);
1923 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1924 state->binding_handle,
1925 state->srv_name_slash,
1926 state->tmp_creds.account_name,
1927 state->tmp_creds.secure_channel_type,
1928 state->tmp_creds.computer_name,
1929 &state->req_auth,
1930 &state->rep_auth,
1931 &state->netr_crypt_password);
1932 if (tevent_req_nomem(subreq, req)) {
1933 status = NT_STATUS_NO_MEMORY;
1934 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1935 return;
1937 } else {
1938 netlogon_creds_des_encrypt(&state->tmp_creds,
1939 &state->samr_password);
1941 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1942 state->binding_handle,
1943 state->srv_name_slash,
1944 state->tmp_creds.account_name,
1945 state->tmp_creds.secure_channel_type,
1946 state->tmp_creds.computer_name,
1947 &state->req_auth,
1948 &state->rep_auth,
1949 &state->samr_password);
1950 if (tevent_req_nomem(subreq, req)) {
1951 status = NT_STATUS_NO_MEMORY;
1952 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1953 return;
1957 tevent_req_set_callback(subreq,
1958 netlogon_creds_cli_ServerPasswordSet_done,
1959 req);
1962 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1964 struct tevent_req *req =
1965 tevent_req_callback_data(subreq,
1966 struct tevent_req);
1967 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1968 tevent_req_data(req,
1969 struct netlogon_creds_cli_ServerPasswordSet_state);
1970 NTSTATUS status;
1971 NTSTATUS result;
1972 bool ok;
1974 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1975 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1976 &result);
1977 TALLOC_FREE(subreq);
1978 if (tevent_req_nterror(req, status)) {
1979 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1980 return;
1982 } else {
1983 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1984 &result);
1985 TALLOC_FREE(subreq);
1986 if (tevent_req_nterror(req, status)) {
1987 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1988 return;
1992 ok = netlogon_creds_client_check(&state->tmp_creds,
1993 &state->rep_auth.cred);
1994 if (!ok) {
1995 status = NT_STATUS_ACCESS_DENIED;
1996 tevent_req_nterror(req, status);
1997 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1998 return;
2001 if (tevent_req_nterror(req, result)) {
2002 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2003 return;
2006 dcerpc_binding_handle_set_timeout(state->binding_handle,
2007 state->old_timeout);
2009 *state->creds = state->tmp_creds;
2010 status = netlogon_creds_cli_store(state->context,
2011 state->creds);
2012 TALLOC_FREE(state->creds);
2013 if (tevent_req_nterror(req, status)) {
2014 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2015 return;
2018 tevent_req_done(req);
2021 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2023 NTSTATUS status;
2025 if (tevent_req_is_nterror(req, &status)) {
2026 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2027 tevent_req_received(req);
2028 return status;
2031 tevent_req_received(req);
2032 return NT_STATUS_OK;
2035 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2036 struct netlogon_creds_cli_context *context,
2037 struct dcerpc_binding_handle *b,
2038 const DATA_BLOB *new_password,
2039 const uint32_t *new_version)
2041 TALLOC_CTX *frame = talloc_stackframe();
2042 struct tevent_context *ev;
2043 struct tevent_req *req;
2044 NTSTATUS status = NT_STATUS_NO_MEMORY;
2046 ev = samba_tevent_context_init(frame);
2047 if (ev == NULL) {
2048 goto fail;
2050 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2051 new_password,
2052 new_version);
2053 if (req == NULL) {
2054 goto fail;
2056 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2057 goto fail;
2059 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2060 fail:
2061 TALLOC_FREE(frame);
2062 return status;
2065 struct netlogon_creds_cli_LogonSamLogon_state {
2066 struct tevent_context *ev;
2067 struct netlogon_creds_cli_context *context;
2068 struct dcerpc_binding_handle *binding_handle;
2070 char *srv_name_slash;
2072 enum netr_LogonInfoClass logon_level;
2073 const union netr_LogonLevel *const_logon;
2074 union netr_LogonLevel *logon;
2075 uint32_t flags;
2077 uint16_t validation_level;
2078 union netr_Validation *validation;
2079 uint8_t authoritative;
2082 * do we need encryption at the application layer?
2084 bool user_encrypt;
2085 bool try_logon_ex;
2086 bool try_validation6;
2089 * the read only credentials before we started the operation
2090 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2092 struct netlogon_creds_CredentialState *ro_creds;
2095 * The (locked) credentials used for the credential chain
2096 * used for netr_LogonSamLogonWithFlags() or
2097 * netr_LogonSamLogonWith().
2099 struct netlogon_creds_CredentialState *lk_creds;
2102 * While we have locked the global credentials (lk_creds above)
2103 * we operate an a temporary copy, because a server
2104 * may not support netr_LogonSamLogonWithFlags() and
2105 * didn't process our netr_Authenticator, so we need to
2106 * restart from lk_creds.
2108 struct netlogon_creds_CredentialState tmp_creds;
2109 struct netr_Authenticator req_auth;
2110 struct netr_Authenticator rep_auth;
2113 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2114 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2115 NTSTATUS status);
2117 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2118 struct tevent_context *ev,
2119 struct netlogon_creds_cli_context *context,
2120 struct dcerpc_binding_handle *b,
2121 enum netr_LogonInfoClass logon_level,
2122 const union netr_LogonLevel *logon,
2123 uint32_t flags)
2125 struct tevent_req *req;
2126 struct netlogon_creds_cli_LogonSamLogon_state *state;
2128 req = tevent_req_create(mem_ctx, &state,
2129 struct netlogon_creds_cli_LogonSamLogon_state);
2130 if (req == NULL) {
2131 return NULL;
2134 state->ev = ev;
2135 state->context = context;
2136 state->binding_handle = b;
2138 state->logon_level = logon_level;
2139 state->const_logon = logon;
2140 state->flags = flags;
2142 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2143 context->server.computer);
2144 if (tevent_req_nomem(state->srv_name_slash, req)) {
2145 return tevent_req_post(req, ev);
2148 switch (logon_level) {
2149 case NetlogonInteractiveInformation:
2150 case NetlogonInteractiveTransitiveInformation:
2151 case NetlogonServiceInformation:
2152 case NetlogonServiceTransitiveInformation:
2153 case NetlogonGenericInformation:
2154 state->user_encrypt = true;
2155 break;
2157 case NetlogonNetworkInformation:
2158 case NetlogonNetworkTransitiveInformation:
2159 break;
2162 state->validation = talloc_zero(state, union netr_Validation);
2163 if (tevent_req_nomem(state->validation, req)) {
2164 return tevent_req_post(req, ev);
2167 netlogon_creds_cli_LogonSamLogon_start(req);
2168 if (!tevent_req_is_in_progress(req)) {
2169 return tevent_req_post(req, ev);
2173 * we defer all callbacks in order to cleanup
2174 * the database record.
2176 tevent_req_defer_callback(req, state->ev);
2177 return req;
2180 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2181 NTSTATUS status)
2183 struct netlogon_creds_cli_LogonSamLogon_state *state =
2184 tevent_req_data(req,
2185 struct netlogon_creds_cli_LogonSamLogon_state);
2187 if (state->lk_creds == NULL) {
2188 return;
2191 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2193 * This is a hack to recover from a bug in old
2194 * Samba servers, when LogonSamLogonEx() fails:
2196 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2198 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2200 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2201 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2202 * If the sign/seal check fails.
2204 * In that case we need to cleanup the netlogon session.
2206 * It's the job of the caller to disconnect the current
2207 * connection, if netlogon_creds_cli_LogonSamLogon()
2208 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2210 if (!state->context->server.try_logon_with) {
2211 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2215 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2216 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2217 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2218 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2219 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2220 TALLOC_FREE(state->lk_creds);
2221 return;
2224 netlogon_creds_cli_delete(state->context, state->lk_creds);
2225 TALLOC_FREE(state->lk_creds);
2228 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2230 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2232 struct netlogon_creds_cli_LogonSamLogon_state *state =
2233 tevent_req_data(req,
2234 struct netlogon_creds_cli_LogonSamLogon_state);
2235 struct tevent_req *subreq;
2236 NTSTATUS status;
2237 enum dcerpc_AuthType auth_type;
2238 enum dcerpc_AuthLevel auth_level;
2240 TALLOC_FREE(state->ro_creds);
2241 TALLOC_FREE(state->logon);
2242 ZERO_STRUCTP(state->validation);
2244 dcerpc_binding_handle_auth_info(state->binding_handle,
2245 &auth_type, &auth_level);
2247 state->try_logon_ex = state->context->server.try_logon_ex;
2248 state->try_validation6 = state->context->server.try_validation6;
2250 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2251 state->try_logon_ex = false;
2254 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2255 state->try_validation6 = false;
2258 if (state->try_logon_ex) {
2259 if (state->try_validation6) {
2260 state->validation_level = 6;
2261 } else {
2262 state->validation_level = 3;
2263 state->user_encrypt = true;
2266 state->logon = netlogon_creds_shallow_copy_logon(state,
2267 state->logon_level,
2268 state->const_logon);
2269 if (tevent_req_nomem(state->logon, req)) {
2270 status = NT_STATUS_NO_MEMORY;
2271 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2272 return;
2275 if (state->user_encrypt) {
2276 status = netlogon_creds_cli_get(state->context,
2277 state,
2278 &state->ro_creds);
2279 if (!NT_STATUS_IS_OK(status)) {
2280 status = NT_STATUS_ACCESS_DENIED;
2281 tevent_req_nterror(req, status);
2282 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2283 return;
2286 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2287 state->logon_level,
2288 state->logon);
2291 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2292 state->binding_handle,
2293 state->srv_name_slash,
2294 state->context->client.computer,
2295 state->logon_level,
2296 state->logon,
2297 state->validation_level,
2298 state->validation,
2299 &state->authoritative,
2300 &state->flags);
2301 if (tevent_req_nomem(subreq, req)) {
2302 status = NT_STATUS_NO_MEMORY;
2303 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2304 return;
2306 tevent_req_set_callback(subreq,
2307 netlogon_creds_cli_LogonSamLogon_done,
2308 req);
2309 return;
2312 if (state->lk_creds == NULL) {
2313 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2314 state->context);
2315 if (tevent_req_nomem(subreq, req)) {
2316 status = NT_STATUS_NO_MEMORY;
2317 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2318 return;
2320 tevent_req_set_callback(subreq,
2321 netlogon_creds_cli_LogonSamLogon_done,
2322 req);
2323 return;
2326 state->tmp_creds = *state->lk_creds;
2327 netlogon_creds_client_authenticator(&state->tmp_creds,
2328 &state->req_auth);
2329 ZERO_STRUCT(state->rep_auth);
2331 state->logon = netlogon_creds_shallow_copy_logon(state,
2332 state->logon_level,
2333 state->const_logon);
2334 if (tevent_req_nomem(state->logon, req)) {
2335 status = NT_STATUS_NO_MEMORY;
2336 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2337 return;
2340 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2341 state->logon_level,
2342 state->logon);
2344 state->validation_level = 3;
2346 if (state->context->server.try_logon_with) {
2347 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2348 state->binding_handle,
2349 state->srv_name_slash,
2350 state->context->client.computer,
2351 &state->req_auth,
2352 &state->rep_auth,
2353 state->logon_level,
2354 state->logon,
2355 state->validation_level,
2356 state->validation,
2357 &state->authoritative,
2358 &state->flags);
2359 if (tevent_req_nomem(subreq, req)) {
2360 status = NT_STATUS_NO_MEMORY;
2361 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2362 return;
2364 } else {
2365 state->flags = 0;
2367 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2368 state->binding_handle,
2369 state->srv_name_slash,
2370 state->context->client.computer,
2371 &state->req_auth,
2372 &state->rep_auth,
2373 state->logon_level,
2374 state->logon,
2375 state->validation_level,
2376 state->validation,
2377 &state->authoritative);
2378 if (tevent_req_nomem(subreq, req)) {
2379 status = NT_STATUS_NO_MEMORY;
2380 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2381 return;
2385 tevent_req_set_callback(subreq,
2386 netlogon_creds_cli_LogonSamLogon_done,
2387 req);
2390 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2392 struct tevent_req *req =
2393 tevent_req_callback_data(subreq,
2394 struct tevent_req);
2395 struct netlogon_creds_cli_LogonSamLogon_state *state =
2396 tevent_req_data(req,
2397 struct netlogon_creds_cli_LogonSamLogon_state);
2398 NTSTATUS status;
2399 NTSTATUS result;
2400 bool ok;
2402 if (state->try_logon_ex) {
2403 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2404 state->validation,
2405 &result);
2406 TALLOC_FREE(subreq);
2407 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2408 state->context->server.try_validation6 = false;
2409 state->context->server.try_logon_ex = false;
2410 netlogon_creds_cli_LogonSamLogon_start(req);
2411 return;
2413 if (tevent_req_nterror(req, status)) {
2414 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2415 return;
2418 if ((state->validation_level == 6) &&
2419 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2420 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2421 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2423 state->context->server.try_validation6 = false;
2424 netlogon_creds_cli_LogonSamLogon_start(req);
2425 return;
2428 if (tevent_req_nterror(req, result)) {
2429 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2430 return;
2433 if (state->ro_creds == NULL) {
2434 tevent_req_done(req);
2435 return;
2438 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2439 if (!ok) {
2441 * We got a race, lets retry with on authenticator
2442 * protection.
2444 * netlogon_creds_cli_LogonSamLogon_start()
2445 * will TALLOC_FREE(state->ro_creds);
2447 state->try_logon_ex = false;
2448 netlogon_creds_cli_LogonSamLogon_start(req);
2449 return;
2452 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2453 state->validation_level,
2454 state->validation);
2456 tevent_req_done(req);
2457 return;
2460 if (state->lk_creds == NULL) {
2461 status = netlogon_creds_cli_lock_recv(subreq, state,
2462 &state->lk_creds);
2463 TALLOC_FREE(subreq);
2464 if (tevent_req_nterror(req, status)) {
2465 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2466 return;
2469 netlogon_creds_cli_LogonSamLogon_start(req);
2470 return;
2473 if (state->context->server.try_logon_with) {
2474 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2475 state->validation,
2476 &result);
2477 TALLOC_FREE(subreq);
2478 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2479 state->context->server.try_logon_with = false;
2480 netlogon_creds_cli_LogonSamLogon_start(req);
2481 return;
2483 if (tevent_req_nterror(req, status)) {
2484 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2485 return;
2487 } else {
2488 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2489 state->validation,
2490 &result);
2491 TALLOC_FREE(subreq);
2492 if (tevent_req_nterror(req, status)) {
2493 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2494 return;
2498 ok = netlogon_creds_client_check(&state->tmp_creds,
2499 &state->rep_auth.cred);
2500 if (!ok) {
2501 status = NT_STATUS_ACCESS_DENIED;
2502 tevent_req_nterror(req, status);
2503 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2504 return;
2507 *state->lk_creds = state->tmp_creds;
2508 status = netlogon_creds_cli_store(state->context,
2509 state->lk_creds);
2510 TALLOC_FREE(state->lk_creds);
2512 if (tevent_req_nterror(req, status)) {
2513 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2514 return;
2517 if (tevent_req_nterror(req, result)) {
2518 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2519 return;
2522 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2523 state->validation_level,
2524 state->validation);
2526 tevent_req_done(req);
2529 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2530 TALLOC_CTX *mem_ctx,
2531 uint16_t *validation_level,
2532 union netr_Validation **validation,
2533 uint8_t *authoritative,
2534 uint32_t *flags)
2536 struct netlogon_creds_cli_LogonSamLogon_state *state =
2537 tevent_req_data(req,
2538 struct netlogon_creds_cli_LogonSamLogon_state);
2539 NTSTATUS status;
2541 /* authoritative is also returned on error */
2542 *authoritative = state->authoritative;
2544 if (tevent_req_is_nterror(req, &status)) {
2545 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2546 tevent_req_received(req);
2547 return status;
2550 *validation_level = state->validation_level;
2551 *validation = talloc_move(mem_ctx, &state->validation);
2552 *flags = state->flags;
2554 tevent_req_received(req);
2555 return NT_STATUS_OK;
2558 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2559 struct netlogon_creds_cli_context *context,
2560 struct dcerpc_binding_handle *b,
2561 enum netr_LogonInfoClass logon_level,
2562 const union netr_LogonLevel *logon,
2563 TALLOC_CTX *mem_ctx,
2564 uint16_t *validation_level,
2565 union netr_Validation **validation,
2566 uint8_t *authoritative,
2567 uint32_t *flags)
2569 TALLOC_CTX *frame = talloc_stackframe();
2570 struct tevent_context *ev;
2571 struct tevent_req *req;
2572 NTSTATUS status = NT_STATUS_NO_MEMORY;
2574 ev = samba_tevent_context_init(frame);
2575 if (ev == NULL) {
2576 goto fail;
2578 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2579 logon_level, logon,
2580 *flags);
2581 if (req == NULL) {
2582 goto fail;
2584 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2585 goto fail;
2587 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2588 validation_level,
2589 validation,
2590 authoritative,
2591 flags);
2592 fail:
2593 TALLOC_FREE(frame);
2594 return status;
2597 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2598 struct tevent_context *ev;
2599 struct netlogon_creds_cli_context *context;
2600 struct dcerpc_binding_handle *binding_handle;
2602 char *srv_name_slash;
2603 enum dcerpc_AuthType auth_type;
2604 enum dcerpc_AuthLevel auth_level;
2606 const char *site_name;
2607 uint32_t dns_ttl;
2608 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2610 struct netlogon_creds_CredentialState *creds;
2611 struct netlogon_creds_CredentialState tmp_creds;
2612 struct netr_Authenticator req_auth;
2613 struct netr_Authenticator rep_auth;
2616 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2617 NTSTATUS status);
2618 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2620 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2621 struct tevent_context *ev,
2622 struct netlogon_creds_cli_context *context,
2623 struct dcerpc_binding_handle *b,
2624 const char *site_name,
2625 uint32_t dns_ttl,
2626 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2628 struct tevent_req *req;
2629 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2630 struct tevent_req *subreq;
2632 req = tevent_req_create(mem_ctx, &state,
2633 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2634 if (req == NULL) {
2635 return NULL;
2638 state->ev = ev;
2639 state->context = context;
2640 state->binding_handle = b;
2642 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2643 context->server.computer);
2644 if (tevent_req_nomem(state->srv_name_slash, req)) {
2645 return tevent_req_post(req, ev);
2648 state->site_name = site_name;
2649 state->dns_ttl = dns_ttl;
2650 state->dns_names = dns_names;
2652 dcerpc_binding_handle_auth_info(state->binding_handle,
2653 &state->auth_type,
2654 &state->auth_level);
2656 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2657 state->context);
2658 if (tevent_req_nomem(subreq, req)) {
2659 return tevent_req_post(req, ev);
2662 tevent_req_set_callback(subreq,
2663 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2664 req);
2666 return req;
2669 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2670 NTSTATUS status)
2672 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2673 tevent_req_data(req,
2674 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2676 if (state->creds == NULL) {
2677 return;
2680 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2681 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2682 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2683 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2684 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2685 TALLOC_FREE(state->creds);
2686 return;
2689 netlogon_creds_cli_delete(state->context, state->creds);
2690 TALLOC_FREE(state->creds);
2693 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2695 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2697 struct tevent_req *req =
2698 tevent_req_callback_data(subreq,
2699 struct tevent_req);
2700 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2701 tevent_req_data(req,
2702 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2703 NTSTATUS status;
2705 status = netlogon_creds_cli_lock_recv(subreq, state,
2706 &state->creds);
2707 TALLOC_FREE(subreq);
2708 if (tevent_req_nterror(req, status)) {
2709 return;
2712 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2713 switch (state->auth_level) {
2714 case DCERPC_AUTH_LEVEL_INTEGRITY:
2715 case DCERPC_AUTH_LEVEL_PRIVACY:
2716 break;
2717 default:
2718 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2719 return;
2721 } else {
2722 uint32_t tmp = state->creds->negotiate_flags;
2724 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2726 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2727 * it should be used, which means
2728 * we had a chance to verify no downgrade
2729 * happened.
2731 * This relies on netlogon_creds_cli_check*
2732 * being called before, as first request after
2733 * the DCERPC bind.
2735 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2736 return;
2741 * we defer all callbacks in order to cleanup
2742 * the database record.
2744 tevent_req_defer_callback(req, state->ev);
2746 state->tmp_creds = *state->creds;
2747 netlogon_creds_client_authenticator(&state->tmp_creds,
2748 &state->req_auth);
2749 ZERO_STRUCT(state->rep_auth);
2751 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2752 state->binding_handle,
2753 state->srv_name_slash,
2754 state->tmp_creds.computer_name,
2755 &state->req_auth,
2756 &state->rep_auth,
2757 state->site_name,
2758 state->dns_ttl,
2759 state->dns_names);
2760 if (tevent_req_nomem(subreq, req)) {
2761 status = NT_STATUS_NO_MEMORY;
2762 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2763 return;
2766 tevent_req_set_callback(subreq,
2767 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2768 req);
2771 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2773 struct tevent_req *req =
2774 tevent_req_callback_data(subreq,
2775 struct tevent_req);
2776 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2777 tevent_req_data(req,
2778 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2779 NTSTATUS status;
2780 NTSTATUS result;
2781 bool ok;
2784 * We use state->dns_names as the memory context, as this is
2785 * the only in/out variable and it has been overwritten by the
2786 * out parameter from the server.
2788 * We need to preserve the return value until the caller can use it.
2790 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2791 &result);
2792 TALLOC_FREE(subreq);
2793 if (tevent_req_nterror(req, status)) {
2794 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2795 return;
2798 ok = netlogon_creds_client_check(&state->tmp_creds,
2799 &state->rep_auth.cred);
2800 if (!ok) {
2801 status = NT_STATUS_ACCESS_DENIED;
2802 tevent_req_nterror(req, status);
2803 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2804 return;
2807 *state->creds = state->tmp_creds;
2808 status = netlogon_creds_cli_store(state->context,
2809 state->creds);
2810 TALLOC_FREE(state->creds);
2812 if (tevent_req_nterror(req, status)) {
2813 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2814 return;
2817 if (tevent_req_nterror(req, result)) {
2818 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2819 return;
2822 tevent_req_done(req);
2825 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2827 NTSTATUS status;
2829 if (tevent_req_is_nterror(req, &status)) {
2830 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2831 tevent_req_received(req);
2832 return status;
2835 tevent_req_received(req);
2836 return NT_STATUS_OK;
2839 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2840 struct netlogon_creds_cli_context *context,
2841 struct dcerpc_binding_handle *b,
2842 const char *site_name,
2843 uint32_t dns_ttl,
2844 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2846 TALLOC_CTX *frame = talloc_stackframe();
2847 struct tevent_context *ev;
2848 struct tevent_req *req;
2849 NTSTATUS status = NT_STATUS_NO_MEMORY;
2851 ev = samba_tevent_context_init(frame);
2852 if (ev == NULL) {
2853 goto fail;
2855 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2856 site_name,
2857 dns_ttl,
2858 dns_names);
2859 if (req == NULL) {
2860 goto fail;
2862 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2863 goto fail;
2865 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2866 fail:
2867 TALLOC_FREE(frame);
2868 return status;
2871 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2872 struct tevent_context *ev;
2873 struct netlogon_creds_cli_context *context;
2874 struct dcerpc_binding_handle *binding_handle;
2876 char *srv_name_slash;
2877 enum dcerpc_AuthType auth_type;
2878 enum dcerpc_AuthLevel auth_level;
2880 struct samr_Password new_owf_password;
2881 struct samr_Password old_owf_password;
2882 struct netr_TrustInfo *trust_info;
2884 struct netlogon_creds_CredentialState *creds;
2885 struct netlogon_creds_CredentialState tmp_creds;
2886 struct netr_Authenticator req_auth;
2887 struct netr_Authenticator rep_auth;
2890 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2891 NTSTATUS status);
2892 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2894 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2895 struct tevent_context *ev,
2896 struct netlogon_creds_cli_context *context,
2897 struct dcerpc_binding_handle *b)
2899 struct tevent_req *req;
2900 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2901 struct tevent_req *subreq;
2903 req = tevent_req_create(mem_ctx, &state,
2904 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2905 if (req == NULL) {
2906 return NULL;
2909 state->ev = ev;
2910 state->context = context;
2911 state->binding_handle = b;
2913 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2914 context->server.computer);
2915 if (tevent_req_nomem(state->srv_name_slash, req)) {
2916 return tevent_req_post(req, ev);
2919 dcerpc_binding_handle_auth_info(state->binding_handle,
2920 &state->auth_type,
2921 &state->auth_level);
2923 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2924 state->context);
2925 if (tevent_req_nomem(subreq, req)) {
2926 return tevent_req_post(req, ev);
2929 tevent_req_set_callback(subreq,
2930 netlogon_creds_cli_ServerGetTrustInfo_locked,
2931 req);
2933 return req;
2936 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2937 NTSTATUS status)
2939 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2940 tevent_req_data(req,
2941 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2943 if (state->creds == NULL) {
2944 return;
2947 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2948 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2949 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2950 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2951 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2952 TALLOC_FREE(state->creds);
2953 return;
2956 netlogon_creds_cli_delete(state->context, state->creds);
2957 TALLOC_FREE(state->creds);
2960 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2962 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2964 struct tevent_req *req =
2965 tevent_req_callback_data(subreq,
2966 struct tevent_req);
2967 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2968 tevent_req_data(req,
2969 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2970 NTSTATUS status;
2972 status = netlogon_creds_cli_lock_recv(subreq, state,
2973 &state->creds);
2974 TALLOC_FREE(subreq);
2975 if (tevent_req_nterror(req, status)) {
2976 return;
2979 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2980 switch (state->auth_level) {
2981 case DCERPC_AUTH_LEVEL_PRIVACY:
2982 break;
2983 default:
2984 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2985 return;
2987 } else {
2988 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2989 return;
2993 * we defer all callbacks in order to cleanup
2994 * the database record.
2996 tevent_req_defer_callback(req, state->ev);
2998 state->tmp_creds = *state->creds;
2999 netlogon_creds_client_authenticator(&state->tmp_creds,
3000 &state->req_auth);
3001 ZERO_STRUCT(state->rep_auth);
3003 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3004 state->binding_handle,
3005 state->srv_name_slash,
3006 state->tmp_creds.account_name,
3007 state->tmp_creds.secure_channel_type,
3008 state->tmp_creds.computer_name,
3009 &state->req_auth,
3010 &state->rep_auth,
3011 &state->new_owf_password,
3012 &state->old_owf_password,
3013 &state->trust_info);
3014 if (tevent_req_nomem(subreq, req)) {
3015 status = NT_STATUS_NO_MEMORY;
3016 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3017 return;
3020 tevent_req_set_callback(subreq,
3021 netlogon_creds_cli_ServerGetTrustInfo_done,
3022 req);
3025 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3027 struct tevent_req *req =
3028 tevent_req_callback_data(subreq,
3029 struct tevent_req);
3030 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3031 tevent_req_data(req,
3032 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3033 NTSTATUS status;
3034 NTSTATUS result;
3035 const struct samr_Password zero = {};
3036 int cmp;
3037 bool ok;
3040 * We use state->dns_names as the memory context, as this is
3041 * the only in/out variable and it has been overwritten by the
3042 * out parameter from the server.
3044 * We need to preserve the return value until the caller can use it.
3046 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3047 TALLOC_FREE(subreq);
3048 if (tevent_req_nterror(req, status)) {
3049 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3050 return;
3053 ok = netlogon_creds_client_check(&state->tmp_creds,
3054 &state->rep_auth.cred);
3055 if (!ok) {
3056 status = NT_STATUS_ACCESS_DENIED;
3057 tevent_req_nterror(req, status);
3058 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3059 return;
3062 cmp = memcmp(state->new_owf_password.hash,
3063 zero.hash, sizeof(zero.hash));
3064 if (cmp != 0) {
3065 netlogon_creds_des_decrypt(&state->tmp_creds,
3066 &state->new_owf_password);
3068 cmp = memcmp(state->old_owf_password.hash,
3069 zero.hash, sizeof(zero.hash));
3070 if (cmp != 0) {
3071 netlogon_creds_des_decrypt(&state->tmp_creds,
3072 &state->old_owf_password);
3075 *state->creds = state->tmp_creds;
3076 status = netlogon_creds_cli_store(state->context,
3077 state->creds);
3078 TALLOC_FREE(state->creds);
3079 if (tevent_req_nterror(req, status)) {
3080 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3081 return;
3084 if (tevent_req_nterror(req, result)) {
3085 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3086 return;
3089 tevent_req_done(req);
3092 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3093 TALLOC_CTX *mem_ctx,
3094 struct samr_Password *new_owf_password,
3095 struct samr_Password *old_owf_password,
3096 struct netr_TrustInfo **trust_info)
3098 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3099 tevent_req_data(req,
3100 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3101 NTSTATUS status;
3103 if (tevent_req_is_nterror(req, &status)) {
3104 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3105 tevent_req_received(req);
3106 return status;
3109 if (new_owf_password != NULL) {
3110 *new_owf_password = state->new_owf_password;
3112 if (old_owf_password != NULL) {
3113 *old_owf_password = state->old_owf_password;
3115 if (trust_info != NULL) {
3116 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3119 tevent_req_received(req);
3120 return NT_STATUS_OK;
3123 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3124 struct netlogon_creds_cli_context *context,
3125 struct dcerpc_binding_handle *b,
3126 TALLOC_CTX *mem_ctx,
3127 struct samr_Password *new_owf_password,
3128 struct samr_Password *old_owf_password,
3129 struct netr_TrustInfo **trust_info)
3131 TALLOC_CTX *frame = talloc_stackframe();
3132 struct tevent_context *ev;
3133 struct tevent_req *req;
3134 NTSTATUS status = NT_STATUS_NO_MEMORY;
3136 ev = samba_tevent_context_init(frame);
3137 if (ev == NULL) {
3138 goto fail;
3140 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3141 if (req == NULL) {
3142 goto fail;
3144 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3145 goto fail;
3147 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3148 mem_ctx,
3149 new_owf_password,
3150 old_owf_password,
3151 trust_info);
3152 fail:
3153 TALLOC_FREE(frame);
3154 return status;
3157 struct netlogon_creds_cli_GetForestTrustInformation_state {
3158 struct tevent_context *ev;
3159 struct netlogon_creds_cli_context *context;
3160 struct dcerpc_binding_handle *binding_handle;
3162 char *srv_name_slash;
3163 enum dcerpc_AuthType auth_type;
3164 enum dcerpc_AuthLevel auth_level;
3166 uint32_t flags;
3167 struct lsa_ForestTrustInformation *forest_trust_info;
3169 struct netlogon_creds_CredentialState *creds;
3170 struct netlogon_creds_CredentialState tmp_creds;
3171 struct netr_Authenticator req_auth;
3172 struct netr_Authenticator rep_auth;
3175 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3176 NTSTATUS status);
3177 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3179 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3180 struct tevent_context *ev,
3181 struct netlogon_creds_cli_context *context,
3182 struct dcerpc_binding_handle *b)
3184 struct tevent_req *req;
3185 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3186 struct tevent_req *subreq;
3188 req = tevent_req_create(mem_ctx, &state,
3189 struct netlogon_creds_cli_GetForestTrustInformation_state);
3190 if (req == NULL) {
3191 return NULL;
3194 state->ev = ev;
3195 state->context = context;
3196 state->binding_handle = b;
3198 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3199 context->server.computer);
3200 if (tevent_req_nomem(state->srv_name_slash, req)) {
3201 return tevent_req_post(req, ev);
3204 state->flags = 0;
3206 dcerpc_binding_handle_auth_info(state->binding_handle,
3207 &state->auth_type,
3208 &state->auth_level);
3210 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3211 state->context);
3212 if (tevent_req_nomem(subreq, req)) {
3213 return tevent_req_post(req, ev);
3216 tevent_req_set_callback(subreq,
3217 netlogon_creds_cli_GetForestTrustInformation_locked,
3218 req);
3220 return req;
3223 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3224 NTSTATUS status)
3226 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3227 tevent_req_data(req,
3228 struct netlogon_creds_cli_GetForestTrustInformation_state);
3230 if (state->creds == NULL) {
3231 return;
3234 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3235 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3236 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3237 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3238 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3239 TALLOC_FREE(state->creds);
3240 return;
3243 netlogon_creds_cli_delete(state->context, state->creds);
3244 TALLOC_FREE(state->creds);
3247 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3249 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3251 struct tevent_req *req =
3252 tevent_req_callback_data(subreq,
3253 struct tevent_req);
3254 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3255 tevent_req_data(req,
3256 struct netlogon_creds_cli_GetForestTrustInformation_state);
3257 NTSTATUS status;
3259 status = netlogon_creds_cli_lock_recv(subreq, state,
3260 &state->creds);
3261 TALLOC_FREE(subreq);
3262 if (tevent_req_nterror(req, status)) {
3263 return;
3266 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3267 switch (state->auth_level) {
3268 case DCERPC_AUTH_LEVEL_INTEGRITY:
3269 case DCERPC_AUTH_LEVEL_PRIVACY:
3270 break;
3271 default:
3272 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3273 return;
3275 } else {
3276 uint32_t tmp = state->creds->negotiate_flags;
3278 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3280 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3281 * it should be used, which means
3282 * we had a chance to verify no downgrade
3283 * happened.
3285 * This relies on netlogon_creds_cli_check*
3286 * being called before, as first request after
3287 * the DCERPC bind.
3289 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3290 return;
3295 * we defer all callbacks in order to cleanup
3296 * the database record.
3298 tevent_req_defer_callback(req, state->ev);
3300 state->tmp_creds = *state->creds;
3301 netlogon_creds_client_authenticator(&state->tmp_creds,
3302 &state->req_auth);
3303 ZERO_STRUCT(state->rep_auth);
3305 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3306 state->binding_handle,
3307 state->srv_name_slash,
3308 state->tmp_creds.computer_name,
3309 &state->req_auth,
3310 &state->rep_auth,
3311 state->flags,
3312 &state->forest_trust_info);
3313 if (tevent_req_nomem(subreq, req)) {
3314 status = NT_STATUS_NO_MEMORY;
3315 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3316 return;
3319 tevent_req_set_callback(subreq,
3320 netlogon_creds_cli_GetForestTrustInformation_done,
3321 req);
3324 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3326 struct tevent_req *req =
3327 tevent_req_callback_data(subreq,
3328 struct tevent_req);
3329 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3330 tevent_req_data(req,
3331 struct netlogon_creds_cli_GetForestTrustInformation_state);
3332 NTSTATUS status;
3333 NTSTATUS result;
3334 bool ok;
3337 * We use state->dns_names as the memory context, as this is
3338 * the only in/out variable and it has been overwritten by the
3339 * out parameter from the server.
3341 * We need to preserve the return value until the caller can use it.
3343 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3344 TALLOC_FREE(subreq);
3345 if (tevent_req_nterror(req, status)) {
3346 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3347 return;
3350 ok = netlogon_creds_client_check(&state->tmp_creds,
3351 &state->rep_auth.cred);
3352 if (!ok) {
3353 status = NT_STATUS_ACCESS_DENIED;
3354 tevent_req_nterror(req, status);
3355 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3356 return;
3359 *state->creds = state->tmp_creds;
3360 status = netlogon_creds_cli_store(state->context,
3361 state->creds);
3362 TALLOC_FREE(state->creds);
3364 if (tevent_req_nterror(req, status)) {
3365 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3366 return;
3369 if (tevent_req_nterror(req, result)) {
3370 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3371 return;
3374 tevent_req_done(req);
3377 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3378 TALLOC_CTX *mem_ctx,
3379 struct lsa_ForestTrustInformation **forest_trust_info)
3381 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3382 tevent_req_data(req,
3383 struct netlogon_creds_cli_GetForestTrustInformation_state);
3384 NTSTATUS status;
3386 if (tevent_req_is_nterror(req, &status)) {
3387 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3388 tevent_req_received(req);
3389 return status;
3392 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3394 tevent_req_received(req);
3395 return NT_STATUS_OK;
3398 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3399 struct netlogon_creds_cli_context *context,
3400 struct dcerpc_binding_handle *b,
3401 TALLOC_CTX *mem_ctx,
3402 struct lsa_ForestTrustInformation **forest_trust_info)
3404 TALLOC_CTX *frame = talloc_stackframe();
3405 struct tevent_context *ev;
3406 struct tevent_req *req;
3407 NTSTATUS status = NT_STATUS_NO_MEMORY;
3409 ev = samba_tevent_context_init(frame);
3410 if (ev == NULL) {
3411 goto fail;
3413 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3414 if (req == NULL) {
3415 goto fail;
3417 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3418 goto fail;
3420 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3421 mem_ctx,
3422 forest_trust_info);
3423 fail:
3424 TALLOC_FREE(frame);
3425 return status;
3428 struct netlogon_creds_cli_SendToSam_state {
3429 struct tevent_context *ev;
3430 struct netlogon_creds_cli_context *context;
3431 struct dcerpc_binding_handle *binding_handle;
3433 char *srv_name_slash;
3434 enum dcerpc_AuthType auth_type;
3435 enum dcerpc_AuthLevel auth_level;
3437 DATA_BLOB opaque;
3439 struct netlogon_creds_CredentialState *creds;
3440 struct netlogon_creds_CredentialState tmp_creds;
3441 struct netr_Authenticator req_auth;
3442 struct netr_Authenticator rep_auth;
3445 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3446 NTSTATUS status);
3447 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3449 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3450 struct tevent_context *ev,
3451 struct netlogon_creds_cli_context *context,
3452 struct dcerpc_binding_handle *b,
3453 struct netr_SendToSamBase *message)
3455 struct tevent_req *req;
3456 struct netlogon_creds_cli_SendToSam_state *state;
3457 struct tevent_req *subreq;
3458 enum ndr_err_code ndr_err;
3460 req = tevent_req_create(mem_ctx, &state,
3461 struct netlogon_creds_cli_SendToSam_state);
3462 if (req == NULL) {
3463 return NULL;
3466 state->ev = ev;
3467 state->context = context;
3468 state->binding_handle = b;
3470 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3471 context->server.computer);
3472 if (tevent_req_nomem(state->srv_name_slash, req)) {
3473 return tevent_req_post(req, ev);
3476 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3477 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3478 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3479 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3480 tevent_req_nterror(req, status);
3481 return tevent_req_post(req, ev);
3484 dcerpc_binding_handle_auth_info(state->binding_handle,
3485 &state->auth_type,
3486 &state->auth_level);
3488 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3489 state->context);
3490 if (tevent_req_nomem(subreq, req)) {
3491 return tevent_req_post(req, ev);
3494 tevent_req_set_callback(subreq,
3495 netlogon_creds_cli_SendToSam_locked,
3496 req);
3498 return req;
3501 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3502 NTSTATUS status)
3504 struct netlogon_creds_cli_SendToSam_state *state =
3505 tevent_req_data(req,
3506 struct netlogon_creds_cli_SendToSam_state);
3508 if (state->creds == NULL) {
3509 return;
3512 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3513 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3514 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3515 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3516 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3517 TALLOC_FREE(state->creds);
3518 return;
3521 netlogon_creds_cli_delete(state->context, state->creds);
3522 TALLOC_FREE(state->creds);
3525 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3527 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3529 struct tevent_req *req =
3530 tevent_req_callback_data(subreq,
3531 struct tevent_req);
3532 struct netlogon_creds_cli_SendToSam_state *state =
3533 tevent_req_data(req,
3534 struct netlogon_creds_cli_SendToSam_state);
3535 NTSTATUS status;
3537 status = netlogon_creds_cli_lock_recv(subreq, state,
3538 &state->creds);
3539 TALLOC_FREE(subreq);
3540 if (tevent_req_nterror(req, status)) {
3541 return;
3544 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3545 switch (state->auth_level) {
3546 case DCERPC_AUTH_LEVEL_INTEGRITY:
3547 case DCERPC_AUTH_LEVEL_PRIVACY:
3548 break;
3549 default:
3550 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3551 return;
3553 } else {
3554 uint32_t tmp = state->creds->negotiate_flags;
3556 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3558 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3559 * it should be used, which means
3560 * we had a chance to verify no downgrade
3561 * happened.
3563 * This relies on netlogon_creds_cli_check*
3564 * being called before, as first request after
3565 * the DCERPC bind.
3567 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3568 return;
3573 * we defer all callbacks in order to cleanup
3574 * the database record.
3576 tevent_req_defer_callback(req, state->ev);
3578 state->tmp_creds = *state->creds;
3579 netlogon_creds_client_authenticator(&state->tmp_creds,
3580 &state->req_auth);
3581 ZERO_STRUCT(state->rep_auth);
3583 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3584 netlogon_creds_aes_encrypt(&state->tmp_creds,
3585 state->opaque.data,
3586 state->opaque.length);
3587 } else {
3588 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3589 state->opaque.data,
3590 state->opaque.length);
3593 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3594 state->binding_handle,
3595 state->srv_name_slash,
3596 state->tmp_creds.computer_name,
3597 &state->req_auth,
3598 &state->rep_auth,
3599 state->opaque.data,
3600 state->opaque.length);
3601 if (tevent_req_nomem(subreq, req)) {
3602 status = NT_STATUS_NO_MEMORY;
3603 netlogon_creds_cli_SendToSam_cleanup(req, status);
3604 return;
3607 tevent_req_set_callback(subreq,
3608 netlogon_creds_cli_SendToSam_done,
3609 req);
3612 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3614 struct tevent_req *req =
3615 tevent_req_callback_data(subreq,
3616 struct tevent_req);
3617 struct netlogon_creds_cli_SendToSam_state *state =
3618 tevent_req_data(req,
3619 struct netlogon_creds_cli_SendToSam_state);
3620 NTSTATUS status;
3621 NTSTATUS result;
3622 bool ok;
3624 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3625 TALLOC_FREE(subreq);
3626 if (tevent_req_nterror(req, status)) {
3627 netlogon_creds_cli_SendToSam_cleanup(req, status);
3628 return;
3631 ok = netlogon_creds_client_check(&state->tmp_creds,
3632 &state->rep_auth.cred);
3633 if (!ok) {
3634 status = NT_STATUS_ACCESS_DENIED;
3635 tevent_req_nterror(req, status);
3636 netlogon_creds_cli_SendToSam_cleanup(req, status);
3637 return;
3640 *state->creds = state->tmp_creds;
3641 status = netlogon_creds_cli_store(state->context,
3642 state->creds);
3643 TALLOC_FREE(state->creds);
3645 if (tevent_req_nterror(req, status)) {
3646 netlogon_creds_cli_SendToSam_cleanup(req, status);
3647 return;
3651 * Creds must be stored before we send back application errors
3652 * e.g. NT_STATUS_NOT_IMPLEMENTED
3654 if (tevent_req_nterror(req, result)) {
3655 netlogon_creds_cli_SendToSam_cleanup(req, result);
3656 return;
3659 tevent_req_done(req);
3662 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3663 struct dcerpc_binding_handle *b,
3664 struct netr_SendToSamBase *message)
3666 TALLOC_CTX *frame = talloc_stackframe();
3667 struct tevent_context *ev;
3668 struct tevent_req *req;
3669 NTSTATUS status = NT_STATUS_OK;
3671 ev = samba_tevent_context_init(frame);
3672 if (ev == NULL) {
3673 goto fail;
3675 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3676 if (req == NULL) {
3677 goto fail;
3679 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3680 goto fail;
3683 /* Ignore the result */
3684 fail:
3685 TALLOC_FREE(frame);
3686 return status;