smbd: Pass "file_id" explicitly to send_break_message()
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blobfdd1195b1835c492e427ed4a19fecd2f2f272ce1
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"
41 #include "auth/credentials/credentials.h"
43 struct netlogon_creds_cli_locked_state;
45 struct netlogon_creds_cli_context {
46 struct {
47 const char *computer;
48 const char *account;
49 uint32_t proposed_flags;
50 uint32_t required_flags;
51 enum netr_SchannelType type;
52 enum dcerpc_AuthLevel auth_level;
53 } client;
55 struct {
56 const char *computer;
57 const char *netbios_domain;
58 const char *dns_domain;
59 uint32_t cached_flags;
60 bool try_validation6;
61 bool try_logon_ex;
62 bool try_logon_with;
63 } server;
65 struct {
66 const char *key_name;
67 TDB_DATA key_data;
68 struct db_context *ctx;
69 struct g_lock_ctx *g_ctx;
70 struct netlogon_creds_cli_locked_state *locked_state;
71 enum netlogon_creds_cli_lck_type lock;
72 } db;
75 struct netlogon_creds_cli_locked_state {
76 struct netlogon_creds_cli_context *context;
77 bool is_glocked;
78 struct netlogon_creds_CredentialState *creds;
81 static int netlogon_creds_cli_locked_state_destructor(
82 struct netlogon_creds_cli_locked_state *state)
84 struct netlogon_creds_cli_context *context = state->context;
86 if (context == NULL) {
87 return 0;
90 if (context->db.locked_state == state) {
91 context->db.locked_state = NULL;
94 if (state->is_glocked) {
95 g_lock_unlock(context->db.g_ctx,
96 string_term_tdb_data(context->db.key_name));
99 return 0;
102 static NTSTATUS netlogon_creds_cli_context_common(
103 const char *client_computer,
104 const char *client_account,
105 enum netr_SchannelType type,
106 enum dcerpc_AuthLevel auth_level,
107 uint32_t proposed_flags,
108 uint32_t required_flags,
109 const char *server_computer,
110 const char *server_netbios_domain,
111 const char *server_dns_domain,
112 TALLOC_CTX *mem_ctx,
113 struct netlogon_creds_cli_context **_context)
115 struct netlogon_creds_cli_context *context = NULL;
116 char *_key_name = NULL;
117 size_t server_netbios_name_len;
118 char *p = NULL;
120 *_context = NULL;
122 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
123 if (context == NULL) {
124 return NT_STATUS_NO_MEMORY;
127 context->client.computer = talloc_strdup(context, client_computer);
128 if (context->client.computer == NULL) {
129 TALLOC_FREE(context);
130 return NT_STATUS_NO_MEMORY;
133 context->client.account = talloc_strdup(context, client_account);
134 if (context->client.account == NULL) {
135 TALLOC_FREE(context);
136 return NT_STATUS_NO_MEMORY;
139 context->client.proposed_flags = proposed_flags;
140 context->client.required_flags = required_flags;
141 context->client.type = type;
142 context->client.auth_level = auth_level;
144 context->server.computer = talloc_strdup(context, server_computer);
145 if (context->server.computer == NULL) {
146 TALLOC_FREE(context);
147 return NT_STATUS_NO_MEMORY;
150 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
151 if (context->server.netbios_domain == NULL) {
152 TALLOC_FREE(context);
153 return NT_STATUS_NO_MEMORY;
156 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
157 if (context->server.dns_domain == NULL) {
158 TALLOC_FREE(context);
159 return NT_STATUS_NO_MEMORY;
163 * TODO:
164 * Force the callers to provide a unique
165 * value for server_computer and use this directly.
167 * For now we have to deal with
168 * "HOSTNAME" vs. "hostname.example.com".
171 p = strchr(server_computer, '.');
172 if (p != NULL) {
173 server_netbios_name_len = p-server_computer;
174 } else {
175 server_netbios_name_len = strlen(server_computer);
178 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
179 client_computer,
180 client_account,
181 (int)server_netbios_name_len,
182 server_computer,
183 server_netbios_domain);
184 if (_key_name == NULL) {
185 TALLOC_FREE(context);
186 return NT_STATUS_NO_MEMORY;
189 context->db.key_name = talloc_strdup_upper(context, _key_name);
190 TALLOC_FREE(_key_name);
191 if (context->db.key_name == NULL) {
192 TALLOC_FREE(context);
193 return NT_STATUS_NO_MEMORY;
196 context->db.key_data = string_term_tdb_data(context->db.key_name);
198 *_context = context;
199 return NT_STATUS_OK;
202 static struct db_context *netlogon_creds_cli_global_db;
204 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
206 if (netlogon_creds_cli_global_db != NULL) {
207 return NT_STATUS_INVALID_PARAMETER_MIX;
210 netlogon_creds_cli_global_db = talloc_move(NULL, db);
211 return NT_STATUS_OK;
214 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
216 char *fname;
217 struct db_context *global_db;
219 if (netlogon_creds_cli_global_db != NULL) {
220 return NT_STATUS_OK;
223 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
224 if (fname == NULL) {
225 return NT_STATUS_NO_MEMORY;
228 global_db = dbwrap_local_open(NULL, lp_ctx,
229 fname, 0,
230 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
231 O_RDWR|O_CREAT,
232 0600, DBWRAP_LOCK_ORDER_2,
233 DBWRAP_FLAG_NONE);
234 if (global_db == NULL) {
235 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
236 fname, strerror(errno)));
237 talloc_free(fname);
238 return NT_STATUS_NO_MEMORY;
240 TALLOC_FREE(fname);
242 netlogon_creds_cli_global_db = global_db;
243 return NT_STATUS_OK;
246 void netlogon_creds_cli_close_global_db(void)
248 TALLOC_FREE(netlogon_creds_cli_global_db);
251 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
252 struct messaging_context *msg_ctx,
253 const char *client_account,
254 enum netr_SchannelType type,
255 const char *server_computer,
256 const char *server_netbios_domain,
257 const char *server_dns_domain,
258 TALLOC_CTX *mem_ctx,
259 struct netlogon_creds_cli_context **_context)
261 TALLOC_CTX *frame = talloc_stackframe();
262 NTSTATUS status;
263 struct netlogon_creds_cli_context *context = NULL;
264 const char *client_computer;
265 uint32_t proposed_flags;
266 uint32_t required_flags = 0;
267 bool reject_md5_servers = false;
268 bool require_strong_key = false;
269 int require_sign_or_seal = true;
270 bool seal_secure_channel = true;
271 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
272 bool neutralize_nt4_emulation = false;
274 *_context = NULL;
276 if (msg_ctx == NULL) {
277 TALLOC_FREE(frame);
278 return NT_STATUS_INVALID_PARAMETER_MIX;
281 client_computer = lpcfg_netbios_name(lp_ctx);
282 if (strlen(client_computer) > 15) {
283 TALLOC_FREE(frame);
284 return NT_STATUS_INVALID_PARAMETER_MIX;
288 * allow overwrite per domain
289 * reject md5 servers:<netbios_domain>
291 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
292 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
293 "reject md5 servers",
294 server_netbios_domain,
295 reject_md5_servers);
298 * allow overwrite per domain
299 * require strong key:<netbios_domain>
301 require_strong_key = lpcfg_require_strong_key(lp_ctx);
302 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
303 "require strong key",
304 server_netbios_domain,
305 require_strong_key);
308 * allow overwrite per domain
309 * client schannel:<netbios_domain>
311 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
312 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
313 "client schannel",
314 server_netbios_domain,
315 require_sign_or_seal);
318 * allow overwrite per domain
319 * winbind sealed pipes:<netbios_domain>
321 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
322 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
323 "winbind sealed pipes",
324 server_netbios_domain,
325 seal_secure_channel);
328 * allow overwrite per domain
329 * neutralize nt4 emulation:<netbios_domain>
331 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
332 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
333 "neutralize nt4 emulation",
334 server_netbios_domain,
335 neutralize_nt4_emulation);
337 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
338 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
340 switch (type) {
341 case SEC_CHAN_WKSTA:
342 if (lpcfg_security(lp_ctx) == SEC_ADS) {
344 * AD domains should be secure
346 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
347 require_sign_or_seal = true;
348 require_strong_key = true;
350 break;
352 case SEC_CHAN_DOMAIN:
353 break;
355 case SEC_CHAN_DNS_DOMAIN:
357 * AD domains should be secure
359 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
360 require_sign_or_seal = true;
361 require_strong_key = true;
362 neutralize_nt4_emulation = true;
363 break;
365 case SEC_CHAN_BDC:
366 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
367 require_sign_or_seal = true;
368 require_strong_key = true;
369 break;
371 case SEC_CHAN_RODC:
372 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
373 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
374 require_sign_or_seal = true;
375 require_strong_key = true;
376 neutralize_nt4_emulation = true;
377 break;
379 default:
380 TALLOC_FREE(frame);
381 return NT_STATUS_INVALID_PARAMETER;
384 if (neutralize_nt4_emulation) {
385 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
388 if (require_sign_or_seal) {
389 required_flags |= NETLOGON_NEG_ARCFOUR;
390 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
391 } else {
392 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
395 if (reject_md5_servers) {
396 required_flags |= NETLOGON_NEG_ARCFOUR;
397 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
398 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
399 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
402 if (require_strong_key) {
403 required_flags |= NETLOGON_NEG_ARCFOUR;
404 required_flags |= NETLOGON_NEG_STRONG_KEYS;
405 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
408 proposed_flags |= required_flags;
410 if (seal_secure_channel) {
411 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
412 } else {
413 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
416 status = netlogon_creds_cli_context_common(client_computer,
417 client_account,
418 type,
419 auth_level,
420 proposed_flags,
421 required_flags,
422 server_computer,
423 server_netbios_domain,
425 mem_ctx,
426 &context);
427 if (!NT_STATUS_IS_OK(status)) {
428 TALLOC_FREE(frame);
429 return status;
432 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
433 if (context->db.g_ctx == NULL) {
434 TALLOC_FREE(context);
435 TALLOC_FREE(frame);
436 return NT_STATUS_NO_MEMORY;
439 status = netlogon_creds_cli_open_global_db(lp_ctx);
440 if (!NT_STATUS_IS_OK(status)) {
441 TALLOC_FREE(context);
442 TALLOC_FREE(frame);
443 return NT_STATUS_NO_MEMORY;
446 context->db.ctx = netlogon_creds_cli_global_db;
447 *_context = context;
448 TALLOC_FREE(frame);
449 return NT_STATUS_OK;
452 NTSTATUS netlogon_creds_bind_cli_credentials(
453 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
454 struct cli_credentials **pcli_creds)
456 struct cli_credentials *cli_creds;
457 struct netlogon_creds_CredentialState *ncreds;
458 NTSTATUS status;
460 cli_creds = cli_credentials_init(mem_ctx);
461 if (cli_creds == NULL) {
462 return NT_STATUS_NO_MEMORY;
464 cli_credentials_set_secure_channel_type(cli_creds,
465 context->client.type);
466 cli_credentials_set_username(cli_creds, context->client.account,
467 CRED_SPECIFIED);
468 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
469 CRED_SPECIFIED);
470 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
471 CRED_SPECIFIED);
473 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
474 if (!NT_STATUS_IS_OK(status)) {
475 TALLOC_FREE(cli_creds);
476 return status;
478 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
480 *pcli_creds = cli_creds;
481 return NT_STATUS_OK;
484 char *netlogon_creds_cli_debug_string(
485 const struct netlogon_creds_cli_context *context,
486 TALLOC_CTX *mem_ctx)
488 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
489 context->db.key_name);
492 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
493 struct netlogon_creds_cli_context *context)
495 return context->client.auth_level;
498 struct netlogon_creds_cli_fetch_state {
499 TALLOC_CTX *mem_ctx;
500 struct netlogon_creds_CredentialState *creds;
501 uint32_t required_flags;
502 NTSTATUS status;
505 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
506 void *private_data)
508 struct netlogon_creds_cli_fetch_state *state =
509 (struct netlogon_creds_cli_fetch_state *)private_data;
510 enum ndr_err_code ndr_err;
511 DATA_BLOB blob;
512 uint32_t tmp_flags;
514 state->creds = talloc_zero(state->mem_ctx,
515 struct netlogon_creds_CredentialState);
516 if (state->creds == NULL) {
517 state->status = NT_STATUS_NO_MEMORY;
518 return;
521 blob.data = data.dptr;
522 blob.length = data.dsize;
524 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
525 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
526 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
527 TALLOC_FREE(state->creds);
528 state->status = ndr_map_error2ntstatus(ndr_err);
529 return;
532 if (DEBUGLEVEL >= 10) {
533 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
536 tmp_flags = state->creds->negotiate_flags;
537 tmp_flags &= state->required_flags;
538 if (tmp_flags != state->required_flags) {
539 TALLOC_FREE(state->creds);
540 state->status = NT_STATUS_DOWNGRADE_DETECTED;
541 return;
544 state->status = NT_STATUS_OK;
547 static NTSTATUS netlogon_creds_cli_get_internal(
548 struct netlogon_creds_cli_context *context,
549 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
551 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
552 TALLOC_CTX *mem_ctx,
553 struct netlogon_creds_CredentialState **_creds)
555 NTSTATUS status;
556 struct netlogon_creds_CredentialState *creds;
558 *_creds = NULL;
560 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
561 if (!NT_STATUS_IS_OK(status)) {
562 return status;
566 * mark it as invalid for step operations.
568 creds->sequence = 0;
569 creds->seed = (struct netr_Credential) {{0}};
570 creds->client = (struct netr_Credential) {{0}};
571 creds->server = (struct netr_Credential) {{0}};
573 *_creds = creds;
574 return NT_STATUS_OK;
577 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
578 const struct netlogon_creds_CredentialState *creds1)
580 TALLOC_CTX *frame = talloc_stackframe();
581 struct netlogon_creds_CredentialState *creds2;
582 DATA_BLOB blob1;
583 DATA_BLOB blob2;
584 NTSTATUS status;
585 enum ndr_err_code ndr_err;
586 int cmp;
588 status = netlogon_creds_cli_get(context, frame, &creds2);
589 if (!NT_STATUS_IS_OK(status)) {
590 TALLOC_FREE(frame);
591 return false;
594 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
595 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
596 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
597 TALLOC_FREE(frame);
598 return false;
601 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
602 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
603 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
604 TALLOC_FREE(frame);
605 return false;
608 cmp = data_blob_cmp(&blob1, &blob2);
610 TALLOC_FREE(frame);
612 return (cmp == 0);
615 static NTSTATUS netlogon_creds_cli_store_internal(
616 struct netlogon_creds_cli_context *context,
617 struct netlogon_creds_CredentialState *creds)
619 NTSTATUS status;
620 enum ndr_err_code ndr_err;
621 DATA_BLOB blob;
622 TDB_DATA data;
624 if (DEBUGLEVEL >= 10) {
625 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
628 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
629 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
630 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
631 status = ndr_map_error2ntstatus(ndr_err);
632 return status;
635 data.dptr = blob.data;
636 data.dsize = blob.length;
638 status = dbwrap_store(context->db.ctx,
639 context->db.key_data,
640 data, TDB_REPLACE);
641 TALLOC_FREE(data.dptr);
642 if (!NT_STATUS_IS_OK(status)) {
643 return status;
646 return NT_STATUS_OK;
649 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
650 struct netlogon_creds_CredentialState *creds)
652 NTSTATUS status;
654 if (context->db.locked_state == NULL) {
656 * this was not the result of netlogon_creds_cli_lock*()
658 return NT_STATUS_INVALID_PAGE_PROTECTION;
661 if (context->db.locked_state->creds != creds) {
663 * this was not the result of netlogon_creds_cli_lock*()
665 return NT_STATUS_INVALID_PAGE_PROTECTION;
668 status = netlogon_creds_cli_store_internal(context, creds);
669 return status;
672 static NTSTATUS netlogon_creds_cli_delete_internal(
673 struct netlogon_creds_cli_context *context)
675 NTSTATUS status;
676 status = dbwrap_delete(context->db.ctx, context->db.key_data);
677 return status;
680 NTSTATUS netlogon_creds_cli_delete_lck(
681 struct netlogon_creds_cli_context *context)
683 NTSTATUS status;
685 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
686 return NT_STATUS_NOT_LOCKED;
689 status = netlogon_creds_cli_delete_internal(context);
690 return status;
693 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
694 struct netlogon_creds_CredentialState *creds)
696 NTSTATUS status;
698 if (context->db.locked_state == NULL) {
700 * this was not the result of netlogon_creds_cli_lock*()
702 return NT_STATUS_INVALID_PAGE_PROTECTION;
705 if (context->db.locked_state->creds != creds) {
707 * this was not the result of netlogon_creds_cli_lock*()
709 return NT_STATUS_INVALID_PAGE_PROTECTION;
712 status = netlogon_creds_cli_delete_internal(context);
713 return status;
716 struct netlogon_creds_cli_lock_state {
717 struct netlogon_creds_cli_locked_state *locked_state;
718 struct netlogon_creds_CredentialState *creds;
721 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
723 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
724 struct tevent_context *ev,
725 struct netlogon_creds_cli_context *context)
727 struct tevent_req *req;
728 struct netlogon_creds_cli_lock_state *state;
729 struct netlogon_creds_cli_locked_state *locked_state;
730 struct tevent_req *subreq;
732 req = tevent_req_create(mem_ctx, &state,
733 struct netlogon_creds_cli_lock_state);
734 if (req == NULL) {
735 return NULL;
738 if (context->db.locked_state != NULL) {
739 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
740 return tevent_req_post(req, ev);
743 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
744 if (tevent_req_nomem(locked_state, req)) {
745 return tevent_req_post(req, ev);
747 talloc_set_destructor(locked_state,
748 netlogon_creds_cli_locked_state_destructor);
749 locked_state->context = context;
751 context->db.locked_state = locked_state;
752 state->locked_state = locked_state;
754 if (context->db.g_ctx == NULL) {
755 NTSTATUS status;
757 status = netlogon_creds_cli_get_internal(
758 context, state, &state->creds);
759 if (tevent_req_nterror(req, status)) {
760 return tevent_req_post(req, ev);
763 return req;
766 subreq = g_lock_lock_send(state, ev,
767 context->db.g_ctx,
768 string_term_tdb_data(context->db.key_name),
769 G_LOCK_WRITE);
770 if (tevent_req_nomem(subreq, req)) {
771 return tevent_req_post(req, ev);
773 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
775 return req;
778 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
780 struct tevent_req *req =
781 tevent_req_callback_data(subreq,
782 struct tevent_req);
783 struct netlogon_creds_cli_lock_state *state =
784 tevent_req_data(req,
785 struct netlogon_creds_cli_lock_state);
786 NTSTATUS status;
788 status = g_lock_lock_recv(subreq);
789 TALLOC_FREE(subreq);
790 if (tevent_req_nterror(req, status)) {
791 return;
793 state->locked_state->is_glocked = true;
795 status = netlogon_creds_cli_get_internal(state->locked_state->context,
796 state, &state->creds);
797 if (tevent_req_nterror(req, status)) {
798 return;
800 tevent_req_done(req);
803 static NTSTATUS netlogon_creds_cli_get_internal(
804 struct netlogon_creds_cli_context *context,
805 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
807 struct netlogon_creds_cli_fetch_state fstate = {
808 .status = NT_STATUS_INTERNAL_ERROR,
809 .required_flags = context->client.required_flags,
811 NTSTATUS status;
813 fstate.mem_ctx = mem_ctx;
814 status = dbwrap_parse_record(context->db.ctx,
815 context->db.key_data,
816 netlogon_creds_cli_fetch_parser,
817 &fstate);
818 if (!NT_STATUS_IS_OK(status)) {
819 return status;
821 if (!NT_STATUS_IS_OK(fstate.status)) {
822 return fstate.status;
825 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
826 *pcreds = fstate.creds;
827 return NT_STATUS_OK;
831 * It is really important to try SamLogonEx here,
832 * because multiple processes can talk to the same
833 * domain controller, without using the credential
834 * chain.
836 * With a normal SamLogon call, we must keep the
837 * credentials chain updated and intact between all
838 * users of the machine account (which would imply
839 * cross-node communication for every NTLM logon).
841 * The credentials chain is not per NETLOGON pipe
842 * connection, but globally on the server/client pair
843 * by computer name.
845 * It's also important to use NetlogonValidationSamInfo4 (6),
846 * because it relies on the rpc transport encryption
847 * and avoids using the global netlogon schannel
848 * session key to en/decrypt secret information
849 * like the user_session_key for network logons.
851 * [MS-APDS] 3.1.5.2 NTLM Network Logon
852 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
853 * NETLOGON_NEG_AUTHENTICATED_RPC set together
854 * are the indication that the server supports
855 * NetlogonValidationSamInfo4 (6). And it must only
856 * be used if "SealSecureChannel" is used.
858 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
859 * check is done in netlogon_creds_cli_LogonSamLogon*().
862 context->server.cached_flags = fstate.creds->negotiate_flags;
863 context->server.try_validation6 = true;
864 context->server.try_logon_ex = true;
865 context->server.try_logon_with = true;
867 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
868 context->server.try_validation6 = false;
869 context->server.try_logon_ex = false;
871 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
872 context->server.try_validation6 = false;
875 *pcreds = fstate.creds;
876 return NT_STATUS_OK;
879 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
880 TALLOC_CTX *mem_ctx,
881 struct netlogon_creds_CredentialState **creds)
883 struct netlogon_creds_cli_lock_state *state =
884 tevent_req_data(req,
885 struct netlogon_creds_cli_lock_state);
886 NTSTATUS status;
888 if (tevent_req_is_nterror(req, &status)) {
889 tevent_req_received(req);
890 return status;
893 talloc_steal(state->creds, state->locked_state);
894 state->locked_state->creds = state->creds;
895 *creds = talloc_move(mem_ctx, &state->creds);
896 tevent_req_received(req);
897 return NT_STATUS_OK;
900 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
901 TALLOC_CTX *mem_ctx,
902 struct netlogon_creds_CredentialState **creds)
904 TALLOC_CTX *frame = talloc_stackframe();
905 struct tevent_context *ev;
906 struct tevent_req *req;
907 NTSTATUS status = NT_STATUS_NO_MEMORY;
909 ev = samba_tevent_context_init(frame);
910 if (ev == NULL) {
911 goto fail;
913 req = netlogon_creds_cli_lock_send(frame, ev, context);
914 if (req == NULL) {
915 goto fail;
917 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
918 goto fail;
920 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
921 fail:
922 TALLOC_FREE(frame);
923 return status;
926 struct netlogon_creds_cli_lck {
927 struct netlogon_creds_cli_context *context;
930 struct netlogon_creds_cli_lck_state {
931 struct netlogon_creds_cli_lck *lck;
932 enum netlogon_creds_cli_lck_type type;
935 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
936 static int netlogon_creds_cli_lck_destructor(
937 struct netlogon_creds_cli_lck *lck);
939 struct tevent_req *netlogon_creds_cli_lck_send(
940 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
941 struct netlogon_creds_cli_context *context,
942 enum netlogon_creds_cli_lck_type type)
944 struct tevent_req *req, *subreq;
945 struct netlogon_creds_cli_lck_state *state;
946 enum g_lock_type gtype;
948 req = tevent_req_create(mem_ctx, &state,
949 struct netlogon_creds_cli_lck_state);
950 if (req == NULL) {
951 return NULL;
954 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
955 DBG_DEBUG("context already locked\n");
956 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
957 return tevent_req_post(req, ev);
960 switch (type) {
961 case NETLOGON_CREDS_CLI_LCK_SHARED:
962 gtype = G_LOCK_READ;
963 break;
964 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
965 gtype = G_LOCK_WRITE;
966 break;
967 default:
968 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
969 return tevent_req_post(req, ev);
972 state->lck = talloc(state, struct netlogon_creds_cli_lck);
973 if (tevent_req_nomem(state->lck, req)) {
974 return tevent_req_post(req, ev);
976 state->lck->context = context;
977 state->type = type;
979 subreq = g_lock_lock_send(state, ev,
980 context->db.g_ctx,
981 string_term_tdb_data(context->db.key_name),
982 gtype);
983 if (tevent_req_nomem(subreq, req)) {
984 return tevent_req_post(req, ev);
986 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
988 return req;
991 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
993 struct tevent_req *req = tevent_req_callback_data(
994 subreq, struct tevent_req);
995 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
996 req, struct netlogon_creds_cli_lck_state);
997 NTSTATUS status;
999 status = g_lock_lock_recv(subreq);
1000 TALLOC_FREE(subreq);
1001 if (tevent_req_nterror(req, status)) {
1002 return;
1005 state->lck->context->db.lock = state->type;
1006 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1008 tevent_req_done(req);
1011 static int netlogon_creds_cli_lck_destructor(
1012 struct netlogon_creds_cli_lck *lck)
1014 struct netlogon_creds_cli_context *ctx = lck->context;
1015 NTSTATUS status;
1017 status = g_lock_unlock(ctx->db.g_ctx,
1018 string_term_tdb_data(ctx->db.key_name));
1019 if (!NT_STATUS_IS_OK(status)) {
1020 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1021 smb_panic("g_lock_unlock failed");
1023 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1024 return 0;
1027 NTSTATUS netlogon_creds_cli_lck_recv(
1028 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1029 struct netlogon_creds_cli_lck **lck)
1031 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1032 req, struct netlogon_creds_cli_lck_state);
1033 NTSTATUS status;
1035 if (tevent_req_is_nterror(req, &status)) {
1036 return status;
1038 *lck = talloc_move(mem_ctx, &state->lck);
1039 return NT_STATUS_OK;
1042 NTSTATUS netlogon_creds_cli_lck(
1043 struct netlogon_creds_cli_context *context,
1044 enum netlogon_creds_cli_lck_type type,
1045 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1047 TALLOC_CTX *frame = talloc_stackframe();
1048 struct tevent_context *ev;
1049 struct tevent_req *req;
1050 NTSTATUS status = NT_STATUS_NO_MEMORY;
1052 ev = samba_tevent_context_init(frame);
1053 if (ev == NULL) {
1054 goto fail;
1056 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1057 if (req == NULL) {
1058 goto fail;
1060 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1061 goto fail;
1063 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1064 fail:
1065 TALLOC_FREE(frame);
1066 return status;
1069 struct netlogon_creds_cli_auth_state {
1070 struct tevent_context *ev;
1071 struct netlogon_creds_cli_context *context;
1072 struct dcerpc_binding_handle *binding_handle;
1073 uint8_t num_nt_hashes;
1074 uint8_t idx_nt_hashes;
1075 const struct samr_Password * const *nt_hashes;
1076 const struct samr_Password *used_nt_hash;
1077 char *srv_name_slash;
1078 uint32_t current_flags;
1079 struct netr_Credential client_challenge;
1080 struct netr_Credential server_challenge;
1081 struct netlogon_creds_CredentialState *creds;
1082 struct netr_Credential client_credential;
1083 struct netr_Credential server_credential;
1084 uint32_t rid;
1085 bool try_auth3;
1086 bool try_auth2;
1087 bool require_auth2;
1090 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1092 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1093 struct tevent_context *ev,
1094 struct netlogon_creds_cli_context *context,
1095 struct dcerpc_binding_handle *b,
1096 uint8_t num_nt_hashes,
1097 const struct samr_Password * const *nt_hashes)
1099 struct tevent_req *req;
1100 struct netlogon_creds_cli_auth_state *state;
1101 NTSTATUS status;
1103 req = tevent_req_create(mem_ctx, &state,
1104 struct netlogon_creds_cli_auth_state);
1105 if (req == NULL) {
1106 return NULL;
1109 state->ev = ev;
1110 state->context = context;
1111 state->binding_handle = b;
1112 if (num_nt_hashes < 1) {
1113 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1114 return tevent_req_post(req, ev);
1116 if (num_nt_hashes > 4) {
1117 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1118 return tevent_req_post(req, ev);
1121 state->num_nt_hashes = num_nt_hashes;
1122 state->idx_nt_hashes = 0;
1123 state->nt_hashes = nt_hashes;
1125 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1126 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1127 return tevent_req_post(req, ev);
1130 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1131 context->server.computer);
1132 if (tevent_req_nomem(state->srv_name_slash, req)) {
1133 return tevent_req_post(req, ev);
1136 state->try_auth3 = true;
1137 state->try_auth2 = true;
1139 if (context->client.required_flags != 0) {
1140 state->require_auth2 = true;
1143 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1144 state->current_flags = context->client.proposed_flags;
1146 status = dbwrap_purge(state->context->db.ctx,
1147 state->context->db.key_data);
1148 if (tevent_req_nterror(req, status)) {
1149 return tevent_req_post(req, ev);
1152 netlogon_creds_cli_auth_challenge_start(req);
1153 if (!tevent_req_is_in_progress(req)) {
1154 return tevent_req_post(req, ev);
1157 return req;
1160 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1162 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1164 struct netlogon_creds_cli_auth_state *state =
1165 tevent_req_data(req,
1166 struct netlogon_creds_cli_auth_state);
1167 struct tevent_req *subreq;
1169 TALLOC_FREE(state->creds);
1171 generate_random_buffer(state->client_challenge.data,
1172 sizeof(state->client_challenge.data));
1174 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1175 state->binding_handle,
1176 state->srv_name_slash,
1177 state->context->client.computer,
1178 &state->client_challenge,
1179 &state->server_challenge);
1180 if (tevent_req_nomem(subreq, req)) {
1181 return;
1183 tevent_req_set_callback(subreq,
1184 netlogon_creds_cli_auth_challenge_done,
1185 req);
1188 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1190 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1192 struct tevent_req *req =
1193 tevent_req_callback_data(subreq,
1194 struct tevent_req);
1195 struct netlogon_creds_cli_auth_state *state =
1196 tevent_req_data(req,
1197 struct netlogon_creds_cli_auth_state);
1198 NTSTATUS status;
1199 NTSTATUS result;
1201 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1202 TALLOC_FREE(subreq);
1203 if (tevent_req_nterror(req, status)) {
1204 return;
1206 if (tevent_req_nterror(req, result)) {
1207 return;
1210 if (!state->try_auth3 && !state->try_auth2) {
1211 state->current_flags = 0;
1214 /* Calculate the session key and client credentials */
1216 state->creds = netlogon_creds_client_init(state,
1217 state->context->client.account,
1218 state->context->client.computer,
1219 state->context->client.type,
1220 &state->client_challenge,
1221 &state->server_challenge,
1222 state->used_nt_hash,
1223 &state->client_credential,
1224 state->current_flags);
1225 if (tevent_req_nomem(state->creds, req)) {
1226 return;
1229 if (state->try_auth3) {
1230 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1231 state->binding_handle,
1232 state->srv_name_slash,
1233 state->context->client.account,
1234 state->context->client.type,
1235 state->context->client.computer,
1236 &state->client_credential,
1237 &state->server_credential,
1238 &state->creds->negotiate_flags,
1239 &state->rid);
1240 if (tevent_req_nomem(subreq, req)) {
1241 return;
1243 } else if (state->try_auth2) {
1244 state->rid = 0;
1246 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1247 state->binding_handle,
1248 state->srv_name_slash,
1249 state->context->client.account,
1250 state->context->client.type,
1251 state->context->client.computer,
1252 &state->client_credential,
1253 &state->server_credential,
1254 &state->creds->negotiate_flags);
1255 if (tevent_req_nomem(subreq, req)) {
1256 return;
1258 } else {
1259 state->rid = 0;
1261 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1262 state->binding_handle,
1263 state->srv_name_slash,
1264 state->context->client.account,
1265 state->context->client.type,
1266 state->context->client.computer,
1267 &state->client_credential,
1268 &state->server_credential);
1269 if (tevent_req_nomem(subreq, req)) {
1270 return;
1273 tevent_req_set_callback(subreq,
1274 netlogon_creds_cli_auth_srvauth_done,
1275 req);
1278 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1280 struct tevent_req *req =
1281 tevent_req_callback_data(subreq,
1282 struct tevent_req);
1283 struct netlogon_creds_cli_auth_state *state =
1284 tevent_req_data(req,
1285 struct netlogon_creds_cli_auth_state);
1286 NTSTATUS status;
1287 NTSTATUS result;
1288 bool ok;
1289 enum ndr_err_code ndr_err;
1290 DATA_BLOB blob;
1291 TDB_DATA data;
1292 uint32_t tmp_flags;
1294 if (state->try_auth3) {
1295 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1296 &result);
1297 TALLOC_FREE(subreq);
1298 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1299 state->try_auth3 = false;
1300 netlogon_creds_cli_auth_challenge_start(req);
1301 return;
1303 if (tevent_req_nterror(req, status)) {
1304 return;
1306 } else if (state->try_auth2) {
1307 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1308 &result);
1309 TALLOC_FREE(subreq);
1310 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1311 state->try_auth2 = false;
1312 if (state->require_auth2) {
1313 status = NT_STATUS_DOWNGRADE_DETECTED;
1314 tevent_req_nterror(req, status);
1315 return;
1317 netlogon_creds_cli_auth_challenge_start(req);
1318 return;
1320 if (tevent_req_nterror(req, status)) {
1321 return;
1323 } else {
1324 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1325 &result);
1326 TALLOC_FREE(subreq);
1327 if (tevent_req_nterror(req, status)) {
1328 return;
1332 if (!NT_STATUS_IS_OK(result) &&
1333 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1335 tevent_req_nterror(req, result);
1336 return;
1339 tmp_flags = state->creds->negotiate_flags;
1340 tmp_flags &= state->context->client.required_flags;
1341 if (tmp_flags != state->context->client.required_flags) {
1342 if (NT_STATUS_IS_OK(result)) {
1343 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1344 return;
1346 tevent_req_nterror(req, result);
1347 return;
1350 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1352 tmp_flags = state->context->client.proposed_flags;
1353 if ((state->current_flags == tmp_flags) &&
1354 (state->creds->negotiate_flags != tmp_flags))
1357 * lets retry with the negotiated flags
1359 state->current_flags = state->creds->negotiate_flags;
1360 netlogon_creds_cli_auth_challenge_start(req);
1361 return;
1364 state->idx_nt_hashes += 1;
1365 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1367 * we already retried, giving up...
1369 tevent_req_nterror(req, result);
1370 return;
1374 * lets retry with the old nt hash.
1376 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1377 state->current_flags = state->context->client.proposed_flags;
1378 netlogon_creds_cli_auth_challenge_start(req);
1379 return;
1382 ok = netlogon_creds_client_check(state->creds,
1383 &state->server_credential);
1384 if (!ok) {
1385 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1386 return;
1389 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1390 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1391 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1392 status = ndr_map_error2ntstatus(ndr_err);
1393 tevent_req_nterror(req, status);
1394 return;
1397 data.dptr = blob.data;
1398 data.dsize = blob.length;
1400 status = dbwrap_store(state->context->db.ctx,
1401 state->context->db.key_data,
1402 data, TDB_REPLACE);
1403 if (tevent_req_nterror(req, status)) {
1404 return;
1407 tevent_req_done(req);
1410 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1411 uint8_t *idx_nt_hashes)
1413 struct netlogon_creds_cli_auth_state *state =
1414 tevent_req_data(req,
1415 struct netlogon_creds_cli_auth_state);
1416 NTSTATUS status;
1418 *idx_nt_hashes = 0;
1420 if (tevent_req_is_nterror(req, &status)) {
1421 tevent_req_received(req);
1422 return status;
1425 *idx_nt_hashes = state->idx_nt_hashes;
1426 tevent_req_received(req);
1427 return NT_STATUS_OK;
1430 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1431 struct dcerpc_binding_handle *b,
1432 uint8_t num_nt_hashes,
1433 const struct samr_Password * const *nt_hashes,
1434 uint8_t *idx_nt_hashes)
1436 TALLOC_CTX *frame = talloc_stackframe();
1437 struct tevent_context *ev;
1438 struct tevent_req *req;
1439 NTSTATUS status = NT_STATUS_NO_MEMORY;
1441 *idx_nt_hashes = 0;
1443 ev = samba_tevent_context_init(frame);
1444 if (ev == NULL) {
1445 goto fail;
1447 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1448 num_nt_hashes, nt_hashes);
1449 if (req == NULL) {
1450 goto fail;
1452 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1453 goto fail;
1455 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1456 fail:
1457 TALLOC_FREE(frame);
1458 return status;
1461 struct netlogon_creds_cli_check_state {
1462 struct tevent_context *ev;
1463 struct netlogon_creds_cli_context *context;
1464 struct dcerpc_binding_handle *binding_handle;
1466 char *srv_name_slash;
1468 union netr_Capabilities caps;
1470 struct netlogon_creds_CredentialState *creds;
1471 struct netr_Authenticator req_auth;
1472 struct netr_Authenticator rep_auth;
1475 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1476 NTSTATUS status);
1477 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1479 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1480 struct tevent_context *ev,
1481 struct netlogon_creds_cli_context *context,
1482 struct dcerpc_binding_handle *b)
1484 struct tevent_req *req;
1485 struct netlogon_creds_cli_check_state *state;
1486 struct tevent_req *subreq;
1487 enum dcerpc_AuthType auth_type;
1488 enum dcerpc_AuthLevel auth_level;
1489 NTSTATUS status;
1491 req = tevent_req_create(mem_ctx, &state,
1492 struct netlogon_creds_cli_check_state);
1493 if (req == NULL) {
1494 return NULL;
1497 state->ev = ev;
1498 state->context = context;
1499 state->binding_handle = b;
1501 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1502 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1503 return tevent_req_post(req, ev);
1506 status = netlogon_creds_cli_get_internal(context, state,
1507 &state->creds);
1508 if (tevent_req_nterror(req, status)) {
1509 return tevent_req_post(req, ev);
1512 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1513 context->server.computer);
1514 if (tevent_req_nomem(state->srv_name_slash, req)) {
1515 return tevent_req_post(req, ev);
1518 dcerpc_binding_handle_auth_info(state->binding_handle,
1519 &auth_type, &auth_level);
1521 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1522 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1523 return tevent_req_post(req, ev);
1526 switch (auth_level) {
1527 case DCERPC_AUTH_LEVEL_INTEGRITY:
1528 case DCERPC_AUTH_LEVEL_PRIVACY:
1529 break;
1530 default:
1531 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1532 return tevent_req_post(req, ev);
1536 * we defer all callbacks in order to cleanup
1537 * the database record.
1539 tevent_req_defer_callback(req, state->ev);
1541 netlogon_creds_client_authenticator(state->creds, &state->req_auth);
1542 ZERO_STRUCT(state->rep_auth);
1544 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1545 state->binding_handle,
1546 state->srv_name_slash,
1547 state->context->client.computer,
1548 &state->req_auth,
1549 &state->rep_auth,
1551 &state->caps);
1552 if (tevent_req_nomem(subreq, req)) {
1553 return tevent_req_post(req, ev);
1556 tevent_req_set_callback(subreq,
1557 netlogon_creds_cli_check_caps,
1558 req);
1560 return req;
1563 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1564 NTSTATUS status)
1566 struct netlogon_creds_cli_check_state *state =
1567 tevent_req_data(req,
1568 struct netlogon_creds_cli_check_state);
1570 if (state->creds == NULL) {
1571 return;
1574 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1575 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1576 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1577 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1578 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1579 TALLOC_FREE(state->creds);
1580 return;
1583 netlogon_creds_cli_delete_lck(state->context);
1584 TALLOC_FREE(state->creds);
1587 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1589 struct tevent_req *req =
1590 tevent_req_callback_data(subreq,
1591 struct tevent_req);
1592 struct netlogon_creds_cli_check_state *state =
1593 tevent_req_data(req,
1594 struct netlogon_creds_cli_check_state);
1595 NTSTATUS status;
1596 NTSTATUS result;
1597 bool ok;
1599 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1600 &result);
1601 TALLOC_FREE(subreq);
1602 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1604 * Note that the negotiated flags are already checked
1605 * for our required flags after the ServerAuthenticate3/2 call.
1607 uint32_t negotiated = state->creds->negotiate_flags;
1609 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1611 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1612 * already, we expect this to work!
1614 status = NT_STATUS_DOWNGRADE_DETECTED;
1615 tevent_req_nterror(req, status);
1616 netlogon_creds_cli_check_cleanup(req, status);
1617 return;
1620 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1622 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1623 * we expect this to work at least as far as the
1624 * NOT_SUPPORTED error handled below!
1626 * NT 4.0 and Old Samba servers are not
1627 * allowed without "require strong key = no"
1629 status = NT_STATUS_DOWNGRADE_DETECTED;
1630 tevent_req_nterror(req, status);
1631 netlogon_creds_cli_check_cleanup(req, status);
1632 return;
1636 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1637 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1638 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1640 * This is needed against NT 4.0 and old Samba servers.
1642 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1643 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1644 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1645 * with the next request as the sequence number processing
1646 * gets out of sync.
1648 netlogon_creds_cli_check_cleanup(req, status);
1649 tevent_req_done(req);
1650 return;
1652 if (tevent_req_nterror(req, status)) {
1653 netlogon_creds_cli_check_cleanup(req, status);
1654 return;
1657 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1659 * Note that the negotiated flags are already checked
1660 * for our required flags after the ServerAuthenticate3/2 call.
1662 uint32_t negotiated = state->creds->negotiate_flags;
1664 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1666 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1667 * already, we expect this to work!
1669 status = NT_STATUS_DOWNGRADE_DETECTED;
1670 tevent_req_nterror(req, status);
1671 netlogon_creds_cli_check_cleanup(req, status);
1672 return;
1676 * This is ok, the server does not support
1677 * NETLOGON_NEG_SUPPORTS_AES.
1679 * netr_LogonGetCapabilities() was
1680 * netr_LogonDummyRoutine1() before
1681 * NETLOGON_NEG_SUPPORTS_AES was invented.
1683 netlogon_creds_cli_check_cleanup(req, result);
1684 tevent_req_done(req);
1685 return;
1688 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1689 if (!ok) {
1690 status = NT_STATUS_ACCESS_DENIED;
1691 tevent_req_nterror(req, status);
1692 netlogon_creds_cli_check_cleanup(req, status);
1693 return;
1696 if (tevent_req_nterror(req, result)) {
1697 netlogon_creds_cli_check_cleanup(req, result);
1698 return;
1701 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1702 status = NT_STATUS_DOWNGRADE_DETECTED;
1703 tevent_req_nterror(req, status);
1704 netlogon_creds_cli_check_cleanup(req, status);
1705 return;
1709 * This is the key check that makes this check secure. If we
1710 * get OK here (rather than NOT_SUPPORTED), then the server
1711 * did support AES. If the server only proposed STRONG_KEYS
1712 * and not AES, then it should have failed with
1713 * NOT_IMPLEMENTED. We always send AES as a client, so the
1714 * server should always have returned it.
1716 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1717 status = NT_STATUS_DOWNGRADE_DETECTED;
1718 tevent_req_nterror(req, status);
1719 netlogon_creds_cli_check_cleanup(req, status);
1720 return;
1723 status = netlogon_creds_cli_store_internal(state->context,
1724 state->creds);
1725 if (tevent_req_nterror(req, status)) {
1726 return;
1729 tevent_req_done(req);
1732 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1733 union netr_Capabilities *capabilities)
1735 struct netlogon_creds_cli_check_state *state = tevent_req_data(
1736 req, struct netlogon_creds_cli_check_state);
1737 NTSTATUS status;
1739 if (tevent_req_is_nterror(req, &status)) {
1740 netlogon_creds_cli_check_cleanup(req, status);
1741 tevent_req_received(req);
1742 return status;
1745 if (capabilities != NULL) {
1746 *capabilities = state->caps;
1749 tevent_req_received(req);
1750 return NT_STATUS_OK;
1753 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1754 struct dcerpc_binding_handle *b,
1755 union netr_Capabilities *capabilities)
1757 TALLOC_CTX *frame = talloc_stackframe();
1758 struct tevent_context *ev;
1759 struct tevent_req *req;
1760 NTSTATUS status = NT_STATUS_NO_MEMORY;
1762 ev = samba_tevent_context_init(frame);
1763 if (ev == NULL) {
1764 goto fail;
1766 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1767 if (req == NULL) {
1768 goto fail;
1770 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1771 goto fail;
1773 status = netlogon_creds_cli_check_recv(req, capabilities);
1774 fail:
1775 TALLOC_FREE(frame);
1776 return status;
1779 struct netlogon_creds_cli_ServerPasswordSet_state {
1780 struct tevent_context *ev;
1781 struct netlogon_creds_cli_context *context;
1782 struct dcerpc_binding_handle *binding_handle;
1783 uint32_t old_timeout;
1785 char *srv_name_slash;
1786 enum dcerpc_AuthType auth_type;
1787 enum dcerpc_AuthLevel auth_level;
1789 struct samr_CryptPassword samr_crypt_password;
1790 struct netr_CryptPassword netr_crypt_password;
1791 struct samr_Password samr_password;
1793 struct netlogon_creds_CredentialState *creds;
1794 struct netlogon_creds_CredentialState tmp_creds;
1795 struct netr_Authenticator req_auth;
1796 struct netr_Authenticator rep_auth;
1799 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1800 NTSTATUS status);
1801 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1803 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1804 struct tevent_context *ev,
1805 struct netlogon_creds_cli_context *context,
1806 struct dcerpc_binding_handle *b,
1807 const DATA_BLOB *new_password,
1808 const uint32_t *new_version)
1810 struct tevent_req *req;
1811 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1812 struct tevent_req *subreq;
1813 bool ok;
1815 req = tevent_req_create(mem_ctx, &state,
1816 struct netlogon_creds_cli_ServerPasswordSet_state);
1817 if (req == NULL) {
1818 return NULL;
1821 state->ev = ev;
1822 state->context = context;
1823 state->binding_handle = b;
1825 if (new_password->length < 14) {
1826 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1827 return tevent_req_post(req, ev);
1831 * netr_ServerPasswordSet
1833 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1836 * netr_ServerPasswordSet2
1838 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1839 new_password);
1840 if (!ok) {
1841 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1842 return tevent_req_post(req, ev);
1845 if (new_version != NULL) {
1846 struct NL_PASSWORD_VERSION version;
1847 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1848 uint32_t ofs = 512 - len;
1849 uint8_t *p;
1851 if (len > 500) {
1852 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1853 return tevent_req_post(req, ev);
1855 ofs -= 12;
1857 version.ReservedField = 0;
1858 version.PasswordVersionNumber = *new_version;
1859 version.PasswordVersionPresent =
1860 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1862 p = state->samr_crypt_password.data + ofs;
1863 SIVAL(p, 0, version.ReservedField);
1864 SIVAL(p, 4, version.PasswordVersionNumber);
1865 SIVAL(p, 8, version.PasswordVersionPresent);
1868 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1869 context->server.computer);
1870 if (tevent_req_nomem(state->srv_name_slash, req)) {
1871 return tevent_req_post(req, ev);
1874 dcerpc_binding_handle_auth_info(state->binding_handle,
1875 &state->auth_type,
1876 &state->auth_level);
1878 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1879 state->context);
1880 if (tevent_req_nomem(subreq, req)) {
1881 return tevent_req_post(req, ev);
1884 tevent_req_set_callback(subreq,
1885 netlogon_creds_cli_ServerPasswordSet_locked,
1886 req);
1888 return req;
1891 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1892 NTSTATUS status)
1894 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1895 tevent_req_data(req,
1896 struct netlogon_creds_cli_ServerPasswordSet_state);
1898 if (state->creds == NULL) {
1899 return;
1902 dcerpc_binding_handle_set_timeout(state->binding_handle,
1903 state->old_timeout);
1905 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1906 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1907 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1908 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1909 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1910 TALLOC_FREE(state->creds);
1911 return;
1914 netlogon_creds_cli_delete(state->context, state->creds);
1915 TALLOC_FREE(state->creds);
1918 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1920 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1922 struct tevent_req *req =
1923 tevent_req_callback_data(subreq,
1924 struct tevent_req);
1925 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1926 tevent_req_data(req,
1927 struct netlogon_creds_cli_ServerPasswordSet_state);
1928 NTSTATUS status;
1930 status = netlogon_creds_cli_lock_recv(subreq, state,
1931 &state->creds);
1932 TALLOC_FREE(subreq);
1933 if (tevent_req_nterror(req, status)) {
1934 return;
1937 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1938 switch (state->auth_level) {
1939 case DCERPC_AUTH_LEVEL_INTEGRITY:
1940 case DCERPC_AUTH_LEVEL_PRIVACY:
1941 break;
1942 default:
1943 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1944 return;
1946 } else {
1947 uint32_t tmp = state->creds->negotiate_flags;
1949 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1951 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1952 * it should be used, which means
1953 * we had a chance to verify no downgrade
1954 * happened.
1956 * This relies on netlogon_creds_cli_check*
1957 * being called before, as first request after
1958 * the DCERPC bind.
1960 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1961 return;
1965 state->old_timeout = dcerpc_binding_handle_set_timeout(
1966 state->binding_handle, 600000);
1969 * we defer all callbacks in order to cleanup
1970 * the database record.
1972 tevent_req_defer_callback(req, state->ev);
1974 state->tmp_creds = *state->creds;
1975 netlogon_creds_client_authenticator(&state->tmp_creds,
1976 &state->req_auth);
1977 ZERO_STRUCT(state->rep_auth);
1979 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1981 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1982 netlogon_creds_aes_encrypt(&state->tmp_creds,
1983 state->samr_crypt_password.data,
1984 516);
1985 } else {
1986 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1987 state->samr_crypt_password.data,
1988 516);
1991 memcpy(state->netr_crypt_password.data,
1992 state->samr_crypt_password.data, 512);
1993 state->netr_crypt_password.length =
1994 IVAL(state->samr_crypt_password.data, 512);
1996 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1997 state->binding_handle,
1998 state->srv_name_slash,
1999 state->tmp_creds.account_name,
2000 state->tmp_creds.secure_channel_type,
2001 state->tmp_creds.computer_name,
2002 &state->req_auth,
2003 &state->rep_auth,
2004 &state->netr_crypt_password);
2005 if (tevent_req_nomem(subreq, req)) {
2006 status = NT_STATUS_NO_MEMORY;
2007 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2008 return;
2010 } else {
2011 netlogon_creds_des_encrypt(&state->tmp_creds,
2012 &state->samr_password);
2014 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2015 state->binding_handle,
2016 state->srv_name_slash,
2017 state->tmp_creds.account_name,
2018 state->tmp_creds.secure_channel_type,
2019 state->tmp_creds.computer_name,
2020 &state->req_auth,
2021 &state->rep_auth,
2022 &state->samr_password);
2023 if (tevent_req_nomem(subreq, req)) {
2024 status = NT_STATUS_NO_MEMORY;
2025 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2026 return;
2030 tevent_req_set_callback(subreq,
2031 netlogon_creds_cli_ServerPasswordSet_done,
2032 req);
2035 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2037 struct tevent_req *req =
2038 tevent_req_callback_data(subreq,
2039 struct tevent_req);
2040 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2041 tevent_req_data(req,
2042 struct netlogon_creds_cli_ServerPasswordSet_state);
2043 NTSTATUS status;
2044 NTSTATUS result;
2045 bool ok;
2047 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2048 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2049 &result);
2050 TALLOC_FREE(subreq);
2051 if (tevent_req_nterror(req, status)) {
2052 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2053 return;
2055 } else {
2056 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2057 &result);
2058 TALLOC_FREE(subreq);
2059 if (tevent_req_nterror(req, status)) {
2060 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2061 return;
2065 ok = netlogon_creds_client_check(&state->tmp_creds,
2066 &state->rep_auth.cred);
2067 if (!ok) {
2068 status = NT_STATUS_ACCESS_DENIED;
2069 tevent_req_nterror(req, status);
2070 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2071 return;
2074 if (tevent_req_nterror(req, result)) {
2075 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2076 return;
2079 dcerpc_binding_handle_set_timeout(state->binding_handle,
2080 state->old_timeout);
2082 *state->creds = state->tmp_creds;
2083 status = netlogon_creds_cli_store(state->context,
2084 state->creds);
2085 TALLOC_FREE(state->creds);
2086 if (tevent_req_nterror(req, status)) {
2087 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2088 return;
2091 tevent_req_done(req);
2094 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2096 NTSTATUS status;
2098 if (tevent_req_is_nterror(req, &status)) {
2099 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2100 tevent_req_received(req);
2101 return status;
2104 tevent_req_received(req);
2105 return NT_STATUS_OK;
2108 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2109 struct netlogon_creds_cli_context *context,
2110 struct dcerpc_binding_handle *b,
2111 const DATA_BLOB *new_password,
2112 const uint32_t *new_version)
2114 TALLOC_CTX *frame = talloc_stackframe();
2115 struct tevent_context *ev;
2116 struct tevent_req *req;
2117 NTSTATUS status = NT_STATUS_NO_MEMORY;
2119 ev = samba_tevent_context_init(frame);
2120 if (ev == NULL) {
2121 goto fail;
2123 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2124 new_password,
2125 new_version);
2126 if (req == NULL) {
2127 goto fail;
2129 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2130 goto fail;
2132 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2133 fail:
2134 TALLOC_FREE(frame);
2135 return status;
2138 struct netlogon_creds_cli_LogonSamLogon_state {
2139 struct tevent_context *ev;
2140 struct netlogon_creds_cli_context *context;
2141 struct dcerpc_binding_handle *binding_handle;
2143 char *srv_name_slash;
2145 enum netr_LogonInfoClass logon_level;
2146 const union netr_LogonLevel *const_logon;
2147 union netr_LogonLevel *logon;
2148 uint32_t flags;
2150 uint16_t validation_level;
2151 union netr_Validation *validation;
2152 uint8_t authoritative;
2155 * do we need encryption at the application layer?
2157 bool user_encrypt;
2158 bool try_logon_ex;
2159 bool try_validation6;
2162 * the read only credentials before we started the operation
2163 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2165 struct netlogon_creds_CredentialState *ro_creds;
2168 * The (locked) credentials used for the credential chain
2169 * used for netr_LogonSamLogonWithFlags() or
2170 * netr_LogonSamLogonWith().
2172 struct netlogon_creds_CredentialState *lk_creds;
2175 * While we have locked the global credentials (lk_creds above)
2176 * we operate an a temporary copy, because a server
2177 * may not support netr_LogonSamLogonWithFlags() and
2178 * didn't process our netr_Authenticator, so we need to
2179 * restart from lk_creds.
2181 struct netlogon_creds_CredentialState tmp_creds;
2182 struct netr_Authenticator req_auth;
2183 struct netr_Authenticator rep_auth;
2186 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2187 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2188 NTSTATUS status);
2190 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2191 struct tevent_context *ev,
2192 struct netlogon_creds_cli_context *context,
2193 struct dcerpc_binding_handle *b,
2194 enum netr_LogonInfoClass logon_level,
2195 const union netr_LogonLevel *logon,
2196 uint32_t flags)
2198 struct tevent_req *req;
2199 struct netlogon_creds_cli_LogonSamLogon_state *state;
2201 req = tevent_req_create(mem_ctx, &state,
2202 struct netlogon_creds_cli_LogonSamLogon_state);
2203 if (req == NULL) {
2204 return NULL;
2207 state->ev = ev;
2208 state->context = context;
2209 state->binding_handle = b;
2211 state->logon_level = logon_level;
2212 state->const_logon = logon;
2213 state->flags = flags;
2215 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2216 context->server.computer);
2217 if (tevent_req_nomem(state->srv_name_slash, req)) {
2218 return tevent_req_post(req, ev);
2221 switch (logon_level) {
2222 case NetlogonInteractiveInformation:
2223 case NetlogonInteractiveTransitiveInformation:
2224 case NetlogonServiceInformation:
2225 case NetlogonServiceTransitiveInformation:
2226 case NetlogonGenericInformation:
2227 state->user_encrypt = true;
2228 break;
2230 case NetlogonNetworkInformation:
2231 case NetlogonNetworkTransitiveInformation:
2232 break;
2235 state->validation = talloc_zero(state, union netr_Validation);
2236 if (tevent_req_nomem(state->validation, req)) {
2237 return tevent_req_post(req, ev);
2240 netlogon_creds_cli_LogonSamLogon_start(req);
2241 if (!tevent_req_is_in_progress(req)) {
2242 return tevent_req_post(req, ev);
2246 * we defer all callbacks in order to cleanup
2247 * the database record.
2249 tevent_req_defer_callback(req, state->ev);
2250 return req;
2253 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2254 NTSTATUS status)
2256 struct netlogon_creds_cli_LogonSamLogon_state *state =
2257 tevent_req_data(req,
2258 struct netlogon_creds_cli_LogonSamLogon_state);
2260 if (state->lk_creds == NULL) {
2261 return;
2264 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2266 * This is a hack to recover from a bug in old
2267 * Samba servers, when LogonSamLogonEx() fails:
2269 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2271 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2273 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2274 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2275 * If the sign/seal check fails.
2277 * In that case we need to cleanup the netlogon session.
2279 * It's the job of the caller to disconnect the current
2280 * connection, if netlogon_creds_cli_LogonSamLogon()
2281 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2283 if (!state->context->server.try_logon_with) {
2284 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2288 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2289 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2290 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2291 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2292 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2293 TALLOC_FREE(state->lk_creds);
2294 return;
2297 netlogon_creds_cli_delete(state->context, state->lk_creds);
2298 TALLOC_FREE(state->lk_creds);
2301 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2303 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2305 struct netlogon_creds_cli_LogonSamLogon_state *state =
2306 tevent_req_data(req,
2307 struct netlogon_creds_cli_LogonSamLogon_state);
2308 struct tevent_req *subreq;
2309 NTSTATUS status;
2310 enum dcerpc_AuthType auth_type;
2311 enum dcerpc_AuthLevel auth_level;
2313 TALLOC_FREE(state->ro_creds);
2314 TALLOC_FREE(state->logon);
2315 ZERO_STRUCTP(state->validation);
2317 dcerpc_binding_handle_auth_info(state->binding_handle,
2318 &auth_type, &auth_level);
2320 state->try_logon_ex = state->context->server.try_logon_ex;
2321 state->try_validation6 = state->context->server.try_validation6;
2323 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2324 state->try_logon_ex = false;
2327 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2328 state->try_validation6 = false;
2331 if (state->try_logon_ex) {
2332 if (state->try_validation6) {
2333 state->validation_level = 6;
2334 } else {
2335 state->validation_level = 3;
2336 state->user_encrypt = true;
2339 state->logon = netlogon_creds_shallow_copy_logon(state,
2340 state->logon_level,
2341 state->const_logon);
2342 if (tevent_req_nomem(state->logon, req)) {
2343 status = NT_STATUS_NO_MEMORY;
2344 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2345 return;
2348 if (state->user_encrypt) {
2349 status = netlogon_creds_cli_get(state->context,
2350 state,
2351 &state->ro_creds);
2352 if (!NT_STATUS_IS_OK(status)) {
2353 status = NT_STATUS_ACCESS_DENIED;
2354 tevent_req_nterror(req, status);
2355 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2356 return;
2359 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2360 state->logon_level,
2361 state->logon);
2364 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2365 state->binding_handle,
2366 state->srv_name_slash,
2367 state->context->client.computer,
2368 state->logon_level,
2369 state->logon,
2370 state->validation_level,
2371 state->validation,
2372 &state->authoritative,
2373 &state->flags);
2374 if (tevent_req_nomem(subreq, req)) {
2375 status = NT_STATUS_NO_MEMORY;
2376 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2377 return;
2379 tevent_req_set_callback(subreq,
2380 netlogon_creds_cli_LogonSamLogon_done,
2381 req);
2382 return;
2385 if (state->lk_creds == NULL) {
2386 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2387 state->context);
2388 if (tevent_req_nomem(subreq, req)) {
2389 status = NT_STATUS_NO_MEMORY;
2390 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2391 return;
2393 tevent_req_set_callback(subreq,
2394 netlogon_creds_cli_LogonSamLogon_done,
2395 req);
2396 return;
2399 state->tmp_creds = *state->lk_creds;
2400 netlogon_creds_client_authenticator(&state->tmp_creds,
2401 &state->req_auth);
2402 ZERO_STRUCT(state->rep_auth);
2404 state->logon = netlogon_creds_shallow_copy_logon(state,
2405 state->logon_level,
2406 state->const_logon);
2407 if (tevent_req_nomem(state->logon, req)) {
2408 status = NT_STATUS_NO_MEMORY;
2409 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2410 return;
2413 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2414 state->logon_level,
2415 state->logon);
2417 state->validation_level = 3;
2419 if (state->context->server.try_logon_with) {
2420 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2421 state->binding_handle,
2422 state->srv_name_slash,
2423 state->context->client.computer,
2424 &state->req_auth,
2425 &state->rep_auth,
2426 state->logon_level,
2427 state->logon,
2428 state->validation_level,
2429 state->validation,
2430 &state->authoritative,
2431 &state->flags);
2432 if (tevent_req_nomem(subreq, req)) {
2433 status = NT_STATUS_NO_MEMORY;
2434 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2435 return;
2437 } else {
2438 state->flags = 0;
2440 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2441 state->binding_handle,
2442 state->srv_name_slash,
2443 state->context->client.computer,
2444 &state->req_auth,
2445 &state->rep_auth,
2446 state->logon_level,
2447 state->logon,
2448 state->validation_level,
2449 state->validation,
2450 &state->authoritative);
2451 if (tevent_req_nomem(subreq, req)) {
2452 status = NT_STATUS_NO_MEMORY;
2453 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2454 return;
2458 tevent_req_set_callback(subreq,
2459 netlogon_creds_cli_LogonSamLogon_done,
2460 req);
2463 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2465 struct tevent_req *req =
2466 tevent_req_callback_data(subreq,
2467 struct tevent_req);
2468 struct netlogon_creds_cli_LogonSamLogon_state *state =
2469 tevent_req_data(req,
2470 struct netlogon_creds_cli_LogonSamLogon_state);
2471 NTSTATUS status;
2472 NTSTATUS result;
2473 bool ok;
2475 if (state->try_logon_ex) {
2476 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2477 state->validation,
2478 &result);
2479 TALLOC_FREE(subreq);
2480 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2481 state->context->server.try_validation6 = false;
2482 state->context->server.try_logon_ex = false;
2483 netlogon_creds_cli_LogonSamLogon_start(req);
2484 return;
2486 if (tevent_req_nterror(req, status)) {
2487 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2488 return;
2491 if ((state->validation_level == 6) &&
2492 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2493 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2494 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2496 state->context->server.try_validation6 = false;
2497 netlogon_creds_cli_LogonSamLogon_start(req);
2498 return;
2501 if (tevent_req_nterror(req, result)) {
2502 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2503 return;
2506 if (state->ro_creds == NULL) {
2507 tevent_req_done(req);
2508 return;
2511 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2512 if (!ok) {
2514 * We got a race, lets retry with on authenticator
2515 * protection.
2517 * netlogon_creds_cli_LogonSamLogon_start()
2518 * will TALLOC_FREE(state->ro_creds);
2520 state->try_logon_ex = false;
2521 netlogon_creds_cli_LogonSamLogon_start(req);
2522 return;
2525 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2526 state->validation_level,
2527 state->validation);
2529 tevent_req_done(req);
2530 return;
2533 if (state->lk_creds == NULL) {
2534 status = netlogon_creds_cli_lock_recv(subreq, state,
2535 &state->lk_creds);
2536 TALLOC_FREE(subreq);
2537 if (tevent_req_nterror(req, status)) {
2538 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2539 return;
2542 netlogon_creds_cli_LogonSamLogon_start(req);
2543 return;
2546 if (state->context->server.try_logon_with) {
2547 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2548 state->validation,
2549 &result);
2550 TALLOC_FREE(subreq);
2551 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2552 state->context->server.try_logon_with = false;
2553 netlogon_creds_cli_LogonSamLogon_start(req);
2554 return;
2556 if (tevent_req_nterror(req, status)) {
2557 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2558 return;
2560 } else {
2561 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2562 state->validation,
2563 &result);
2564 TALLOC_FREE(subreq);
2565 if (tevent_req_nterror(req, status)) {
2566 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2567 return;
2571 ok = netlogon_creds_client_check(&state->tmp_creds,
2572 &state->rep_auth.cred);
2573 if (!ok) {
2574 status = NT_STATUS_ACCESS_DENIED;
2575 tevent_req_nterror(req, status);
2576 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2577 return;
2580 *state->lk_creds = state->tmp_creds;
2581 status = netlogon_creds_cli_store(state->context,
2582 state->lk_creds);
2583 TALLOC_FREE(state->lk_creds);
2585 if (tevent_req_nterror(req, status)) {
2586 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2587 return;
2590 if (tevent_req_nterror(req, result)) {
2591 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2592 return;
2595 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2596 state->validation_level,
2597 state->validation);
2599 tevent_req_done(req);
2602 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2603 TALLOC_CTX *mem_ctx,
2604 uint16_t *validation_level,
2605 union netr_Validation **validation,
2606 uint8_t *authoritative,
2607 uint32_t *flags)
2609 struct netlogon_creds_cli_LogonSamLogon_state *state =
2610 tevent_req_data(req,
2611 struct netlogon_creds_cli_LogonSamLogon_state);
2612 NTSTATUS status;
2614 /* authoritative is also returned on error */
2615 *authoritative = state->authoritative;
2617 if (tevent_req_is_nterror(req, &status)) {
2618 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2619 tevent_req_received(req);
2620 return status;
2623 *validation_level = state->validation_level;
2624 *validation = talloc_move(mem_ctx, &state->validation);
2625 *flags = state->flags;
2627 tevent_req_received(req);
2628 return NT_STATUS_OK;
2631 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2632 struct netlogon_creds_cli_context *context,
2633 struct dcerpc_binding_handle *b,
2634 enum netr_LogonInfoClass logon_level,
2635 const union netr_LogonLevel *logon,
2636 TALLOC_CTX *mem_ctx,
2637 uint16_t *validation_level,
2638 union netr_Validation **validation,
2639 uint8_t *authoritative,
2640 uint32_t *flags)
2642 TALLOC_CTX *frame = talloc_stackframe();
2643 struct tevent_context *ev;
2644 struct tevent_req *req;
2645 NTSTATUS status = NT_STATUS_NO_MEMORY;
2647 ev = samba_tevent_context_init(frame);
2648 if (ev == NULL) {
2649 goto fail;
2651 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2652 logon_level, logon,
2653 *flags);
2654 if (req == NULL) {
2655 goto fail;
2657 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2658 goto fail;
2660 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2661 validation_level,
2662 validation,
2663 authoritative,
2664 flags);
2665 fail:
2666 TALLOC_FREE(frame);
2667 return status;
2670 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2671 struct tevent_context *ev;
2672 struct netlogon_creds_cli_context *context;
2673 struct dcerpc_binding_handle *binding_handle;
2675 char *srv_name_slash;
2676 enum dcerpc_AuthType auth_type;
2677 enum dcerpc_AuthLevel auth_level;
2679 const char *site_name;
2680 uint32_t dns_ttl;
2681 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2683 struct netlogon_creds_CredentialState *creds;
2684 struct netlogon_creds_CredentialState tmp_creds;
2685 struct netr_Authenticator req_auth;
2686 struct netr_Authenticator rep_auth;
2689 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2690 NTSTATUS status);
2691 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2693 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2694 struct tevent_context *ev,
2695 struct netlogon_creds_cli_context *context,
2696 struct dcerpc_binding_handle *b,
2697 const char *site_name,
2698 uint32_t dns_ttl,
2699 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2701 struct tevent_req *req;
2702 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2703 struct tevent_req *subreq;
2705 req = tevent_req_create(mem_ctx, &state,
2706 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2707 if (req == NULL) {
2708 return NULL;
2711 state->ev = ev;
2712 state->context = context;
2713 state->binding_handle = b;
2715 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2716 context->server.computer);
2717 if (tevent_req_nomem(state->srv_name_slash, req)) {
2718 return tevent_req_post(req, ev);
2721 state->site_name = site_name;
2722 state->dns_ttl = dns_ttl;
2723 state->dns_names = dns_names;
2725 dcerpc_binding_handle_auth_info(state->binding_handle,
2726 &state->auth_type,
2727 &state->auth_level);
2729 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2730 state->context);
2731 if (tevent_req_nomem(subreq, req)) {
2732 return tevent_req_post(req, ev);
2735 tevent_req_set_callback(subreq,
2736 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2737 req);
2739 return req;
2742 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2743 NTSTATUS status)
2745 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2746 tevent_req_data(req,
2747 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2749 if (state->creds == NULL) {
2750 return;
2753 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2754 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2755 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2756 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2757 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2758 TALLOC_FREE(state->creds);
2759 return;
2762 netlogon_creds_cli_delete(state->context, state->creds);
2763 TALLOC_FREE(state->creds);
2766 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2768 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2770 struct tevent_req *req =
2771 tevent_req_callback_data(subreq,
2772 struct tevent_req);
2773 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2774 tevent_req_data(req,
2775 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2776 NTSTATUS status;
2778 status = netlogon_creds_cli_lock_recv(subreq, state,
2779 &state->creds);
2780 TALLOC_FREE(subreq);
2781 if (tevent_req_nterror(req, status)) {
2782 return;
2785 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2786 switch (state->auth_level) {
2787 case DCERPC_AUTH_LEVEL_INTEGRITY:
2788 case DCERPC_AUTH_LEVEL_PRIVACY:
2789 break;
2790 default:
2791 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2792 return;
2794 } else {
2795 uint32_t tmp = state->creds->negotiate_flags;
2797 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2799 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2800 * it should be used, which means
2801 * we had a chance to verify no downgrade
2802 * happened.
2804 * This relies on netlogon_creds_cli_check*
2805 * being called before, as first request after
2806 * the DCERPC bind.
2808 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2809 return;
2814 * we defer all callbacks in order to cleanup
2815 * the database record.
2817 tevent_req_defer_callback(req, state->ev);
2819 state->tmp_creds = *state->creds;
2820 netlogon_creds_client_authenticator(&state->tmp_creds,
2821 &state->req_auth);
2822 ZERO_STRUCT(state->rep_auth);
2824 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2825 state->binding_handle,
2826 state->srv_name_slash,
2827 state->tmp_creds.computer_name,
2828 &state->req_auth,
2829 &state->rep_auth,
2830 state->site_name,
2831 state->dns_ttl,
2832 state->dns_names);
2833 if (tevent_req_nomem(subreq, req)) {
2834 status = NT_STATUS_NO_MEMORY;
2835 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2836 return;
2839 tevent_req_set_callback(subreq,
2840 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2841 req);
2844 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2846 struct tevent_req *req =
2847 tevent_req_callback_data(subreq,
2848 struct tevent_req);
2849 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2850 tevent_req_data(req,
2851 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2852 NTSTATUS status;
2853 NTSTATUS result;
2854 bool ok;
2857 * We use state->dns_names as the memory context, as this is
2858 * the only in/out variable and it has been overwritten by the
2859 * out parameter from the server.
2861 * We need to preserve the return value until the caller can use it.
2863 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2864 &result);
2865 TALLOC_FREE(subreq);
2866 if (tevent_req_nterror(req, status)) {
2867 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2868 return;
2871 ok = netlogon_creds_client_check(&state->tmp_creds,
2872 &state->rep_auth.cred);
2873 if (!ok) {
2874 status = NT_STATUS_ACCESS_DENIED;
2875 tevent_req_nterror(req, status);
2876 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2877 return;
2880 *state->creds = state->tmp_creds;
2881 status = netlogon_creds_cli_store(state->context,
2882 state->creds);
2883 TALLOC_FREE(state->creds);
2885 if (tevent_req_nterror(req, status)) {
2886 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2887 return;
2890 if (tevent_req_nterror(req, result)) {
2891 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2892 return;
2895 tevent_req_done(req);
2898 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2900 NTSTATUS status;
2902 if (tevent_req_is_nterror(req, &status)) {
2903 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2904 tevent_req_received(req);
2905 return status;
2908 tevent_req_received(req);
2909 return NT_STATUS_OK;
2912 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2913 struct netlogon_creds_cli_context *context,
2914 struct dcerpc_binding_handle *b,
2915 const char *site_name,
2916 uint32_t dns_ttl,
2917 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2919 TALLOC_CTX *frame = talloc_stackframe();
2920 struct tevent_context *ev;
2921 struct tevent_req *req;
2922 NTSTATUS status = NT_STATUS_NO_MEMORY;
2924 ev = samba_tevent_context_init(frame);
2925 if (ev == NULL) {
2926 goto fail;
2928 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2929 site_name,
2930 dns_ttl,
2931 dns_names);
2932 if (req == NULL) {
2933 goto fail;
2935 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2936 goto fail;
2938 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2939 fail:
2940 TALLOC_FREE(frame);
2941 return status;
2944 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2945 struct tevent_context *ev;
2946 struct netlogon_creds_cli_context *context;
2947 struct dcerpc_binding_handle *binding_handle;
2949 char *srv_name_slash;
2950 enum dcerpc_AuthType auth_type;
2951 enum dcerpc_AuthLevel auth_level;
2953 struct samr_Password new_owf_password;
2954 struct samr_Password old_owf_password;
2955 struct netr_TrustInfo *trust_info;
2957 struct netlogon_creds_CredentialState *creds;
2958 struct netlogon_creds_CredentialState tmp_creds;
2959 struct netr_Authenticator req_auth;
2960 struct netr_Authenticator rep_auth;
2963 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2964 NTSTATUS status);
2965 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2967 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2968 struct tevent_context *ev,
2969 struct netlogon_creds_cli_context *context,
2970 struct dcerpc_binding_handle *b)
2972 struct tevent_req *req;
2973 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2974 struct tevent_req *subreq;
2976 req = tevent_req_create(mem_ctx, &state,
2977 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2978 if (req == NULL) {
2979 return NULL;
2982 state->ev = ev;
2983 state->context = context;
2984 state->binding_handle = b;
2986 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2987 context->server.computer);
2988 if (tevent_req_nomem(state->srv_name_slash, req)) {
2989 return tevent_req_post(req, ev);
2992 dcerpc_binding_handle_auth_info(state->binding_handle,
2993 &state->auth_type,
2994 &state->auth_level);
2996 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2997 state->context);
2998 if (tevent_req_nomem(subreq, req)) {
2999 return tevent_req_post(req, ev);
3002 tevent_req_set_callback(subreq,
3003 netlogon_creds_cli_ServerGetTrustInfo_locked,
3004 req);
3006 return req;
3009 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3010 NTSTATUS status)
3012 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3013 tevent_req_data(req,
3014 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3016 if (state->creds == NULL) {
3017 return;
3020 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3021 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3022 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3023 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3024 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3025 TALLOC_FREE(state->creds);
3026 return;
3029 netlogon_creds_cli_delete(state->context, state->creds);
3030 TALLOC_FREE(state->creds);
3033 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3035 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3037 struct tevent_req *req =
3038 tevent_req_callback_data(subreq,
3039 struct tevent_req);
3040 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3041 tevent_req_data(req,
3042 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3043 NTSTATUS status;
3045 status = netlogon_creds_cli_lock_recv(subreq, state,
3046 &state->creds);
3047 TALLOC_FREE(subreq);
3048 if (tevent_req_nterror(req, status)) {
3049 return;
3052 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3053 switch (state->auth_level) {
3054 case DCERPC_AUTH_LEVEL_PRIVACY:
3055 break;
3056 default:
3057 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3058 return;
3060 } else {
3061 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3062 return;
3066 * we defer all callbacks in order to cleanup
3067 * the database record.
3069 tevent_req_defer_callback(req, state->ev);
3071 state->tmp_creds = *state->creds;
3072 netlogon_creds_client_authenticator(&state->tmp_creds,
3073 &state->req_auth);
3074 ZERO_STRUCT(state->rep_auth);
3076 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3077 state->binding_handle,
3078 state->srv_name_slash,
3079 state->tmp_creds.account_name,
3080 state->tmp_creds.secure_channel_type,
3081 state->tmp_creds.computer_name,
3082 &state->req_auth,
3083 &state->rep_auth,
3084 &state->new_owf_password,
3085 &state->old_owf_password,
3086 &state->trust_info);
3087 if (tevent_req_nomem(subreq, req)) {
3088 status = NT_STATUS_NO_MEMORY;
3089 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3090 return;
3093 tevent_req_set_callback(subreq,
3094 netlogon_creds_cli_ServerGetTrustInfo_done,
3095 req);
3098 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3100 struct tevent_req *req =
3101 tevent_req_callback_data(subreq,
3102 struct tevent_req);
3103 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3104 tevent_req_data(req,
3105 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3106 NTSTATUS status;
3107 NTSTATUS result;
3108 const struct samr_Password zero = {};
3109 int cmp;
3110 bool ok;
3113 * We use state->dns_names as the memory context, as this is
3114 * the only in/out variable and it has been overwritten by the
3115 * out parameter from the server.
3117 * We need to preserve the return value until the caller can use it.
3119 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3120 TALLOC_FREE(subreq);
3121 if (tevent_req_nterror(req, status)) {
3122 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3123 return;
3126 ok = netlogon_creds_client_check(&state->tmp_creds,
3127 &state->rep_auth.cred);
3128 if (!ok) {
3129 status = NT_STATUS_ACCESS_DENIED;
3130 tevent_req_nterror(req, status);
3131 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3132 return;
3135 cmp = memcmp(state->new_owf_password.hash,
3136 zero.hash, sizeof(zero.hash));
3137 if (cmp != 0) {
3138 netlogon_creds_des_decrypt(&state->tmp_creds,
3139 &state->new_owf_password);
3141 cmp = memcmp(state->old_owf_password.hash,
3142 zero.hash, sizeof(zero.hash));
3143 if (cmp != 0) {
3144 netlogon_creds_des_decrypt(&state->tmp_creds,
3145 &state->old_owf_password);
3148 *state->creds = state->tmp_creds;
3149 status = netlogon_creds_cli_store(state->context,
3150 state->creds);
3151 TALLOC_FREE(state->creds);
3152 if (tevent_req_nterror(req, status)) {
3153 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3154 return;
3157 if (tevent_req_nterror(req, result)) {
3158 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3159 return;
3162 tevent_req_done(req);
3165 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3166 TALLOC_CTX *mem_ctx,
3167 struct samr_Password *new_owf_password,
3168 struct samr_Password *old_owf_password,
3169 struct netr_TrustInfo **trust_info)
3171 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3172 tevent_req_data(req,
3173 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3174 NTSTATUS status;
3176 if (tevent_req_is_nterror(req, &status)) {
3177 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3178 tevent_req_received(req);
3179 return status;
3182 if (new_owf_password != NULL) {
3183 *new_owf_password = state->new_owf_password;
3185 if (old_owf_password != NULL) {
3186 *old_owf_password = state->old_owf_password;
3188 if (trust_info != NULL) {
3189 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3192 tevent_req_received(req);
3193 return NT_STATUS_OK;
3196 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3197 struct netlogon_creds_cli_context *context,
3198 struct dcerpc_binding_handle *b,
3199 TALLOC_CTX *mem_ctx,
3200 struct samr_Password *new_owf_password,
3201 struct samr_Password *old_owf_password,
3202 struct netr_TrustInfo **trust_info)
3204 TALLOC_CTX *frame = talloc_stackframe();
3205 struct tevent_context *ev;
3206 struct tevent_req *req;
3207 NTSTATUS status = NT_STATUS_NO_MEMORY;
3209 ev = samba_tevent_context_init(frame);
3210 if (ev == NULL) {
3211 goto fail;
3213 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3214 if (req == NULL) {
3215 goto fail;
3217 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3218 goto fail;
3220 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3221 mem_ctx,
3222 new_owf_password,
3223 old_owf_password,
3224 trust_info);
3225 fail:
3226 TALLOC_FREE(frame);
3227 return status;
3230 struct netlogon_creds_cli_GetForestTrustInformation_state {
3231 struct tevent_context *ev;
3232 struct netlogon_creds_cli_context *context;
3233 struct dcerpc_binding_handle *binding_handle;
3235 char *srv_name_slash;
3236 enum dcerpc_AuthType auth_type;
3237 enum dcerpc_AuthLevel auth_level;
3239 uint32_t flags;
3240 struct lsa_ForestTrustInformation *forest_trust_info;
3242 struct netlogon_creds_CredentialState *creds;
3243 struct netlogon_creds_CredentialState tmp_creds;
3244 struct netr_Authenticator req_auth;
3245 struct netr_Authenticator rep_auth;
3248 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3249 NTSTATUS status);
3250 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3252 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3253 struct tevent_context *ev,
3254 struct netlogon_creds_cli_context *context,
3255 struct dcerpc_binding_handle *b)
3257 struct tevent_req *req;
3258 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3259 struct tevent_req *subreq;
3261 req = tevent_req_create(mem_ctx, &state,
3262 struct netlogon_creds_cli_GetForestTrustInformation_state);
3263 if (req == NULL) {
3264 return NULL;
3267 state->ev = ev;
3268 state->context = context;
3269 state->binding_handle = b;
3271 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3272 context->server.computer);
3273 if (tevent_req_nomem(state->srv_name_slash, req)) {
3274 return tevent_req_post(req, ev);
3277 state->flags = 0;
3279 dcerpc_binding_handle_auth_info(state->binding_handle,
3280 &state->auth_type,
3281 &state->auth_level);
3283 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3284 state->context);
3285 if (tevent_req_nomem(subreq, req)) {
3286 return tevent_req_post(req, ev);
3289 tevent_req_set_callback(subreq,
3290 netlogon_creds_cli_GetForestTrustInformation_locked,
3291 req);
3293 return req;
3296 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3297 NTSTATUS status)
3299 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3300 tevent_req_data(req,
3301 struct netlogon_creds_cli_GetForestTrustInformation_state);
3303 if (state->creds == NULL) {
3304 return;
3307 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3308 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3309 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3310 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3311 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3312 TALLOC_FREE(state->creds);
3313 return;
3316 netlogon_creds_cli_delete(state->context, state->creds);
3317 TALLOC_FREE(state->creds);
3320 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3322 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3324 struct tevent_req *req =
3325 tevent_req_callback_data(subreq,
3326 struct tevent_req);
3327 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3328 tevent_req_data(req,
3329 struct netlogon_creds_cli_GetForestTrustInformation_state);
3330 NTSTATUS status;
3332 status = netlogon_creds_cli_lock_recv(subreq, state,
3333 &state->creds);
3334 TALLOC_FREE(subreq);
3335 if (tevent_req_nterror(req, status)) {
3336 return;
3339 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3340 switch (state->auth_level) {
3341 case DCERPC_AUTH_LEVEL_INTEGRITY:
3342 case DCERPC_AUTH_LEVEL_PRIVACY:
3343 break;
3344 default:
3345 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3346 return;
3348 } else {
3349 uint32_t tmp = state->creds->negotiate_flags;
3351 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3353 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3354 * it should be used, which means
3355 * we had a chance to verify no downgrade
3356 * happened.
3358 * This relies on netlogon_creds_cli_check*
3359 * being called before, as first request after
3360 * the DCERPC bind.
3362 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3363 return;
3368 * we defer all callbacks in order to cleanup
3369 * the database record.
3371 tevent_req_defer_callback(req, state->ev);
3373 state->tmp_creds = *state->creds;
3374 netlogon_creds_client_authenticator(&state->tmp_creds,
3375 &state->req_auth);
3376 ZERO_STRUCT(state->rep_auth);
3378 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3379 state->binding_handle,
3380 state->srv_name_slash,
3381 state->tmp_creds.computer_name,
3382 &state->req_auth,
3383 &state->rep_auth,
3384 state->flags,
3385 &state->forest_trust_info);
3386 if (tevent_req_nomem(subreq, req)) {
3387 status = NT_STATUS_NO_MEMORY;
3388 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3389 return;
3392 tevent_req_set_callback(subreq,
3393 netlogon_creds_cli_GetForestTrustInformation_done,
3394 req);
3397 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3399 struct tevent_req *req =
3400 tevent_req_callback_data(subreq,
3401 struct tevent_req);
3402 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3403 tevent_req_data(req,
3404 struct netlogon_creds_cli_GetForestTrustInformation_state);
3405 NTSTATUS status;
3406 NTSTATUS result;
3407 bool ok;
3410 * We use state->dns_names as the memory context, as this is
3411 * the only in/out variable and it has been overwritten by the
3412 * out parameter from the server.
3414 * We need to preserve the return value until the caller can use it.
3416 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3417 TALLOC_FREE(subreq);
3418 if (tevent_req_nterror(req, status)) {
3419 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3420 return;
3423 ok = netlogon_creds_client_check(&state->tmp_creds,
3424 &state->rep_auth.cred);
3425 if (!ok) {
3426 status = NT_STATUS_ACCESS_DENIED;
3427 tevent_req_nterror(req, status);
3428 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3429 return;
3432 *state->creds = state->tmp_creds;
3433 status = netlogon_creds_cli_store(state->context,
3434 state->creds);
3435 TALLOC_FREE(state->creds);
3437 if (tevent_req_nterror(req, status)) {
3438 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3439 return;
3442 if (tevent_req_nterror(req, result)) {
3443 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3444 return;
3447 tevent_req_done(req);
3450 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3451 TALLOC_CTX *mem_ctx,
3452 struct lsa_ForestTrustInformation **forest_trust_info)
3454 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3455 tevent_req_data(req,
3456 struct netlogon_creds_cli_GetForestTrustInformation_state);
3457 NTSTATUS status;
3459 if (tevent_req_is_nterror(req, &status)) {
3460 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3461 tevent_req_received(req);
3462 return status;
3465 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3467 tevent_req_received(req);
3468 return NT_STATUS_OK;
3471 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3472 struct netlogon_creds_cli_context *context,
3473 struct dcerpc_binding_handle *b,
3474 TALLOC_CTX *mem_ctx,
3475 struct lsa_ForestTrustInformation **forest_trust_info)
3477 TALLOC_CTX *frame = talloc_stackframe();
3478 struct tevent_context *ev;
3479 struct tevent_req *req;
3480 NTSTATUS status = NT_STATUS_NO_MEMORY;
3482 ev = samba_tevent_context_init(frame);
3483 if (ev == NULL) {
3484 goto fail;
3486 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3487 if (req == NULL) {
3488 goto fail;
3490 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3491 goto fail;
3493 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3494 mem_ctx,
3495 forest_trust_info);
3496 fail:
3497 TALLOC_FREE(frame);
3498 return status;
3501 struct netlogon_creds_cli_SendToSam_state {
3502 struct tevent_context *ev;
3503 struct netlogon_creds_cli_context *context;
3504 struct dcerpc_binding_handle *binding_handle;
3506 char *srv_name_slash;
3507 enum dcerpc_AuthType auth_type;
3508 enum dcerpc_AuthLevel auth_level;
3510 DATA_BLOB opaque;
3512 struct netlogon_creds_CredentialState *creds;
3513 struct netlogon_creds_CredentialState tmp_creds;
3514 struct netr_Authenticator req_auth;
3515 struct netr_Authenticator rep_auth;
3518 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3519 NTSTATUS status);
3520 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3522 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3523 struct tevent_context *ev,
3524 struct netlogon_creds_cli_context *context,
3525 struct dcerpc_binding_handle *b,
3526 struct netr_SendToSamBase *message)
3528 struct tevent_req *req;
3529 struct netlogon_creds_cli_SendToSam_state *state;
3530 struct tevent_req *subreq;
3531 enum ndr_err_code ndr_err;
3533 req = tevent_req_create(mem_ctx, &state,
3534 struct netlogon_creds_cli_SendToSam_state);
3535 if (req == NULL) {
3536 return NULL;
3539 state->ev = ev;
3540 state->context = context;
3541 state->binding_handle = b;
3543 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3544 context->server.computer);
3545 if (tevent_req_nomem(state->srv_name_slash, req)) {
3546 return tevent_req_post(req, ev);
3549 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3550 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3551 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3552 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3553 tevent_req_nterror(req, status);
3554 return tevent_req_post(req, ev);
3557 dcerpc_binding_handle_auth_info(state->binding_handle,
3558 &state->auth_type,
3559 &state->auth_level);
3561 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3562 state->context);
3563 if (tevent_req_nomem(subreq, req)) {
3564 return tevent_req_post(req, ev);
3567 tevent_req_set_callback(subreq,
3568 netlogon_creds_cli_SendToSam_locked,
3569 req);
3571 return req;
3574 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3575 NTSTATUS status)
3577 struct netlogon_creds_cli_SendToSam_state *state =
3578 tevent_req_data(req,
3579 struct netlogon_creds_cli_SendToSam_state);
3581 if (state->creds == NULL) {
3582 return;
3585 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3586 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3587 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3588 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3589 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3590 TALLOC_FREE(state->creds);
3591 return;
3594 netlogon_creds_cli_delete(state->context, state->creds);
3595 TALLOC_FREE(state->creds);
3598 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3600 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3602 struct tevent_req *req =
3603 tevent_req_callback_data(subreq,
3604 struct tevent_req);
3605 struct netlogon_creds_cli_SendToSam_state *state =
3606 tevent_req_data(req,
3607 struct netlogon_creds_cli_SendToSam_state);
3608 NTSTATUS status;
3610 status = netlogon_creds_cli_lock_recv(subreq, state,
3611 &state->creds);
3612 TALLOC_FREE(subreq);
3613 if (tevent_req_nterror(req, status)) {
3614 return;
3617 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3618 switch (state->auth_level) {
3619 case DCERPC_AUTH_LEVEL_INTEGRITY:
3620 case DCERPC_AUTH_LEVEL_PRIVACY:
3621 break;
3622 default:
3623 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3624 return;
3626 } else {
3627 uint32_t tmp = state->creds->negotiate_flags;
3629 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3631 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3632 * it should be used, which means
3633 * we had a chance to verify no downgrade
3634 * happened.
3636 * This relies on netlogon_creds_cli_check*
3637 * being called before, as first request after
3638 * the DCERPC bind.
3640 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3641 return;
3646 * we defer all callbacks in order to cleanup
3647 * the database record.
3649 tevent_req_defer_callback(req, state->ev);
3651 state->tmp_creds = *state->creds;
3652 netlogon_creds_client_authenticator(&state->tmp_creds,
3653 &state->req_auth);
3654 ZERO_STRUCT(state->rep_auth);
3656 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3657 netlogon_creds_aes_encrypt(&state->tmp_creds,
3658 state->opaque.data,
3659 state->opaque.length);
3660 } else {
3661 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3662 state->opaque.data,
3663 state->opaque.length);
3666 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3667 state->binding_handle,
3668 state->srv_name_slash,
3669 state->tmp_creds.computer_name,
3670 &state->req_auth,
3671 &state->rep_auth,
3672 state->opaque.data,
3673 state->opaque.length);
3674 if (tevent_req_nomem(subreq, req)) {
3675 status = NT_STATUS_NO_MEMORY;
3676 netlogon_creds_cli_SendToSam_cleanup(req, status);
3677 return;
3680 tevent_req_set_callback(subreq,
3681 netlogon_creds_cli_SendToSam_done,
3682 req);
3685 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3687 struct tevent_req *req =
3688 tevent_req_callback_data(subreq,
3689 struct tevent_req);
3690 struct netlogon_creds_cli_SendToSam_state *state =
3691 tevent_req_data(req,
3692 struct netlogon_creds_cli_SendToSam_state);
3693 NTSTATUS status;
3694 NTSTATUS result;
3695 bool ok;
3697 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3698 TALLOC_FREE(subreq);
3699 if (tevent_req_nterror(req, status)) {
3700 netlogon_creds_cli_SendToSam_cleanup(req, status);
3701 return;
3704 ok = netlogon_creds_client_check(&state->tmp_creds,
3705 &state->rep_auth.cred);
3706 if (!ok) {
3707 status = NT_STATUS_ACCESS_DENIED;
3708 tevent_req_nterror(req, status);
3709 netlogon_creds_cli_SendToSam_cleanup(req, status);
3710 return;
3713 *state->creds = state->tmp_creds;
3714 status = netlogon_creds_cli_store(state->context,
3715 state->creds);
3716 TALLOC_FREE(state->creds);
3718 if (tevent_req_nterror(req, status)) {
3719 netlogon_creds_cli_SendToSam_cleanup(req, status);
3720 return;
3724 * Creds must be stored before we send back application errors
3725 * e.g. NT_STATUS_NOT_IMPLEMENTED
3727 if (tevent_req_nterror(req, result)) {
3728 netlogon_creds_cli_SendToSam_cleanup(req, result);
3729 return;
3732 tevent_req_done(req);
3735 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3736 struct dcerpc_binding_handle *b,
3737 struct netr_SendToSamBase *message)
3739 TALLOC_CTX *frame = talloc_stackframe();
3740 struct tevent_context *ev;
3741 struct tevent_req *req;
3742 NTSTATUS status = NT_STATUS_OK;
3744 ev = samba_tevent_context_init(frame);
3745 if (ev == NULL) {
3746 goto fail;
3748 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3749 if (req == NULL) {
3750 goto fail;
3752 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3753 goto fail;
3756 /* Ignore the result */
3757 fail:
3758 TALLOC_FREE(frame);
3759 return status;