netlogon_creds_cli: Print netlogon_creds_CredentialState
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob178d9c88b92029ee33aa3c602b4d7c5a03c8febc
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 if (DEBUGLEVEL >= 10) {
499 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
502 tmp_flags = state->creds->negotiate_flags;
503 tmp_flags &= state->required_flags;
504 if (tmp_flags != state->required_flags) {
505 TALLOC_FREE(state->creds);
506 state->status = NT_STATUS_DOWNGRADE_DETECTED;
507 return;
510 state->status = NT_STATUS_OK;
513 static NTSTATUS netlogon_creds_cli_get_internal(
514 struct netlogon_creds_cli_context *context,
515 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
517 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
518 TALLOC_CTX *mem_ctx,
519 struct netlogon_creds_CredentialState **_creds)
521 NTSTATUS status;
522 struct netlogon_creds_CredentialState *creds;
524 *_creds = NULL;
526 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
527 if (!NT_STATUS_IS_OK(status)) {
528 return status;
532 * mark it as invalid for step operations.
534 creds->sequence = 0;
535 creds->seed = (struct netr_Credential) {{0}};
536 creds->client = (struct netr_Credential) {{0}};
537 creds->server = (struct netr_Credential) {{0}};
539 *_creds = creds;
540 return NT_STATUS_OK;
543 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
544 const struct netlogon_creds_CredentialState *creds1)
546 TALLOC_CTX *frame = talloc_stackframe();
547 struct netlogon_creds_CredentialState *creds2;
548 DATA_BLOB blob1;
549 DATA_BLOB blob2;
550 NTSTATUS status;
551 enum ndr_err_code ndr_err;
552 int cmp;
554 status = netlogon_creds_cli_get(context, frame, &creds2);
555 if (!NT_STATUS_IS_OK(status)) {
556 TALLOC_FREE(frame);
557 return false;
560 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
561 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
562 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
563 TALLOC_FREE(frame);
564 return false;
567 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
568 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
569 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
570 TALLOC_FREE(frame);
571 return false;
574 cmp = data_blob_cmp(&blob1, &blob2);
576 TALLOC_FREE(frame);
578 return (cmp == 0);
581 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
582 struct netlogon_creds_CredentialState *creds)
584 NTSTATUS status;
585 enum ndr_err_code ndr_err;
586 DATA_BLOB blob;
587 TDB_DATA data;
589 if (context->db.locked_state == NULL) {
591 * this was not the result of netlogon_creds_cli_lock*()
593 return NT_STATUS_INVALID_PAGE_PROTECTION;
596 if (context->db.locked_state->creds != creds) {
598 * this was not the result of netlogon_creds_cli_lock*()
600 return NT_STATUS_INVALID_PAGE_PROTECTION;
603 if (DEBUGLEVEL >= 10) {
604 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
607 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
608 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
609 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
610 status = ndr_map_error2ntstatus(ndr_err);
611 return status;
614 data.dptr = blob.data;
615 data.dsize = blob.length;
617 status = dbwrap_store(context->db.ctx,
618 context->db.key_data,
619 data, TDB_REPLACE);
620 TALLOC_FREE(data.dptr);
621 if (!NT_STATUS_IS_OK(status)) {
622 return status;
625 return NT_STATUS_OK;
628 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
629 struct netlogon_creds_CredentialState *creds)
631 NTSTATUS status;
633 if (context->db.locked_state == NULL) {
635 * this was not the result of netlogon_creds_cli_lock*()
637 return NT_STATUS_INVALID_PAGE_PROTECTION;
640 if (context->db.locked_state->creds != creds) {
642 * this was not the result of netlogon_creds_cli_lock*()
644 return NT_STATUS_INVALID_PAGE_PROTECTION;
647 status = dbwrap_delete(context->db.ctx,
648 context->db.key_data);
649 if (!NT_STATUS_IS_OK(status)) {
650 return status;
653 return NT_STATUS_OK;
656 struct netlogon_creds_cli_lock_state {
657 struct netlogon_creds_cli_locked_state *locked_state;
658 struct netlogon_creds_CredentialState *creds;
661 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
663 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
664 struct tevent_context *ev,
665 struct netlogon_creds_cli_context *context)
667 struct tevent_req *req;
668 struct netlogon_creds_cli_lock_state *state;
669 struct netlogon_creds_cli_locked_state *locked_state;
670 struct tevent_req *subreq;
672 req = tevent_req_create(mem_ctx, &state,
673 struct netlogon_creds_cli_lock_state);
674 if (req == NULL) {
675 return NULL;
678 if (context->db.locked_state != NULL) {
679 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
680 return tevent_req_post(req, ev);
683 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
684 if (tevent_req_nomem(locked_state, req)) {
685 return tevent_req_post(req, ev);
687 talloc_set_destructor(locked_state,
688 netlogon_creds_cli_locked_state_destructor);
689 locked_state->context = context;
691 context->db.locked_state = locked_state;
692 state->locked_state = locked_state;
694 if (context->db.g_ctx == NULL) {
695 NTSTATUS status;
697 status = netlogon_creds_cli_get_internal(
698 context, state, &state->creds);
699 if (tevent_req_nterror(req, status)) {
700 return tevent_req_post(req, ev);
703 return req;
706 subreq = g_lock_lock_send(state, ev,
707 context->db.g_ctx,
708 context->db.key_name,
709 G_LOCK_WRITE);
710 if (tevent_req_nomem(subreq, req)) {
711 return tevent_req_post(req, ev);
713 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
715 return req;
718 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
720 struct tevent_req *req =
721 tevent_req_callback_data(subreq,
722 struct tevent_req);
723 struct netlogon_creds_cli_lock_state *state =
724 tevent_req_data(req,
725 struct netlogon_creds_cli_lock_state);
726 NTSTATUS status;
728 status = g_lock_lock_recv(subreq);
729 TALLOC_FREE(subreq);
730 if (tevent_req_nterror(req, status)) {
731 return;
733 state->locked_state->is_glocked = true;
735 status = netlogon_creds_cli_get_internal(state->locked_state->context,
736 state, &state->creds);
737 if (tevent_req_nterror(req, status)) {
738 return;
740 tevent_req_done(req);
743 static NTSTATUS netlogon_creds_cli_get_internal(
744 struct netlogon_creds_cli_context *context,
745 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
747 struct netlogon_creds_cli_fetch_state fstate = {
748 .status = NT_STATUS_INTERNAL_ERROR,
749 .required_flags = context->client.required_flags,
751 NTSTATUS status;
753 fstate.mem_ctx = mem_ctx;
754 status = dbwrap_parse_record(context->db.ctx,
755 context->db.key_data,
756 netlogon_creds_cli_fetch_parser,
757 &fstate);
758 if (!NT_STATUS_IS_OK(status)) {
759 return status;
761 if (!NT_STATUS_IS_OK(fstate.status)) {
762 return fstate.status;
765 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
766 *pcreds = fstate.creds;
767 return NT_STATUS_OK;
771 * It is really important to try SamLogonEx here,
772 * because multiple processes can talk to the same
773 * domain controller, without using the credential
774 * chain.
776 * With a normal SamLogon call, we must keep the
777 * credentials chain updated and intact between all
778 * users of the machine account (which would imply
779 * cross-node communication for every NTLM logon).
781 * The credentials chain is not per NETLOGON pipe
782 * connection, but globally on the server/client pair
783 * by computer name.
785 * It's also important to use NetlogonValidationSamInfo4 (6),
786 * because it relies on the rpc transport encryption
787 * and avoids using the global netlogon schannel
788 * session key to en/decrypt secret information
789 * like the user_session_key for network logons.
791 * [MS-APDS] 3.1.5.2 NTLM Network Logon
792 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
793 * NETLOGON_NEG_AUTHENTICATED_RPC set together
794 * are the indication that the server supports
795 * NetlogonValidationSamInfo4 (6). And it must only
796 * be used if "SealSecureChannel" is used.
798 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
799 * check is done in netlogon_creds_cli_LogonSamLogon*().
802 context->server.cached_flags = fstate.creds->negotiate_flags;
803 context->server.try_validation6 = true;
804 context->server.try_logon_ex = true;
805 context->server.try_logon_with = true;
807 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
808 context->server.try_validation6 = false;
809 context->server.try_logon_ex = false;
811 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
812 context->server.try_validation6 = false;
815 *pcreds = fstate.creds;
816 return NT_STATUS_OK;
819 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
820 TALLOC_CTX *mem_ctx,
821 struct netlogon_creds_CredentialState **creds)
823 struct netlogon_creds_cli_lock_state *state =
824 tevent_req_data(req,
825 struct netlogon_creds_cli_lock_state);
826 NTSTATUS status;
828 if (tevent_req_is_nterror(req, &status)) {
829 tevent_req_received(req);
830 return status;
833 talloc_steal(state->creds, state->locked_state);
834 state->locked_state->creds = state->creds;
835 *creds = talloc_move(mem_ctx, &state->creds);
836 tevent_req_received(req);
837 return NT_STATUS_OK;
840 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
841 TALLOC_CTX *mem_ctx,
842 struct netlogon_creds_CredentialState **creds)
844 TALLOC_CTX *frame = talloc_stackframe();
845 struct tevent_context *ev;
846 struct tevent_req *req;
847 NTSTATUS status = NT_STATUS_NO_MEMORY;
849 ev = samba_tevent_context_init(frame);
850 if (ev == NULL) {
851 goto fail;
853 req = netlogon_creds_cli_lock_send(frame, ev, context);
854 if (req == NULL) {
855 goto fail;
857 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
858 goto fail;
860 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
861 fail:
862 TALLOC_FREE(frame);
863 return status;
866 struct netlogon_creds_cli_auth_state {
867 struct tevent_context *ev;
868 struct netlogon_creds_cli_context *context;
869 struct dcerpc_binding_handle *binding_handle;
870 uint8_t num_nt_hashes;
871 uint8_t idx_nt_hashes;
872 const struct samr_Password * const *nt_hashes;
873 const struct samr_Password *used_nt_hash;
874 char *srv_name_slash;
875 uint32_t current_flags;
876 struct netr_Credential client_challenge;
877 struct netr_Credential server_challenge;
878 struct netlogon_creds_CredentialState *creds;
879 struct netr_Credential client_credential;
880 struct netr_Credential server_credential;
881 uint32_t rid;
882 bool try_auth3;
883 bool try_auth2;
884 bool require_auth2;
885 struct netlogon_creds_cli_locked_state *locked_state;
888 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
889 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
891 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
892 struct tevent_context *ev,
893 struct netlogon_creds_cli_context *context,
894 struct dcerpc_binding_handle *b,
895 uint8_t num_nt_hashes,
896 const struct samr_Password * const *nt_hashes)
898 struct tevent_req *req;
899 struct netlogon_creds_cli_auth_state *state;
900 struct netlogon_creds_cli_locked_state *locked_state;
901 NTSTATUS status;
903 req = tevent_req_create(mem_ctx, &state,
904 struct netlogon_creds_cli_auth_state);
905 if (req == NULL) {
906 return NULL;
909 state->ev = ev;
910 state->context = context;
911 state->binding_handle = b;
912 if (num_nt_hashes < 1) {
913 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
914 return tevent_req_post(req, ev);
916 if (num_nt_hashes > 4) {
917 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
918 return tevent_req_post(req, ev);
921 state->num_nt_hashes = num_nt_hashes;
922 state->idx_nt_hashes = 0;
923 state->nt_hashes = nt_hashes;
925 if (context->db.locked_state != NULL) {
926 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
927 return tevent_req_post(req, ev);
930 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
931 if (tevent_req_nomem(locked_state, req)) {
932 return tevent_req_post(req, ev);
934 talloc_set_destructor(locked_state,
935 netlogon_creds_cli_locked_state_destructor);
936 locked_state->context = context;
938 context->db.locked_state = locked_state;
939 state->locked_state = locked_state;
941 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
942 context->server.computer);
943 if (tevent_req_nomem(state->srv_name_slash, req)) {
944 return tevent_req_post(req, ev);
947 state->try_auth3 = true;
948 state->try_auth2 = true;
950 if (context->client.required_flags != 0) {
951 state->require_auth2 = true;
954 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
955 state->current_flags = context->client.proposed_flags;
957 if (context->db.g_ctx != NULL) {
958 struct tevent_req *subreq;
960 subreq = g_lock_lock_send(state, ev,
961 context->db.g_ctx,
962 context->db.key_name,
963 G_LOCK_WRITE);
964 if (tevent_req_nomem(subreq, req)) {
965 return tevent_req_post(req, ev);
967 tevent_req_set_callback(subreq,
968 netlogon_creds_cli_auth_locked,
969 req);
971 return req;
974 status = dbwrap_purge(state->context->db.ctx,
975 state->context->db.key_data);
976 if (tevent_req_nterror(req, status)) {
977 return tevent_req_post(req, ev);
980 netlogon_creds_cli_auth_challenge_start(req);
981 if (!tevent_req_is_in_progress(req)) {
982 return tevent_req_post(req, ev);
985 return req;
988 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
990 struct tevent_req *req =
991 tevent_req_callback_data(subreq,
992 struct tevent_req);
993 struct netlogon_creds_cli_auth_state *state =
994 tevent_req_data(req,
995 struct netlogon_creds_cli_auth_state);
996 NTSTATUS status;
998 status = g_lock_lock_recv(subreq);
999 TALLOC_FREE(subreq);
1000 if (tevent_req_nterror(req, status)) {
1001 return;
1003 state->locked_state->is_glocked = true;
1005 status = dbwrap_purge(state->context->db.ctx,
1006 state->context->db.key_data);
1007 if (tevent_req_nterror(req, status)) {
1008 return;
1011 netlogon_creds_cli_auth_challenge_start(req);
1014 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1016 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1018 struct netlogon_creds_cli_auth_state *state =
1019 tevent_req_data(req,
1020 struct netlogon_creds_cli_auth_state);
1021 struct tevent_req *subreq;
1023 TALLOC_FREE(state->creds);
1025 generate_random_buffer(state->client_challenge.data,
1026 sizeof(state->client_challenge.data));
1028 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1029 state->binding_handle,
1030 state->srv_name_slash,
1031 state->context->client.computer,
1032 &state->client_challenge,
1033 &state->server_challenge);
1034 if (tevent_req_nomem(subreq, req)) {
1035 return;
1037 tevent_req_set_callback(subreq,
1038 netlogon_creds_cli_auth_challenge_done,
1039 req);
1042 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1044 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1046 struct tevent_req *req =
1047 tevent_req_callback_data(subreq,
1048 struct tevent_req);
1049 struct netlogon_creds_cli_auth_state *state =
1050 tevent_req_data(req,
1051 struct netlogon_creds_cli_auth_state);
1052 NTSTATUS status;
1053 NTSTATUS result;
1055 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1056 TALLOC_FREE(subreq);
1057 if (tevent_req_nterror(req, status)) {
1058 return;
1060 if (tevent_req_nterror(req, result)) {
1061 return;
1064 if (!state->try_auth3 && !state->try_auth2) {
1065 state->current_flags = 0;
1068 /* Calculate the session key and client credentials */
1070 state->creds = netlogon_creds_client_init(state,
1071 state->context->client.account,
1072 state->context->client.computer,
1073 state->context->client.type,
1074 &state->client_challenge,
1075 &state->server_challenge,
1076 state->used_nt_hash,
1077 &state->client_credential,
1078 state->current_flags);
1079 if (tevent_req_nomem(state->creds, req)) {
1080 return;
1083 if (state->try_auth3) {
1084 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1085 state->binding_handle,
1086 state->srv_name_slash,
1087 state->context->client.account,
1088 state->context->client.type,
1089 state->context->client.computer,
1090 &state->client_credential,
1091 &state->server_credential,
1092 &state->creds->negotiate_flags,
1093 &state->rid);
1094 if (tevent_req_nomem(subreq, req)) {
1095 return;
1097 } else if (state->try_auth2) {
1098 state->rid = 0;
1100 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1101 state->binding_handle,
1102 state->srv_name_slash,
1103 state->context->client.account,
1104 state->context->client.type,
1105 state->context->client.computer,
1106 &state->client_credential,
1107 &state->server_credential,
1108 &state->creds->negotiate_flags);
1109 if (tevent_req_nomem(subreq, req)) {
1110 return;
1112 } else {
1113 state->rid = 0;
1115 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1116 state->binding_handle,
1117 state->srv_name_slash,
1118 state->context->client.account,
1119 state->context->client.type,
1120 state->context->client.computer,
1121 &state->client_credential,
1122 &state->server_credential);
1123 if (tevent_req_nomem(subreq, req)) {
1124 return;
1127 tevent_req_set_callback(subreq,
1128 netlogon_creds_cli_auth_srvauth_done,
1129 req);
1132 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1134 struct tevent_req *req =
1135 tevent_req_callback_data(subreq,
1136 struct tevent_req);
1137 struct netlogon_creds_cli_auth_state *state =
1138 tevent_req_data(req,
1139 struct netlogon_creds_cli_auth_state);
1140 NTSTATUS status;
1141 NTSTATUS result;
1142 bool ok;
1143 enum ndr_err_code ndr_err;
1144 DATA_BLOB blob;
1145 TDB_DATA data;
1146 uint32_t tmp_flags;
1148 if (state->try_auth3) {
1149 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1150 &result);
1151 TALLOC_FREE(subreq);
1152 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1153 state->try_auth3 = false;
1154 netlogon_creds_cli_auth_challenge_start(req);
1155 return;
1157 if (tevent_req_nterror(req, status)) {
1158 return;
1160 } else if (state->try_auth2) {
1161 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1162 &result);
1163 TALLOC_FREE(subreq);
1164 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1165 state->try_auth2 = false;
1166 if (state->require_auth2) {
1167 status = NT_STATUS_DOWNGRADE_DETECTED;
1168 tevent_req_nterror(req, status);
1169 return;
1171 netlogon_creds_cli_auth_challenge_start(req);
1172 return;
1174 if (tevent_req_nterror(req, status)) {
1175 return;
1177 } else {
1178 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1179 &result);
1180 TALLOC_FREE(subreq);
1181 if (tevent_req_nterror(req, status)) {
1182 return;
1186 if (!NT_STATUS_IS_OK(result) &&
1187 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1189 tevent_req_nterror(req, result);
1190 return;
1193 tmp_flags = state->creds->negotiate_flags;
1194 tmp_flags &= state->context->client.required_flags;
1195 if (tmp_flags != state->context->client.required_flags) {
1196 if (NT_STATUS_IS_OK(result)) {
1197 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1198 return;
1200 tevent_req_nterror(req, result);
1201 return;
1204 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1206 tmp_flags = state->context->client.proposed_flags;
1207 if ((state->current_flags == tmp_flags) &&
1208 (state->creds->negotiate_flags != tmp_flags))
1211 * lets retry with the negotiated flags
1213 state->current_flags = state->creds->negotiate_flags;
1214 netlogon_creds_cli_auth_challenge_start(req);
1215 return;
1218 state->idx_nt_hashes += 1;
1219 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1221 * we already retried, giving up...
1223 tevent_req_nterror(req, result);
1224 return;
1228 * lets retry with the old nt hash.
1230 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1231 state->current_flags = state->context->client.proposed_flags;
1232 netlogon_creds_cli_auth_challenge_start(req);
1233 return;
1236 ok = netlogon_creds_client_check(state->creds,
1237 &state->server_credential);
1238 if (!ok) {
1239 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1240 return;
1243 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1244 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1245 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1246 status = ndr_map_error2ntstatus(ndr_err);
1247 tevent_req_nterror(req, status);
1248 return;
1251 data.dptr = blob.data;
1252 data.dsize = blob.length;
1254 status = dbwrap_store(state->context->db.ctx,
1255 state->context->db.key_data,
1256 data, TDB_REPLACE);
1257 TALLOC_FREE(state->locked_state);
1258 if (tevent_req_nterror(req, status)) {
1259 return;
1262 tevent_req_done(req);
1265 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1266 uint8_t *idx_nt_hashes)
1268 struct netlogon_creds_cli_auth_state *state =
1269 tevent_req_data(req,
1270 struct netlogon_creds_cli_auth_state);
1271 NTSTATUS status;
1273 *idx_nt_hashes = 0;
1275 if (tevent_req_is_nterror(req, &status)) {
1276 tevent_req_received(req);
1277 return status;
1280 *idx_nt_hashes = state->idx_nt_hashes;
1281 tevent_req_received(req);
1282 return NT_STATUS_OK;
1285 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1286 struct dcerpc_binding_handle *b,
1287 uint8_t num_nt_hashes,
1288 const struct samr_Password * const *nt_hashes,
1289 uint8_t *idx_nt_hashes)
1291 TALLOC_CTX *frame = talloc_stackframe();
1292 struct tevent_context *ev;
1293 struct tevent_req *req;
1294 NTSTATUS status = NT_STATUS_NO_MEMORY;
1296 *idx_nt_hashes = 0;
1298 ev = samba_tevent_context_init(frame);
1299 if (ev == NULL) {
1300 goto fail;
1302 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1303 num_nt_hashes, nt_hashes);
1304 if (req == NULL) {
1305 goto fail;
1307 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1308 goto fail;
1310 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1311 fail:
1312 TALLOC_FREE(frame);
1313 return status;
1316 struct netlogon_creds_cli_check_state {
1317 struct tevent_context *ev;
1318 struct netlogon_creds_cli_context *context;
1319 struct dcerpc_binding_handle *binding_handle;
1321 char *srv_name_slash;
1323 union netr_Capabilities caps;
1325 struct netlogon_creds_CredentialState *creds;
1326 struct netlogon_creds_CredentialState tmp_creds;
1327 struct netr_Authenticator req_auth;
1328 struct netr_Authenticator rep_auth;
1331 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1332 NTSTATUS status);
1333 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1335 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1336 struct tevent_context *ev,
1337 struct netlogon_creds_cli_context *context,
1338 struct dcerpc_binding_handle *b)
1340 struct tevent_req *req;
1341 struct netlogon_creds_cli_check_state *state;
1342 struct tevent_req *subreq;
1343 enum dcerpc_AuthType auth_type;
1344 enum dcerpc_AuthLevel auth_level;
1346 req = tevent_req_create(mem_ctx, &state,
1347 struct netlogon_creds_cli_check_state);
1348 if (req == NULL) {
1349 return NULL;
1352 state->ev = ev;
1353 state->context = context;
1354 state->binding_handle = b;
1356 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1357 context->server.computer);
1358 if (tevent_req_nomem(state->srv_name_slash, req)) {
1359 return tevent_req_post(req, ev);
1362 dcerpc_binding_handle_auth_info(state->binding_handle,
1363 &auth_type, &auth_level);
1365 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1366 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1367 return tevent_req_post(req, ev);
1370 switch (auth_level) {
1371 case DCERPC_AUTH_LEVEL_INTEGRITY:
1372 case DCERPC_AUTH_LEVEL_PRIVACY:
1373 break;
1374 default:
1375 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1376 return tevent_req_post(req, ev);
1379 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1380 state->context);
1381 if (tevent_req_nomem(subreq, req)) {
1382 return tevent_req_post(req, ev);
1385 tevent_req_set_callback(subreq,
1386 netlogon_creds_cli_check_locked,
1387 req);
1389 return req;
1392 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1393 NTSTATUS status)
1395 struct netlogon_creds_cli_check_state *state =
1396 tevent_req_data(req,
1397 struct netlogon_creds_cli_check_state);
1399 if (state->creds == NULL) {
1400 return;
1403 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1404 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1405 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1406 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1407 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1408 TALLOC_FREE(state->creds);
1409 return;
1412 netlogon_creds_cli_delete(state->context, state->creds);
1413 TALLOC_FREE(state->creds);
1416 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1418 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1420 struct tevent_req *req =
1421 tevent_req_callback_data(subreq,
1422 struct tevent_req);
1423 struct netlogon_creds_cli_check_state *state =
1424 tevent_req_data(req,
1425 struct netlogon_creds_cli_check_state);
1426 NTSTATUS status;
1428 status = netlogon_creds_cli_lock_recv(subreq, state,
1429 &state->creds);
1430 TALLOC_FREE(subreq);
1431 if (tevent_req_nterror(req, status)) {
1432 return;
1436 * we defer all callbacks in order to cleanup
1437 * the database record.
1439 tevent_req_defer_callback(req, state->ev);
1441 state->tmp_creds = *state->creds;
1442 netlogon_creds_client_authenticator(&state->tmp_creds,
1443 &state->req_auth);
1444 ZERO_STRUCT(state->rep_auth);
1446 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1447 state->binding_handle,
1448 state->srv_name_slash,
1449 state->context->client.computer,
1450 &state->req_auth,
1451 &state->rep_auth,
1453 &state->caps);
1454 if (tevent_req_nomem(subreq, req)) {
1455 status = NT_STATUS_NO_MEMORY;
1456 netlogon_creds_cli_check_cleanup(req, status);
1457 return;
1459 tevent_req_set_callback(subreq,
1460 netlogon_creds_cli_check_caps,
1461 req);
1464 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1466 struct tevent_req *req =
1467 tevent_req_callback_data(subreq,
1468 struct tevent_req);
1469 struct netlogon_creds_cli_check_state *state =
1470 tevent_req_data(req,
1471 struct netlogon_creds_cli_check_state);
1472 NTSTATUS status;
1473 NTSTATUS result;
1474 bool ok;
1476 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1477 &result);
1478 TALLOC_FREE(subreq);
1479 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1481 * Note that the negotiated flags are already checked
1482 * for our required flags after the ServerAuthenticate3/2 call.
1484 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1486 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1488 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1489 * already, we expect this to work!
1491 status = NT_STATUS_DOWNGRADE_DETECTED;
1492 tevent_req_nterror(req, status);
1493 netlogon_creds_cli_check_cleanup(req, status);
1494 return;
1497 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1499 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1500 * we expect this to work at least as far as the
1501 * NOT_SUPPORTED error handled below!
1503 * NT 4.0 and Old Samba servers are not
1504 * allowed without "require strong key = no"
1506 status = NT_STATUS_DOWNGRADE_DETECTED;
1507 tevent_req_nterror(req, status);
1508 netlogon_creds_cli_check_cleanup(req, status);
1509 return;
1513 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1514 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1515 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1517 * This is needed against NT 4.0 and old Samba servers.
1519 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1520 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1521 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1522 * with the next request as the sequence number processing
1523 * gets out of sync.
1525 netlogon_creds_cli_check_cleanup(req, status);
1526 tevent_req_done(req);
1527 return;
1529 if (tevent_req_nterror(req, status)) {
1530 netlogon_creds_cli_check_cleanup(req, status);
1531 return;
1534 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1536 * Note that the negotiated flags are already checked
1537 * for our required flags after the ServerAuthenticate3/2 call.
1539 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1541 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1543 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1544 * already, we expect this to work!
1546 status = NT_STATUS_DOWNGRADE_DETECTED;
1547 tevent_req_nterror(req, status);
1548 netlogon_creds_cli_check_cleanup(req, status);
1549 return;
1553 * This is ok, the server does not support
1554 * NETLOGON_NEG_SUPPORTS_AES.
1556 * netr_LogonGetCapabilities() was
1557 * netr_LogonDummyRoutine1() before
1558 * NETLOGON_NEG_SUPPORTS_AES was invented.
1560 netlogon_creds_cli_check_cleanup(req, result);
1561 tevent_req_done(req);
1562 return;
1565 ok = netlogon_creds_client_check(&state->tmp_creds,
1566 &state->rep_auth.cred);
1567 if (!ok) {
1568 status = NT_STATUS_ACCESS_DENIED;
1569 tevent_req_nterror(req, status);
1570 netlogon_creds_cli_check_cleanup(req, status);
1571 return;
1574 if (tevent_req_nterror(req, result)) {
1575 netlogon_creds_cli_check_cleanup(req, result);
1576 return;
1579 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1580 status = NT_STATUS_DOWNGRADE_DETECTED;
1581 tevent_req_nterror(req, status);
1582 netlogon_creds_cli_check_cleanup(req, status);
1583 return;
1587 * This is the key check that makes this check secure. If we
1588 * get OK here (rather than NOT_SUPPORTED), then the server
1589 * did support AES. If the server only proposed STRONG_KEYS
1590 * and not AES, then it should have failed with
1591 * NOT_IMPLEMENTED. We always send AES as a client, so the
1592 * server should always have returned it.
1594 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1595 status = NT_STATUS_DOWNGRADE_DETECTED;
1596 tevent_req_nterror(req, status);
1597 netlogon_creds_cli_check_cleanup(req, status);
1598 return;
1601 *state->creds = state->tmp_creds;
1602 status = netlogon_creds_cli_store(state->context,
1603 state->creds);
1604 TALLOC_FREE(state->creds);
1605 if (tevent_req_nterror(req, status)) {
1606 return;
1609 tevent_req_done(req);
1612 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1614 NTSTATUS status;
1616 if (tevent_req_is_nterror(req, &status)) {
1617 netlogon_creds_cli_check_cleanup(req, status);
1618 tevent_req_received(req);
1619 return status;
1622 tevent_req_received(req);
1623 return NT_STATUS_OK;
1626 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1627 struct dcerpc_binding_handle *b)
1629 TALLOC_CTX *frame = talloc_stackframe();
1630 struct tevent_context *ev;
1631 struct tevent_req *req;
1632 NTSTATUS status = NT_STATUS_NO_MEMORY;
1634 ev = samba_tevent_context_init(frame);
1635 if (ev == NULL) {
1636 goto fail;
1638 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1639 if (req == NULL) {
1640 goto fail;
1642 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1643 goto fail;
1645 status = netlogon_creds_cli_check_recv(req);
1646 fail:
1647 TALLOC_FREE(frame);
1648 return status;
1651 struct netlogon_creds_cli_ServerPasswordSet_state {
1652 struct tevent_context *ev;
1653 struct netlogon_creds_cli_context *context;
1654 struct dcerpc_binding_handle *binding_handle;
1655 uint32_t old_timeout;
1657 char *srv_name_slash;
1658 enum dcerpc_AuthType auth_type;
1659 enum dcerpc_AuthLevel auth_level;
1661 struct samr_CryptPassword samr_crypt_password;
1662 struct netr_CryptPassword netr_crypt_password;
1663 struct samr_Password samr_password;
1665 struct netlogon_creds_CredentialState *creds;
1666 struct netlogon_creds_CredentialState tmp_creds;
1667 struct netr_Authenticator req_auth;
1668 struct netr_Authenticator rep_auth;
1671 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1672 NTSTATUS status);
1673 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1675 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1676 struct tevent_context *ev,
1677 struct netlogon_creds_cli_context *context,
1678 struct dcerpc_binding_handle *b,
1679 const DATA_BLOB *new_password,
1680 const uint32_t *new_version)
1682 struct tevent_req *req;
1683 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1684 struct tevent_req *subreq;
1685 bool ok;
1687 req = tevent_req_create(mem_ctx, &state,
1688 struct netlogon_creds_cli_ServerPasswordSet_state);
1689 if (req == NULL) {
1690 return NULL;
1693 state->ev = ev;
1694 state->context = context;
1695 state->binding_handle = b;
1697 if (new_password->length < 14) {
1698 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1699 return tevent_req_post(req, ev);
1703 * netr_ServerPasswordSet
1705 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1708 * netr_ServerPasswordSet2
1710 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1711 new_password);
1712 if (!ok) {
1713 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1714 return tevent_req_post(req, ev);
1717 if (new_version != NULL) {
1718 struct NL_PASSWORD_VERSION version;
1719 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1720 uint32_t ofs = 512 - len;
1721 uint8_t *p;
1723 if (len > 500) {
1724 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1725 return tevent_req_post(req, ev);
1727 ofs -= 12;
1729 version.ReservedField = 0;
1730 version.PasswordVersionNumber = *new_version;
1731 version.PasswordVersionPresent =
1732 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1734 p = state->samr_crypt_password.data + ofs;
1735 SIVAL(p, 0, version.ReservedField);
1736 SIVAL(p, 4, version.PasswordVersionNumber);
1737 SIVAL(p, 8, version.PasswordVersionPresent);
1740 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1741 context->server.computer);
1742 if (tevent_req_nomem(state->srv_name_slash, req)) {
1743 return tevent_req_post(req, ev);
1746 dcerpc_binding_handle_auth_info(state->binding_handle,
1747 &state->auth_type,
1748 &state->auth_level);
1750 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1751 state->context);
1752 if (tevent_req_nomem(subreq, req)) {
1753 return tevent_req_post(req, ev);
1756 tevent_req_set_callback(subreq,
1757 netlogon_creds_cli_ServerPasswordSet_locked,
1758 req);
1760 return req;
1763 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1764 NTSTATUS status)
1766 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1767 tevent_req_data(req,
1768 struct netlogon_creds_cli_ServerPasswordSet_state);
1770 if (state->creds == NULL) {
1771 return;
1774 dcerpc_binding_handle_set_timeout(state->binding_handle,
1775 state->old_timeout);
1777 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1778 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1779 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1780 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1781 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1782 TALLOC_FREE(state->creds);
1783 return;
1786 netlogon_creds_cli_delete(state->context, state->creds);
1787 TALLOC_FREE(state->creds);
1790 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1792 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1794 struct tevent_req *req =
1795 tevent_req_callback_data(subreq,
1796 struct tevent_req);
1797 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1798 tevent_req_data(req,
1799 struct netlogon_creds_cli_ServerPasswordSet_state);
1800 NTSTATUS status;
1802 status = netlogon_creds_cli_lock_recv(subreq, state,
1803 &state->creds);
1804 TALLOC_FREE(subreq);
1805 if (tevent_req_nterror(req, status)) {
1806 return;
1809 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1810 switch (state->auth_level) {
1811 case DCERPC_AUTH_LEVEL_INTEGRITY:
1812 case DCERPC_AUTH_LEVEL_PRIVACY:
1813 break;
1814 default:
1815 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1816 return;
1818 } else {
1819 uint32_t tmp = state->creds->negotiate_flags;
1821 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1823 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1824 * it should be used, which means
1825 * we had a chance to verify no downgrade
1826 * happened.
1828 * This relies on netlogon_creds_cli_check*
1829 * being called before, as first request after
1830 * the DCERPC bind.
1832 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1833 return;
1837 state->old_timeout = dcerpc_binding_handle_set_timeout(
1838 state->binding_handle, 600000);
1841 * we defer all callbacks in order to cleanup
1842 * the database record.
1844 tevent_req_defer_callback(req, state->ev);
1846 state->tmp_creds = *state->creds;
1847 netlogon_creds_client_authenticator(&state->tmp_creds,
1848 &state->req_auth);
1849 ZERO_STRUCT(state->rep_auth);
1851 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1853 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1854 netlogon_creds_aes_encrypt(&state->tmp_creds,
1855 state->samr_crypt_password.data,
1856 516);
1857 } else {
1858 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1859 state->samr_crypt_password.data,
1860 516);
1863 memcpy(state->netr_crypt_password.data,
1864 state->samr_crypt_password.data, 512);
1865 state->netr_crypt_password.length =
1866 IVAL(state->samr_crypt_password.data, 512);
1868 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1869 state->binding_handle,
1870 state->srv_name_slash,
1871 state->tmp_creds.account_name,
1872 state->tmp_creds.secure_channel_type,
1873 state->tmp_creds.computer_name,
1874 &state->req_auth,
1875 &state->rep_auth,
1876 &state->netr_crypt_password);
1877 if (tevent_req_nomem(subreq, req)) {
1878 status = NT_STATUS_NO_MEMORY;
1879 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1880 return;
1882 } else {
1883 netlogon_creds_des_encrypt(&state->tmp_creds,
1884 &state->samr_password);
1886 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1887 state->binding_handle,
1888 state->srv_name_slash,
1889 state->tmp_creds.account_name,
1890 state->tmp_creds.secure_channel_type,
1891 state->tmp_creds.computer_name,
1892 &state->req_auth,
1893 &state->rep_auth,
1894 &state->samr_password);
1895 if (tevent_req_nomem(subreq, req)) {
1896 status = NT_STATUS_NO_MEMORY;
1897 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1898 return;
1902 tevent_req_set_callback(subreq,
1903 netlogon_creds_cli_ServerPasswordSet_done,
1904 req);
1907 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1909 struct tevent_req *req =
1910 tevent_req_callback_data(subreq,
1911 struct tevent_req);
1912 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1913 tevent_req_data(req,
1914 struct netlogon_creds_cli_ServerPasswordSet_state);
1915 NTSTATUS status;
1916 NTSTATUS result;
1917 bool ok;
1919 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1920 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1921 &result);
1922 TALLOC_FREE(subreq);
1923 if (tevent_req_nterror(req, status)) {
1924 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1925 return;
1927 } else {
1928 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1929 &result);
1930 TALLOC_FREE(subreq);
1931 if (tevent_req_nterror(req, status)) {
1932 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1933 return;
1937 ok = netlogon_creds_client_check(&state->tmp_creds,
1938 &state->rep_auth.cred);
1939 if (!ok) {
1940 status = NT_STATUS_ACCESS_DENIED;
1941 tevent_req_nterror(req, status);
1942 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1943 return;
1946 if (tevent_req_nterror(req, result)) {
1947 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
1948 return;
1951 dcerpc_binding_handle_set_timeout(state->binding_handle,
1952 state->old_timeout);
1954 *state->creds = state->tmp_creds;
1955 status = netlogon_creds_cli_store(state->context,
1956 state->creds);
1957 TALLOC_FREE(state->creds);
1958 if (tevent_req_nterror(req, status)) {
1959 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1960 return;
1963 tevent_req_done(req);
1966 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
1968 NTSTATUS status;
1970 if (tevent_req_is_nterror(req, &status)) {
1971 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1972 tevent_req_received(req);
1973 return status;
1976 tevent_req_received(req);
1977 return NT_STATUS_OK;
1980 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
1981 struct netlogon_creds_cli_context *context,
1982 struct dcerpc_binding_handle *b,
1983 const DATA_BLOB *new_password,
1984 const uint32_t *new_version)
1986 TALLOC_CTX *frame = talloc_stackframe();
1987 struct tevent_context *ev;
1988 struct tevent_req *req;
1989 NTSTATUS status = NT_STATUS_NO_MEMORY;
1991 ev = samba_tevent_context_init(frame);
1992 if (ev == NULL) {
1993 goto fail;
1995 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
1996 new_password,
1997 new_version);
1998 if (req == NULL) {
1999 goto fail;
2001 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2002 goto fail;
2004 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2005 fail:
2006 TALLOC_FREE(frame);
2007 return status;
2010 struct netlogon_creds_cli_LogonSamLogon_state {
2011 struct tevent_context *ev;
2012 struct netlogon_creds_cli_context *context;
2013 struct dcerpc_binding_handle *binding_handle;
2015 char *srv_name_slash;
2017 enum netr_LogonInfoClass logon_level;
2018 const union netr_LogonLevel *const_logon;
2019 union netr_LogonLevel *logon;
2020 uint32_t flags;
2022 uint16_t validation_level;
2023 union netr_Validation *validation;
2024 uint8_t authoritative;
2027 * do we need encryption at the application layer?
2029 bool user_encrypt;
2030 bool try_logon_ex;
2031 bool try_validation6;
2034 * the read only credentials before we started the operation
2035 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2037 struct netlogon_creds_CredentialState *ro_creds;
2040 * The (locked) credentials used for the credential chain
2041 * used for netr_LogonSamLogonWithFlags() or
2042 * netr_LogonSamLogonWith().
2044 struct netlogon_creds_CredentialState *lk_creds;
2047 * While we have locked the global credentials (lk_creds above)
2048 * we operate an a temporary copy, because a server
2049 * may not support netr_LogonSamLogonWithFlags() and
2050 * didn't process our netr_Authenticator, so we need to
2051 * restart from lk_creds.
2053 struct netlogon_creds_CredentialState tmp_creds;
2054 struct netr_Authenticator req_auth;
2055 struct netr_Authenticator rep_auth;
2058 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2059 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2060 NTSTATUS status);
2062 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2063 struct tevent_context *ev,
2064 struct netlogon_creds_cli_context *context,
2065 struct dcerpc_binding_handle *b,
2066 enum netr_LogonInfoClass logon_level,
2067 const union netr_LogonLevel *logon,
2068 uint32_t flags)
2070 struct tevent_req *req;
2071 struct netlogon_creds_cli_LogonSamLogon_state *state;
2073 req = tevent_req_create(mem_ctx, &state,
2074 struct netlogon_creds_cli_LogonSamLogon_state);
2075 if (req == NULL) {
2076 return NULL;
2079 state->ev = ev;
2080 state->context = context;
2081 state->binding_handle = b;
2083 state->logon_level = logon_level;
2084 state->const_logon = logon;
2085 state->flags = flags;
2087 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2088 context->server.computer);
2089 if (tevent_req_nomem(state->srv_name_slash, req)) {
2090 return tevent_req_post(req, ev);
2093 switch (logon_level) {
2094 case NetlogonInteractiveInformation:
2095 case NetlogonInteractiveTransitiveInformation:
2096 case NetlogonServiceInformation:
2097 case NetlogonServiceTransitiveInformation:
2098 case NetlogonGenericInformation:
2099 state->user_encrypt = true;
2100 break;
2102 case NetlogonNetworkInformation:
2103 case NetlogonNetworkTransitiveInformation:
2104 break;
2107 state->validation = talloc_zero(state, union netr_Validation);
2108 if (tevent_req_nomem(state->validation, req)) {
2109 return tevent_req_post(req, ev);
2112 netlogon_creds_cli_LogonSamLogon_start(req);
2113 if (!tevent_req_is_in_progress(req)) {
2114 return tevent_req_post(req, ev);
2118 * we defer all callbacks in order to cleanup
2119 * the database record.
2121 tevent_req_defer_callback(req, state->ev);
2122 return req;
2125 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2126 NTSTATUS status)
2128 struct netlogon_creds_cli_LogonSamLogon_state *state =
2129 tevent_req_data(req,
2130 struct netlogon_creds_cli_LogonSamLogon_state);
2132 if (state->lk_creds == NULL) {
2133 return;
2136 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2138 * This is a hack to recover from a bug in old
2139 * Samba servers, when LogonSamLogonEx() fails:
2141 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2143 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2145 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2146 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2147 * If the sign/seal check fails.
2149 * In that case we need to cleanup the netlogon session.
2151 * It's the job of the caller to disconnect the current
2152 * connection, if netlogon_creds_cli_LogonSamLogon()
2153 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2155 if (!state->context->server.try_logon_with) {
2156 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2160 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2161 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2162 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2163 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2164 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2165 TALLOC_FREE(state->lk_creds);
2166 return;
2169 netlogon_creds_cli_delete(state->context, state->lk_creds);
2170 TALLOC_FREE(state->lk_creds);
2173 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2175 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2177 struct netlogon_creds_cli_LogonSamLogon_state *state =
2178 tevent_req_data(req,
2179 struct netlogon_creds_cli_LogonSamLogon_state);
2180 struct tevent_req *subreq;
2181 NTSTATUS status;
2182 enum dcerpc_AuthType auth_type;
2183 enum dcerpc_AuthLevel auth_level;
2185 TALLOC_FREE(state->ro_creds);
2186 TALLOC_FREE(state->logon);
2187 ZERO_STRUCTP(state->validation);
2189 dcerpc_binding_handle_auth_info(state->binding_handle,
2190 &auth_type, &auth_level);
2192 state->try_logon_ex = state->context->server.try_logon_ex;
2193 state->try_validation6 = state->context->server.try_validation6;
2195 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2196 state->try_logon_ex = false;
2199 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2200 state->try_validation6 = false;
2203 if (state->try_logon_ex) {
2204 if (state->try_validation6) {
2205 state->validation_level = 6;
2206 } else {
2207 state->validation_level = 3;
2208 state->user_encrypt = true;
2211 state->logon = netlogon_creds_shallow_copy_logon(state,
2212 state->logon_level,
2213 state->const_logon);
2214 if (tevent_req_nomem(state->logon, req)) {
2215 status = NT_STATUS_NO_MEMORY;
2216 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2217 return;
2220 if (state->user_encrypt) {
2221 status = netlogon_creds_cli_get(state->context,
2222 state,
2223 &state->ro_creds);
2224 if (!NT_STATUS_IS_OK(status)) {
2225 status = NT_STATUS_ACCESS_DENIED;
2226 tevent_req_nterror(req, status);
2227 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2228 return;
2231 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2232 state->logon_level,
2233 state->logon);
2236 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2237 state->binding_handle,
2238 state->srv_name_slash,
2239 state->context->client.computer,
2240 state->logon_level,
2241 state->logon,
2242 state->validation_level,
2243 state->validation,
2244 &state->authoritative,
2245 &state->flags);
2246 if (tevent_req_nomem(subreq, req)) {
2247 status = NT_STATUS_NO_MEMORY;
2248 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2249 return;
2251 tevent_req_set_callback(subreq,
2252 netlogon_creds_cli_LogonSamLogon_done,
2253 req);
2254 return;
2257 if (state->lk_creds == NULL) {
2258 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2259 state->context);
2260 if (tevent_req_nomem(subreq, req)) {
2261 status = NT_STATUS_NO_MEMORY;
2262 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2263 return;
2265 tevent_req_set_callback(subreq,
2266 netlogon_creds_cli_LogonSamLogon_done,
2267 req);
2268 return;
2271 state->tmp_creds = *state->lk_creds;
2272 netlogon_creds_client_authenticator(&state->tmp_creds,
2273 &state->req_auth);
2274 ZERO_STRUCT(state->rep_auth);
2276 state->logon = netlogon_creds_shallow_copy_logon(state,
2277 state->logon_level,
2278 state->const_logon);
2279 if (tevent_req_nomem(state->logon, req)) {
2280 status = NT_STATUS_NO_MEMORY;
2281 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2282 return;
2285 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2286 state->logon_level,
2287 state->logon);
2289 state->validation_level = 3;
2291 if (state->context->server.try_logon_with) {
2292 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2293 state->binding_handle,
2294 state->srv_name_slash,
2295 state->context->client.computer,
2296 &state->req_auth,
2297 &state->rep_auth,
2298 state->logon_level,
2299 state->logon,
2300 state->validation_level,
2301 state->validation,
2302 &state->authoritative,
2303 &state->flags);
2304 if (tevent_req_nomem(subreq, req)) {
2305 status = NT_STATUS_NO_MEMORY;
2306 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2307 return;
2309 } else {
2310 state->flags = 0;
2312 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2313 state->binding_handle,
2314 state->srv_name_slash,
2315 state->context->client.computer,
2316 &state->req_auth,
2317 &state->rep_auth,
2318 state->logon_level,
2319 state->logon,
2320 state->validation_level,
2321 state->validation,
2322 &state->authoritative);
2323 if (tevent_req_nomem(subreq, req)) {
2324 status = NT_STATUS_NO_MEMORY;
2325 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2326 return;
2330 tevent_req_set_callback(subreq,
2331 netlogon_creds_cli_LogonSamLogon_done,
2332 req);
2335 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2337 struct tevent_req *req =
2338 tevent_req_callback_data(subreq,
2339 struct tevent_req);
2340 struct netlogon_creds_cli_LogonSamLogon_state *state =
2341 tevent_req_data(req,
2342 struct netlogon_creds_cli_LogonSamLogon_state);
2343 NTSTATUS status;
2344 NTSTATUS result;
2345 bool ok;
2347 if (state->try_logon_ex) {
2348 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2349 state->validation,
2350 &result);
2351 TALLOC_FREE(subreq);
2352 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2353 state->context->server.try_validation6 = false;
2354 state->context->server.try_logon_ex = false;
2355 netlogon_creds_cli_LogonSamLogon_start(req);
2356 return;
2358 if (tevent_req_nterror(req, status)) {
2359 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2360 return;
2363 if ((state->validation_level == 6) &&
2364 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2365 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2366 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2368 state->context->server.try_validation6 = false;
2369 netlogon_creds_cli_LogonSamLogon_start(req);
2370 return;
2373 if (tevent_req_nterror(req, result)) {
2374 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2375 return;
2378 if (state->ro_creds == NULL) {
2379 tevent_req_done(req);
2380 return;
2383 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2384 if (!ok) {
2386 * We got a race, lets retry with on authenticator
2387 * protection.
2389 * netlogon_creds_cli_LogonSamLogon_start()
2390 * will TALLOC_FREE(state->ro_creds);
2392 state->try_logon_ex = false;
2393 netlogon_creds_cli_LogonSamLogon_start(req);
2394 return;
2397 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2398 state->validation_level,
2399 state->validation);
2401 tevent_req_done(req);
2402 return;
2405 if (state->lk_creds == NULL) {
2406 status = netlogon_creds_cli_lock_recv(subreq, state,
2407 &state->lk_creds);
2408 TALLOC_FREE(subreq);
2409 if (tevent_req_nterror(req, status)) {
2410 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2411 return;
2414 netlogon_creds_cli_LogonSamLogon_start(req);
2415 return;
2418 if (state->context->server.try_logon_with) {
2419 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2420 state->validation,
2421 &result);
2422 TALLOC_FREE(subreq);
2423 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2424 state->context->server.try_logon_with = false;
2425 netlogon_creds_cli_LogonSamLogon_start(req);
2426 return;
2428 if (tevent_req_nterror(req, status)) {
2429 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2430 return;
2432 } else {
2433 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2434 state->validation,
2435 &result);
2436 TALLOC_FREE(subreq);
2437 if (tevent_req_nterror(req, status)) {
2438 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2439 return;
2443 ok = netlogon_creds_client_check(&state->tmp_creds,
2444 &state->rep_auth.cred);
2445 if (!ok) {
2446 status = NT_STATUS_ACCESS_DENIED;
2447 tevent_req_nterror(req, status);
2448 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2449 return;
2452 *state->lk_creds = state->tmp_creds;
2453 status = netlogon_creds_cli_store(state->context,
2454 state->lk_creds);
2455 TALLOC_FREE(state->lk_creds);
2457 if (tevent_req_nterror(req, status)) {
2458 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2459 return;
2462 if (tevent_req_nterror(req, result)) {
2463 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2464 return;
2467 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2468 state->validation_level,
2469 state->validation);
2471 tevent_req_done(req);
2474 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2475 TALLOC_CTX *mem_ctx,
2476 uint16_t *validation_level,
2477 union netr_Validation **validation,
2478 uint8_t *authoritative,
2479 uint32_t *flags)
2481 struct netlogon_creds_cli_LogonSamLogon_state *state =
2482 tevent_req_data(req,
2483 struct netlogon_creds_cli_LogonSamLogon_state);
2484 NTSTATUS status;
2486 /* authoritative is also returned on error */
2487 *authoritative = state->authoritative;
2489 if (tevent_req_is_nterror(req, &status)) {
2490 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2491 tevent_req_received(req);
2492 return status;
2495 *validation_level = state->validation_level;
2496 *validation = talloc_move(mem_ctx, &state->validation);
2497 *flags = state->flags;
2499 tevent_req_received(req);
2500 return NT_STATUS_OK;
2503 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2504 struct netlogon_creds_cli_context *context,
2505 struct dcerpc_binding_handle *b,
2506 enum netr_LogonInfoClass logon_level,
2507 const union netr_LogonLevel *logon,
2508 TALLOC_CTX *mem_ctx,
2509 uint16_t *validation_level,
2510 union netr_Validation **validation,
2511 uint8_t *authoritative,
2512 uint32_t *flags)
2514 TALLOC_CTX *frame = talloc_stackframe();
2515 struct tevent_context *ev;
2516 struct tevent_req *req;
2517 NTSTATUS status = NT_STATUS_NO_MEMORY;
2519 ev = samba_tevent_context_init(frame);
2520 if (ev == NULL) {
2521 goto fail;
2523 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2524 logon_level, logon,
2525 *flags);
2526 if (req == NULL) {
2527 goto fail;
2529 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2530 goto fail;
2532 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2533 validation_level,
2534 validation,
2535 authoritative,
2536 flags);
2537 fail:
2538 TALLOC_FREE(frame);
2539 return status;
2542 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2543 struct tevent_context *ev;
2544 struct netlogon_creds_cli_context *context;
2545 struct dcerpc_binding_handle *binding_handle;
2547 char *srv_name_slash;
2548 enum dcerpc_AuthType auth_type;
2549 enum dcerpc_AuthLevel auth_level;
2551 const char *site_name;
2552 uint32_t dns_ttl;
2553 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2555 struct netlogon_creds_CredentialState *creds;
2556 struct netlogon_creds_CredentialState tmp_creds;
2557 struct netr_Authenticator req_auth;
2558 struct netr_Authenticator rep_auth;
2561 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2562 NTSTATUS status);
2563 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2565 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2566 struct tevent_context *ev,
2567 struct netlogon_creds_cli_context *context,
2568 struct dcerpc_binding_handle *b,
2569 const char *site_name,
2570 uint32_t dns_ttl,
2571 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2573 struct tevent_req *req;
2574 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2575 struct tevent_req *subreq;
2577 req = tevent_req_create(mem_ctx, &state,
2578 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2579 if (req == NULL) {
2580 return NULL;
2583 state->ev = ev;
2584 state->context = context;
2585 state->binding_handle = b;
2587 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2588 context->server.computer);
2589 if (tevent_req_nomem(state->srv_name_slash, req)) {
2590 return tevent_req_post(req, ev);
2593 state->site_name = site_name;
2594 state->dns_ttl = dns_ttl;
2595 state->dns_names = dns_names;
2597 dcerpc_binding_handle_auth_info(state->binding_handle,
2598 &state->auth_type,
2599 &state->auth_level);
2601 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2602 state->context);
2603 if (tevent_req_nomem(subreq, req)) {
2604 return tevent_req_post(req, ev);
2607 tevent_req_set_callback(subreq,
2608 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2609 req);
2611 return req;
2614 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2615 NTSTATUS status)
2617 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2618 tevent_req_data(req,
2619 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2621 if (state->creds == NULL) {
2622 return;
2625 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2626 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2627 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2628 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2629 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2630 TALLOC_FREE(state->creds);
2631 return;
2634 netlogon_creds_cli_delete(state->context, state->creds);
2635 TALLOC_FREE(state->creds);
2638 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2640 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2642 struct tevent_req *req =
2643 tevent_req_callback_data(subreq,
2644 struct tevent_req);
2645 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2646 tevent_req_data(req,
2647 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2648 NTSTATUS status;
2650 status = netlogon_creds_cli_lock_recv(subreq, state,
2651 &state->creds);
2652 TALLOC_FREE(subreq);
2653 if (tevent_req_nterror(req, status)) {
2654 return;
2657 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2658 switch (state->auth_level) {
2659 case DCERPC_AUTH_LEVEL_INTEGRITY:
2660 case DCERPC_AUTH_LEVEL_PRIVACY:
2661 break;
2662 default:
2663 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2664 return;
2666 } else {
2667 uint32_t tmp = state->creds->negotiate_flags;
2669 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2671 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2672 * it should be used, which means
2673 * we had a chance to verify no downgrade
2674 * happened.
2676 * This relies on netlogon_creds_cli_check*
2677 * being called before, as first request after
2678 * the DCERPC bind.
2680 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2681 return;
2686 * we defer all callbacks in order to cleanup
2687 * the database record.
2689 tevent_req_defer_callback(req, state->ev);
2691 state->tmp_creds = *state->creds;
2692 netlogon_creds_client_authenticator(&state->tmp_creds,
2693 &state->req_auth);
2694 ZERO_STRUCT(state->rep_auth);
2696 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2697 state->binding_handle,
2698 state->srv_name_slash,
2699 state->tmp_creds.computer_name,
2700 &state->req_auth,
2701 &state->rep_auth,
2702 state->site_name,
2703 state->dns_ttl,
2704 state->dns_names);
2705 if (tevent_req_nomem(subreq, req)) {
2706 status = NT_STATUS_NO_MEMORY;
2707 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2708 return;
2711 tevent_req_set_callback(subreq,
2712 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2713 req);
2716 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2718 struct tevent_req *req =
2719 tevent_req_callback_data(subreq,
2720 struct tevent_req);
2721 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2722 tevent_req_data(req,
2723 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2724 NTSTATUS status;
2725 NTSTATUS result;
2726 bool ok;
2729 * We use state->dns_names as the memory context, as this is
2730 * the only in/out variable and it has been overwritten by the
2731 * out parameter from the server.
2733 * We need to preserve the return value until the caller can use it.
2735 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2736 &result);
2737 TALLOC_FREE(subreq);
2738 if (tevent_req_nterror(req, status)) {
2739 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2740 return;
2743 ok = netlogon_creds_client_check(&state->tmp_creds,
2744 &state->rep_auth.cred);
2745 if (!ok) {
2746 status = NT_STATUS_ACCESS_DENIED;
2747 tevent_req_nterror(req, status);
2748 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2749 return;
2752 *state->creds = state->tmp_creds;
2753 status = netlogon_creds_cli_store(state->context,
2754 state->creds);
2755 TALLOC_FREE(state->creds);
2757 if (tevent_req_nterror(req, status)) {
2758 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2759 return;
2762 if (tevent_req_nterror(req, result)) {
2763 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2764 return;
2767 tevent_req_done(req);
2770 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2772 NTSTATUS status;
2774 if (tevent_req_is_nterror(req, &status)) {
2775 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2776 tevent_req_received(req);
2777 return status;
2780 tevent_req_received(req);
2781 return NT_STATUS_OK;
2784 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2785 struct netlogon_creds_cli_context *context,
2786 struct dcerpc_binding_handle *b,
2787 const char *site_name,
2788 uint32_t dns_ttl,
2789 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2791 TALLOC_CTX *frame = talloc_stackframe();
2792 struct tevent_context *ev;
2793 struct tevent_req *req;
2794 NTSTATUS status = NT_STATUS_NO_MEMORY;
2796 ev = samba_tevent_context_init(frame);
2797 if (ev == NULL) {
2798 goto fail;
2800 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2801 site_name,
2802 dns_ttl,
2803 dns_names);
2804 if (req == NULL) {
2805 goto fail;
2807 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2808 goto fail;
2810 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2811 fail:
2812 TALLOC_FREE(frame);
2813 return status;
2816 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2817 struct tevent_context *ev;
2818 struct netlogon_creds_cli_context *context;
2819 struct dcerpc_binding_handle *binding_handle;
2821 char *srv_name_slash;
2822 enum dcerpc_AuthType auth_type;
2823 enum dcerpc_AuthLevel auth_level;
2825 struct samr_Password new_owf_password;
2826 struct samr_Password old_owf_password;
2827 struct netr_TrustInfo *trust_info;
2829 struct netlogon_creds_CredentialState *creds;
2830 struct netlogon_creds_CredentialState tmp_creds;
2831 struct netr_Authenticator req_auth;
2832 struct netr_Authenticator rep_auth;
2835 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2836 NTSTATUS status);
2837 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2839 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2840 struct tevent_context *ev,
2841 struct netlogon_creds_cli_context *context,
2842 struct dcerpc_binding_handle *b)
2844 struct tevent_req *req;
2845 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2846 struct tevent_req *subreq;
2848 req = tevent_req_create(mem_ctx, &state,
2849 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2850 if (req == NULL) {
2851 return NULL;
2854 state->ev = ev;
2855 state->context = context;
2856 state->binding_handle = b;
2858 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2859 context->server.computer);
2860 if (tevent_req_nomem(state->srv_name_slash, req)) {
2861 return tevent_req_post(req, ev);
2864 dcerpc_binding_handle_auth_info(state->binding_handle,
2865 &state->auth_type,
2866 &state->auth_level);
2868 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2869 state->context);
2870 if (tevent_req_nomem(subreq, req)) {
2871 return tevent_req_post(req, ev);
2874 tevent_req_set_callback(subreq,
2875 netlogon_creds_cli_ServerGetTrustInfo_locked,
2876 req);
2878 return req;
2881 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2882 NTSTATUS status)
2884 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2885 tevent_req_data(req,
2886 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2888 if (state->creds == NULL) {
2889 return;
2892 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2893 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2894 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2895 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2896 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2897 TALLOC_FREE(state->creds);
2898 return;
2901 netlogon_creds_cli_delete(state->context, state->creds);
2902 TALLOC_FREE(state->creds);
2905 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2907 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2909 struct tevent_req *req =
2910 tevent_req_callback_data(subreq,
2911 struct tevent_req);
2912 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2913 tevent_req_data(req,
2914 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2915 NTSTATUS status;
2917 status = netlogon_creds_cli_lock_recv(subreq, state,
2918 &state->creds);
2919 TALLOC_FREE(subreq);
2920 if (tevent_req_nterror(req, status)) {
2921 return;
2924 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2925 switch (state->auth_level) {
2926 case DCERPC_AUTH_LEVEL_PRIVACY:
2927 break;
2928 default:
2929 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2930 return;
2932 } else {
2933 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2934 return;
2938 * we defer all callbacks in order to cleanup
2939 * the database record.
2941 tevent_req_defer_callback(req, state->ev);
2943 state->tmp_creds = *state->creds;
2944 netlogon_creds_client_authenticator(&state->tmp_creds,
2945 &state->req_auth);
2946 ZERO_STRUCT(state->rep_auth);
2948 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
2949 state->binding_handle,
2950 state->srv_name_slash,
2951 state->tmp_creds.account_name,
2952 state->tmp_creds.secure_channel_type,
2953 state->tmp_creds.computer_name,
2954 &state->req_auth,
2955 &state->rep_auth,
2956 &state->new_owf_password,
2957 &state->old_owf_password,
2958 &state->trust_info);
2959 if (tevent_req_nomem(subreq, req)) {
2960 status = NT_STATUS_NO_MEMORY;
2961 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
2962 return;
2965 tevent_req_set_callback(subreq,
2966 netlogon_creds_cli_ServerGetTrustInfo_done,
2967 req);
2970 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
2972 struct tevent_req *req =
2973 tevent_req_callback_data(subreq,
2974 struct tevent_req);
2975 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2976 tevent_req_data(req,
2977 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2978 NTSTATUS status;
2979 NTSTATUS result;
2980 const struct samr_Password zero = {};
2981 int cmp;
2982 bool ok;
2985 * We use state->dns_names as the memory context, as this is
2986 * the only in/out variable and it has been overwritten by the
2987 * out parameter from the server.
2989 * We need to preserve the return value until the caller can use it.
2991 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
2992 TALLOC_FREE(subreq);
2993 if (tevent_req_nterror(req, status)) {
2994 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
2995 return;
2998 ok = netlogon_creds_client_check(&state->tmp_creds,
2999 &state->rep_auth.cred);
3000 if (!ok) {
3001 status = NT_STATUS_ACCESS_DENIED;
3002 tevent_req_nterror(req, status);
3003 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3004 return;
3007 cmp = memcmp(state->new_owf_password.hash,
3008 zero.hash, sizeof(zero.hash));
3009 if (cmp != 0) {
3010 netlogon_creds_des_decrypt(&state->tmp_creds,
3011 &state->new_owf_password);
3013 cmp = memcmp(state->old_owf_password.hash,
3014 zero.hash, sizeof(zero.hash));
3015 if (cmp != 0) {
3016 netlogon_creds_des_decrypt(&state->tmp_creds,
3017 &state->old_owf_password);
3020 *state->creds = state->tmp_creds;
3021 status = netlogon_creds_cli_store(state->context,
3022 state->creds);
3023 TALLOC_FREE(state->creds);
3024 if (tevent_req_nterror(req, status)) {
3025 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3026 return;
3029 if (tevent_req_nterror(req, result)) {
3030 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3031 return;
3034 tevent_req_done(req);
3037 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3038 TALLOC_CTX *mem_ctx,
3039 struct samr_Password *new_owf_password,
3040 struct samr_Password *old_owf_password,
3041 struct netr_TrustInfo **trust_info)
3043 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3044 tevent_req_data(req,
3045 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3046 NTSTATUS status;
3048 if (tevent_req_is_nterror(req, &status)) {
3049 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3050 tevent_req_received(req);
3051 return status;
3054 if (new_owf_password != NULL) {
3055 *new_owf_password = state->new_owf_password;
3057 if (old_owf_password != NULL) {
3058 *old_owf_password = state->old_owf_password;
3060 if (trust_info != NULL) {
3061 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3064 tevent_req_received(req);
3065 return NT_STATUS_OK;
3068 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3069 struct netlogon_creds_cli_context *context,
3070 struct dcerpc_binding_handle *b,
3071 TALLOC_CTX *mem_ctx,
3072 struct samr_Password *new_owf_password,
3073 struct samr_Password *old_owf_password,
3074 struct netr_TrustInfo **trust_info)
3076 TALLOC_CTX *frame = talloc_stackframe();
3077 struct tevent_context *ev;
3078 struct tevent_req *req;
3079 NTSTATUS status = NT_STATUS_NO_MEMORY;
3081 ev = samba_tevent_context_init(frame);
3082 if (ev == NULL) {
3083 goto fail;
3085 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3086 if (req == NULL) {
3087 goto fail;
3089 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3090 goto fail;
3092 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3093 mem_ctx,
3094 new_owf_password,
3095 old_owf_password,
3096 trust_info);
3097 fail:
3098 TALLOC_FREE(frame);
3099 return status;
3102 struct netlogon_creds_cli_GetForestTrustInformation_state {
3103 struct tevent_context *ev;
3104 struct netlogon_creds_cli_context *context;
3105 struct dcerpc_binding_handle *binding_handle;
3107 char *srv_name_slash;
3108 enum dcerpc_AuthType auth_type;
3109 enum dcerpc_AuthLevel auth_level;
3111 uint32_t flags;
3112 struct lsa_ForestTrustInformation *forest_trust_info;
3114 struct netlogon_creds_CredentialState *creds;
3115 struct netlogon_creds_CredentialState tmp_creds;
3116 struct netr_Authenticator req_auth;
3117 struct netr_Authenticator rep_auth;
3120 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3121 NTSTATUS status);
3122 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3124 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3125 struct tevent_context *ev,
3126 struct netlogon_creds_cli_context *context,
3127 struct dcerpc_binding_handle *b)
3129 struct tevent_req *req;
3130 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3131 struct tevent_req *subreq;
3133 req = tevent_req_create(mem_ctx, &state,
3134 struct netlogon_creds_cli_GetForestTrustInformation_state);
3135 if (req == NULL) {
3136 return NULL;
3139 state->ev = ev;
3140 state->context = context;
3141 state->binding_handle = b;
3143 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3144 context->server.computer);
3145 if (tevent_req_nomem(state->srv_name_slash, req)) {
3146 return tevent_req_post(req, ev);
3149 state->flags = 0;
3151 dcerpc_binding_handle_auth_info(state->binding_handle,
3152 &state->auth_type,
3153 &state->auth_level);
3155 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3156 state->context);
3157 if (tevent_req_nomem(subreq, req)) {
3158 return tevent_req_post(req, ev);
3161 tevent_req_set_callback(subreq,
3162 netlogon_creds_cli_GetForestTrustInformation_locked,
3163 req);
3165 return req;
3168 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3169 NTSTATUS status)
3171 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3172 tevent_req_data(req,
3173 struct netlogon_creds_cli_GetForestTrustInformation_state);
3175 if (state->creds == NULL) {
3176 return;
3179 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3180 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3181 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3182 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3183 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3184 TALLOC_FREE(state->creds);
3185 return;
3188 netlogon_creds_cli_delete(state->context, state->creds);
3189 TALLOC_FREE(state->creds);
3192 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3194 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3196 struct tevent_req *req =
3197 tevent_req_callback_data(subreq,
3198 struct tevent_req);
3199 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3200 tevent_req_data(req,
3201 struct netlogon_creds_cli_GetForestTrustInformation_state);
3202 NTSTATUS status;
3204 status = netlogon_creds_cli_lock_recv(subreq, state,
3205 &state->creds);
3206 TALLOC_FREE(subreq);
3207 if (tevent_req_nterror(req, status)) {
3208 return;
3211 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3212 switch (state->auth_level) {
3213 case DCERPC_AUTH_LEVEL_INTEGRITY:
3214 case DCERPC_AUTH_LEVEL_PRIVACY:
3215 break;
3216 default:
3217 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3218 return;
3220 } else {
3221 uint32_t tmp = state->creds->negotiate_flags;
3223 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3225 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3226 * it should be used, which means
3227 * we had a chance to verify no downgrade
3228 * happened.
3230 * This relies on netlogon_creds_cli_check*
3231 * being called before, as first request after
3232 * the DCERPC bind.
3234 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3235 return;
3240 * we defer all callbacks in order to cleanup
3241 * the database record.
3243 tevent_req_defer_callback(req, state->ev);
3245 state->tmp_creds = *state->creds;
3246 netlogon_creds_client_authenticator(&state->tmp_creds,
3247 &state->req_auth);
3248 ZERO_STRUCT(state->rep_auth);
3250 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3251 state->binding_handle,
3252 state->srv_name_slash,
3253 state->tmp_creds.computer_name,
3254 &state->req_auth,
3255 &state->rep_auth,
3256 state->flags,
3257 &state->forest_trust_info);
3258 if (tevent_req_nomem(subreq, req)) {
3259 status = NT_STATUS_NO_MEMORY;
3260 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3261 return;
3264 tevent_req_set_callback(subreq,
3265 netlogon_creds_cli_GetForestTrustInformation_done,
3266 req);
3269 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3271 struct tevent_req *req =
3272 tevent_req_callback_data(subreq,
3273 struct tevent_req);
3274 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3275 tevent_req_data(req,
3276 struct netlogon_creds_cli_GetForestTrustInformation_state);
3277 NTSTATUS status;
3278 NTSTATUS result;
3279 bool ok;
3282 * We use state->dns_names as the memory context, as this is
3283 * the only in/out variable and it has been overwritten by the
3284 * out parameter from the server.
3286 * We need to preserve the return value until the caller can use it.
3288 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3289 TALLOC_FREE(subreq);
3290 if (tevent_req_nterror(req, status)) {
3291 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3292 return;
3295 ok = netlogon_creds_client_check(&state->tmp_creds,
3296 &state->rep_auth.cred);
3297 if (!ok) {
3298 status = NT_STATUS_ACCESS_DENIED;
3299 tevent_req_nterror(req, status);
3300 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3301 return;
3304 *state->creds = state->tmp_creds;
3305 status = netlogon_creds_cli_store(state->context,
3306 state->creds);
3307 TALLOC_FREE(state->creds);
3309 if (tevent_req_nterror(req, status)) {
3310 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3311 return;
3314 if (tevent_req_nterror(req, result)) {
3315 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3316 return;
3319 tevent_req_done(req);
3322 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3323 TALLOC_CTX *mem_ctx,
3324 struct lsa_ForestTrustInformation **forest_trust_info)
3326 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3327 tevent_req_data(req,
3328 struct netlogon_creds_cli_GetForestTrustInformation_state);
3329 NTSTATUS status;
3331 if (tevent_req_is_nterror(req, &status)) {
3332 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3333 tevent_req_received(req);
3334 return status;
3337 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3339 tevent_req_received(req);
3340 return NT_STATUS_OK;
3343 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3344 struct netlogon_creds_cli_context *context,
3345 struct dcerpc_binding_handle *b,
3346 TALLOC_CTX *mem_ctx,
3347 struct lsa_ForestTrustInformation **forest_trust_info)
3349 TALLOC_CTX *frame = talloc_stackframe();
3350 struct tevent_context *ev;
3351 struct tevent_req *req;
3352 NTSTATUS status = NT_STATUS_NO_MEMORY;
3354 ev = samba_tevent_context_init(frame);
3355 if (ev == NULL) {
3356 goto fail;
3358 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3359 if (req == NULL) {
3360 goto fail;
3362 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3363 goto fail;
3365 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3366 mem_ctx,
3367 forest_trust_info);
3368 fail:
3369 TALLOC_FREE(frame);
3370 return status;
3373 struct netlogon_creds_cli_SendToSam_state {
3374 struct tevent_context *ev;
3375 struct netlogon_creds_cli_context *context;
3376 struct dcerpc_binding_handle *binding_handle;
3378 char *srv_name_slash;
3379 enum dcerpc_AuthType auth_type;
3380 enum dcerpc_AuthLevel auth_level;
3382 DATA_BLOB opaque;
3384 struct netlogon_creds_CredentialState *creds;
3385 struct netlogon_creds_CredentialState tmp_creds;
3386 struct netr_Authenticator req_auth;
3387 struct netr_Authenticator rep_auth;
3390 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3391 NTSTATUS status);
3392 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3394 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3395 struct tevent_context *ev,
3396 struct netlogon_creds_cli_context *context,
3397 struct dcerpc_binding_handle *b,
3398 struct netr_SendToSamBase *message)
3400 struct tevent_req *req;
3401 struct netlogon_creds_cli_SendToSam_state *state;
3402 struct tevent_req *subreq;
3403 enum ndr_err_code ndr_err;
3405 req = tevent_req_create(mem_ctx, &state,
3406 struct netlogon_creds_cli_SendToSam_state);
3407 if (req == NULL) {
3408 return NULL;
3411 state->ev = ev;
3412 state->context = context;
3413 state->binding_handle = b;
3415 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3416 context->server.computer);
3417 if (tevent_req_nomem(state->srv_name_slash, req)) {
3418 return tevent_req_post(req, ev);
3421 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3422 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3423 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3424 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3425 tevent_req_nterror(req, status);
3426 return tevent_req_post(req, ev);
3429 dcerpc_binding_handle_auth_info(state->binding_handle,
3430 &state->auth_type,
3431 &state->auth_level);
3433 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3434 state->context);
3435 if (tevent_req_nomem(subreq, req)) {
3436 return tevent_req_post(req, ev);
3439 tevent_req_set_callback(subreq,
3440 netlogon_creds_cli_SendToSam_locked,
3441 req);
3443 return req;
3446 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3447 NTSTATUS status)
3449 struct netlogon_creds_cli_SendToSam_state *state =
3450 tevent_req_data(req,
3451 struct netlogon_creds_cli_SendToSam_state);
3453 if (state->creds == NULL) {
3454 return;
3457 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3458 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3459 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3460 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3461 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3462 TALLOC_FREE(state->creds);
3463 return;
3466 netlogon_creds_cli_delete(state->context, state->creds);
3467 TALLOC_FREE(state->creds);
3470 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3472 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3474 struct tevent_req *req =
3475 tevent_req_callback_data(subreq,
3476 struct tevent_req);
3477 struct netlogon_creds_cli_SendToSam_state *state =
3478 tevent_req_data(req,
3479 struct netlogon_creds_cli_SendToSam_state);
3480 NTSTATUS status;
3482 status = netlogon_creds_cli_lock_recv(subreq, state,
3483 &state->creds);
3484 TALLOC_FREE(subreq);
3485 if (tevent_req_nterror(req, status)) {
3486 return;
3489 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3490 switch (state->auth_level) {
3491 case DCERPC_AUTH_LEVEL_INTEGRITY:
3492 case DCERPC_AUTH_LEVEL_PRIVACY:
3493 break;
3494 default:
3495 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3496 return;
3498 } else {
3499 uint32_t tmp = state->creds->negotiate_flags;
3501 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3503 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3504 * it should be used, which means
3505 * we had a chance to verify no downgrade
3506 * happened.
3508 * This relies on netlogon_creds_cli_check*
3509 * being called before, as first request after
3510 * the DCERPC bind.
3512 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3513 return;
3518 * we defer all callbacks in order to cleanup
3519 * the database record.
3521 tevent_req_defer_callback(req, state->ev);
3523 state->tmp_creds = *state->creds;
3524 netlogon_creds_client_authenticator(&state->tmp_creds,
3525 &state->req_auth);
3526 ZERO_STRUCT(state->rep_auth);
3528 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3529 netlogon_creds_aes_encrypt(&state->tmp_creds,
3530 state->opaque.data,
3531 state->opaque.length);
3532 } else {
3533 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3534 state->opaque.data,
3535 state->opaque.length);
3538 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3539 state->binding_handle,
3540 state->srv_name_slash,
3541 state->tmp_creds.computer_name,
3542 &state->req_auth,
3543 &state->rep_auth,
3544 state->opaque.data,
3545 state->opaque.length);
3546 if (tevent_req_nomem(subreq, req)) {
3547 status = NT_STATUS_NO_MEMORY;
3548 netlogon_creds_cli_SendToSam_cleanup(req, status);
3549 return;
3552 tevent_req_set_callback(subreq,
3553 netlogon_creds_cli_SendToSam_done,
3554 req);
3557 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3559 struct tevent_req *req =
3560 tevent_req_callback_data(subreq,
3561 struct tevent_req);
3562 struct netlogon_creds_cli_SendToSam_state *state =
3563 tevent_req_data(req,
3564 struct netlogon_creds_cli_SendToSam_state);
3565 NTSTATUS status;
3566 NTSTATUS result;
3567 bool ok;
3569 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3570 TALLOC_FREE(subreq);
3571 if (tevent_req_nterror(req, status)) {
3572 netlogon_creds_cli_SendToSam_cleanup(req, status);
3573 return;
3576 ok = netlogon_creds_client_check(&state->tmp_creds,
3577 &state->rep_auth.cred);
3578 if (!ok) {
3579 status = NT_STATUS_ACCESS_DENIED;
3580 tevent_req_nterror(req, status);
3581 netlogon_creds_cli_SendToSam_cleanup(req, status);
3582 return;
3585 *state->creds = state->tmp_creds;
3586 status = netlogon_creds_cli_store(state->context,
3587 state->creds);
3588 TALLOC_FREE(state->creds);
3590 if (tevent_req_nterror(req, status)) {
3591 netlogon_creds_cli_SendToSam_cleanup(req, status);
3592 return;
3596 * Creds must be stored before we send back application errors
3597 * e.g. NT_STATUS_NOT_IMPLEMENTED
3599 if (tevent_req_nterror(req, result)) {
3600 netlogon_creds_cli_SendToSam_cleanup(req, result);
3601 return;
3604 tevent_req_done(req);
3607 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3608 struct dcerpc_binding_handle *b,
3609 struct netr_SendToSamBase *message)
3611 TALLOC_CTX *frame = talloc_stackframe();
3612 struct tevent_context *ev;
3613 struct tevent_req *req;
3614 NTSTATUS status = NT_STATUS_OK;
3616 ev = samba_tevent_context_init(frame);
3617 if (ev == NULL) {
3618 goto fail;
3620 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3621 if (req == NULL) {
3622 goto fail;
3624 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3625 goto fail;
3628 /* Ignore the result */
3629 fail:
3630 TALLOC_FREE(frame);
3631 return status;