netlogon_creds_cli: Remove tevent_req handling from netlogon_creds_cli_lock_fetch
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob73d6bb97988610c33924065f3f5f298e02e9be8d
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 char *netlogon_creds_cli_debug_string(
451 const struct netlogon_creds_cli_context *context,
452 TALLOC_CTX *mem_ctx)
454 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
455 context->db.key_name);
458 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
459 struct netlogon_creds_cli_context *context)
461 return context->client.auth_level;
464 struct netlogon_creds_cli_fetch_state {
465 TALLOC_CTX *mem_ctx;
466 struct netlogon_creds_CredentialState *creds;
467 uint32_t required_flags;
468 NTSTATUS status;
471 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
472 void *private_data)
474 struct netlogon_creds_cli_fetch_state *state =
475 (struct netlogon_creds_cli_fetch_state *)private_data;
476 enum ndr_err_code ndr_err;
477 DATA_BLOB blob;
478 uint32_t tmp_flags;
480 state->creds = talloc_zero(state->mem_ctx,
481 struct netlogon_creds_CredentialState);
482 if (state->creds == NULL) {
483 state->status = NT_STATUS_NO_MEMORY;
484 return;
487 blob.data = data.dptr;
488 blob.length = data.dsize;
490 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
491 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
492 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
493 TALLOC_FREE(state->creds);
494 state->status = ndr_map_error2ntstatus(ndr_err);
495 return;
498 tmp_flags = state->creds->negotiate_flags;
499 tmp_flags &= state->required_flags;
500 if (tmp_flags != state->required_flags) {
501 TALLOC_FREE(state->creds);
502 state->status = NT_STATUS_DOWNGRADE_DETECTED;
503 return;
506 state->status = NT_STATUS_OK;
509 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
510 TALLOC_CTX *mem_ctx,
511 struct netlogon_creds_CredentialState **_creds)
513 NTSTATUS status;
514 struct netlogon_creds_cli_fetch_state fstate = {
515 .mem_ctx = mem_ctx,
516 .status = NT_STATUS_INTERNAL_ERROR,
517 .required_flags = context->client.required_flags,
520 *_creds = NULL;
522 status = dbwrap_parse_record(context->db.ctx,
523 context->db.key_data,
524 netlogon_creds_cli_fetch_parser,
525 &fstate);
526 if (!NT_STATUS_IS_OK(status)) {
527 return status;
529 status = fstate.status;
530 if (!NT_STATUS_IS_OK(status)) {
531 return status;
535 * mark it as invalid for step operations.
537 fstate.creds->sequence = 0;
538 fstate.creds->seed = (struct netr_Credential) {{0}};
539 fstate.creds->client = (struct netr_Credential) {{0}};
540 fstate.creds->server = (struct netr_Credential) {{0}};
542 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
543 *_creds = fstate.creds;
544 return NT_STATUS_OK;
548 * It is really important to try SamLogonEx here,
549 * because multiple processes can talk to the same
550 * domain controller, without using the credential
551 * chain.
553 * With a normal SamLogon call, we must keep the
554 * credentials chain updated and intact between all
555 * users of the machine account (which would imply
556 * cross-node communication for every NTLM logon).
558 * The credentials chain is not per NETLOGON pipe
559 * connection, but globally on the server/client pair
560 * by computer name.
562 * It's also important to use NetlogonValidationSamInfo4 (6),
563 * because it relies on the rpc transport encryption
564 * and avoids using the global netlogon schannel
565 * session key to en/decrypt secret information
566 * like the user_session_key for network logons.
568 * [MS-APDS] 3.1.5.2 NTLM Network Logon
569 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
570 * NETLOGON_NEG_AUTHENTICATED_RPC set together
571 * are the indication that the server supports
572 * NetlogonValidationSamInfo4 (6). And it must only
573 * be used if "SealSecureChannel" is used.
575 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
576 * check is done in netlogon_creds_cli_LogonSamLogon*().
578 context->server.cached_flags = fstate.creds->negotiate_flags;
579 context->server.try_validation6 = true;
580 context->server.try_logon_ex = true;
581 context->server.try_logon_with = true;
583 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
584 context->server.try_validation6 = false;
585 context->server.try_logon_ex = false;
587 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
588 context->server.try_validation6 = false;
591 *_creds = fstate.creds;
592 return NT_STATUS_OK;
595 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
596 const struct netlogon_creds_CredentialState *creds1)
598 TALLOC_CTX *frame = talloc_stackframe();
599 struct netlogon_creds_CredentialState *creds2;
600 DATA_BLOB blob1;
601 DATA_BLOB blob2;
602 NTSTATUS status;
603 enum ndr_err_code ndr_err;
604 int cmp;
606 status = netlogon_creds_cli_get(context, frame, &creds2);
607 if (!NT_STATUS_IS_OK(status)) {
608 TALLOC_FREE(frame);
609 return false;
612 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
613 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
614 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
615 TALLOC_FREE(frame);
616 return false;
619 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
620 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
621 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
622 TALLOC_FREE(frame);
623 return false;
626 cmp = data_blob_cmp(&blob1, &blob2);
628 TALLOC_FREE(frame);
630 return (cmp == 0);
633 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
634 struct netlogon_creds_CredentialState *creds)
636 NTSTATUS status;
637 enum ndr_err_code ndr_err;
638 DATA_BLOB blob;
639 TDB_DATA data;
641 if (context->db.locked_state == NULL) {
643 * this was not the result of netlogon_creds_cli_lock*()
645 return NT_STATUS_INVALID_PAGE_PROTECTION;
648 if (context->db.locked_state->creds != creds) {
650 * this was not the result of netlogon_creds_cli_lock*()
652 return NT_STATUS_INVALID_PAGE_PROTECTION;
655 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
656 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
657 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
658 status = ndr_map_error2ntstatus(ndr_err);
659 return status;
662 data.dptr = blob.data;
663 data.dsize = blob.length;
665 status = dbwrap_store(context->db.ctx,
666 context->db.key_data,
667 data, TDB_REPLACE);
668 TALLOC_FREE(data.dptr);
669 if (!NT_STATUS_IS_OK(status)) {
670 return status;
673 return NT_STATUS_OK;
676 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
677 struct netlogon_creds_CredentialState *creds)
679 NTSTATUS status;
681 if (context->db.locked_state == NULL) {
683 * this was not the result of netlogon_creds_cli_lock*()
685 return NT_STATUS_INVALID_PAGE_PROTECTION;
688 if (context->db.locked_state->creds != creds) {
690 * this was not the result of netlogon_creds_cli_lock*()
692 return NT_STATUS_INVALID_PAGE_PROTECTION;
695 status = dbwrap_delete(context->db.ctx,
696 context->db.key_data);
697 if (!NT_STATUS_IS_OK(status)) {
698 return status;
701 return NT_STATUS_OK;
704 struct netlogon_creds_cli_lock_state {
705 struct netlogon_creds_cli_locked_state *locked_state;
706 struct netlogon_creds_CredentialState *creds;
709 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
710 static NTSTATUS netlogon_creds_cli_lock_fetch(
711 struct netlogon_creds_cli_context *context,
712 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
714 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
715 struct tevent_context *ev,
716 struct netlogon_creds_cli_context *context)
718 struct tevent_req *req;
719 struct netlogon_creds_cli_lock_state *state;
720 struct netlogon_creds_cli_locked_state *locked_state;
721 struct tevent_req *subreq;
723 req = tevent_req_create(mem_ctx, &state,
724 struct netlogon_creds_cli_lock_state);
725 if (req == NULL) {
726 return NULL;
729 if (context->db.locked_state != NULL) {
730 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
731 return tevent_req_post(req, ev);
734 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
735 if (tevent_req_nomem(locked_state, req)) {
736 return tevent_req_post(req, ev);
738 talloc_set_destructor(locked_state,
739 netlogon_creds_cli_locked_state_destructor);
740 locked_state->context = context;
742 context->db.locked_state = locked_state;
743 state->locked_state = locked_state;
745 if (context->db.g_ctx == NULL) {
746 NTSTATUS status;
748 status = netlogon_creds_cli_lock_fetch(
749 context, state, &state->creds);
750 if (tevent_req_nterror(req, status)) {
751 return tevent_req_post(req, ev);
754 return req;
757 subreq = g_lock_lock_send(state, ev,
758 context->db.g_ctx,
759 context->db.key_name,
760 G_LOCK_WRITE);
761 if (tevent_req_nomem(subreq, req)) {
762 return tevent_req_post(req, ev);
764 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
766 return req;
769 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
771 struct tevent_req *req =
772 tevent_req_callback_data(subreq,
773 struct tevent_req);
774 struct netlogon_creds_cli_lock_state *state =
775 tevent_req_data(req,
776 struct netlogon_creds_cli_lock_state);
777 NTSTATUS status;
779 status = g_lock_lock_recv(subreq);
780 TALLOC_FREE(subreq);
781 if (tevent_req_nterror(req, status)) {
782 return;
784 state->locked_state->is_glocked = true;
786 status = netlogon_creds_cli_lock_fetch(state->locked_state->context,
787 state, &state->creds);
788 if (tevent_req_nterror(req, status)) {
789 return;
791 tevent_req_done(req);
794 static NTSTATUS netlogon_creds_cli_lock_fetch(
795 struct netlogon_creds_cli_context *context,
796 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
798 struct netlogon_creds_cli_fetch_state fstate = {
799 .status = NT_STATUS_INTERNAL_ERROR,
800 .required_flags = context->client.required_flags,
802 NTSTATUS status;
804 fstate.mem_ctx = mem_ctx;
805 status = dbwrap_parse_record(context->db.ctx,
806 context->db.key_data,
807 netlogon_creds_cli_fetch_parser,
808 &fstate);
809 if (!NT_STATUS_IS_OK(status)) {
810 return status;
812 if (!NT_STATUS_IS_OK(fstate.status)) {
813 return fstate.status;
816 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
817 *pcreds = fstate.creds;
818 return NT_STATUS_OK;
821 context->server.cached_flags = fstate.creds->negotiate_flags;
822 context->server.try_validation6 = true;
823 context->server.try_logon_ex = true;
824 context->server.try_logon_with = true;
826 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
827 context->server.try_validation6 = false;
828 context->server.try_logon_ex = false;
830 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
831 context->server.try_validation6 = false;
834 *pcreds = fstate.creds;
835 return NT_STATUS_OK;
838 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
839 TALLOC_CTX *mem_ctx,
840 struct netlogon_creds_CredentialState **creds)
842 struct netlogon_creds_cli_lock_state *state =
843 tevent_req_data(req,
844 struct netlogon_creds_cli_lock_state);
845 NTSTATUS status;
847 if (tevent_req_is_nterror(req, &status)) {
848 tevent_req_received(req);
849 return status;
852 talloc_steal(state->creds, state->locked_state);
853 state->locked_state->creds = state->creds;
854 *creds = talloc_move(mem_ctx, &state->creds);
855 tevent_req_received(req);
856 return NT_STATUS_OK;
859 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
860 TALLOC_CTX *mem_ctx,
861 struct netlogon_creds_CredentialState **creds)
863 TALLOC_CTX *frame = talloc_stackframe();
864 struct tevent_context *ev;
865 struct tevent_req *req;
866 NTSTATUS status = NT_STATUS_NO_MEMORY;
868 ev = samba_tevent_context_init(frame);
869 if (ev == NULL) {
870 goto fail;
872 req = netlogon_creds_cli_lock_send(frame, ev, context);
873 if (req == NULL) {
874 goto fail;
876 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
877 goto fail;
879 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
880 fail:
881 TALLOC_FREE(frame);
882 return status;
885 struct netlogon_creds_cli_auth_state {
886 struct tevent_context *ev;
887 struct netlogon_creds_cli_context *context;
888 struct dcerpc_binding_handle *binding_handle;
889 uint8_t num_nt_hashes;
890 uint8_t idx_nt_hashes;
891 const struct samr_Password * const *nt_hashes;
892 const struct samr_Password *used_nt_hash;
893 char *srv_name_slash;
894 uint32_t current_flags;
895 struct netr_Credential client_challenge;
896 struct netr_Credential server_challenge;
897 struct netlogon_creds_CredentialState *creds;
898 struct netr_Credential client_credential;
899 struct netr_Credential server_credential;
900 uint32_t rid;
901 bool try_auth3;
902 bool try_auth2;
903 bool require_auth2;
904 struct netlogon_creds_cli_locked_state *locked_state;
907 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
908 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
910 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
911 struct tevent_context *ev,
912 struct netlogon_creds_cli_context *context,
913 struct dcerpc_binding_handle *b,
914 uint8_t num_nt_hashes,
915 const struct samr_Password * const *nt_hashes)
917 struct tevent_req *req;
918 struct netlogon_creds_cli_auth_state *state;
919 struct netlogon_creds_cli_locked_state *locked_state;
920 NTSTATUS status;
922 req = tevent_req_create(mem_ctx, &state,
923 struct netlogon_creds_cli_auth_state);
924 if (req == NULL) {
925 return NULL;
928 state->ev = ev;
929 state->context = context;
930 state->binding_handle = b;
931 if (num_nt_hashes < 1) {
932 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
933 return tevent_req_post(req, ev);
935 if (num_nt_hashes > 4) {
936 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
937 return tevent_req_post(req, ev);
940 state->num_nt_hashes = num_nt_hashes;
941 state->idx_nt_hashes = 0;
942 state->nt_hashes = nt_hashes;
944 if (context->db.locked_state != NULL) {
945 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
946 return tevent_req_post(req, ev);
949 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
950 if (tevent_req_nomem(locked_state, req)) {
951 return tevent_req_post(req, ev);
953 talloc_set_destructor(locked_state,
954 netlogon_creds_cli_locked_state_destructor);
955 locked_state->context = context;
957 context->db.locked_state = locked_state;
958 state->locked_state = locked_state;
960 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
961 context->server.computer);
962 if (tevent_req_nomem(state->srv_name_slash, req)) {
963 return tevent_req_post(req, ev);
966 state->try_auth3 = true;
967 state->try_auth2 = true;
969 if (context->client.required_flags != 0) {
970 state->require_auth2 = true;
973 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
974 state->current_flags = context->client.proposed_flags;
976 if (context->db.g_ctx != NULL) {
977 struct tevent_req *subreq;
979 subreq = g_lock_lock_send(state, ev,
980 context->db.g_ctx,
981 context->db.key_name,
982 G_LOCK_WRITE);
983 if (tevent_req_nomem(subreq, req)) {
984 return tevent_req_post(req, ev);
986 tevent_req_set_callback(subreq,
987 netlogon_creds_cli_auth_locked,
988 req);
990 return req;
993 status = dbwrap_purge(state->context->db.ctx,
994 state->context->db.key_data);
995 if (tevent_req_nterror(req, status)) {
996 return tevent_req_post(req, ev);
999 netlogon_creds_cli_auth_challenge_start(req);
1000 if (!tevent_req_is_in_progress(req)) {
1001 return tevent_req_post(req, ev);
1004 return req;
1007 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1009 struct tevent_req *req =
1010 tevent_req_callback_data(subreq,
1011 struct tevent_req);
1012 struct netlogon_creds_cli_auth_state *state =
1013 tevent_req_data(req,
1014 struct netlogon_creds_cli_auth_state);
1015 NTSTATUS status;
1017 status = g_lock_lock_recv(subreq);
1018 TALLOC_FREE(subreq);
1019 if (tevent_req_nterror(req, status)) {
1020 return;
1022 state->locked_state->is_glocked = true;
1024 status = dbwrap_purge(state->context->db.ctx,
1025 state->context->db.key_data);
1026 if (tevent_req_nterror(req, status)) {
1027 return;
1030 netlogon_creds_cli_auth_challenge_start(req);
1033 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1035 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1037 struct netlogon_creds_cli_auth_state *state =
1038 tevent_req_data(req,
1039 struct netlogon_creds_cli_auth_state);
1040 struct tevent_req *subreq;
1042 TALLOC_FREE(state->creds);
1044 generate_random_buffer(state->client_challenge.data,
1045 sizeof(state->client_challenge.data));
1047 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1048 state->binding_handle,
1049 state->srv_name_slash,
1050 state->context->client.computer,
1051 &state->client_challenge,
1052 &state->server_challenge);
1053 if (tevent_req_nomem(subreq, req)) {
1054 return;
1056 tevent_req_set_callback(subreq,
1057 netlogon_creds_cli_auth_challenge_done,
1058 req);
1061 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1063 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1065 struct tevent_req *req =
1066 tevent_req_callback_data(subreq,
1067 struct tevent_req);
1068 struct netlogon_creds_cli_auth_state *state =
1069 tevent_req_data(req,
1070 struct netlogon_creds_cli_auth_state);
1071 NTSTATUS status;
1072 NTSTATUS result;
1074 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1075 TALLOC_FREE(subreq);
1076 if (tevent_req_nterror(req, status)) {
1077 return;
1079 if (tevent_req_nterror(req, result)) {
1080 return;
1083 if (!state->try_auth3 && !state->try_auth2) {
1084 state->current_flags = 0;
1087 /* Calculate the session key and client credentials */
1089 state->creds = netlogon_creds_client_init(state,
1090 state->context->client.account,
1091 state->context->client.computer,
1092 state->context->client.type,
1093 &state->client_challenge,
1094 &state->server_challenge,
1095 state->used_nt_hash,
1096 &state->client_credential,
1097 state->current_flags);
1098 if (tevent_req_nomem(state->creds, req)) {
1099 return;
1102 if (state->try_auth3) {
1103 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1104 state->binding_handle,
1105 state->srv_name_slash,
1106 state->context->client.account,
1107 state->context->client.type,
1108 state->context->client.computer,
1109 &state->client_credential,
1110 &state->server_credential,
1111 &state->creds->negotiate_flags,
1112 &state->rid);
1113 if (tevent_req_nomem(subreq, req)) {
1114 return;
1116 } else if (state->try_auth2) {
1117 state->rid = 0;
1119 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1120 state->binding_handle,
1121 state->srv_name_slash,
1122 state->context->client.account,
1123 state->context->client.type,
1124 state->context->client.computer,
1125 &state->client_credential,
1126 &state->server_credential,
1127 &state->creds->negotiate_flags);
1128 if (tevent_req_nomem(subreq, req)) {
1129 return;
1131 } else {
1132 state->rid = 0;
1134 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1135 state->binding_handle,
1136 state->srv_name_slash,
1137 state->context->client.account,
1138 state->context->client.type,
1139 state->context->client.computer,
1140 &state->client_credential,
1141 &state->server_credential);
1142 if (tevent_req_nomem(subreq, req)) {
1143 return;
1146 tevent_req_set_callback(subreq,
1147 netlogon_creds_cli_auth_srvauth_done,
1148 req);
1151 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1153 struct tevent_req *req =
1154 tevent_req_callback_data(subreq,
1155 struct tevent_req);
1156 struct netlogon_creds_cli_auth_state *state =
1157 tevent_req_data(req,
1158 struct netlogon_creds_cli_auth_state);
1159 NTSTATUS status;
1160 NTSTATUS result;
1161 bool ok;
1162 enum ndr_err_code ndr_err;
1163 DATA_BLOB blob;
1164 TDB_DATA data;
1165 uint32_t tmp_flags;
1167 if (state->try_auth3) {
1168 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1169 &result);
1170 TALLOC_FREE(subreq);
1171 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1172 state->try_auth3 = false;
1173 netlogon_creds_cli_auth_challenge_start(req);
1174 return;
1176 if (tevent_req_nterror(req, status)) {
1177 return;
1179 } else if (state->try_auth2) {
1180 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1181 &result);
1182 TALLOC_FREE(subreq);
1183 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1184 state->try_auth2 = false;
1185 if (state->require_auth2) {
1186 status = NT_STATUS_DOWNGRADE_DETECTED;
1187 tevent_req_nterror(req, status);
1188 return;
1190 netlogon_creds_cli_auth_challenge_start(req);
1191 return;
1193 if (tevent_req_nterror(req, status)) {
1194 return;
1196 } else {
1197 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1198 &result);
1199 TALLOC_FREE(subreq);
1200 if (tevent_req_nterror(req, status)) {
1201 return;
1205 if (!NT_STATUS_IS_OK(result) &&
1206 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1208 tevent_req_nterror(req, result);
1209 return;
1212 tmp_flags = state->creds->negotiate_flags;
1213 tmp_flags &= state->context->client.required_flags;
1214 if (tmp_flags != state->context->client.required_flags) {
1215 if (NT_STATUS_IS_OK(result)) {
1216 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1217 return;
1219 tevent_req_nterror(req, result);
1220 return;
1223 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1225 tmp_flags = state->context->client.proposed_flags;
1226 if ((state->current_flags == tmp_flags) &&
1227 (state->creds->negotiate_flags != tmp_flags))
1230 * lets retry with the negotiated flags
1232 state->current_flags = state->creds->negotiate_flags;
1233 netlogon_creds_cli_auth_challenge_start(req);
1234 return;
1237 state->idx_nt_hashes += 1;
1238 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1240 * we already retried, giving up...
1242 tevent_req_nterror(req, result);
1243 return;
1247 * lets retry with the old nt hash.
1249 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1250 state->current_flags = state->context->client.proposed_flags;
1251 netlogon_creds_cli_auth_challenge_start(req);
1252 return;
1255 ok = netlogon_creds_client_check(state->creds,
1256 &state->server_credential);
1257 if (!ok) {
1258 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1259 return;
1262 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1263 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1264 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1265 status = ndr_map_error2ntstatus(ndr_err);
1266 tevent_req_nterror(req, status);
1267 return;
1270 data.dptr = blob.data;
1271 data.dsize = blob.length;
1273 status = dbwrap_store(state->context->db.ctx,
1274 state->context->db.key_data,
1275 data, TDB_REPLACE);
1276 TALLOC_FREE(state->locked_state);
1277 if (tevent_req_nterror(req, status)) {
1278 return;
1281 tevent_req_done(req);
1284 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1285 uint8_t *idx_nt_hashes)
1287 struct netlogon_creds_cli_auth_state *state =
1288 tevent_req_data(req,
1289 struct netlogon_creds_cli_auth_state);
1290 NTSTATUS status;
1292 *idx_nt_hashes = 0;
1294 if (tevent_req_is_nterror(req, &status)) {
1295 tevent_req_received(req);
1296 return status;
1299 *idx_nt_hashes = state->idx_nt_hashes;
1300 tevent_req_received(req);
1301 return NT_STATUS_OK;
1304 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1305 struct dcerpc_binding_handle *b,
1306 uint8_t num_nt_hashes,
1307 const struct samr_Password * const *nt_hashes,
1308 uint8_t *idx_nt_hashes)
1310 TALLOC_CTX *frame = talloc_stackframe();
1311 struct tevent_context *ev;
1312 struct tevent_req *req;
1313 NTSTATUS status = NT_STATUS_NO_MEMORY;
1315 *idx_nt_hashes = 0;
1317 ev = samba_tevent_context_init(frame);
1318 if (ev == NULL) {
1319 goto fail;
1321 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1322 num_nt_hashes, nt_hashes);
1323 if (req == NULL) {
1324 goto fail;
1326 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1327 goto fail;
1329 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1330 fail:
1331 TALLOC_FREE(frame);
1332 return status;
1335 struct netlogon_creds_cli_check_state {
1336 struct tevent_context *ev;
1337 struct netlogon_creds_cli_context *context;
1338 struct dcerpc_binding_handle *binding_handle;
1340 char *srv_name_slash;
1342 union netr_Capabilities caps;
1344 struct netlogon_creds_CredentialState *creds;
1345 struct netlogon_creds_CredentialState tmp_creds;
1346 struct netr_Authenticator req_auth;
1347 struct netr_Authenticator rep_auth;
1350 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1351 NTSTATUS status);
1352 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1354 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1355 struct tevent_context *ev,
1356 struct netlogon_creds_cli_context *context,
1357 struct dcerpc_binding_handle *b)
1359 struct tevent_req *req;
1360 struct netlogon_creds_cli_check_state *state;
1361 struct tevent_req *subreq;
1362 enum dcerpc_AuthType auth_type;
1363 enum dcerpc_AuthLevel auth_level;
1365 req = tevent_req_create(mem_ctx, &state,
1366 struct netlogon_creds_cli_check_state);
1367 if (req == NULL) {
1368 return NULL;
1371 state->ev = ev;
1372 state->context = context;
1373 state->binding_handle = b;
1375 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1376 context->server.computer);
1377 if (tevent_req_nomem(state->srv_name_slash, req)) {
1378 return tevent_req_post(req, ev);
1381 dcerpc_binding_handle_auth_info(state->binding_handle,
1382 &auth_type, &auth_level);
1384 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1385 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1386 return tevent_req_post(req, ev);
1389 switch (auth_level) {
1390 case DCERPC_AUTH_LEVEL_INTEGRITY:
1391 case DCERPC_AUTH_LEVEL_PRIVACY:
1392 break;
1393 default:
1394 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1395 return tevent_req_post(req, ev);
1398 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1399 state->context);
1400 if (tevent_req_nomem(subreq, req)) {
1401 return tevent_req_post(req, ev);
1404 tevent_req_set_callback(subreq,
1405 netlogon_creds_cli_check_locked,
1406 req);
1408 return req;
1411 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1412 NTSTATUS status)
1414 struct netlogon_creds_cli_check_state *state =
1415 tevent_req_data(req,
1416 struct netlogon_creds_cli_check_state);
1418 if (state->creds == NULL) {
1419 return;
1422 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1423 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1424 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1425 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1426 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1427 TALLOC_FREE(state->creds);
1428 return;
1431 netlogon_creds_cli_delete(state->context, state->creds);
1432 TALLOC_FREE(state->creds);
1435 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1437 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1439 struct tevent_req *req =
1440 tevent_req_callback_data(subreq,
1441 struct tevent_req);
1442 struct netlogon_creds_cli_check_state *state =
1443 tevent_req_data(req,
1444 struct netlogon_creds_cli_check_state);
1445 NTSTATUS status;
1447 status = netlogon_creds_cli_lock_recv(subreq, state,
1448 &state->creds);
1449 TALLOC_FREE(subreq);
1450 if (tevent_req_nterror(req, status)) {
1451 return;
1455 * we defer all callbacks in order to cleanup
1456 * the database record.
1458 tevent_req_defer_callback(req, state->ev);
1460 state->tmp_creds = *state->creds;
1461 netlogon_creds_client_authenticator(&state->tmp_creds,
1462 &state->req_auth);
1463 ZERO_STRUCT(state->rep_auth);
1465 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1466 state->binding_handle,
1467 state->srv_name_slash,
1468 state->context->client.computer,
1469 &state->req_auth,
1470 &state->rep_auth,
1472 &state->caps);
1473 if (tevent_req_nomem(subreq, req)) {
1474 status = NT_STATUS_NO_MEMORY;
1475 netlogon_creds_cli_check_cleanup(req, status);
1476 return;
1478 tevent_req_set_callback(subreq,
1479 netlogon_creds_cli_check_caps,
1480 req);
1483 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1485 struct tevent_req *req =
1486 tevent_req_callback_data(subreq,
1487 struct tevent_req);
1488 struct netlogon_creds_cli_check_state *state =
1489 tevent_req_data(req,
1490 struct netlogon_creds_cli_check_state);
1491 NTSTATUS status;
1492 NTSTATUS result;
1493 bool ok;
1495 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1496 &result);
1497 TALLOC_FREE(subreq);
1498 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1500 * Note that the negotiated flags are already checked
1501 * for our required flags after the ServerAuthenticate3/2 call.
1503 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1505 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1507 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1508 * already, we expect this to work!
1510 status = NT_STATUS_DOWNGRADE_DETECTED;
1511 tevent_req_nterror(req, status);
1512 netlogon_creds_cli_check_cleanup(req, status);
1513 return;
1516 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1518 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1519 * we expect this to work at least as far as the
1520 * NOT_SUPPORTED error handled below!
1522 * NT 4.0 and Old Samba servers are not
1523 * allowed without "require strong key = no"
1525 status = NT_STATUS_DOWNGRADE_DETECTED;
1526 tevent_req_nterror(req, status);
1527 netlogon_creds_cli_check_cleanup(req, status);
1528 return;
1532 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1533 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1534 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1536 * This is needed against NT 4.0 and old Samba servers.
1538 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1539 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1540 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1541 * with the next request as the sequence number processing
1542 * gets out of sync.
1544 netlogon_creds_cli_check_cleanup(req, status);
1545 tevent_req_done(req);
1546 return;
1548 if (tevent_req_nterror(req, status)) {
1549 netlogon_creds_cli_check_cleanup(req, status);
1550 return;
1553 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1555 * Note that the negotiated flags are already checked
1556 * for our required flags after the ServerAuthenticate3/2 call.
1558 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1560 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1562 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1563 * already, we expect this to work!
1565 status = NT_STATUS_DOWNGRADE_DETECTED;
1566 tevent_req_nterror(req, status);
1567 netlogon_creds_cli_check_cleanup(req, status);
1568 return;
1572 * This is ok, the server does not support
1573 * NETLOGON_NEG_SUPPORTS_AES.
1575 * netr_LogonGetCapabilities() was
1576 * netr_LogonDummyRoutine1() before
1577 * NETLOGON_NEG_SUPPORTS_AES was invented.
1579 netlogon_creds_cli_check_cleanup(req, result);
1580 tevent_req_done(req);
1581 return;
1584 ok = netlogon_creds_client_check(&state->tmp_creds,
1585 &state->rep_auth.cred);
1586 if (!ok) {
1587 status = NT_STATUS_ACCESS_DENIED;
1588 tevent_req_nterror(req, status);
1589 netlogon_creds_cli_check_cleanup(req, status);
1590 return;
1593 if (tevent_req_nterror(req, result)) {
1594 netlogon_creds_cli_check_cleanup(req, result);
1595 return;
1598 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1599 status = NT_STATUS_DOWNGRADE_DETECTED;
1600 tevent_req_nterror(req, status);
1601 netlogon_creds_cli_check_cleanup(req, status);
1602 return;
1606 * This is the key check that makes this check secure. If we
1607 * get OK here (rather than NOT_SUPPORTED), then the server
1608 * did support AES. If the server only proposed STRONG_KEYS
1609 * and not AES, then it should have failed with
1610 * NOT_IMPLEMENTED. We always send AES as a client, so the
1611 * server should always have returned it.
1613 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1614 status = NT_STATUS_DOWNGRADE_DETECTED;
1615 tevent_req_nterror(req, status);
1616 netlogon_creds_cli_check_cleanup(req, status);
1617 return;
1620 *state->creds = state->tmp_creds;
1621 status = netlogon_creds_cli_store(state->context,
1622 state->creds);
1623 TALLOC_FREE(state->creds);
1624 if (tevent_req_nterror(req, status)) {
1625 return;
1628 tevent_req_done(req);
1631 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1633 NTSTATUS status;
1635 if (tevent_req_is_nterror(req, &status)) {
1636 netlogon_creds_cli_check_cleanup(req, status);
1637 tevent_req_received(req);
1638 return status;
1641 tevent_req_received(req);
1642 return NT_STATUS_OK;
1645 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1646 struct dcerpc_binding_handle *b)
1648 TALLOC_CTX *frame = talloc_stackframe();
1649 struct tevent_context *ev;
1650 struct tevent_req *req;
1651 NTSTATUS status = NT_STATUS_NO_MEMORY;
1653 ev = samba_tevent_context_init(frame);
1654 if (ev == NULL) {
1655 goto fail;
1657 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1658 if (req == NULL) {
1659 goto fail;
1661 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1662 goto fail;
1664 status = netlogon_creds_cli_check_recv(req);
1665 fail:
1666 TALLOC_FREE(frame);
1667 return status;
1670 struct netlogon_creds_cli_ServerPasswordSet_state {
1671 struct tevent_context *ev;
1672 struct netlogon_creds_cli_context *context;
1673 struct dcerpc_binding_handle *binding_handle;
1674 uint32_t old_timeout;
1676 char *srv_name_slash;
1677 enum dcerpc_AuthType auth_type;
1678 enum dcerpc_AuthLevel auth_level;
1680 struct samr_CryptPassword samr_crypt_password;
1681 struct netr_CryptPassword netr_crypt_password;
1682 struct samr_Password samr_password;
1684 struct netlogon_creds_CredentialState *creds;
1685 struct netlogon_creds_CredentialState tmp_creds;
1686 struct netr_Authenticator req_auth;
1687 struct netr_Authenticator rep_auth;
1690 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1691 NTSTATUS status);
1692 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1694 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1695 struct tevent_context *ev,
1696 struct netlogon_creds_cli_context *context,
1697 struct dcerpc_binding_handle *b,
1698 const DATA_BLOB *new_password,
1699 const uint32_t *new_version)
1701 struct tevent_req *req;
1702 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1703 struct tevent_req *subreq;
1704 bool ok;
1706 req = tevent_req_create(mem_ctx, &state,
1707 struct netlogon_creds_cli_ServerPasswordSet_state);
1708 if (req == NULL) {
1709 return NULL;
1712 state->ev = ev;
1713 state->context = context;
1714 state->binding_handle = b;
1716 if (new_password->length < 14) {
1717 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1718 return tevent_req_post(req, ev);
1722 * netr_ServerPasswordSet
1724 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1727 * netr_ServerPasswordSet2
1729 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1730 new_password);
1731 if (!ok) {
1732 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1733 return tevent_req_post(req, ev);
1736 if (new_version != NULL) {
1737 struct NL_PASSWORD_VERSION version;
1738 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1739 uint32_t ofs = 512 - len;
1740 uint8_t *p;
1742 if (len > 500) {
1743 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1744 return tevent_req_post(req, ev);
1746 ofs -= 12;
1748 version.ReservedField = 0;
1749 version.PasswordVersionNumber = *new_version;
1750 version.PasswordVersionPresent =
1751 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1753 p = state->samr_crypt_password.data + ofs;
1754 SIVAL(p, 0, version.ReservedField);
1755 SIVAL(p, 4, version.PasswordVersionNumber);
1756 SIVAL(p, 8, version.PasswordVersionPresent);
1759 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1760 context->server.computer);
1761 if (tevent_req_nomem(state->srv_name_slash, req)) {
1762 return tevent_req_post(req, ev);
1765 dcerpc_binding_handle_auth_info(state->binding_handle,
1766 &state->auth_type,
1767 &state->auth_level);
1769 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1770 state->context);
1771 if (tevent_req_nomem(subreq, req)) {
1772 return tevent_req_post(req, ev);
1775 tevent_req_set_callback(subreq,
1776 netlogon_creds_cli_ServerPasswordSet_locked,
1777 req);
1779 return req;
1782 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1783 NTSTATUS status)
1785 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1786 tevent_req_data(req,
1787 struct netlogon_creds_cli_ServerPasswordSet_state);
1789 if (state->creds == NULL) {
1790 return;
1793 dcerpc_binding_handle_set_timeout(state->binding_handle,
1794 state->old_timeout);
1796 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1797 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1798 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1799 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1800 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1801 TALLOC_FREE(state->creds);
1802 return;
1805 netlogon_creds_cli_delete(state->context, state->creds);
1806 TALLOC_FREE(state->creds);
1809 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1811 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1813 struct tevent_req *req =
1814 tevent_req_callback_data(subreq,
1815 struct tevent_req);
1816 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1817 tevent_req_data(req,
1818 struct netlogon_creds_cli_ServerPasswordSet_state);
1819 NTSTATUS status;
1821 status = netlogon_creds_cli_lock_recv(subreq, state,
1822 &state->creds);
1823 TALLOC_FREE(subreq);
1824 if (tevent_req_nterror(req, status)) {
1825 return;
1828 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1829 switch (state->auth_level) {
1830 case DCERPC_AUTH_LEVEL_INTEGRITY:
1831 case DCERPC_AUTH_LEVEL_PRIVACY:
1832 break;
1833 default:
1834 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1835 return;
1837 } else {
1838 uint32_t tmp = state->creds->negotiate_flags;
1840 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1842 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1843 * it should be used, which means
1844 * we had a chance to verify no downgrade
1845 * happened.
1847 * This relies on netlogon_creds_cli_check*
1848 * being called before, as first request after
1849 * the DCERPC bind.
1851 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1852 return;
1856 state->old_timeout = dcerpc_binding_handle_set_timeout(
1857 state->binding_handle, 600000);
1860 * we defer all callbacks in order to cleanup
1861 * the database record.
1863 tevent_req_defer_callback(req, state->ev);
1865 state->tmp_creds = *state->creds;
1866 netlogon_creds_client_authenticator(&state->tmp_creds,
1867 &state->req_auth);
1868 ZERO_STRUCT(state->rep_auth);
1870 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1872 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1873 netlogon_creds_aes_encrypt(&state->tmp_creds,
1874 state->samr_crypt_password.data,
1875 516);
1876 } else {
1877 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1878 state->samr_crypt_password.data,
1879 516);
1882 memcpy(state->netr_crypt_password.data,
1883 state->samr_crypt_password.data, 512);
1884 state->netr_crypt_password.length =
1885 IVAL(state->samr_crypt_password.data, 512);
1887 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1888 state->binding_handle,
1889 state->srv_name_slash,
1890 state->tmp_creds.account_name,
1891 state->tmp_creds.secure_channel_type,
1892 state->tmp_creds.computer_name,
1893 &state->req_auth,
1894 &state->rep_auth,
1895 &state->netr_crypt_password);
1896 if (tevent_req_nomem(subreq, req)) {
1897 status = NT_STATUS_NO_MEMORY;
1898 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1899 return;
1901 } else {
1902 netlogon_creds_des_encrypt(&state->tmp_creds,
1903 &state->samr_password);
1905 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1906 state->binding_handle,
1907 state->srv_name_slash,
1908 state->tmp_creds.account_name,
1909 state->tmp_creds.secure_channel_type,
1910 state->tmp_creds.computer_name,
1911 &state->req_auth,
1912 &state->rep_auth,
1913 &state->samr_password);
1914 if (tevent_req_nomem(subreq, req)) {
1915 status = NT_STATUS_NO_MEMORY;
1916 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1917 return;
1921 tevent_req_set_callback(subreq,
1922 netlogon_creds_cli_ServerPasswordSet_done,
1923 req);
1926 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1928 struct tevent_req *req =
1929 tevent_req_callback_data(subreq,
1930 struct tevent_req);
1931 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1932 tevent_req_data(req,
1933 struct netlogon_creds_cli_ServerPasswordSet_state);
1934 NTSTATUS status;
1935 NTSTATUS result;
1936 bool ok;
1938 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1939 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1940 &result);
1941 TALLOC_FREE(subreq);
1942 if (tevent_req_nterror(req, status)) {
1943 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1944 return;
1946 } else {
1947 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1948 &result);
1949 TALLOC_FREE(subreq);
1950 if (tevent_req_nterror(req, status)) {
1951 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1952 return;
1956 ok = netlogon_creds_client_check(&state->tmp_creds,
1957 &state->rep_auth.cred);
1958 if (!ok) {
1959 status = NT_STATUS_ACCESS_DENIED;
1960 tevent_req_nterror(req, status);
1961 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1962 return;
1965 if (tevent_req_nterror(req, result)) {
1966 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
1967 return;
1970 dcerpc_binding_handle_set_timeout(state->binding_handle,
1971 state->old_timeout);
1973 *state->creds = state->tmp_creds;
1974 status = netlogon_creds_cli_store(state->context,
1975 state->creds);
1976 TALLOC_FREE(state->creds);
1977 if (tevent_req_nterror(req, status)) {
1978 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1979 return;
1982 tevent_req_done(req);
1985 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
1987 NTSTATUS status;
1989 if (tevent_req_is_nterror(req, &status)) {
1990 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1991 tevent_req_received(req);
1992 return status;
1995 tevent_req_received(req);
1996 return NT_STATUS_OK;
1999 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2000 struct netlogon_creds_cli_context *context,
2001 struct dcerpc_binding_handle *b,
2002 const DATA_BLOB *new_password,
2003 const uint32_t *new_version)
2005 TALLOC_CTX *frame = talloc_stackframe();
2006 struct tevent_context *ev;
2007 struct tevent_req *req;
2008 NTSTATUS status = NT_STATUS_NO_MEMORY;
2010 ev = samba_tevent_context_init(frame);
2011 if (ev == NULL) {
2012 goto fail;
2014 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2015 new_password,
2016 new_version);
2017 if (req == NULL) {
2018 goto fail;
2020 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2021 goto fail;
2023 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2024 fail:
2025 TALLOC_FREE(frame);
2026 return status;
2029 struct netlogon_creds_cli_LogonSamLogon_state {
2030 struct tevent_context *ev;
2031 struct netlogon_creds_cli_context *context;
2032 struct dcerpc_binding_handle *binding_handle;
2034 char *srv_name_slash;
2036 enum netr_LogonInfoClass logon_level;
2037 const union netr_LogonLevel *const_logon;
2038 union netr_LogonLevel *logon;
2039 uint32_t flags;
2041 uint16_t validation_level;
2042 union netr_Validation *validation;
2043 uint8_t authoritative;
2046 * do we need encryption at the application layer?
2048 bool user_encrypt;
2049 bool try_logon_ex;
2050 bool try_validation6;
2053 * the read only credentials before we started the operation
2054 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2056 struct netlogon_creds_CredentialState *ro_creds;
2059 * The (locked) credentials used for the credential chain
2060 * used for netr_LogonSamLogonWithFlags() or
2061 * netr_LogonSamLogonWith().
2063 struct netlogon_creds_CredentialState *lk_creds;
2066 * While we have locked the global credentials (lk_creds above)
2067 * we operate an a temporary copy, because a server
2068 * may not support netr_LogonSamLogonWithFlags() and
2069 * didn't process our netr_Authenticator, so we need to
2070 * restart from lk_creds.
2072 struct netlogon_creds_CredentialState tmp_creds;
2073 struct netr_Authenticator req_auth;
2074 struct netr_Authenticator rep_auth;
2077 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2078 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2079 NTSTATUS status);
2081 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2082 struct tevent_context *ev,
2083 struct netlogon_creds_cli_context *context,
2084 struct dcerpc_binding_handle *b,
2085 enum netr_LogonInfoClass logon_level,
2086 const union netr_LogonLevel *logon,
2087 uint32_t flags)
2089 struct tevent_req *req;
2090 struct netlogon_creds_cli_LogonSamLogon_state *state;
2092 req = tevent_req_create(mem_ctx, &state,
2093 struct netlogon_creds_cli_LogonSamLogon_state);
2094 if (req == NULL) {
2095 return NULL;
2098 state->ev = ev;
2099 state->context = context;
2100 state->binding_handle = b;
2102 state->logon_level = logon_level;
2103 state->const_logon = logon;
2104 state->flags = flags;
2106 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2107 context->server.computer);
2108 if (tevent_req_nomem(state->srv_name_slash, req)) {
2109 return tevent_req_post(req, ev);
2112 switch (logon_level) {
2113 case NetlogonInteractiveInformation:
2114 case NetlogonInteractiveTransitiveInformation:
2115 case NetlogonServiceInformation:
2116 case NetlogonServiceTransitiveInformation:
2117 case NetlogonGenericInformation:
2118 state->user_encrypt = true;
2119 break;
2121 case NetlogonNetworkInformation:
2122 case NetlogonNetworkTransitiveInformation:
2123 break;
2126 state->validation = talloc_zero(state, union netr_Validation);
2127 if (tevent_req_nomem(state->validation, req)) {
2128 return tevent_req_post(req, ev);
2131 netlogon_creds_cli_LogonSamLogon_start(req);
2132 if (!tevent_req_is_in_progress(req)) {
2133 return tevent_req_post(req, ev);
2137 * we defer all callbacks in order to cleanup
2138 * the database record.
2140 tevent_req_defer_callback(req, state->ev);
2141 return req;
2144 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2145 NTSTATUS status)
2147 struct netlogon_creds_cli_LogonSamLogon_state *state =
2148 tevent_req_data(req,
2149 struct netlogon_creds_cli_LogonSamLogon_state);
2151 if (state->lk_creds == NULL) {
2152 return;
2155 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2157 * This is a hack to recover from a bug in old
2158 * Samba servers, when LogonSamLogonEx() fails:
2160 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2162 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2164 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2165 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2166 * If the sign/seal check fails.
2168 * In that case we need to cleanup the netlogon session.
2170 * It's the job of the caller to disconnect the current
2171 * connection, if netlogon_creds_cli_LogonSamLogon()
2172 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2174 if (!state->context->server.try_logon_with) {
2175 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2179 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2180 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2181 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2182 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2183 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2184 TALLOC_FREE(state->lk_creds);
2185 return;
2188 netlogon_creds_cli_delete(state->context, state->lk_creds);
2189 TALLOC_FREE(state->lk_creds);
2192 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2194 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2196 struct netlogon_creds_cli_LogonSamLogon_state *state =
2197 tevent_req_data(req,
2198 struct netlogon_creds_cli_LogonSamLogon_state);
2199 struct tevent_req *subreq;
2200 NTSTATUS status;
2201 enum dcerpc_AuthType auth_type;
2202 enum dcerpc_AuthLevel auth_level;
2204 TALLOC_FREE(state->ro_creds);
2205 TALLOC_FREE(state->logon);
2206 ZERO_STRUCTP(state->validation);
2208 dcerpc_binding_handle_auth_info(state->binding_handle,
2209 &auth_type, &auth_level);
2211 state->try_logon_ex = state->context->server.try_logon_ex;
2212 state->try_validation6 = state->context->server.try_validation6;
2214 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2215 state->try_logon_ex = false;
2218 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2219 state->try_validation6 = false;
2222 if (state->try_logon_ex) {
2223 if (state->try_validation6) {
2224 state->validation_level = 6;
2225 } else {
2226 state->validation_level = 3;
2227 state->user_encrypt = true;
2230 state->logon = netlogon_creds_shallow_copy_logon(state,
2231 state->logon_level,
2232 state->const_logon);
2233 if (tevent_req_nomem(state->logon, req)) {
2234 status = NT_STATUS_NO_MEMORY;
2235 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2236 return;
2239 if (state->user_encrypt) {
2240 status = netlogon_creds_cli_get(state->context,
2241 state,
2242 &state->ro_creds);
2243 if (!NT_STATUS_IS_OK(status)) {
2244 status = NT_STATUS_ACCESS_DENIED;
2245 tevent_req_nterror(req, status);
2246 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2247 return;
2250 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2251 state->logon_level,
2252 state->logon);
2255 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2256 state->binding_handle,
2257 state->srv_name_slash,
2258 state->context->client.computer,
2259 state->logon_level,
2260 state->logon,
2261 state->validation_level,
2262 state->validation,
2263 &state->authoritative,
2264 &state->flags);
2265 if (tevent_req_nomem(subreq, req)) {
2266 status = NT_STATUS_NO_MEMORY;
2267 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2268 return;
2270 tevent_req_set_callback(subreq,
2271 netlogon_creds_cli_LogonSamLogon_done,
2272 req);
2273 return;
2276 if (state->lk_creds == NULL) {
2277 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2278 state->context);
2279 if (tevent_req_nomem(subreq, req)) {
2280 status = NT_STATUS_NO_MEMORY;
2281 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2282 return;
2284 tevent_req_set_callback(subreq,
2285 netlogon_creds_cli_LogonSamLogon_done,
2286 req);
2287 return;
2290 state->tmp_creds = *state->lk_creds;
2291 netlogon_creds_client_authenticator(&state->tmp_creds,
2292 &state->req_auth);
2293 ZERO_STRUCT(state->rep_auth);
2295 state->logon = netlogon_creds_shallow_copy_logon(state,
2296 state->logon_level,
2297 state->const_logon);
2298 if (tevent_req_nomem(state->logon, req)) {
2299 status = NT_STATUS_NO_MEMORY;
2300 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2301 return;
2304 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2305 state->logon_level,
2306 state->logon);
2308 state->validation_level = 3;
2310 if (state->context->server.try_logon_with) {
2311 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2312 state->binding_handle,
2313 state->srv_name_slash,
2314 state->context->client.computer,
2315 &state->req_auth,
2316 &state->rep_auth,
2317 state->logon_level,
2318 state->logon,
2319 state->validation_level,
2320 state->validation,
2321 &state->authoritative,
2322 &state->flags);
2323 if (tevent_req_nomem(subreq, req)) {
2324 status = NT_STATUS_NO_MEMORY;
2325 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2326 return;
2328 } else {
2329 state->flags = 0;
2331 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2332 state->binding_handle,
2333 state->srv_name_slash,
2334 state->context->client.computer,
2335 &state->req_auth,
2336 &state->rep_auth,
2337 state->logon_level,
2338 state->logon,
2339 state->validation_level,
2340 state->validation,
2341 &state->authoritative);
2342 if (tevent_req_nomem(subreq, req)) {
2343 status = NT_STATUS_NO_MEMORY;
2344 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2345 return;
2349 tevent_req_set_callback(subreq,
2350 netlogon_creds_cli_LogonSamLogon_done,
2351 req);
2354 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2356 struct tevent_req *req =
2357 tevent_req_callback_data(subreq,
2358 struct tevent_req);
2359 struct netlogon_creds_cli_LogonSamLogon_state *state =
2360 tevent_req_data(req,
2361 struct netlogon_creds_cli_LogonSamLogon_state);
2362 NTSTATUS status;
2363 NTSTATUS result;
2364 bool ok;
2366 if (state->try_logon_ex) {
2367 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2368 state->validation,
2369 &result);
2370 TALLOC_FREE(subreq);
2371 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2372 state->context->server.try_validation6 = false;
2373 state->context->server.try_logon_ex = false;
2374 netlogon_creds_cli_LogonSamLogon_start(req);
2375 return;
2377 if (tevent_req_nterror(req, status)) {
2378 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2379 return;
2382 if ((state->validation_level == 6) &&
2383 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2384 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2385 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2387 state->context->server.try_validation6 = false;
2388 netlogon_creds_cli_LogonSamLogon_start(req);
2389 return;
2392 if (tevent_req_nterror(req, result)) {
2393 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2394 return;
2397 if (state->ro_creds == NULL) {
2398 tevent_req_done(req);
2399 return;
2402 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2403 if (!ok) {
2405 * We got a race, lets retry with on authenticator
2406 * protection.
2408 * netlogon_creds_cli_LogonSamLogon_start()
2409 * will TALLOC_FREE(state->ro_creds);
2411 state->try_logon_ex = false;
2412 netlogon_creds_cli_LogonSamLogon_start(req);
2413 return;
2416 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2417 state->validation_level,
2418 state->validation);
2420 tevent_req_done(req);
2421 return;
2424 if (state->lk_creds == NULL) {
2425 status = netlogon_creds_cli_lock_recv(subreq, state,
2426 &state->lk_creds);
2427 TALLOC_FREE(subreq);
2428 if (tevent_req_nterror(req, status)) {
2429 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2430 return;
2433 netlogon_creds_cli_LogonSamLogon_start(req);
2434 return;
2437 if (state->context->server.try_logon_with) {
2438 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2439 state->validation,
2440 &result);
2441 TALLOC_FREE(subreq);
2442 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2443 state->context->server.try_logon_with = false;
2444 netlogon_creds_cli_LogonSamLogon_start(req);
2445 return;
2447 if (tevent_req_nterror(req, status)) {
2448 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2449 return;
2451 } else {
2452 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2453 state->validation,
2454 &result);
2455 TALLOC_FREE(subreq);
2456 if (tevent_req_nterror(req, status)) {
2457 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2458 return;
2462 ok = netlogon_creds_client_check(&state->tmp_creds,
2463 &state->rep_auth.cred);
2464 if (!ok) {
2465 status = NT_STATUS_ACCESS_DENIED;
2466 tevent_req_nterror(req, status);
2467 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2468 return;
2471 *state->lk_creds = state->tmp_creds;
2472 status = netlogon_creds_cli_store(state->context,
2473 state->lk_creds);
2474 TALLOC_FREE(state->lk_creds);
2476 if (tevent_req_nterror(req, status)) {
2477 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2478 return;
2481 if (tevent_req_nterror(req, result)) {
2482 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2483 return;
2486 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2487 state->validation_level,
2488 state->validation);
2490 tevent_req_done(req);
2493 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2494 TALLOC_CTX *mem_ctx,
2495 uint16_t *validation_level,
2496 union netr_Validation **validation,
2497 uint8_t *authoritative,
2498 uint32_t *flags)
2500 struct netlogon_creds_cli_LogonSamLogon_state *state =
2501 tevent_req_data(req,
2502 struct netlogon_creds_cli_LogonSamLogon_state);
2503 NTSTATUS status;
2505 /* authoritative is also returned on error */
2506 *authoritative = state->authoritative;
2508 if (tevent_req_is_nterror(req, &status)) {
2509 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2510 tevent_req_received(req);
2511 return status;
2514 *validation_level = state->validation_level;
2515 *validation = talloc_move(mem_ctx, &state->validation);
2516 *flags = state->flags;
2518 tevent_req_received(req);
2519 return NT_STATUS_OK;
2522 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2523 struct netlogon_creds_cli_context *context,
2524 struct dcerpc_binding_handle *b,
2525 enum netr_LogonInfoClass logon_level,
2526 const union netr_LogonLevel *logon,
2527 TALLOC_CTX *mem_ctx,
2528 uint16_t *validation_level,
2529 union netr_Validation **validation,
2530 uint8_t *authoritative,
2531 uint32_t *flags)
2533 TALLOC_CTX *frame = talloc_stackframe();
2534 struct tevent_context *ev;
2535 struct tevent_req *req;
2536 NTSTATUS status = NT_STATUS_NO_MEMORY;
2538 ev = samba_tevent_context_init(frame);
2539 if (ev == NULL) {
2540 goto fail;
2542 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2543 logon_level, logon,
2544 *flags);
2545 if (req == NULL) {
2546 goto fail;
2548 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2549 goto fail;
2551 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2552 validation_level,
2553 validation,
2554 authoritative,
2555 flags);
2556 fail:
2557 TALLOC_FREE(frame);
2558 return status;
2561 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2562 struct tevent_context *ev;
2563 struct netlogon_creds_cli_context *context;
2564 struct dcerpc_binding_handle *binding_handle;
2566 char *srv_name_slash;
2567 enum dcerpc_AuthType auth_type;
2568 enum dcerpc_AuthLevel auth_level;
2570 const char *site_name;
2571 uint32_t dns_ttl;
2572 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2574 struct netlogon_creds_CredentialState *creds;
2575 struct netlogon_creds_CredentialState tmp_creds;
2576 struct netr_Authenticator req_auth;
2577 struct netr_Authenticator rep_auth;
2580 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2581 NTSTATUS status);
2582 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2584 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2585 struct tevent_context *ev,
2586 struct netlogon_creds_cli_context *context,
2587 struct dcerpc_binding_handle *b,
2588 const char *site_name,
2589 uint32_t dns_ttl,
2590 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2592 struct tevent_req *req;
2593 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2594 struct tevent_req *subreq;
2596 req = tevent_req_create(mem_ctx, &state,
2597 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2598 if (req == NULL) {
2599 return NULL;
2602 state->ev = ev;
2603 state->context = context;
2604 state->binding_handle = b;
2606 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2607 context->server.computer);
2608 if (tevent_req_nomem(state->srv_name_slash, req)) {
2609 return tevent_req_post(req, ev);
2612 state->site_name = site_name;
2613 state->dns_ttl = dns_ttl;
2614 state->dns_names = dns_names;
2616 dcerpc_binding_handle_auth_info(state->binding_handle,
2617 &state->auth_type,
2618 &state->auth_level);
2620 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2621 state->context);
2622 if (tevent_req_nomem(subreq, req)) {
2623 return tevent_req_post(req, ev);
2626 tevent_req_set_callback(subreq,
2627 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2628 req);
2630 return req;
2633 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2634 NTSTATUS status)
2636 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2637 tevent_req_data(req,
2638 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2640 if (state->creds == NULL) {
2641 return;
2644 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2645 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2646 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2647 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2648 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2649 TALLOC_FREE(state->creds);
2650 return;
2653 netlogon_creds_cli_delete(state->context, state->creds);
2654 TALLOC_FREE(state->creds);
2657 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2659 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2661 struct tevent_req *req =
2662 tevent_req_callback_data(subreq,
2663 struct tevent_req);
2664 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2665 tevent_req_data(req,
2666 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2667 NTSTATUS status;
2669 status = netlogon_creds_cli_lock_recv(subreq, state,
2670 &state->creds);
2671 TALLOC_FREE(subreq);
2672 if (tevent_req_nterror(req, status)) {
2673 return;
2676 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2677 switch (state->auth_level) {
2678 case DCERPC_AUTH_LEVEL_INTEGRITY:
2679 case DCERPC_AUTH_LEVEL_PRIVACY:
2680 break;
2681 default:
2682 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2683 return;
2685 } else {
2686 uint32_t tmp = state->creds->negotiate_flags;
2688 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2690 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2691 * it should be used, which means
2692 * we had a chance to verify no downgrade
2693 * happened.
2695 * This relies on netlogon_creds_cli_check*
2696 * being called before, as first request after
2697 * the DCERPC bind.
2699 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2700 return;
2705 * we defer all callbacks in order to cleanup
2706 * the database record.
2708 tevent_req_defer_callback(req, state->ev);
2710 state->tmp_creds = *state->creds;
2711 netlogon_creds_client_authenticator(&state->tmp_creds,
2712 &state->req_auth);
2713 ZERO_STRUCT(state->rep_auth);
2715 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2716 state->binding_handle,
2717 state->srv_name_slash,
2718 state->tmp_creds.computer_name,
2719 &state->req_auth,
2720 &state->rep_auth,
2721 state->site_name,
2722 state->dns_ttl,
2723 state->dns_names);
2724 if (tevent_req_nomem(subreq, req)) {
2725 status = NT_STATUS_NO_MEMORY;
2726 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2727 return;
2730 tevent_req_set_callback(subreq,
2731 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2732 req);
2735 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2737 struct tevent_req *req =
2738 tevent_req_callback_data(subreq,
2739 struct tevent_req);
2740 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2741 tevent_req_data(req,
2742 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2743 NTSTATUS status;
2744 NTSTATUS result;
2745 bool ok;
2748 * We use state->dns_names as the memory context, as this is
2749 * the only in/out variable and it has been overwritten by the
2750 * out parameter from the server.
2752 * We need to preserve the return value until the caller can use it.
2754 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2755 &result);
2756 TALLOC_FREE(subreq);
2757 if (tevent_req_nterror(req, status)) {
2758 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2759 return;
2762 ok = netlogon_creds_client_check(&state->tmp_creds,
2763 &state->rep_auth.cred);
2764 if (!ok) {
2765 status = NT_STATUS_ACCESS_DENIED;
2766 tevent_req_nterror(req, status);
2767 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2768 return;
2771 *state->creds = state->tmp_creds;
2772 status = netlogon_creds_cli_store(state->context,
2773 state->creds);
2774 TALLOC_FREE(state->creds);
2776 if (tevent_req_nterror(req, status)) {
2777 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2778 return;
2781 if (tevent_req_nterror(req, result)) {
2782 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2783 return;
2786 tevent_req_done(req);
2789 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2791 NTSTATUS status;
2793 if (tevent_req_is_nterror(req, &status)) {
2794 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2795 tevent_req_received(req);
2796 return status;
2799 tevent_req_received(req);
2800 return NT_STATUS_OK;
2803 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2804 struct netlogon_creds_cli_context *context,
2805 struct dcerpc_binding_handle *b,
2806 const char *site_name,
2807 uint32_t dns_ttl,
2808 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2810 TALLOC_CTX *frame = talloc_stackframe();
2811 struct tevent_context *ev;
2812 struct tevent_req *req;
2813 NTSTATUS status = NT_STATUS_NO_MEMORY;
2815 ev = samba_tevent_context_init(frame);
2816 if (ev == NULL) {
2817 goto fail;
2819 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2820 site_name,
2821 dns_ttl,
2822 dns_names);
2823 if (req == NULL) {
2824 goto fail;
2826 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2827 goto fail;
2829 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2830 fail:
2831 TALLOC_FREE(frame);
2832 return status;
2835 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2836 struct tevent_context *ev;
2837 struct netlogon_creds_cli_context *context;
2838 struct dcerpc_binding_handle *binding_handle;
2840 char *srv_name_slash;
2841 enum dcerpc_AuthType auth_type;
2842 enum dcerpc_AuthLevel auth_level;
2844 struct samr_Password new_owf_password;
2845 struct samr_Password old_owf_password;
2846 struct netr_TrustInfo *trust_info;
2848 struct netlogon_creds_CredentialState *creds;
2849 struct netlogon_creds_CredentialState tmp_creds;
2850 struct netr_Authenticator req_auth;
2851 struct netr_Authenticator rep_auth;
2854 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2855 NTSTATUS status);
2856 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2858 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2859 struct tevent_context *ev,
2860 struct netlogon_creds_cli_context *context,
2861 struct dcerpc_binding_handle *b)
2863 struct tevent_req *req;
2864 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2865 struct tevent_req *subreq;
2867 req = tevent_req_create(mem_ctx, &state,
2868 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2869 if (req == NULL) {
2870 return NULL;
2873 state->ev = ev;
2874 state->context = context;
2875 state->binding_handle = b;
2877 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2878 context->server.computer);
2879 if (tevent_req_nomem(state->srv_name_slash, req)) {
2880 return tevent_req_post(req, ev);
2883 dcerpc_binding_handle_auth_info(state->binding_handle,
2884 &state->auth_type,
2885 &state->auth_level);
2887 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2888 state->context);
2889 if (tevent_req_nomem(subreq, req)) {
2890 return tevent_req_post(req, ev);
2893 tevent_req_set_callback(subreq,
2894 netlogon_creds_cli_ServerGetTrustInfo_locked,
2895 req);
2897 return req;
2900 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2901 NTSTATUS status)
2903 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2904 tevent_req_data(req,
2905 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2907 if (state->creds == NULL) {
2908 return;
2911 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2912 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2913 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2914 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2915 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2916 TALLOC_FREE(state->creds);
2917 return;
2920 netlogon_creds_cli_delete(state->context, state->creds);
2921 TALLOC_FREE(state->creds);
2924 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2926 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2928 struct tevent_req *req =
2929 tevent_req_callback_data(subreq,
2930 struct tevent_req);
2931 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2932 tevent_req_data(req,
2933 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2934 NTSTATUS status;
2936 status = netlogon_creds_cli_lock_recv(subreq, state,
2937 &state->creds);
2938 TALLOC_FREE(subreq);
2939 if (tevent_req_nterror(req, status)) {
2940 return;
2943 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2944 switch (state->auth_level) {
2945 case DCERPC_AUTH_LEVEL_PRIVACY:
2946 break;
2947 default:
2948 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2949 return;
2951 } else {
2952 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2953 return;
2957 * we defer all callbacks in order to cleanup
2958 * the database record.
2960 tevent_req_defer_callback(req, state->ev);
2962 state->tmp_creds = *state->creds;
2963 netlogon_creds_client_authenticator(&state->tmp_creds,
2964 &state->req_auth);
2965 ZERO_STRUCT(state->rep_auth);
2967 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
2968 state->binding_handle,
2969 state->srv_name_slash,
2970 state->tmp_creds.account_name,
2971 state->tmp_creds.secure_channel_type,
2972 state->tmp_creds.computer_name,
2973 &state->req_auth,
2974 &state->rep_auth,
2975 &state->new_owf_password,
2976 &state->old_owf_password,
2977 &state->trust_info);
2978 if (tevent_req_nomem(subreq, req)) {
2979 status = NT_STATUS_NO_MEMORY;
2980 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
2981 return;
2984 tevent_req_set_callback(subreq,
2985 netlogon_creds_cli_ServerGetTrustInfo_done,
2986 req);
2989 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
2991 struct tevent_req *req =
2992 tevent_req_callback_data(subreq,
2993 struct tevent_req);
2994 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2995 tevent_req_data(req,
2996 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2997 NTSTATUS status;
2998 NTSTATUS result;
2999 const struct samr_Password zero = {};
3000 int cmp;
3001 bool ok;
3004 * We use state->dns_names as the memory context, as this is
3005 * the only in/out variable and it has been overwritten by the
3006 * out parameter from the server.
3008 * We need to preserve the return value until the caller can use it.
3010 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3011 TALLOC_FREE(subreq);
3012 if (tevent_req_nterror(req, status)) {
3013 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3014 return;
3017 ok = netlogon_creds_client_check(&state->tmp_creds,
3018 &state->rep_auth.cred);
3019 if (!ok) {
3020 status = NT_STATUS_ACCESS_DENIED;
3021 tevent_req_nterror(req, status);
3022 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3023 return;
3026 cmp = memcmp(state->new_owf_password.hash,
3027 zero.hash, sizeof(zero.hash));
3028 if (cmp != 0) {
3029 netlogon_creds_des_decrypt(&state->tmp_creds,
3030 &state->new_owf_password);
3032 cmp = memcmp(state->old_owf_password.hash,
3033 zero.hash, sizeof(zero.hash));
3034 if (cmp != 0) {
3035 netlogon_creds_des_decrypt(&state->tmp_creds,
3036 &state->old_owf_password);
3039 *state->creds = state->tmp_creds;
3040 status = netlogon_creds_cli_store(state->context,
3041 state->creds);
3042 TALLOC_FREE(state->creds);
3043 if (tevent_req_nterror(req, status)) {
3044 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3045 return;
3048 if (tevent_req_nterror(req, result)) {
3049 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3050 return;
3053 tevent_req_done(req);
3056 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3057 TALLOC_CTX *mem_ctx,
3058 struct samr_Password *new_owf_password,
3059 struct samr_Password *old_owf_password,
3060 struct netr_TrustInfo **trust_info)
3062 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3063 tevent_req_data(req,
3064 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3065 NTSTATUS status;
3067 if (tevent_req_is_nterror(req, &status)) {
3068 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3069 tevent_req_received(req);
3070 return status;
3073 if (new_owf_password != NULL) {
3074 *new_owf_password = state->new_owf_password;
3076 if (old_owf_password != NULL) {
3077 *old_owf_password = state->old_owf_password;
3079 if (trust_info != NULL) {
3080 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3083 tevent_req_received(req);
3084 return NT_STATUS_OK;
3087 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3088 struct netlogon_creds_cli_context *context,
3089 struct dcerpc_binding_handle *b,
3090 TALLOC_CTX *mem_ctx,
3091 struct samr_Password *new_owf_password,
3092 struct samr_Password *old_owf_password,
3093 struct netr_TrustInfo **trust_info)
3095 TALLOC_CTX *frame = talloc_stackframe();
3096 struct tevent_context *ev;
3097 struct tevent_req *req;
3098 NTSTATUS status = NT_STATUS_NO_MEMORY;
3100 ev = samba_tevent_context_init(frame);
3101 if (ev == NULL) {
3102 goto fail;
3104 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3105 if (req == NULL) {
3106 goto fail;
3108 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3109 goto fail;
3111 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3112 mem_ctx,
3113 new_owf_password,
3114 old_owf_password,
3115 trust_info);
3116 fail:
3117 TALLOC_FREE(frame);
3118 return status;
3121 struct netlogon_creds_cli_GetForestTrustInformation_state {
3122 struct tevent_context *ev;
3123 struct netlogon_creds_cli_context *context;
3124 struct dcerpc_binding_handle *binding_handle;
3126 char *srv_name_slash;
3127 enum dcerpc_AuthType auth_type;
3128 enum dcerpc_AuthLevel auth_level;
3130 uint32_t flags;
3131 struct lsa_ForestTrustInformation *forest_trust_info;
3133 struct netlogon_creds_CredentialState *creds;
3134 struct netlogon_creds_CredentialState tmp_creds;
3135 struct netr_Authenticator req_auth;
3136 struct netr_Authenticator rep_auth;
3139 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3140 NTSTATUS status);
3141 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3143 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3144 struct tevent_context *ev,
3145 struct netlogon_creds_cli_context *context,
3146 struct dcerpc_binding_handle *b)
3148 struct tevent_req *req;
3149 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3150 struct tevent_req *subreq;
3152 req = tevent_req_create(mem_ctx, &state,
3153 struct netlogon_creds_cli_GetForestTrustInformation_state);
3154 if (req == NULL) {
3155 return NULL;
3158 state->ev = ev;
3159 state->context = context;
3160 state->binding_handle = b;
3162 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3163 context->server.computer);
3164 if (tevent_req_nomem(state->srv_name_slash, req)) {
3165 return tevent_req_post(req, ev);
3168 state->flags = 0;
3170 dcerpc_binding_handle_auth_info(state->binding_handle,
3171 &state->auth_type,
3172 &state->auth_level);
3174 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3175 state->context);
3176 if (tevent_req_nomem(subreq, req)) {
3177 return tevent_req_post(req, ev);
3180 tevent_req_set_callback(subreq,
3181 netlogon_creds_cli_GetForestTrustInformation_locked,
3182 req);
3184 return req;
3187 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3188 NTSTATUS status)
3190 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3191 tevent_req_data(req,
3192 struct netlogon_creds_cli_GetForestTrustInformation_state);
3194 if (state->creds == NULL) {
3195 return;
3198 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3199 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3200 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3201 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3202 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3203 TALLOC_FREE(state->creds);
3204 return;
3207 netlogon_creds_cli_delete(state->context, state->creds);
3208 TALLOC_FREE(state->creds);
3211 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3213 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3215 struct tevent_req *req =
3216 tevent_req_callback_data(subreq,
3217 struct tevent_req);
3218 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3219 tevent_req_data(req,
3220 struct netlogon_creds_cli_GetForestTrustInformation_state);
3221 NTSTATUS status;
3223 status = netlogon_creds_cli_lock_recv(subreq, state,
3224 &state->creds);
3225 TALLOC_FREE(subreq);
3226 if (tevent_req_nterror(req, status)) {
3227 return;
3230 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3231 switch (state->auth_level) {
3232 case DCERPC_AUTH_LEVEL_INTEGRITY:
3233 case DCERPC_AUTH_LEVEL_PRIVACY:
3234 break;
3235 default:
3236 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3237 return;
3239 } else {
3240 uint32_t tmp = state->creds->negotiate_flags;
3242 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3244 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3245 * it should be used, which means
3246 * we had a chance to verify no downgrade
3247 * happened.
3249 * This relies on netlogon_creds_cli_check*
3250 * being called before, as first request after
3251 * the DCERPC bind.
3253 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3254 return;
3259 * we defer all callbacks in order to cleanup
3260 * the database record.
3262 tevent_req_defer_callback(req, state->ev);
3264 state->tmp_creds = *state->creds;
3265 netlogon_creds_client_authenticator(&state->tmp_creds,
3266 &state->req_auth);
3267 ZERO_STRUCT(state->rep_auth);
3269 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3270 state->binding_handle,
3271 state->srv_name_slash,
3272 state->tmp_creds.computer_name,
3273 &state->req_auth,
3274 &state->rep_auth,
3275 state->flags,
3276 &state->forest_trust_info);
3277 if (tevent_req_nomem(subreq, req)) {
3278 status = NT_STATUS_NO_MEMORY;
3279 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3280 return;
3283 tevent_req_set_callback(subreq,
3284 netlogon_creds_cli_GetForestTrustInformation_done,
3285 req);
3288 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3290 struct tevent_req *req =
3291 tevent_req_callback_data(subreq,
3292 struct tevent_req);
3293 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3294 tevent_req_data(req,
3295 struct netlogon_creds_cli_GetForestTrustInformation_state);
3296 NTSTATUS status;
3297 NTSTATUS result;
3298 bool ok;
3301 * We use state->dns_names as the memory context, as this is
3302 * the only in/out variable and it has been overwritten by the
3303 * out parameter from the server.
3305 * We need to preserve the return value until the caller can use it.
3307 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3308 TALLOC_FREE(subreq);
3309 if (tevent_req_nterror(req, status)) {
3310 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3311 return;
3314 ok = netlogon_creds_client_check(&state->tmp_creds,
3315 &state->rep_auth.cred);
3316 if (!ok) {
3317 status = NT_STATUS_ACCESS_DENIED;
3318 tevent_req_nterror(req, status);
3319 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3320 return;
3323 *state->creds = state->tmp_creds;
3324 status = netlogon_creds_cli_store(state->context,
3325 state->creds);
3326 TALLOC_FREE(state->creds);
3328 if (tevent_req_nterror(req, status)) {
3329 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3330 return;
3333 if (tevent_req_nterror(req, result)) {
3334 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3335 return;
3338 tevent_req_done(req);
3341 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3342 TALLOC_CTX *mem_ctx,
3343 struct lsa_ForestTrustInformation **forest_trust_info)
3345 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3346 tevent_req_data(req,
3347 struct netlogon_creds_cli_GetForestTrustInformation_state);
3348 NTSTATUS status;
3350 if (tevent_req_is_nterror(req, &status)) {
3351 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3352 tevent_req_received(req);
3353 return status;
3356 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3358 tevent_req_received(req);
3359 return NT_STATUS_OK;
3362 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3363 struct netlogon_creds_cli_context *context,
3364 struct dcerpc_binding_handle *b,
3365 TALLOC_CTX *mem_ctx,
3366 struct lsa_ForestTrustInformation **forest_trust_info)
3368 TALLOC_CTX *frame = talloc_stackframe();
3369 struct tevent_context *ev;
3370 struct tevent_req *req;
3371 NTSTATUS status = NT_STATUS_NO_MEMORY;
3373 ev = samba_tevent_context_init(frame);
3374 if (ev == NULL) {
3375 goto fail;
3377 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3378 if (req == NULL) {
3379 goto fail;
3381 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3382 goto fail;
3384 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3385 mem_ctx,
3386 forest_trust_info);
3387 fail:
3388 TALLOC_FREE(frame);
3389 return status;
3392 struct netlogon_creds_cli_SendToSam_state {
3393 struct tevent_context *ev;
3394 struct netlogon_creds_cli_context *context;
3395 struct dcerpc_binding_handle *binding_handle;
3397 char *srv_name_slash;
3398 enum dcerpc_AuthType auth_type;
3399 enum dcerpc_AuthLevel auth_level;
3401 DATA_BLOB opaque;
3403 struct netlogon_creds_CredentialState *creds;
3404 struct netlogon_creds_CredentialState tmp_creds;
3405 struct netr_Authenticator req_auth;
3406 struct netr_Authenticator rep_auth;
3409 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3410 NTSTATUS status);
3411 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3413 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3414 struct tevent_context *ev,
3415 struct netlogon_creds_cli_context *context,
3416 struct dcerpc_binding_handle *b,
3417 struct netr_SendToSamBase *message)
3419 struct tevent_req *req;
3420 struct netlogon_creds_cli_SendToSam_state *state;
3421 struct tevent_req *subreq;
3422 enum ndr_err_code ndr_err;
3424 req = tevent_req_create(mem_ctx, &state,
3425 struct netlogon_creds_cli_SendToSam_state);
3426 if (req == NULL) {
3427 return NULL;
3430 state->ev = ev;
3431 state->context = context;
3432 state->binding_handle = b;
3434 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3435 context->server.computer);
3436 if (tevent_req_nomem(state->srv_name_slash, req)) {
3437 return tevent_req_post(req, ev);
3440 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3441 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3442 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3443 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3444 tevent_req_nterror(req, status);
3445 return tevent_req_post(req, ev);
3448 dcerpc_binding_handle_auth_info(state->binding_handle,
3449 &state->auth_type,
3450 &state->auth_level);
3452 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3453 state->context);
3454 if (tevent_req_nomem(subreq, req)) {
3455 return tevent_req_post(req, ev);
3458 tevent_req_set_callback(subreq,
3459 netlogon_creds_cli_SendToSam_locked,
3460 req);
3462 return req;
3465 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3466 NTSTATUS status)
3468 struct netlogon_creds_cli_SendToSam_state *state =
3469 tevent_req_data(req,
3470 struct netlogon_creds_cli_SendToSam_state);
3472 if (state->creds == NULL) {
3473 return;
3476 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3477 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3478 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3479 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3480 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3481 TALLOC_FREE(state->creds);
3482 return;
3485 netlogon_creds_cli_delete(state->context, state->creds);
3486 TALLOC_FREE(state->creds);
3489 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3491 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3493 struct tevent_req *req =
3494 tevent_req_callback_data(subreq,
3495 struct tevent_req);
3496 struct netlogon_creds_cli_SendToSam_state *state =
3497 tevent_req_data(req,
3498 struct netlogon_creds_cli_SendToSam_state);
3499 NTSTATUS status;
3501 status = netlogon_creds_cli_lock_recv(subreq, state,
3502 &state->creds);
3503 TALLOC_FREE(subreq);
3504 if (tevent_req_nterror(req, status)) {
3505 return;
3508 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3509 switch (state->auth_level) {
3510 case DCERPC_AUTH_LEVEL_INTEGRITY:
3511 case DCERPC_AUTH_LEVEL_PRIVACY:
3512 break;
3513 default:
3514 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3515 return;
3517 } else {
3518 uint32_t tmp = state->creds->negotiate_flags;
3520 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3522 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3523 * it should be used, which means
3524 * we had a chance to verify no downgrade
3525 * happened.
3527 * This relies on netlogon_creds_cli_check*
3528 * being called before, as first request after
3529 * the DCERPC bind.
3531 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3532 return;
3537 * we defer all callbacks in order to cleanup
3538 * the database record.
3540 tevent_req_defer_callback(req, state->ev);
3542 state->tmp_creds = *state->creds;
3543 netlogon_creds_client_authenticator(&state->tmp_creds,
3544 &state->req_auth);
3545 ZERO_STRUCT(state->rep_auth);
3547 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3548 netlogon_creds_aes_encrypt(&state->tmp_creds,
3549 state->opaque.data,
3550 state->opaque.length);
3551 } else {
3552 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3553 state->opaque.data,
3554 state->opaque.length);
3557 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3558 state->binding_handle,
3559 state->srv_name_slash,
3560 state->tmp_creds.computer_name,
3561 &state->req_auth,
3562 &state->rep_auth,
3563 state->opaque.data,
3564 state->opaque.length);
3565 if (tevent_req_nomem(subreq, req)) {
3566 status = NT_STATUS_NO_MEMORY;
3567 netlogon_creds_cli_SendToSam_cleanup(req, status);
3568 return;
3571 tevent_req_set_callback(subreq,
3572 netlogon_creds_cli_SendToSam_done,
3573 req);
3576 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3578 struct tevent_req *req =
3579 tevent_req_callback_data(subreq,
3580 struct tevent_req);
3581 struct netlogon_creds_cli_SendToSam_state *state =
3582 tevent_req_data(req,
3583 struct netlogon_creds_cli_SendToSam_state);
3584 NTSTATUS status;
3585 NTSTATUS result;
3586 bool ok;
3588 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3589 TALLOC_FREE(subreq);
3590 if (tevent_req_nterror(req, status)) {
3591 netlogon_creds_cli_SendToSam_cleanup(req, status);
3592 return;
3595 ok = netlogon_creds_client_check(&state->tmp_creds,
3596 &state->rep_auth.cred);
3597 if (!ok) {
3598 status = NT_STATUS_ACCESS_DENIED;
3599 tevent_req_nterror(req, status);
3600 netlogon_creds_cli_SendToSam_cleanup(req, status);
3601 return;
3604 *state->creds = state->tmp_creds;
3605 status = netlogon_creds_cli_store(state->context,
3606 state->creds);
3607 TALLOC_FREE(state->creds);
3609 if (tevent_req_nterror(req, status)) {
3610 netlogon_creds_cli_SendToSam_cleanup(req, status);
3611 return;
3615 * Creds must be stored before we send back application errors
3616 * e.g. NT_STATUS_NOT_IMPLEMENTED
3618 if (tevent_req_nterror(req, result)) {
3619 netlogon_creds_cli_SendToSam_cleanup(req, result);
3620 return;
3623 tevent_req_done(req);
3626 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3627 struct dcerpc_binding_handle *b,
3628 struct netr_SendToSamBase *message)
3630 TALLOC_CTX *frame = talloc_stackframe();
3631 struct tevent_context *ev;
3632 struct tevent_req *req;
3633 NTSTATUS status = NT_STATUS_OK;
3635 ev = samba_tevent_context_init(frame);
3636 if (ev == NULL) {
3637 goto fail;
3639 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3640 if (req == NULL) {
3641 goto fail;
3643 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3644 goto fail;
3647 /* Ignore the result */
3648 fail:
3649 TALLOC_FREE(frame);
3650 return status;