s3/torture/pdbtest: delete trusted domain at test end
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blobcb3d6a9eeb4a8a6fa56602a138ddccd7e05e34b7
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 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 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 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, ctx->db.key_name);
1018 if (!NT_STATUS_IS_OK(status)) {
1019 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1020 smb_panic("g_lock_unlock failed");
1022 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1023 return 0;
1026 NTSTATUS netlogon_creds_cli_lck_recv(
1027 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1028 struct netlogon_creds_cli_lck **lck)
1030 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1031 req, struct netlogon_creds_cli_lck_state);
1032 NTSTATUS status;
1034 if (tevent_req_is_nterror(req, &status)) {
1035 return status;
1037 *lck = talloc_move(mem_ctx, &state->lck);
1038 return NT_STATUS_OK;
1041 NTSTATUS netlogon_creds_cli_lck(
1042 struct netlogon_creds_cli_context *context,
1043 enum netlogon_creds_cli_lck_type type,
1044 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1046 TALLOC_CTX *frame = talloc_stackframe();
1047 struct tevent_context *ev;
1048 struct tevent_req *req;
1049 NTSTATUS status = NT_STATUS_NO_MEMORY;
1051 ev = samba_tevent_context_init(frame);
1052 if (ev == NULL) {
1053 goto fail;
1055 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1056 if (req == NULL) {
1057 goto fail;
1059 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1060 goto fail;
1062 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1063 fail:
1064 TALLOC_FREE(frame);
1065 return status;
1068 struct netlogon_creds_cli_auth_state {
1069 struct tevent_context *ev;
1070 struct netlogon_creds_cli_context *context;
1071 struct dcerpc_binding_handle *binding_handle;
1072 uint8_t num_nt_hashes;
1073 uint8_t idx_nt_hashes;
1074 const struct samr_Password * const *nt_hashes;
1075 const struct samr_Password *used_nt_hash;
1076 char *srv_name_slash;
1077 uint32_t current_flags;
1078 struct netr_Credential client_challenge;
1079 struct netr_Credential server_challenge;
1080 struct netlogon_creds_CredentialState *creds;
1081 struct netr_Credential client_credential;
1082 struct netr_Credential server_credential;
1083 uint32_t rid;
1084 bool try_auth3;
1085 bool try_auth2;
1086 bool require_auth2;
1089 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1091 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1092 struct tevent_context *ev,
1093 struct netlogon_creds_cli_context *context,
1094 struct dcerpc_binding_handle *b,
1095 uint8_t num_nt_hashes,
1096 const struct samr_Password * const *nt_hashes)
1098 struct tevent_req *req;
1099 struct netlogon_creds_cli_auth_state *state;
1100 NTSTATUS status;
1102 req = tevent_req_create(mem_ctx, &state,
1103 struct netlogon_creds_cli_auth_state);
1104 if (req == NULL) {
1105 return NULL;
1108 state->ev = ev;
1109 state->context = context;
1110 state->binding_handle = b;
1111 if (num_nt_hashes < 1) {
1112 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1113 return tevent_req_post(req, ev);
1115 if (num_nt_hashes > 4) {
1116 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1117 return tevent_req_post(req, ev);
1120 state->num_nt_hashes = num_nt_hashes;
1121 state->idx_nt_hashes = 0;
1122 state->nt_hashes = nt_hashes;
1124 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1125 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1126 return tevent_req_post(req, ev);
1129 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1130 context->server.computer);
1131 if (tevent_req_nomem(state->srv_name_slash, req)) {
1132 return tevent_req_post(req, ev);
1135 state->try_auth3 = true;
1136 state->try_auth2 = true;
1138 if (context->client.required_flags != 0) {
1139 state->require_auth2 = true;
1142 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1143 state->current_flags = context->client.proposed_flags;
1145 status = dbwrap_purge(state->context->db.ctx,
1146 state->context->db.key_data);
1147 if (tevent_req_nterror(req, status)) {
1148 return tevent_req_post(req, ev);
1151 netlogon_creds_cli_auth_challenge_start(req);
1152 if (!tevent_req_is_in_progress(req)) {
1153 return tevent_req_post(req, ev);
1156 return req;
1159 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1161 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1163 struct netlogon_creds_cli_auth_state *state =
1164 tevent_req_data(req,
1165 struct netlogon_creds_cli_auth_state);
1166 struct tevent_req *subreq;
1168 TALLOC_FREE(state->creds);
1170 generate_random_buffer(state->client_challenge.data,
1171 sizeof(state->client_challenge.data));
1173 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1174 state->binding_handle,
1175 state->srv_name_slash,
1176 state->context->client.computer,
1177 &state->client_challenge,
1178 &state->server_challenge);
1179 if (tevent_req_nomem(subreq, req)) {
1180 return;
1182 tevent_req_set_callback(subreq,
1183 netlogon_creds_cli_auth_challenge_done,
1184 req);
1187 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1189 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1191 struct tevent_req *req =
1192 tevent_req_callback_data(subreq,
1193 struct tevent_req);
1194 struct netlogon_creds_cli_auth_state *state =
1195 tevent_req_data(req,
1196 struct netlogon_creds_cli_auth_state);
1197 NTSTATUS status;
1198 NTSTATUS result;
1200 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1201 TALLOC_FREE(subreq);
1202 if (tevent_req_nterror(req, status)) {
1203 return;
1205 if (tevent_req_nterror(req, result)) {
1206 return;
1209 if (!state->try_auth3 && !state->try_auth2) {
1210 state->current_flags = 0;
1213 /* Calculate the session key and client credentials */
1215 state->creds = netlogon_creds_client_init(state,
1216 state->context->client.account,
1217 state->context->client.computer,
1218 state->context->client.type,
1219 &state->client_challenge,
1220 &state->server_challenge,
1221 state->used_nt_hash,
1222 &state->client_credential,
1223 state->current_flags);
1224 if (tevent_req_nomem(state->creds, req)) {
1225 return;
1228 if (state->try_auth3) {
1229 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1230 state->binding_handle,
1231 state->srv_name_slash,
1232 state->context->client.account,
1233 state->context->client.type,
1234 state->context->client.computer,
1235 &state->client_credential,
1236 &state->server_credential,
1237 &state->creds->negotiate_flags,
1238 &state->rid);
1239 if (tevent_req_nomem(subreq, req)) {
1240 return;
1242 } else if (state->try_auth2) {
1243 state->rid = 0;
1245 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1246 state->binding_handle,
1247 state->srv_name_slash,
1248 state->context->client.account,
1249 state->context->client.type,
1250 state->context->client.computer,
1251 &state->client_credential,
1252 &state->server_credential,
1253 &state->creds->negotiate_flags);
1254 if (tevent_req_nomem(subreq, req)) {
1255 return;
1257 } else {
1258 state->rid = 0;
1260 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1261 state->binding_handle,
1262 state->srv_name_slash,
1263 state->context->client.account,
1264 state->context->client.type,
1265 state->context->client.computer,
1266 &state->client_credential,
1267 &state->server_credential);
1268 if (tevent_req_nomem(subreq, req)) {
1269 return;
1272 tevent_req_set_callback(subreq,
1273 netlogon_creds_cli_auth_srvauth_done,
1274 req);
1277 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1279 struct tevent_req *req =
1280 tevent_req_callback_data(subreq,
1281 struct tevent_req);
1282 struct netlogon_creds_cli_auth_state *state =
1283 tevent_req_data(req,
1284 struct netlogon_creds_cli_auth_state);
1285 NTSTATUS status;
1286 NTSTATUS result;
1287 bool ok;
1288 enum ndr_err_code ndr_err;
1289 DATA_BLOB blob;
1290 TDB_DATA data;
1291 uint32_t tmp_flags;
1293 if (state->try_auth3) {
1294 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1295 &result);
1296 TALLOC_FREE(subreq);
1297 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1298 state->try_auth3 = false;
1299 netlogon_creds_cli_auth_challenge_start(req);
1300 return;
1302 if (tevent_req_nterror(req, status)) {
1303 return;
1305 } else if (state->try_auth2) {
1306 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1307 &result);
1308 TALLOC_FREE(subreq);
1309 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1310 state->try_auth2 = false;
1311 if (state->require_auth2) {
1312 status = NT_STATUS_DOWNGRADE_DETECTED;
1313 tevent_req_nterror(req, status);
1314 return;
1316 netlogon_creds_cli_auth_challenge_start(req);
1317 return;
1319 if (tevent_req_nterror(req, status)) {
1320 return;
1322 } else {
1323 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1324 &result);
1325 TALLOC_FREE(subreq);
1326 if (tevent_req_nterror(req, status)) {
1327 return;
1331 if (!NT_STATUS_IS_OK(result) &&
1332 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1334 tevent_req_nterror(req, result);
1335 return;
1338 tmp_flags = state->creds->negotiate_flags;
1339 tmp_flags &= state->context->client.required_flags;
1340 if (tmp_flags != state->context->client.required_flags) {
1341 if (NT_STATUS_IS_OK(result)) {
1342 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1343 return;
1345 tevent_req_nterror(req, result);
1346 return;
1349 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1351 tmp_flags = state->context->client.proposed_flags;
1352 if ((state->current_flags == tmp_flags) &&
1353 (state->creds->negotiate_flags != tmp_flags))
1356 * lets retry with the negotiated flags
1358 state->current_flags = state->creds->negotiate_flags;
1359 netlogon_creds_cli_auth_challenge_start(req);
1360 return;
1363 state->idx_nt_hashes += 1;
1364 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1366 * we already retried, giving up...
1368 tevent_req_nterror(req, result);
1369 return;
1373 * lets retry with the old nt hash.
1375 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1376 state->current_flags = state->context->client.proposed_flags;
1377 netlogon_creds_cli_auth_challenge_start(req);
1378 return;
1381 ok = netlogon_creds_client_check(state->creds,
1382 &state->server_credential);
1383 if (!ok) {
1384 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1385 return;
1388 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1389 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1390 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1391 status = ndr_map_error2ntstatus(ndr_err);
1392 tevent_req_nterror(req, status);
1393 return;
1396 data.dptr = blob.data;
1397 data.dsize = blob.length;
1399 status = dbwrap_store(state->context->db.ctx,
1400 state->context->db.key_data,
1401 data, TDB_REPLACE);
1402 if (tevent_req_nterror(req, status)) {
1403 return;
1406 tevent_req_done(req);
1409 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1410 uint8_t *idx_nt_hashes)
1412 struct netlogon_creds_cli_auth_state *state =
1413 tevent_req_data(req,
1414 struct netlogon_creds_cli_auth_state);
1415 NTSTATUS status;
1417 *idx_nt_hashes = 0;
1419 if (tevent_req_is_nterror(req, &status)) {
1420 tevent_req_received(req);
1421 return status;
1424 *idx_nt_hashes = state->idx_nt_hashes;
1425 tevent_req_received(req);
1426 return NT_STATUS_OK;
1429 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1430 struct dcerpc_binding_handle *b,
1431 uint8_t num_nt_hashes,
1432 const struct samr_Password * const *nt_hashes,
1433 uint8_t *idx_nt_hashes)
1435 TALLOC_CTX *frame = talloc_stackframe();
1436 struct tevent_context *ev;
1437 struct tevent_req *req;
1438 NTSTATUS status = NT_STATUS_NO_MEMORY;
1440 *idx_nt_hashes = 0;
1442 ev = samba_tevent_context_init(frame);
1443 if (ev == NULL) {
1444 goto fail;
1446 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1447 num_nt_hashes, nt_hashes);
1448 if (req == NULL) {
1449 goto fail;
1451 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1452 goto fail;
1454 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1455 fail:
1456 TALLOC_FREE(frame);
1457 return status;
1460 struct netlogon_creds_cli_check_state {
1461 struct tevent_context *ev;
1462 struct netlogon_creds_cli_context *context;
1463 struct dcerpc_binding_handle *binding_handle;
1465 char *srv_name_slash;
1467 union netr_Capabilities caps;
1469 struct netlogon_creds_CredentialState *creds;
1470 struct netr_Authenticator req_auth;
1471 struct netr_Authenticator rep_auth;
1474 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1475 NTSTATUS status);
1476 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1478 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1479 struct tevent_context *ev,
1480 struct netlogon_creds_cli_context *context,
1481 struct dcerpc_binding_handle *b)
1483 struct tevent_req *req;
1484 struct netlogon_creds_cli_check_state *state;
1485 struct tevent_req *subreq;
1486 enum dcerpc_AuthType auth_type;
1487 enum dcerpc_AuthLevel auth_level;
1488 NTSTATUS status;
1490 req = tevent_req_create(mem_ctx, &state,
1491 struct netlogon_creds_cli_check_state);
1492 if (req == NULL) {
1493 return NULL;
1496 state->ev = ev;
1497 state->context = context;
1498 state->binding_handle = b;
1500 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1501 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1502 return tevent_req_post(req, ev);
1505 status = netlogon_creds_cli_get_internal(context, state,
1506 &state->creds);
1507 if (tevent_req_nterror(req, status)) {
1508 return tevent_req_post(req, ev);
1511 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1512 context->server.computer);
1513 if (tevent_req_nomem(state->srv_name_slash, req)) {
1514 return tevent_req_post(req, ev);
1517 dcerpc_binding_handle_auth_info(state->binding_handle,
1518 &auth_type, &auth_level);
1520 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1521 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1522 return tevent_req_post(req, ev);
1525 switch (auth_level) {
1526 case DCERPC_AUTH_LEVEL_INTEGRITY:
1527 case DCERPC_AUTH_LEVEL_PRIVACY:
1528 break;
1529 default:
1530 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1531 return tevent_req_post(req, ev);
1535 * we defer all callbacks in order to cleanup
1536 * the database record.
1538 tevent_req_defer_callback(req, state->ev);
1540 netlogon_creds_client_authenticator(state->creds, &state->req_auth);
1541 ZERO_STRUCT(state->rep_auth);
1543 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1544 state->binding_handle,
1545 state->srv_name_slash,
1546 state->context->client.computer,
1547 &state->req_auth,
1548 &state->rep_auth,
1550 &state->caps);
1551 if (tevent_req_nomem(subreq, req)) {
1552 return tevent_req_post(req, ev);
1555 tevent_req_set_callback(subreq,
1556 netlogon_creds_cli_check_caps,
1557 req);
1559 return req;
1562 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1563 NTSTATUS status)
1565 struct netlogon_creds_cli_check_state *state =
1566 tevent_req_data(req,
1567 struct netlogon_creds_cli_check_state);
1569 if (state->creds == NULL) {
1570 return;
1573 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1574 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1575 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1576 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1577 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1578 TALLOC_FREE(state->creds);
1579 return;
1582 netlogon_creds_cli_delete_lck(state->context);
1583 TALLOC_FREE(state->creds);
1586 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1588 struct tevent_req *req =
1589 tevent_req_callback_data(subreq,
1590 struct tevent_req);
1591 struct netlogon_creds_cli_check_state *state =
1592 tevent_req_data(req,
1593 struct netlogon_creds_cli_check_state);
1594 NTSTATUS status;
1595 NTSTATUS result;
1596 bool ok;
1598 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1599 &result);
1600 TALLOC_FREE(subreq);
1601 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1603 * Note that the negotiated flags are already checked
1604 * for our required flags after the ServerAuthenticate3/2 call.
1606 uint32_t negotiated = state->creds->negotiate_flags;
1608 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1610 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1611 * already, we expect this to work!
1613 status = NT_STATUS_DOWNGRADE_DETECTED;
1614 tevent_req_nterror(req, status);
1615 netlogon_creds_cli_check_cleanup(req, status);
1616 return;
1619 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1621 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1622 * we expect this to work at least as far as the
1623 * NOT_SUPPORTED error handled below!
1625 * NT 4.0 and Old Samba servers are not
1626 * allowed without "require strong key = no"
1628 status = NT_STATUS_DOWNGRADE_DETECTED;
1629 tevent_req_nterror(req, status);
1630 netlogon_creds_cli_check_cleanup(req, status);
1631 return;
1635 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1636 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1637 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1639 * This is needed against NT 4.0 and old Samba servers.
1641 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1642 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1643 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1644 * with the next request as the sequence number processing
1645 * gets out of sync.
1647 netlogon_creds_cli_check_cleanup(req, status);
1648 tevent_req_done(req);
1649 return;
1651 if (tevent_req_nterror(req, status)) {
1652 netlogon_creds_cli_check_cleanup(req, status);
1653 return;
1656 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1658 * Note that the negotiated flags are already checked
1659 * for our required flags after the ServerAuthenticate3/2 call.
1661 uint32_t negotiated = state->creds->negotiate_flags;
1663 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1665 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1666 * already, we expect this to work!
1668 status = NT_STATUS_DOWNGRADE_DETECTED;
1669 tevent_req_nterror(req, status);
1670 netlogon_creds_cli_check_cleanup(req, status);
1671 return;
1675 * This is ok, the server does not support
1676 * NETLOGON_NEG_SUPPORTS_AES.
1678 * netr_LogonGetCapabilities() was
1679 * netr_LogonDummyRoutine1() before
1680 * NETLOGON_NEG_SUPPORTS_AES was invented.
1682 netlogon_creds_cli_check_cleanup(req, result);
1683 tevent_req_done(req);
1684 return;
1687 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1688 if (!ok) {
1689 status = NT_STATUS_ACCESS_DENIED;
1690 tevent_req_nterror(req, status);
1691 netlogon_creds_cli_check_cleanup(req, status);
1692 return;
1695 if (tevent_req_nterror(req, result)) {
1696 netlogon_creds_cli_check_cleanup(req, result);
1697 return;
1700 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1701 status = NT_STATUS_DOWNGRADE_DETECTED;
1702 tevent_req_nterror(req, status);
1703 netlogon_creds_cli_check_cleanup(req, status);
1704 return;
1708 * This is the key check that makes this check secure. If we
1709 * get OK here (rather than NOT_SUPPORTED), then the server
1710 * did support AES. If the server only proposed STRONG_KEYS
1711 * and not AES, then it should have failed with
1712 * NOT_IMPLEMENTED. We always send AES as a client, so the
1713 * server should always have returned it.
1715 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1716 status = NT_STATUS_DOWNGRADE_DETECTED;
1717 tevent_req_nterror(req, status);
1718 netlogon_creds_cli_check_cleanup(req, status);
1719 return;
1722 status = netlogon_creds_cli_store_internal(state->context,
1723 state->creds);
1724 if (tevent_req_nterror(req, status)) {
1725 return;
1728 tevent_req_done(req);
1731 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1732 union netr_Capabilities *capabilities)
1734 struct netlogon_creds_cli_check_state *state = tevent_req_data(
1735 req, struct netlogon_creds_cli_check_state);
1736 NTSTATUS status;
1738 if (tevent_req_is_nterror(req, &status)) {
1739 netlogon_creds_cli_check_cleanup(req, status);
1740 tevent_req_received(req);
1741 return status;
1744 if (capabilities != NULL) {
1745 *capabilities = state->caps;
1748 tevent_req_received(req);
1749 return NT_STATUS_OK;
1752 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1753 struct dcerpc_binding_handle *b,
1754 union netr_Capabilities *capabilities)
1756 TALLOC_CTX *frame = talloc_stackframe();
1757 struct tevent_context *ev;
1758 struct tevent_req *req;
1759 NTSTATUS status = NT_STATUS_NO_MEMORY;
1761 ev = samba_tevent_context_init(frame);
1762 if (ev == NULL) {
1763 goto fail;
1765 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1766 if (req == NULL) {
1767 goto fail;
1769 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1770 goto fail;
1772 status = netlogon_creds_cli_check_recv(req, capabilities);
1773 fail:
1774 TALLOC_FREE(frame);
1775 return status;
1778 struct netlogon_creds_cli_ServerPasswordSet_state {
1779 struct tevent_context *ev;
1780 struct netlogon_creds_cli_context *context;
1781 struct dcerpc_binding_handle *binding_handle;
1782 uint32_t old_timeout;
1784 char *srv_name_slash;
1785 enum dcerpc_AuthType auth_type;
1786 enum dcerpc_AuthLevel auth_level;
1788 struct samr_CryptPassword samr_crypt_password;
1789 struct netr_CryptPassword netr_crypt_password;
1790 struct samr_Password samr_password;
1792 struct netlogon_creds_CredentialState *creds;
1793 struct netlogon_creds_CredentialState tmp_creds;
1794 struct netr_Authenticator req_auth;
1795 struct netr_Authenticator rep_auth;
1798 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1799 NTSTATUS status);
1800 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1802 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1803 struct tevent_context *ev,
1804 struct netlogon_creds_cli_context *context,
1805 struct dcerpc_binding_handle *b,
1806 const DATA_BLOB *new_password,
1807 const uint32_t *new_version)
1809 struct tevent_req *req;
1810 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1811 struct tevent_req *subreq;
1812 bool ok;
1814 req = tevent_req_create(mem_ctx, &state,
1815 struct netlogon_creds_cli_ServerPasswordSet_state);
1816 if (req == NULL) {
1817 return NULL;
1820 state->ev = ev;
1821 state->context = context;
1822 state->binding_handle = b;
1824 if (new_password->length < 14) {
1825 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1826 return tevent_req_post(req, ev);
1830 * netr_ServerPasswordSet
1832 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1835 * netr_ServerPasswordSet2
1837 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1838 new_password);
1839 if (!ok) {
1840 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1841 return tevent_req_post(req, ev);
1844 if (new_version != NULL) {
1845 struct NL_PASSWORD_VERSION version;
1846 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1847 uint32_t ofs = 512 - len;
1848 uint8_t *p;
1850 if (len > 500) {
1851 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1852 return tevent_req_post(req, ev);
1854 ofs -= 12;
1856 version.ReservedField = 0;
1857 version.PasswordVersionNumber = *new_version;
1858 version.PasswordVersionPresent =
1859 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1861 p = state->samr_crypt_password.data + ofs;
1862 SIVAL(p, 0, version.ReservedField);
1863 SIVAL(p, 4, version.PasswordVersionNumber);
1864 SIVAL(p, 8, version.PasswordVersionPresent);
1867 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1868 context->server.computer);
1869 if (tevent_req_nomem(state->srv_name_slash, req)) {
1870 return tevent_req_post(req, ev);
1873 dcerpc_binding_handle_auth_info(state->binding_handle,
1874 &state->auth_type,
1875 &state->auth_level);
1877 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1878 state->context);
1879 if (tevent_req_nomem(subreq, req)) {
1880 return tevent_req_post(req, ev);
1883 tevent_req_set_callback(subreq,
1884 netlogon_creds_cli_ServerPasswordSet_locked,
1885 req);
1887 return req;
1890 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1891 NTSTATUS status)
1893 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1894 tevent_req_data(req,
1895 struct netlogon_creds_cli_ServerPasswordSet_state);
1897 if (state->creds == NULL) {
1898 return;
1901 dcerpc_binding_handle_set_timeout(state->binding_handle,
1902 state->old_timeout);
1904 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1905 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1906 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1907 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1908 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1909 TALLOC_FREE(state->creds);
1910 return;
1913 netlogon_creds_cli_delete(state->context, state->creds);
1914 TALLOC_FREE(state->creds);
1917 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1919 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1921 struct tevent_req *req =
1922 tevent_req_callback_data(subreq,
1923 struct tevent_req);
1924 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1925 tevent_req_data(req,
1926 struct netlogon_creds_cli_ServerPasswordSet_state);
1927 NTSTATUS status;
1929 status = netlogon_creds_cli_lock_recv(subreq, state,
1930 &state->creds);
1931 TALLOC_FREE(subreq);
1932 if (tevent_req_nterror(req, status)) {
1933 return;
1936 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1937 switch (state->auth_level) {
1938 case DCERPC_AUTH_LEVEL_INTEGRITY:
1939 case DCERPC_AUTH_LEVEL_PRIVACY:
1940 break;
1941 default:
1942 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1943 return;
1945 } else {
1946 uint32_t tmp = state->creds->negotiate_flags;
1948 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1950 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1951 * it should be used, which means
1952 * we had a chance to verify no downgrade
1953 * happened.
1955 * This relies on netlogon_creds_cli_check*
1956 * being called before, as first request after
1957 * the DCERPC bind.
1959 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1960 return;
1964 state->old_timeout = dcerpc_binding_handle_set_timeout(
1965 state->binding_handle, 600000);
1968 * we defer all callbacks in order to cleanup
1969 * the database record.
1971 tevent_req_defer_callback(req, state->ev);
1973 state->tmp_creds = *state->creds;
1974 netlogon_creds_client_authenticator(&state->tmp_creds,
1975 &state->req_auth);
1976 ZERO_STRUCT(state->rep_auth);
1978 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1980 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1981 netlogon_creds_aes_encrypt(&state->tmp_creds,
1982 state->samr_crypt_password.data,
1983 516);
1984 } else {
1985 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1986 state->samr_crypt_password.data,
1987 516);
1990 memcpy(state->netr_crypt_password.data,
1991 state->samr_crypt_password.data, 512);
1992 state->netr_crypt_password.length =
1993 IVAL(state->samr_crypt_password.data, 512);
1995 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1996 state->binding_handle,
1997 state->srv_name_slash,
1998 state->tmp_creds.account_name,
1999 state->tmp_creds.secure_channel_type,
2000 state->tmp_creds.computer_name,
2001 &state->req_auth,
2002 &state->rep_auth,
2003 &state->netr_crypt_password);
2004 if (tevent_req_nomem(subreq, req)) {
2005 status = NT_STATUS_NO_MEMORY;
2006 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2007 return;
2009 } else {
2010 netlogon_creds_des_encrypt(&state->tmp_creds,
2011 &state->samr_password);
2013 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2014 state->binding_handle,
2015 state->srv_name_slash,
2016 state->tmp_creds.account_name,
2017 state->tmp_creds.secure_channel_type,
2018 state->tmp_creds.computer_name,
2019 &state->req_auth,
2020 &state->rep_auth,
2021 &state->samr_password);
2022 if (tevent_req_nomem(subreq, req)) {
2023 status = NT_STATUS_NO_MEMORY;
2024 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2025 return;
2029 tevent_req_set_callback(subreq,
2030 netlogon_creds_cli_ServerPasswordSet_done,
2031 req);
2034 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2036 struct tevent_req *req =
2037 tevent_req_callback_data(subreq,
2038 struct tevent_req);
2039 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2040 tevent_req_data(req,
2041 struct netlogon_creds_cli_ServerPasswordSet_state);
2042 NTSTATUS status;
2043 NTSTATUS result;
2044 bool ok;
2046 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2047 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2048 &result);
2049 TALLOC_FREE(subreq);
2050 if (tevent_req_nterror(req, status)) {
2051 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2052 return;
2054 } else {
2055 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2056 &result);
2057 TALLOC_FREE(subreq);
2058 if (tevent_req_nterror(req, status)) {
2059 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2060 return;
2064 ok = netlogon_creds_client_check(&state->tmp_creds,
2065 &state->rep_auth.cred);
2066 if (!ok) {
2067 status = NT_STATUS_ACCESS_DENIED;
2068 tevent_req_nterror(req, status);
2069 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2070 return;
2073 if (tevent_req_nterror(req, result)) {
2074 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2075 return;
2078 dcerpc_binding_handle_set_timeout(state->binding_handle,
2079 state->old_timeout);
2081 *state->creds = state->tmp_creds;
2082 status = netlogon_creds_cli_store(state->context,
2083 state->creds);
2084 TALLOC_FREE(state->creds);
2085 if (tevent_req_nterror(req, status)) {
2086 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2087 return;
2090 tevent_req_done(req);
2093 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2095 NTSTATUS status;
2097 if (tevent_req_is_nterror(req, &status)) {
2098 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2099 tevent_req_received(req);
2100 return status;
2103 tevent_req_received(req);
2104 return NT_STATUS_OK;
2107 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2108 struct netlogon_creds_cli_context *context,
2109 struct dcerpc_binding_handle *b,
2110 const DATA_BLOB *new_password,
2111 const uint32_t *new_version)
2113 TALLOC_CTX *frame = talloc_stackframe();
2114 struct tevent_context *ev;
2115 struct tevent_req *req;
2116 NTSTATUS status = NT_STATUS_NO_MEMORY;
2118 ev = samba_tevent_context_init(frame);
2119 if (ev == NULL) {
2120 goto fail;
2122 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2123 new_password,
2124 new_version);
2125 if (req == NULL) {
2126 goto fail;
2128 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2129 goto fail;
2131 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2132 fail:
2133 TALLOC_FREE(frame);
2134 return status;
2137 struct netlogon_creds_cli_LogonSamLogon_state {
2138 struct tevent_context *ev;
2139 struct netlogon_creds_cli_context *context;
2140 struct dcerpc_binding_handle *binding_handle;
2142 char *srv_name_slash;
2144 enum netr_LogonInfoClass logon_level;
2145 const union netr_LogonLevel *const_logon;
2146 union netr_LogonLevel *logon;
2147 uint32_t flags;
2149 uint16_t validation_level;
2150 union netr_Validation *validation;
2151 uint8_t authoritative;
2154 * do we need encryption at the application layer?
2156 bool user_encrypt;
2157 bool try_logon_ex;
2158 bool try_validation6;
2161 * the read only credentials before we started the operation
2162 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2164 struct netlogon_creds_CredentialState *ro_creds;
2167 * The (locked) credentials used for the credential chain
2168 * used for netr_LogonSamLogonWithFlags() or
2169 * netr_LogonSamLogonWith().
2171 struct netlogon_creds_CredentialState *lk_creds;
2174 * While we have locked the global credentials (lk_creds above)
2175 * we operate an a temporary copy, because a server
2176 * may not support netr_LogonSamLogonWithFlags() and
2177 * didn't process our netr_Authenticator, so we need to
2178 * restart from lk_creds.
2180 struct netlogon_creds_CredentialState tmp_creds;
2181 struct netr_Authenticator req_auth;
2182 struct netr_Authenticator rep_auth;
2185 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2186 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2187 NTSTATUS status);
2189 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2190 struct tevent_context *ev,
2191 struct netlogon_creds_cli_context *context,
2192 struct dcerpc_binding_handle *b,
2193 enum netr_LogonInfoClass logon_level,
2194 const union netr_LogonLevel *logon,
2195 uint32_t flags)
2197 struct tevent_req *req;
2198 struct netlogon_creds_cli_LogonSamLogon_state *state;
2200 req = tevent_req_create(mem_ctx, &state,
2201 struct netlogon_creds_cli_LogonSamLogon_state);
2202 if (req == NULL) {
2203 return NULL;
2206 state->ev = ev;
2207 state->context = context;
2208 state->binding_handle = b;
2210 state->logon_level = logon_level;
2211 state->const_logon = logon;
2212 state->flags = flags;
2214 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2215 context->server.computer);
2216 if (tevent_req_nomem(state->srv_name_slash, req)) {
2217 return tevent_req_post(req, ev);
2220 switch (logon_level) {
2221 case NetlogonInteractiveInformation:
2222 case NetlogonInteractiveTransitiveInformation:
2223 case NetlogonServiceInformation:
2224 case NetlogonServiceTransitiveInformation:
2225 case NetlogonGenericInformation:
2226 state->user_encrypt = true;
2227 break;
2229 case NetlogonNetworkInformation:
2230 case NetlogonNetworkTransitiveInformation:
2231 break;
2234 state->validation = talloc_zero(state, union netr_Validation);
2235 if (tevent_req_nomem(state->validation, req)) {
2236 return tevent_req_post(req, ev);
2239 netlogon_creds_cli_LogonSamLogon_start(req);
2240 if (!tevent_req_is_in_progress(req)) {
2241 return tevent_req_post(req, ev);
2245 * we defer all callbacks in order to cleanup
2246 * the database record.
2248 tevent_req_defer_callback(req, state->ev);
2249 return req;
2252 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2253 NTSTATUS status)
2255 struct netlogon_creds_cli_LogonSamLogon_state *state =
2256 tevent_req_data(req,
2257 struct netlogon_creds_cli_LogonSamLogon_state);
2259 if (state->lk_creds == NULL) {
2260 return;
2263 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2265 * This is a hack to recover from a bug in old
2266 * Samba servers, when LogonSamLogonEx() fails:
2268 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2270 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2272 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2273 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2274 * If the sign/seal check fails.
2276 * In that case we need to cleanup the netlogon session.
2278 * It's the job of the caller to disconnect the current
2279 * connection, if netlogon_creds_cli_LogonSamLogon()
2280 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2282 if (!state->context->server.try_logon_with) {
2283 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2287 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2288 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2289 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2290 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2291 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2292 TALLOC_FREE(state->lk_creds);
2293 return;
2296 netlogon_creds_cli_delete(state->context, state->lk_creds);
2297 TALLOC_FREE(state->lk_creds);
2300 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2302 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2304 struct netlogon_creds_cli_LogonSamLogon_state *state =
2305 tevent_req_data(req,
2306 struct netlogon_creds_cli_LogonSamLogon_state);
2307 struct tevent_req *subreq;
2308 NTSTATUS status;
2309 enum dcerpc_AuthType auth_type;
2310 enum dcerpc_AuthLevel auth_level;
2312 TALLOC_FREE(state->ro_creds);
2313 TALLOC_FREE(state->logon);
2314 ZERO_STRUCTP(state->validation);
2316 dcerpc_binding_handle_auth_info(state->binding_handle,
2317 &auth_type, &auth_level);
2319 state->try_logon_ex = state->context->server.try_logon_ex;
2320 state->try_validation6 = state->context->server.try_validation6;
2322 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2323 state->try_logon_ex = false;
2326 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2327 state->try_validation6 = false;
2330 if (state->try_logon_ex) {
2331 if (state->try_validation6) {
2332 state->validation_level = 6;
2333 } else {
2334 state->validation_level = 3;
2335 state->user_encrypt = true;
2338 state->logon = netlogon_creds_shallow_copy_logon(state,
2339 state->logon_level,
2340 state->const_logon);
2341 if (tevent_req_nomem(state->logon, req)) {
2342 status = NT_STATUS_NO_MEMORY;
2343 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2344 return;
2347 if (state->user_encrypt) {
2348 status = netlogon_creds_cli_get(state->context,
2349 state,
2350 &state->ro_creds);
2351 if (!NT_STATUS_IS_OK(status)) {
2352 status = NT_STATUS_ACCESS_DENIED;
2353 tevent_req_nterror(req, status);
2354 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2355 return;
2358 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2359 state->logon_level,
2360 state->logon);
2363 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2364 state->binding_handle,
2365 state->srv_name_slash,
2366 state->context->client.computer,
2367 state->logon_level,
2368 state->logon,
2369 state->validation_level,
2370 state->validation,
2371 &state->authoritative,
2372 &state->flags);
2373 if (tevent_req_nomem(subreq, req)) {
2374 status = NT_STATUS_NO_MEMORY;
2375 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2376 return;
2378 tevent_req_set_callback(subreq,
2379 netlogon_creds_cli_LogonSamLogon_done,
2380 req);
2381 return;
2384 if (state->lk_creds == NULL) {
2385 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2386 state->context);
2387 if (tevent_req_nomem(subreq, req)) {
2388 status = NT_STATUS_NO_MEMORY;
2389 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2390 return;
2392 tevent_req_set_callback(subreq,
2393 netlogon_creds_cli_LogonSamLogon_done,
2394 req);
2395 return;
2398 state->tmp_creds = *state->lk_creds;
2399 netlogon_creds_client_authenticator(&state->tmp_creds,
2400 &state->req_auth);
2401 ZERO_STRUCT(state->rep_auth);
2403 state->logon = netlogon_creds_shallow_copy_logon(state,
2404 state->logon_level,
2405 state->const_logon);
2406 if (tevent_req_nomem(state->logon, req)) {
2407 status = NT_STATUS_NO_MEMORY;
2408 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2409 return;
2412 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2413 state->logon_level,
2414 state->logon);
2416 state->validation_level = 3;
2418 if (state->context->server.try_logon_with) {
2419 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2420 state->binding_handle,
2421 state->srv_name_slash,
2422 state->context->client.computer,
2423 &state->req_auth,
2424 &state->rep_auth,
2425 state->logon_level,
2426 state->logon,
2427 state->validation_level,
2428 state->validation,
2429 &state->authoritative,
2430 &state->flags);
2431 if (tevent_req_nomem(subreq, req)) {
2432 status = NT_STATUS_NO_MEMORY;
2433 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2434 return;
2436 } else {
2437 state->flags = 0;
2439 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2440 state->binding_handle,
2441 state->srv_name_slash,
2442 state->context->client.computer,
2443 &state->req_auth,
2444 &state->rep_auth,
2445 state->logon_level,
2446 state->logon,
2447 state->validation_level,
2448 state->validation,
2449 &state->authoritative);
2450 if (tevent_req_nomem(subreq, req)) {
2451 status = NT_STATUS_NO_MEMORY;
2452 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2453 return;
2457 tevent_req_set_callback(subreq,
2458 netlogon_creds_cli_LogonSamLogon_done,
2459 req);
2462 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2464 struct tevent_req *req =
2465 tevent_req_callback_data(subreq,
2466 struct tevent_req);
2467 struct netlogon_creds_cli_LogonSamLogon_state *state =
2468 tevent_req_data(req,
2469 struct netlogon_creds_cli_LogonSamLogon_state);
2470 NTSTATUS status;
2471 NTSTATUS result;
2472 bool ok;
2474 if (state->try_logon_ex) {
2475 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2476 state->validation,
2477 &result);
2478 TALLOC_FREE(subreq);
2479 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2480 state->context->server.try_validation6 = false;
2481 state->context->server.try_logon_ex = false;
2482 netlogon_creds_cli_LogonSamLogon_start(req);
2483 return;
2485 if (tevent_req_nterror(req, status)) {
2486 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2487 return;
2490 if ((state->validation_level == 6) &&
2491 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2492 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2493 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2495 state->context->server.try_validation6 = false;
2496 netlogon_creds_cli_LogonSamLogon_start(req);
2497 return;
2500 if (tevent_req_nterror(req, result)) {
2501 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2502 return;
2505 if (state->ro_creds == NULL) {
2506 tevent_req_done(req);
2507 return;
2510 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2511 if (!ok) {
2513 * We got a race, lets retry with on authenticator
2514 * protection.
2516 * netlogon_creds_cli_LogonSamLogon_start()
2517 * will TALLOC_FREE(state->ro_creds);
2519 state->try_logon_ex = false;
2520 netlogon_creds_cli_LogonSamLogon_start(req);
2521 return;
2524 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2525 state->validation_level,
2526 state->validation);
2528 tevent_req_done(req);
2529 return;
2532 if (state->lk_creds == NULL) {
2533 status = netlogon_creds_cli_lock_recv(subreq, state,
2534 &state->lk_creds);
2535 TALLOC_FREE(subreq);
2536 if (tevent_req_nterror(req, status)) {
2537 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2538 return;
2541 netlogon_creds_cli_LogonSamLogon_start(req);
2542 return;
2545 if (state->context->server.try_logon_with) {
2546 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2547 state->validation,
2548 &result);
2549 TALLOC_FREE(subreq);
2550 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2551 state->context->server.try_logon_with = false;
2552 netlogon_creds_cli_LogonSamLogon_start(req);
2553 return;
2555 if (tevent_req_nterror(req, status)) {
2556 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2557 return;
2559 } else {
2560 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2561 state->validation,
2562 &result);
2563 TALLOC_FREE(subreq);
2564 if (tevent_req_nterror(req, status)) {
2565 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2566 return;
2570 ok = netlogon_creds_client_check(&state->tmp_creds,
2571 &state->rep_auth.cred);
2572 if (!ok) {
2573 status = NT_STATUS_ACCESS_DENIED;
2574 tevent_req_nterror(req, status);
2575 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2576 return;
2579 *state->lk_creds = state->tmp_creds;
2580 status = netlogon_creds_cli_store(state->context,
2581 state->lk_creds);
2582 TALLOC_FREE(state->lk_creds);
2584 if (tevent_req_nterror(req, status)) {
2585 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2586 return;
2589 if (tevent_req_nterror(req, result)) {
2590 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2591 return;
2594 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2595 state->validation_level,
2596 state->validation);
2598 tevent_req_done(req);
2601 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2602 TALLOC_CTX *mem_ctx,
2603 uint16_t *validation_level,
2604 union netr_Validation **validation,
2605 uint8_t *authoritative,
2606 uint32_t *flags)
2608 struct netlogon_creds_cli_LogonSamLogon_state *state =
2609 tevent_req_data(req,
2610 struct netlogon_creds_cli_LogonSamLogon_state);
2611 NTSTATUS status;
2613 /* authoritative is also returned on error */
2614 *authoritative = state->authoritative;
2616 if (tevent_req_is_nterror(req, &status)) {
2617 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2618 tevent_req_received(req);
2619 return status;
2622 *validation_level = state->validation_level;
2623 *validation = talloc_move(mem_ctx, &state->validation);
2624 *flags = state->flags;
2626 tevent_req_received(req);
2627 return NT_STATUS_OK;
2630 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2631 struct netlogon_creds_cli_context *context,
2632 struct dcerpc_binding_handle *b,
2633 enum netr_LogonInfoClass logon_level,
2634 const union netr_LogonLevel *logon,
2635 TALLOC_CTX *mem_ctx,
2636 uint16_t *validation_level,
2637 union netr_Validation **validation,
2638 uint8_t *authoritative,
2639 uint32_t *flags)
2641 TALLOC_CTX *frame = talloc_stackframe();
2642 struct tevent_context *ev;
2643 struct tevent_req *req;
2644 NTSTATUS status = NT_STATUS_NO_MEMORY;
2646 ev = samba_tevent_context_init(frame);
2647 if (ev == NULL) {
2648 goto fail;
2650 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2651 logon_level, logon,
2652 *flags);
2653 if (req == NULL) {
2654 goto fail;
2656 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2657 goto fail;
2659 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2660 validation_level,
2661 validation,
2662 authoritative,
2663 flags);
2664 fail:
2665 TALLOC_FREE(frame);
2666 return status;
2669 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2670 struct tevent_context *ev;
2671 struct netlogon_creds_cli_context *context;
2672 struct dcerpc_binding_handle *binding_handle;
2674 char *srv_name_slash;
2675 enum dcerpc_AuthType auth_type;
2676 enum dcerpc_AuthLevel auth_level;
2678 const char *site_name;
2679 uint32_t dns_ttl;
2680 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2682 struct netlogon_creds_CredentialState *creds;
2683 struct netlogon_creds_CredentialState tmp_creds;
2684 struct netr_Authenticator req_auth;
2685 struct netr_Authenticator rep_auth;
2688 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2689 NTSTATUS status);
2690 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2692 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2693 struct tevent_context *ev,
2694 struct netlogon_creds_cli_context *context,
2695 struct dcerpc_binding_handle *b,
2696 const char *site_name,
2697 uint32_t dns_ttl,
2698 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2700 struct tevent_req *req;
2701 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2702 struct tevent_req *subreq;
2704 req = tevent_req_create(mem_ctx, &state,
2705 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2706 if (req == NULL) {
2707 return NULL;
2710 state->ev = ev;
2711 state->context = context;
2712 state->binding_handle = b;
2714 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2715 context->server.computer);
2716 if (tevent_req_nomem(state->srv_name_slash, req)) {
2717 return tevent_req_post(req, ev);
2720 state->site_name = site_name;
2721 state->dns_ttl = dns_ttl;
2722 state->dns_names = dns_names;
2724 dcerpc_binding_handle_auth_info(state->binding_handle,
2725 &state->auth_type,
2726 &state->auth_level);
2728 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2729 state->context);
2730 if (tevent_req_nomem(subreq, req)) {
2731 return tevent_req_post(req, ev);
2734 tevent_req_set_callback(subreq,
2735 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2736 req);
2738 return req;
2741 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2742 NTSTATUS status)
2744 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2745 tevent_req_data(req,
2746 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2748 if (state->creds == NULL) {
2749 return;
2752 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2753 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2754 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2755 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2756 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2757 TALLOC_FREE(state->creds);
2758 return;
2761 netlogon_creds_cli_delete(state->context, state->creds);
2762 TALLOC_FREE(state->creds);
2765 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2767 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2769 struct tevent_req *req =
2770 tevent_req_callback_data(subreq,
2771 struct tevent_req);
2772 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2773 tevent_req_data(req,
2774 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2775 NTSTATUS status;
2777 status = netlogon_creds_cli_lock_recv(subreq, state,
2778 &state->creds);
2779 TALLOC_FREE(subreq);
2780 if (tevent_req_nterror(req, status)) {
2781 return;
2784 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2785 switch (state->auth_level) {
2786 case DCERPC_AUTH_LEVEL_INTEGRITY:
2787 case DCERPC_AUTH_LEVEL_PRIVACY:
2788 break;
2789 default:
2790 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2791 return;
2793 } else {
2794 uint32_t tmp = state->creds->negotiate_flags;
2796 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2798 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2799 * it should be used, which means
2800 * we had a chance to verify no downgrade
2801 * happened.
2803 * This relies on netlogon_creds_cli_check*
2804 * being called before, as first request after
2805 * the DCERPC bind.
2807 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2808 return;
2813 * we defer all callbacks in order to cleanup
2814 * the database record.
2816 tevent_req_defer_callback(req, state->ev);
2818 state->tmp_creds = *state->creds;
2819 netlogon_creds_client_authenticator(&state->tmp_creds,
2820 &state->req_auth);
2821 ZERO_STRUCT(state->rep_auth);
2823 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2824 state->binding_handle,
2825 state->srv_name_slash,
2826 state->tmp_creds.computer_name,
2827 &state->req_auth,
2828 &state->rep_auth,
2829 state->site_name,
2830 state->dns_ttl,
2831 state->dns_names);
2832 if (tevent_req_nomem(subreq, req)) {
2833 status = NT_STATUS_NO_MEMORY;
2834 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2835 return;
2838 tevent_req_set_callback(subreq,
2839 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2840 req);
2843 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2845 struct tevent_req *req =
2846 tevent_req_callback_data(subreq,
2847 struct tevent_req);
2848 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2849 tevent_req_data(req,
2850 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2851 NTSTATUS status;
2852 NTSTATUS result;
2853 bool ok;
2856 * We use state->dns_names as the memory context, as this is
2857 * the only in/out variable and it has been overwritten by the
2858 * out parameter from the server.
2860 * We need to preserve the return value until the caller can use it.
2862 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2863 &result);
2864 TALLOC_FREE(subreq);
2865 if (tevent_req_nterror(req, status)) {
2866 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2867 return;
2870 ok = netlogon_creds_client_check(&state->tmp_creds,
2871 &state->rep_auth.cred);
2872 if (!ok) {
2873 status = NT_STATUS_ACCESS_DENIED;
2874 tevent_req_nterror(req, status);
2875 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2876 return;
2879 *state->creds = state->tmp_creds;
2880 status = netlogon_creds_cli_store(state->context,
2881 state->creds);
2882 TALLOC_FREE(state->creds);
2884 if (tevent_req_nterror(req, status)) {
2885 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2886 return;
2889 if (tevent_req_nterror(req, result)) {
2890 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2891 return;
2894 tevent_req_done(req);
2897 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2899 NTSTATUS status;
2901 if (tevent_req_is_nterror(req, &status)) {
2902 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2903 tevent_req_received(req);
2904 return status;
2907 tevent_req_received(req);
2908 return NT_STATUS_OK;
2911 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2912 struct netlogon_creds_cli_context *context,
2913 struct dcerpc_binding_handle *b,
2914 const char *site_name,
2915 uint32_t dns_ttl,
2916 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2918 TALLOC_CTX *frame = talloc_stackframe();
2919 struct tevent_context *ev;
2920 struct tevent_req *req;
2921 NTSTATUS status = NT_STATUS_NO_MEMORY;
2923 ev = samba_tevent_context_init(frame);
2924 if (ev == NULL) {
2925 goto fail;
2927 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2928 site_name,
2929 dns_ttl,
2930 dns_names);
2931 if (req == NULL) {
2932 goto fail;
2934 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2935 goto fail;
2937 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2938 fail:
2939 TALLOC_FREE(frame);
2940 return status;
2943 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2944 struct tevent_context *ev;
2945 struct netlogon_creds_cli_context *context;
2946 struct dcerpc_binding_handle *binding_handle;
2948 char *srv_name_slash;
2949 enum dcerpc_AuthType auth_type;
2950 enum dcerpc_AuthLevel auth_level;
2952 struct samr_Password new_owf_password;
2953 struct samr_Password old_owf_password;
2954 struct netr_TrustInfo *trust_info;
2956 struct netlogon_creds_CredentialState *creds;
2957 struct netlogon_creds_CredentialState tmp_creds;
2958 struct netr_Authenticator req_auth;
2959 struct netr_Authenticator rep_auth;
2962 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2963 NTSTATUS status);
2964 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2966 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2967 struct tevent_context *ev,
2968 struct netlogon_creds_cli_context *context,
2969 struct dcerpc_binding_handle *b)
2971 struct tevent_req *req;
2972 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2973 struct tevent_req *subreq;
2975 req = tevent_req_create(mem_ctx, &state,
2976 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2977 if (req == NULL) {
2978 return NULL;
2981 state->ev = ev;
2982 state->context = context;
2983 state->binding_handle = b;
2985 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2986 context->server.computer);
2987 if (tevent_req_nomem(state->srv_name_slash, req)) {
2988 return tevent_req_post(req, ev);
2991 dcerpc_binding_handle_auth_info(state->binding_handle,
2992 &state->auth_type,
2993 &state->auth_level);
2995 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2996 state->context);
2997 if (tevent_req_nomem(subreq, req)) {
2998 return tevent_req_post(req, ev);
3001 tevent_req_set_callback(subreq,
3002 netlogon_creds_cli_ServerGetTrustInfo_locked,
3003 req);
3005 return req;
3008 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3009 NTSTATUS status)
3011 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3012 tevent_req_data(req,
3013 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3015 if (state->creds == NULL) {
3016 return;
3019 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3020 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3021 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3022 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3023 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3024 TALLOC_FREE(state->creds);
3025 return;
3028 netlogon_creds_cli_delete(state->context, state->creds);
3029 TALLOC_FREE(state->creds);
3032 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3034 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3036 struct tevent_req *req =
3037 tevent_req_callback_data(subreq,
3038 struct tevent_req);
3039 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3040 tevent_req_data(req,
3041 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3042 NTSTATUS status;
3044 status = netlogon_creds_cli_lock_recv(subreq, state,
3045 &state->creds);
3046 TALLOC_FREE(subreq);
3047 if (tevent_req_nterror(req, status)) {
3048 return;
3051 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3052 switch (state->auth_level) {
3053 case DCERPC_AUTH_LEVEL_PRIVACY:
3054 break;
3055 default:
3056 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3057 return;
3059 } else {
3060 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3061 return;
3065 * we defer all callbacks in order to cleanup
3066 * the database record.
3068 tevent_req_defer_callback(req, state->ev);
3070 state->tmp_creds = *state->creds;
3071 netlogon_creds_client_authenticator(&state->tmp_creds,
3072 &state->req_auth);
3073 ZERO_STRUCT(state->rep_auth);
3075 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3076 state->binding_handle,
3077 state->srv_name_slash,
3078 state->tmp_creds.account_name,
3079 state->tmp_creds.secure_channel_type,
3080 state->tmp_creds.computer_name,
3081 &state->req_auth,
3082 &state->rep_auth,
3083 &state->new_owf_password,
3084 &state->old_owf_password,
3085 &state->trust_info);
3086 if (tevent_req_nomem(subreq, req)) {
3087 status = NT_STATUS_NO_MEMORY;
3088 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3089 return;
3092 tevent_req_set_callback(subreq,
3093 netlogon_creds_cli_ServerGetTrustInfo_done,
3094 req);
3097 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3099 struct tevent_req *req =
3100 tevent_req_callback_data(subreq,
3101 struct tevent_req);
3102 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3103 tevent_req_data(req,
3104 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3105 NTSTATUS status;
3106 NTSTATUS result;
3107 const struct samr_Password zero = {};
3108 int cmp;
3109 bool ok;
3112 * We use state->dns_names as the memory context, as this is
3113 * the only in/out variable and it has been overwritten by the
3114 * out parameter from the server.
3116 * We need to preserve the return value until the caller can use it.
3118 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3119 TALLOC_FREE(subreq);
3120 if (tevent_req_nterror(req, status)) {
3121 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3122 return;
3125 ok = netlogon_creds_client_check(&state->tmp_creds,
3126 &state->rep_auth.cred);
3127 if (!ok) {
3128 status = NT_STATUS_ACCESS_DENIED;
3129 tevent_req_nterror(req, status);
3130 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3131 return;
3134 cmp = memcmp(state->new_owf_password.hash,
3135 zero.hash, sizeof(zero.hash));
3136 if (cmp != 0) {
3137 netlogon_creds_des_decrypt(&state->tmp_creds,
3138 &state->new_owf_password);
3140 cmp = memcmp(state->old_owf_password.hash,
3141 zero.hash, sizeof(zero.hash));
3142 if (cmp != 0) {
3143 netlogon_creds_des_decrypt(&state->tmp_creds,
3144 &state->old_owf_password);
3147 *state->creds = state->tmp_creds;
3148 status = netlogon_creds_cli_store(state->context,
3149 state->creds);
3150 TALLOC_FREE(state->creds);
3151 if (tevent_req_nterror(req, status)) {
3152 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3153 return;
3156 if (tevent_req_nterror(req, result)) {
3157 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3158 return;
3161 tevent_req_done(req);
3164 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3165 TALLOC_CTX *mem_ctx,
3166 struct samr_Password *new_owf_password,
3167 struct samr_Password *old_owf_password,
3168 struct netr_TrustInfo **trust_info)
3170 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3171 tevent_req_data(req,
3172 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3173 NTSTATUS status;
3175 if (tevent_req_is_nterror(req, &status)) {
3176 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3177 tevent_req_received(req);
3178 return status;
3181 if (new_owf_password != NULL) {
3182 *new_owf_password = state->new_owf_password;
3184 if (old_owf_password != NULL) {
3185 *old_owf_password = state->old_owf_password;
3187 if (trust_info != NULL) {
3188 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3191 tevent_req_received(req);
3192 return NT_STATUS_OK;
3195 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3196 struct netlogon_creds_cli_context *context,
3197 struct dcerpc_binding_handle *b,
3198 TALLOC_CTX *mem_ctx,
3199 struct samr_Password *new_owf_password,
3200 struct samr_Password *old_owf_password,
3201 struct netr_TrustInfo **trust_info)
3203 TALLOC_CTX *frame = talloc_stackframe();
3204 struct tevent_context *ev;
3205 struct tevent_req *req;
3206 NTSTATUS status = NT_STATUS_NO_MEMORY;
3208 ev = samba_tevent_context_init(frame);
3209 if (ev == NULL) {
3210 goto fail;
3212 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3213 if (req == NULL) {
3214 goto fail;
3216 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3217 goto fail;
3219 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3220 mem_ctx,
3221 new_owf_password,
3222 old_owf_password,
3223 trust_info);
3224 fail:
3225 TALLOC_FREE(frame);
3226 return status;
3229 struct netlogon_creds_cli_GetForestTrustInformation_state {
3230 struct tevent_context *ev;
3231 struct netlogon_creds_cli_context *context;
3232 struct dcerpc_binding_handle *binding_handle;
3234 char *srv_name_slash;
3235 enum dcerpc_AuthType auth_type;
3236 enum dcerpc_AuthLevel auth_level;
3238 uint32_t flags;
3239 struct lsa_ForestTrustInformation *forest_trust_info;
3241 struct netlogon_creds_CredentialState *creds;
3242 struct netlogon_creds_CredentialState tmp_creds;
3243 struct netr_Authenticator req_auth;
3244 struct netr_Authenticator rep_auth;
3247 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3248 NTSTATUS status);
3249 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3251 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3252 struct tevent_context *ev,
3253 struct netlogon_creds_cli_context *context,
3254 struct dcerpc_binding_handle *b)
3256 struct tevent_req *req;
3257 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3258 struct tevent_req *subreq;
3260 req = tevent_req_create(mem_ctx, &state,
3261 struct netlogon_creds_cli_GetForestTrustInformation_state);
3262 if (req == NULL) {
3263 return NULL;
3266 state->ev = ev;
3267 state->context = context;
3268 state->binding_handle = b;
3270 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3271 context->server.computer);
3272 if (tevent_req_nomem(state->srv_name_slash, req)) {
3273 return tevent_req_post(req, ev);
3276 state->flags = 0;
3278 dcerpc_binding_handle_auth_info(state->binding_handle,
3279 &state->auth_type,
3280 &state->auth_level);
3282 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3283 state->context);
3284 if (tevent_req_nomem(subreq, req)) {
3285 return tevent_req_post(req, ev);
3288 tevent_req_set_callback(subreq,
3289 netlogon_creds_cli_GetForestTrustInformation_locked,
3290 req);
3292 return req;
3295 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3296 NTSTATUS status)
3298 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3299 tevent_req_data(req,
3300 struct netlogon_creds_cli_GetForestTrustInformation_state);
3302 if (state->creds == NULL) {
3303 return;
3306 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3307 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3308 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3309 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3310 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3311 TALLOC_FREE(state->creds);
3312 return;
3315 netlogon_creds_cli_delete(state->context, state->creds);
3316 TALLOC_FREE(state->creds);
3319 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3321 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3323 struct tevent_req *req =
3324 tevent_req_callback_data(subreq,
3325 struct tevent_req);
3326 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3327 tevent_req_data(req,
3328 struct netlogon_creds_cli_GetForestTrustInformation_state);
3329 NTSTATUS status;
3331 status = netlogon_creds_cli_lock_recv(subreq, state,
3332 &state->creds);
3333 TALLOC_FREE(subreq);
3334 if (tevent_req_nterror(req, status)) {
3335 return;
3338 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3339 switch (state->auth_level) {
3340 case DCERPC_AUTH_LEVEL_INTEGRITY:
3341 case DCERPC_AUTH_LEVEL_PRIVACY:
3342 break;
3343 default:
3344 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3345 return;
3347 } else {
3348 uint32_t tmp = state->creds->negotiate_flags;
3350 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3352 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3353 * it should be used, which means
3354 * we had a chance to verify no downgrade
3355 * happened.
3357 * This relies on netlogon_creds_cli_check*
3358 * being called before, as first request after
3359 * the DCERPC bind.
3361 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3362 return;
3367 * we defer all callbacks in order to cleanup
3368 * the database record.
3370 tevent_req_defer_callback(req, state->ev);
3372 state->tmp_creds = *state->creds;
3373 netlogon_creds_client_authenticator(&state->tmp_creds,
3374 &state->req_auth);
3375 ZERO_STRUCT(state->rep_auth);
3377 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3378 state->binding_handle,
3379 state->srv_name_slash,
3380 state->tmp_creds.computer_name,
3381 &state->req_auth,
3382 &state->rep_auth,
3383 state->flags,
3384 &state->forest_trust_info);
3385 if (tevent_req_nomem(subreq, req)) {
3386 status = NT_STATUS_NO_MEMORY;
3387 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3388 return;
3391 tevent_req_set_callback(subreq,
3392 netlogon_creds_cli_GetForestTrustInformation_done,
3393 req);
3396 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3398 struct tevent_req *req =
3399 tevent_req_callback_data(subreq,
3400 struct tevent_req);
3401 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3402 tevent_req_data(req,
3403 struct netlogon_creds_cli_GetForestTrustInformation_state);
3404 NTSTATUS status;
3405 NTSTATUS result;
3406 bool ok;
3409 * We use state->dns_names as the memory context, as this is
3410 * the only in/out variable and it has been overwritten by the
3411 * out parameter from the server.
3413 * We need to preserve the return value until the caller can use it.
3415 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3416 TALLOC_FREE(subreq);
3417 if (tevent_req_nterror(req, status)) {
3418 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3419 return;
3422 ok = netlogon_creds_client_check(&state->tmp_creds,
3423 &state->rep_auth.cred);
3424 if (!ok) {
3425 status = NT_STATUS_ACCESS_DENIED;
3426 tevent_req_nterror(req, status);
3427 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3428 return;
3431 *state->creds = state->tmp_creds;
3432 status = netlogon_creds_cli_store(state->context,
3433 state->creds);
3434 TALLOC_FREE(state->creds);
3436 if (tevent_req_nterror(req, status)) {
3437 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3438 return;
3441 if (tevent_req_nterror(req, result)) {
3442 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3443 return;
3446 tevent_req_done(req);
3449 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3450 TALLOC_CTX *mem_ctx,
3451 struct lsa_ForestTrustInformation **forest_trust_info)
3453 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3454 tevent_req_data(req,
3455 struct netlogon_creds_cli_GetForestTrustInformation_state);
3456 NTSTATUS status;
3458 if (tevent_req_is_nterror(req, &status)) {
3459 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3460 tevent_req_received(req);
3461 return status;
3464 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3466 tevent_req_received(req);
3467 return NT_STATUS_OK;
3470 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3471 struct netlogon_creds_cli_context *context,
3472 struct dcerpc_binding_handle *b,
3473 TALLOC_CTX *mem_ctx,
3474 struct lsa_ForestTrustInformation **forest_trust_info)
3476 TALLOC_CTX *frame = talloc_stackframe();
3477 struct tevent_context *ev;
3478 struct tevent_req *req;
3479 NTSTATUS status = NT_STATUS_NO_MEMORY;
3481 ev = samba_tevent_context_init(frame);
3482 if (ev == NULL) {
3483 goto fail;
3485 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3486 if (req == NULL) {
3487 goto fail;
3489 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3490 goto fail;
3492 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3493 mem_ctx,
3494 forest_trust_info);
3495 fail:
3496 TALLOC_FREE(frame);
3497 return status;
3500 struct netlogon_creds_cli_SendToSam_state {
3501 struct tevent_context *ev;
3502 struct netlogon_creds_cli_context *context;
3503 struct dcerpc_binding_handle *binding_handle;
3505 char *srv_name_slash;
3506 enum dcerpc_AuthType auth_type;
3507 enum dcerpc_AuthLevel auth_level;
3509 DATA_BLOB opaque;
3511 struct netlogon_creds_CredentialState *creds;
3512 struct netlogon_creds_CredentialState tmp_creds;
3513 struct netr_Authenticator req_auth;
3514 struct netr_Authenticator rep_auth;
3517 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3518 NTSTATUS status);
3519 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3521 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3522 struct tevent_context *ev,
3523 struct netlogon_creds_cli_context *context,
3524 struct dcerpc_binding_handle *b,
3525 struct netr_SendToSamBase *message)
3527 struct tevent_req *req;
3528 struct netlogon_creds_cli_SendToSam_state *state;
3529 struct tevent_req *subreq;
3530 enum ndr_err_code ndr_err;
3532 req = tevent_req_create(mem_ctx, &state,
3533 struct netlogon_creds_cli_SendToSam_state);
3534 if (req == NULL) {
3535 return NULL;
3538 state->ev = ev;
3539 state->context = context;
3540 state->binding_handle = b;
3542 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3543 context->server.computer);
3544 if (tevent_req_nomem(state->srv_name_slash, req)) {
3545 return tevent_req_post(req, ev);
3548 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3549 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3550 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3551 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3552 tevent_req_nterror(req, status);
3553 return tevent_req_post(req, ev);
3556 dcerpc_binding_handle_auth_info(state->binding_handle,
3557 &state->auth_type,
3558 &state->auth_level);
3560 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3561 state->context);
3562 if (tevent_req_nomem(subreq, req)) {
3563 return tevent_req_post(req, ev);
3566 tevent_req_set_callback(subreq,
3567 netlogon_creds_cli_SendToSam_locked,
3568 req);
3570 return req;
3573 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3574 NTSTATUS status)
3576 struct netlogon_creds_cli_SendToSam_state *state =
3577 tevent_req_data(req,
3578 struct netlogon_creds_cli_SendToSam_state);
3580 if (state->creds == NULL) {
3581 return;
3584 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3585 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3586 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3587 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3588 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3589 TALLOC_FREE(state->creds);
3590 return;
3593 netlogon_creds_cli_delete(state->context, state->creds);
3594 TALLOC_FREE(state->creds);
3597 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3599 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3601 struct tevent_req *req =
3602 tevent_req_callback_data(subreq,
3603 struct tevent_req);
3604 struct netlogon_creds_cli_SendToSam_state *state =
3605 tevent_req_data(req,
3606 struct netlogon_creds_cli_SendToSam_state);
3607 NTSTATUS status;
3609 status = netlogon_creds_cli_lock_recv(subreq, state,
3610 &state->creds);
3611 TALLOC_FREE(subreq);
3612 if (tevent_req_nterror(req, status)) {
3613 return;
3616 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3617 switch (state->auth_level) {
3618 case DCERPC_AUTH_LEVEL_INTEGRITY:
3619 case DCERPC_AUTH_LEVEL_PRIVACY:
3620 break;
3621 default:
3622 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3623 return;
3625 } else {
3626 uint32_t tmp = state->creds->negotiate_flags;
3628 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3630 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3631 * it should be used, which means
3632 * we had a chance to verify no downgrade
3633 * happened.
3635 * This relies on netlogon_creds_cli_check*
3636 * being called before, as first request after
3637 * the DCERPC bind.
3639 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3640 return;
3645 * we defer all callbacks in order to cleanup
3646 * the database record.
3648 tevent_req_defer_callback(req, state->ev);
3650 state->tmp_creds = *state->creds;
3651 netlogon_creds_client_authenticator(&state->tmp_creds,
3652 &state->req_auth);
3653 ZERO_STRUCT(state->rep_auth);
3655 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3656 netlogon_creds_aes_encrypt(&state->tmp_creds,
3657 state->opaque.data,
3658 state->opaque.length);
3659 } else {
3660 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3661 state->opaque.data,
3662 state->opaque.length);
3665 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3666 state->binding_handle,
3667 state->srv_name_slash,
3668 state->tmp_creds.computer_name,
3669 &state->req_auth,
3670 &state->rep_auth,
3671 state->opaque.data,
3672 state->opaque.length);
3673 if (tevent_req_nomem(subreq, req)) {
3674 status = NT_STATUS_NO_MEMORY;
3675 netlogon_creds_cli_SendToSam_cleanup(req, status);
3676 return;
3679 tevent_req_set_callback(subreq,
3680 netlogon_creds_cli_SendToSam_done,
3681 req);
3684 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3686 struct tevent_req *req =
3687 tevent_req_callback_data(subreq,
3688 struct tevent_req);
3689 struct netlogon_creds_cli_SendToSam_state *state =
3690 tevent_req_data(req,
3691 struct netlogon_creds_cli_SendToSam_state);
3692 NTSTATUS status;
3693 NTSTATUS result;
3694 bool ok;
3696 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3697 TALLOC_FREE(subreq);
3698 if (tevent_req_nterror(req, status)) {
3699 netlogon_creds_cli_SendToSam_cleanup(req, status);
3700 return;
3703 ok = netlogon_creds_client_check(&state->tmp_creds,
3704 &state->rep_auth.cred);
3705 if (!ok) {
3706 status = NT_STATUS_ACCESS_DENIED;
3707 tevent_req_nterror(req, status);
3708 netlogon_creds_cli_SendToSam_cleanup(req, status);
3709 return;
3712 *state->creds = state->tmp_creds;
3713 status = netlogon_creds_cli_store(state->context,
3714 state->creds);
3715 TALLOC_FREE(state->creds);
3717 if (tevent_req_nterror(req, status)) {
3718 netlogon_creds_cli_SendToSam_cleanup(req, status);
3719 return;
3723 * Creds must be stored before we send back application errors
3724 * e.g. NT_STATUS_NOT_IMPLEMENTED
3726 if (tevent_req_nterror(req, result)) {
3727 netlogon_creds_cli_SendToSam_cleanup(req, result);
3728 return;
3731 tevent_req_done(req);
3734 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3735 struct dcerpc_binding_handle *b,
3736 struct netr_SendToSamBase *message)
3738 TALLOC_CTX *frame = talloc_stackframe();
3739 struct tevent_context *ev;
3740 struct tevent_req *req;
3741 NTSTATUS status = NT_STATUS_OK;
3743 ev = samba_tevent_context_init(frame);
3744 if (ev == NULL) {
3745 goto fail;
3747 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3748 if (req == NULL) {
3749 goto fail;
3751 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3752 goto fail;
3755 /* Ignore the result */
3756 fail:
3757 TALLOC_FREE(frame);
3758 return status;