s3:smbd: when storing DOS attribute call dos_mode() beforehand
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob50a5f50a57d9d53f5cd381ccba73ae6000ee2501
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/md4.h"
41 #include "auth/credentials/credentials.h"
43 struct netlogon_creds_cli_locked_state;
45 struct netlogon_creds_cli_context {
46 struct {
47 const char *computer;
48 const char *account;
49 uint32_t proposed_flags;
50 uint32_t required_flags;
51 enum netr_SchannelType type;
52 enum dcerpc_AuthLevel auth_level;
53 } client;
55 struct {
56 const char *computer;
57 const char *netbios_domain;
58 const char *dns_domain;
59 uint32_t cached_flags;
60 bool try_validation6;
61 bool try_logon_ex;
62 bool try_logon_with;
63 } server;
65 struct {
66 const char *key_name;
67 TDB_DATA key_data;
68 struct db_context *ctx;
69 struct g_lock_ctx *g_ctx;
70 struct netlogon_creds_cli_locked_state *locked_state;
71 enum netlogon_creds_cli_lck_type lock;
72 } db;
75 struct netlogon_creds_cli_locked_state {
76 struct netlogon_creds_cli_context *context;
77 bool is_glocked;
78 struct netlogon_creds_CredentialState *creds;
81 static int netlogon_creds_cli_locked_state_destructor(
82 struct netlogon_creds_cli_locked_state *state)
84 struct netlogon_creds_cli_context *context = state->context;
86 if (context == NULL) {
87 return 0;
90 if (context->db.locked_state == state) {
91 context->db.locked_state = NULL;
94 if (state->is_glocked) {
95 g_lock_unlock(context->db.g_ctx,
96 string_term_tdb_data(context->db.key_name));
99 return 0;
102 static NTSTATUS netlogon_creds_cli_context_common(
103 const char *client_computer,
104 const char *client_account,
105 enum netr_SchannelType type,
106 enum dcerpc_AuthLevel auth_level,
107 uint32_t proposed_flags,
108 uint32_t required_flags,
109 const char *server_computer,
110 const char *server_netbios_domain,
111 const char *server_dns_domain,
112 TALLOC_CTX *mem_ctx,
113 struct netlogon_creds_cli_context **_context)
115 struct netlogon_creds_cli_context *context = NULL;
116 char *_key_name = NULL;
117 size_t server_netbios_name_len;
118 char *p = NULL;
120 *_context = NULL;
122 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
123 if (context == NULL) {
124 return NT_STATUS_NO_MEMORY;
127 context->client.computer = talloc_strdup(context, client_computer);
128 if (context->client.computer == NULL) {
129 TALLOC_FREE(context);
130 return NT_STATUS_NO_MEMORY;
133 context->client.account = talloc_strdup(context, client_account);
134 if (context->client.account == NULL) {
135 TALLOC_FREE(context);
136 return NT_STATUS_NO_MEMORY;
139 context->client.proposed_flags = proposed_flags;
140 context->client.required_flags = required_flags;
141 context->client.type = type;
142 context->client.auth_level = auth_level;
144 context->server.computer = talloc_strdup(context, server_computer);
145 if (context->server.computer == NULL) {
146 TALLOC_FREE(context);
147 return NT_STATUS_NO_MEMORY;
150 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
151 if (context->server.netbios_domain == NULL) {
152 TALLOC_FREE(context);
153 return NT_STATUS_NO_MEMORY;
156 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
157 if (context->server.dns_domain == NULL) {
158 TALLOC_FREE(context);
159 return NT_STATUS_NO_MEMORY;
163 * TODO:
164 * Force the callers to provide a unique
165 * value for server_computer and use this directly.
167 * For now we have to deal with
168 * "HOSTNAME" vs. "hostname.example.com".
171 p = strchr(server_computer, '.');
172 if (p != NULL) {
173 server_netbios_name_len = p-server_computer;
174 } else {
175 server_netbios_name_len = strlen(server_computer);
178 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
179 client_computer,
180 client_account,
181 (int)server_netbios_name_len,
182 server_computer,
183 server_netbios_domain);
184 if (_key_name == NULL) {
185 TALLOC_FREE(context);
186 return NT_STATUS_NO_MEMORY;
189 context->db.key_name = talloc_strdup_upper(context, _key_name);
190 TALLOC_FREE(_key_name);
191 if (context->db.key_name == NULL) {
192 TALLOC_FREE(context);
193 return NT_STATUS_NO_MEMORY;
196 context->db.key_data = string_term_tdb_data(context->db.key_name);
198 *_context = context;
199 return NT_STATUS_OK;
202 static struct db_context *netlogon_creds_cli_global_db;
204 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
206 if (netlogon_creds_cli_global_db != NULL) {
207 return NT_STATUS_INVALID_PARAMETER_MIX;
210 netlogon_creds_cli_global_db = talloc_move(NULL, db);
211 return NT_STATUS_OK;
214 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
216 char *fname;
217 struct db_context *global_db;
218 int hash_size, tdb_flags;
220 if (netlogon_creds_cli_global_db != NULL) {
221 return NT_STATUS_OK;
224 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
225 if (fname == NULL) {
226 return NT_STATUS_NO_MEMORY;
229 hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
230 tdb_flags = lpcfg_tdb_flags(
231 lp_ctx,
232 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
234 global_db = dbwrap_local_open(
235 NULL,
236 fname,
237 hash_size,
238 tdb_flags,
239 O_RDWR|O_CREAT,
240 0600,
241 DBWRAP_LOCK_ORDER_2,
242 DBWRAP_FLAG_NONE);
243 if (global_db == NULL) {
244 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
245 fname, strerror(errno)));
246 talloc_free(fname);
247 return NT_STATUS_NO_MEMORY;
249 TALLOC_FREE(fname);
251 netlogon_creds_cli_global_db = global_db;
252 return NT_STATUS_OK;
255 void netlogon_creds_cli_close_global_db(void)
257 TALLOC_FREE(netlogon_creds_cli_global_db);
260 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
261 struct messaging_context *msg_ctx,
262 const char *client_account,
263 enum netr_SchannelType type,
264 const char *server_computer,
265 const char *server_netbios_domain,
266 const char *server_dns_domain,
267 TALLOC_CTX *mem_ctx,
268 struct netlogon_creds_cli_context **_context)
270 TALLOC_CTX *frame = talloc_stackframe();
271 NTSTATUS status;
272 struct netlogon_creds_cli_context *context = NULL;
273 const char *client_computer;
274 uint32_t proposed_flags;
275 uint32_t required_flags = 0;
276 bool reject_md5_servers = false;
277 bool require_strong_key = false;
278 int require_sign_or_seal = true;
279 bool seal_secure_channel = true;
280 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
281 bool neutralize_nt4_emulation = false;
283 *_context = NULL;
285 if (msg_ctx == NULL) {
286 TALLOC_FREE(frame);
287 return NT_STATUS_INVALID_PARAMETER_MIX;
290 client_computer = lpcfg_netbios_name(lp_ctx);
291 if (strlen(client_computer) > 15) {
292 TALLOC_FREE(frame);
293 return NT_STATUS_INVALID_PARAMETER_MIX;
297 * allow overwrite per domain
298 * reject md5 servers:<netbios_domain>
300 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
301 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
302 "reject md5 servers",
303 server_netbios_domain,
304 reject_md5_servers);
307 * allow overwrite per domain
308 * require strong key:<netbios_domain>
310 require_strong_key = lpcfg_require_strong_key(lp_ctx);
311 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
312 "require strong key",
313 server_netbios_domain,
314 require_strong_key);
317 * allow overwrite per domain
318 * client schannel:<netbios_domain>
320 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
321 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
322 "client schannel",
323 server_netbios_domain,
324 require_sign_or_seal);
327 * allow overwrite per domain
328 * winbind sealed pipes:<netbios_domain>
330 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
331 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
332 "winbind sealed pipes",
333 server_netbios_domain,
334 seal_secure_channel);
337 * allow overwrite per domain
338 * neutralize nt4 emulation:<netbios_domain>
340 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
341 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
342 "neutralize nt4 emulation",
343 server_netbios_domain,
344 neutralize_nt4_emulation);
346 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
347 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
349 switch (type) {
350 case SEC_CHAN_WKSTA:
351 if (lpcfg_security(lp_ctx) == SEC_ADS) {
353 * AD domains should be secure
355 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
356 require_sign_or_seal = true;
357 require_strong_key = true;
359 break;
361 case SEC_CHAN_DOMAIN:
362 break;
364 case SEC_CHAN_DNS_DOMAIN:
366 * AD domains should be secure
368 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
369 require_sign_or_seal = true;
370 require_strong_key = true;
371 neutralize_nt4_emulation = true;
372 break;
374 case SEC_CHAN_BDC:
375 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
376 require_sign_or_seal = true;
377 require_strong_key = true;
378 break;
380 case SEC_CHAN_RODC:
381 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
382 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
383 require_sign_or_seal = true;
384 require_strong_key = true;
385 neutralize_nt4_emulation = true;
386 break;
388 default:
389 TALLOC_FREE(frame);
390 return NT_STATUS_INVALID_PARAMETER;
393 if (neutralize_nt4_emulation) {
394 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
397 if (require_sign_or_seal) {
398 required_flags |= NETLOGON_NEG_ARCFOUR;
399 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
400 } else {
401 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
404 if (reject_md5_servers) {
405 required_flags |= NETLOGON_NEG_ARCFOUR;
406 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
407 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
408 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
411 if (require_strong_key) {
412 required_flags |= NETLOGON_NEG_ARCFOUR;
413 required_flags |= NETLOGON_NEG_STRONG_KEYS;
414 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
417 proposed_flags |= required_flags;
419 if (seal_secure_channel) {
420 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
421 } else {
422 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
425 status = netlogon_creds_cli_context_common(client_computer,
426 client_account,
427 type,
428 auth_level,
429 proposed_flags,
430 required_flags,
431 server_computer,
432 server_netbios_domain,
434 mem_ctx,
435 &context);
436 if (!NT_STATUS_IS_OK(status)) {
437 TALLOC_FREE(frame);
438 return status;
441 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
442 if (context->db.g_ctx == NULL) {
443 TALLOC_FREE(context);
444 TALLOC_FREE(frame);
445 return NT_STATUS_NO_MEMORY;
448 status = netlogon_creds_cli_open_global_db(lp_ctx);
449 if (!NT_STATUS_IS_OK(status)) {
450 TALLOC_FREE(context);
451 TALLOC_FREE(frame);
452 return NT_STATUS_NO_MEMORY;
455 context->db.ctx = netlogon_creds_cli_global_db;
456 *_context = context;
457 TALLOC_FREE(frame);
458 return NT_STATUS_OK;
461 NTSTATUS netlogon_creds_bind_cli_credentials(
462 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
463 struct cli_credentials **pcli_creds)
465 struct cli_credentials *cli_creds;
466 struct netlogon_creds_CredentialState *ncreds;
467 NTSTATUS status;
469 cli_creds = cli_credentials_init(mem_ctx);
470 if (cli_creds == NULL) {
471 return NT_STATUS_NO_MEMORY;
473 cli_credentials_set_secure_channel_type(cli_creds,
474 context->client.type);
475 cli_credentials_set_username(cli_creds, context->client.account,
476 CRED_SPECIFIED);
477 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
478 CRED_SPECIFIED);
479 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
480 CRED_SPECIFIED);
482 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
483 if (!NT_STATUS_IS_OK(status)) {
484 TALLOC_FREE(cli_creds);
485 return status;
487 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
489 *pcli_creds = cli_creds;
490 return NT_STATUS_OK;
493 char *netlogon_creds_cli_debug_string(
494 const struct netlogon_creds_cli_context *context,
495 TALLOC_CTX *mem_ctx)
497 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
498 context->db.key_name);
501 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
502 struct netlogon_creds_cli_context *context)
504 return context->client.auth_level;
507 struct netlogon_creds_cli_fetch_state {
508 TALLOC_CTX *mem_ctx;
509 struct netlogon_creds_CredentialState *creds;
510 uint32_t required_flags;
511 NTSTATUS status;
514 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
515 void *private_data)
517 struct netlogon_creds_cli_fetch_state *state =
518 (struct netlogon_creds_cli_fetch_state *)private_data;
519 enum ndr_err_code ndr_err;
520 DATA_BLOB blob;
521 uint32_t tmp_flags;
523 state->creds = talloc_zero(state->mem_ctx,
524 struct netlogon_creds_CredentialState);
525 if (state->creds == NULL) {
526 state->status = NT_STATUS_NO_MEMORY;
527 return;
530 blob.data = data.dptr;
531 blob.length = data.dsize;
533 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
534 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
535 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
536 TALLOC_FREE(state->creds);
537 state->status = ndr_map_error2ntstatus(ndr_err);
538 return;
541 if (DEBUGLEVEL >= 10) {
542 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
545 tmp_flags = state->creds->negotiate_flags;
546 tmp_flags &= state->required_flags;
547 if (tmp_flags != state->required_flags) {
548 TALLOC_FREE(state->creds);
549 state->status = NT_STATUS_DOWNGRADE_DETECTED;
550 return;
553 state->status = NT_STATUS_OK;
556 static NTSTATUS netlogon_creds_cli_get_internal(
557 struct netlogon_creds_cli_context *context,
558 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
560 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
561 TALLOC_CTX *mem_ctx,
562 struct netlogon_creds_CredentialState **_creds)
564 NTSTATUS status;
565 struct netlogon_creds_CredentialState *creds;
567 *_creds = NULL;
569 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
570 if (!NT_STATUS_IS_OK(status)) {
571 return status;
575 * mark it as invalid for step operations.
577 creds->sequence = 0;
578 creds->seed = (struct netr_Credential) {{0}};
579 creds->client = (struct netr_Credential) {{0}};
580 creds->server = (struct netr_Credential) {{0}};
582 *_creds = creds;
583 return NT_STATUS_OK;
586 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
587 const struct netlogon_creds_CredentialState *creds1)
589 TALLOC_CTX *frame = talloc_stackframe();
590 struct netlogon_creds_CredentialState *creds2;
591 DATA_BLOB blob1;
592 DATA_BLOB blob2;
593 NTSTATUS status;
594 enum ndr_err_code ndr_err;
595 int cmp;
597 status = netlogon_creds_cli_get(context, frame, &creds2);
598 if (!NT_STATUS_IS_OK(status)) {
599 TALLOC_FREE(frame);
600 return false;
603 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
604 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
605 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
606 TALLOC_FREE(frame);
607 return false;
610 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
611 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
612 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
613 TALLOC_FREE(frame);
614 return false;
617 cmp = data_blob_cmp(&blob1, &blob2);
619 TALLOC_FREE(frame);
621 return (cmp == 0);
624 static NTSTATUS netlogon_creds_cli_store_internal(
625 struct netlogon_creds_cli_context *context,
626 struct netlogon_creds_CredentialState *creds)
628 NTSTATUS status;
629 enum ndr_err_code ndr_err;
630 DATA_BLOB blob;
631 TDB_DATA data;
633 if (DEBUGLEVEL >= 10) {
634 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
637 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
638 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
639 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
640 status = ndr_map_error2ntstatus(ndr_err);
641 return status;
644 data.dptr = blob.data;
645 data.dsize = blob.length;
647 status = dbwrap_store(context->db.ctx,
648 context->db.key_data,
649 data, TDB_REPLACE);
650 TALLOC_FREE(data.dptr);
651 if (!NT_STATUS_IS_OK(status)) {
652 return status;
655 return NT_STATUS_OK;
658 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
659 struct netlogon_creds_CredentialState *creds)
661 NTSTATUS status;
663 if (context->db.locked_state == NULL) {
665 * this was not the result of netlogon_creds_cli_lock*()
667 return NT_STATUS_INVALID_PAGE_PROTECTION;
670 if (context->db.locked_state->creds != creds) {
672 * this was not the result of netlogon_creds_cli_lock*()
674 return NT_STATUS_INVALID_PAGE_PROTECTION;
677 status = netlogon_creds_cli_store_internal(context, creds);
678 return status;
681 static NTSTATUS netlogon_creds_cli_delete_internal(
682 struct netlogon_creds_cli_context *context)
684 NTSTATUS status;
685 status = dbwrap_delete(context->db.ctx, context->db.key_data);
686 return status;
689 NTSTATUS netlogon_creds_cli_delete_lck(
690 struct netlogon_creds_cli_context *context)
692 NTSTATUS status;
694 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
695 return NT_STATUS_NOT_LOCKED;
698 status = netlogon_creds_cli_delete_internal(context);
699 return status;
702 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
703 struct netlogon_creds_CredentialState *creds)
705 NTSTATUS status;
707 if (context->db.locked_state == NULL) {
709 * this was not the result of netlogon_creds_cli_lock*()
711 return NT_STATUS_INVALID_PAGE_PROTECTION;
714 if (context->db.locked_state->creds != creds) {
716 * this was not the result of netlogon_creds_cli_lock*()
718 return NT_STATUS_INVALID_PAGE_PROTECTION;
721 status = netlogon_creds_cli_delete_internal(context);
722 return status;
725 struct netlogon_creds_cli_lock_state {
726 struct netlogon_creds_cli_locked_state *locked_state;
727 struct netlogon_creds_CredentialState *creds;
730 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
732 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
733 struct tevent_context *ev,
734 struct netlogon_creds_cli_context *context)
736 struct tevent_req *req;
737 struct netlogon_creds_cli_lock_state *state;
738 struct netlogon_creds_cli_locked_state *locked_state;
739 struct tevent_req *subreq;
741 req = tevent_req_create(mem_ctx, &state,
742 struct netlogon_creds_cli_lock_state);
743 if (req == NULL) {
744 return NULL;
747 if (context->db.locked_state != NULL) {
748 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
749 return tevent_req_post(req, ev);
752 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
753 if (tevent_req_nomem(locked_state, req)) {
754 return tevent_req_post(req, ev);
756 talloc_set_destructor(locked_state,
757 netlogon_creds_cli_locked_state_destructor);
758 locked_state->context = context;
760 context->db.locked_state = locked_state;
761 state->locked_state = locked_state;
763 if (context->db.g_ctx == NULL) {
764 NTSTATUS status;
766 status = netlogon_creds_cli_get_internal(
767 context, state, &state->creds);
768 if (tevent_req_nterror(req, status)) {
769 return tevent_req_post(req, ev);
772 return req;
775 subreq = g_lock_lock_send(state, ev,
776 context->db.g_ctx,
777 string_term_tdb_data(context->db.key_name),
778 G_LOCK_WRITE);
779 if (tevent_req_nomem(subreq, req)) {
780 return tevent_req_post(req, ev);
782 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
784 return req;
787 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
789 struct tevent_req *req =
790 tevent_req_callback_data(subreq,
791 struct tevent_req);
792 struct netlogon_creds_cli_lock_state *state =
793 tevent_req_data(req,
794 struct netlogon_creds_cli_lock_state);
795 NTSTATUS status;
797 status = g_lock_lock_recv(subreq);
798 TALLOC_FREE(subreq);
799 if (tevent_req_nterror(req, status)) {
800 return;
802 state->locked_state->is_glocked = true;
804 status = netlogon_creds_cli_get_internal(state->locked_state->context,
805 state, &state->creds);
806 if (tevent_req_nterror(req, status)) {
807 return;
809 tevent_req_done(req);
812 static NTSTATUS netlogon_creds_cli_get_internal(
813 struct netlogon_creds_cli_context *context,
814 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
816 struct netlogon_creds_cli_fetch_state fstate = {
817 .status = NT_STATUS_INTERNAL_ERROR,
818 .required_flags = context->client.required_flags,
820 NTSTATUS status;
822 fstate.mem_ctx = mem_ctx;
823 status = dbwrap_parse_record(context->db.ctx,
824 context->db.key_data,
825 netlogon_creds_cli_fetch_parser,
826 &fstate);
827 if (!NT_STATUS_IS_OK(status)) {
828 return status;
830 if (!NT_STATUS_IS_OK(fstate.status)) {
831 return fstate.status;
834 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
835 *pcreds = fstate.creds;
836 return NT_STATUS_OK;
840 * It is really important to try SamLogonEx here,
841 * because multiple processes can talk to the same
842 * domain controller, without using the credential
843 * chain.
845 * With a normal SamLogon call, we must keep the
846 * credentials chain updated and intact between all
847 * users of the machine account (which would imply
848 * cross-node communication for every NTLM logon).
850 * The credentials chain is not per NETLOGON pipe
851 * connection, but globally on the server/client pair
852 * by computer name.
854 * It's also important to use NetlogonValidationSamInfo4 (6),
855 * because it relies on the rpc transport encryption
856 * and avoids using the global netlogon schannel
857 * session key to en/decrypt secret information
858 * like the user_session_key for network logons.
860 * [MS-APDS] 3.1.5.2 NTLM Network Logon
861 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
862 * NETLOGON_NEG_AUTHENTICATED_RPC set together
863 * are the indication that the server supports
864 * NetlogonValidationSamInfo4 (6). And it must only
865 * be used if "SealSecureChannel" is used.
867 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
868 * check is done in netlogon_creds_cli_LogonSamLogon*().
871 context->server.cached_flags = fstate.creds->negotiate_flags;
872 context->server.try_validation6 = true;
873 context->server.try_logon_ex = true;
874 context->server.try_logon_with = true;
876 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
877 context->server.try_validation6 = false;
878 context->server.try_logon_ex = false;
880 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
881 context->server.try_validation6 = false;
884 *pcreds = fstate.creds;
885 return NT_STATUS_OK;
888 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
889 TALLOC_CTX *mem_ctx,
890 struct netlogon_creds_CredentialState **creds)
892 struct netlogon_creds_cli_lock_state *state =
893 tevent_req_data(req,
894 struct netlogon_creds_cli_lock_state);
895 NTSTATUS status;
897 if (tevent_req_is_nterror(req, &status)) {
898 tevent_req_received(req);
899 return status;
902 talloc_steal(state->creds, state->locked_state);
903 state->locked_state->creds = state->creds;
904 *creds = talloc_move(mem_ctx, &state->creds);
905 tevent_req_received(req);
906 return NT_STATUS_OK;
909 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
910 TALLOC_CTX *mem_ctx,
911 struct netlogon_creds_CredentialState **creds)
913 TALLOC_CTX *frame = talloc_stackframe();
914 struct tevent_context *ev;
915 struct tevent_req *req;
916 NTSTATUS status = NT_STATUS_NO_MEMORY;
918 ev = samba_tevent_context_init(frame);
919 if (ev == NULL) {
920 goto fail;
922 req = netlogon_creds_cli_lock_send(frame, ev, context);
923 if (req == NULL) {
924 goto fail;
926 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
927 goto fail;
929 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
930 fail:
931 TALLOC_FREE(frame);
932 return status;
935 struct netlogon_creds_cli_lck {
936 struct netlogon_creds_cli_context *context;
939 struct netlogon_creds_cli_lck_state {
940 struct netlogon_creds_cli_lck *lck;
941 enum netlogon_creds_cli_lck_type type;
944 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
945 static int netlogon_creds_cli_lck_destructor(
946 struct netlogon_creds_cli_lck *lck);
948 struct tevent_req *netlogon_creds_cli_lck_send(
949 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
950 struct netlogon_creds_cli_context *context,
951 enum netlogon_creds_cli_lck_type type)
953 struct tevent_req *req, *subreq;
954 struct netlogon_creds_cli_lck_state *state;
955 enum g_lock_type gtype;
957 req = tevent_req_create(mem_ctx, &state,
958 struct netlogon_creds_cli_lck_state);
959 if (req == NULL) {
960 return NULL;
963 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
964 DBG_DEBUG("context already locked\n");
965 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
966 return tevent_req_post(req, ev);
969 switch (type) {
970 case NETLOGON_CREDS_CLI_LCK_SHARED:
971 gtype = G_LOCK_READ;
972 break;
973 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
974 gtype = G_LOCK_WRITE;
975 break;
976 default:
977 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
978 return tevent_req_post(req, ev);
981 state->lck = talloc(state, struct netlogon_creds_cli_lck);
982 if (tevent_req_nomem(state->lck, req)) {
983 return tevent_req_post(req, ev);
985 state->lck->context = context;
986 state->type = type;
988 subreq = g_lock_lock_send(state, ev,
989 context->db.g_ctx,
990 string_term_tdb_data(context->db.key_name),
991 gtype);
992 if (tevent_req_nomem(subreq, req)) {
993 return tevent_req_post(req, ev);
995 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
997 return req;
1000 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
1002 struct tevent_req *req = tevent_req_callback_data(
1003 subreq, struct tevent_req);
1004 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1005 req, struct netlogon_creds_cli_lck_state);
1006 NTSTATUS status;
1008 status = g_lock_lock_recv(subreq);
1009 TALLOC_FREE(subreq);
1010 if (tevent_req_nterror(req, status)) {
1011 return;
1014 state->lck->context->db.lock = state->type;
1015 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1017 tevent_req_done(req);
1020 static int netlogon_creds_cli_lck_destructor(
1021 struct netlogon_creds_cli_lck *lck)
1023 struct netlogon_creds_cli_context *ctx = lck->context;
1024 NTSTATUS status;
1026 status = g_lock_unlock(ctx->db.g_ctx,
1027 string_term_tdb_data(ctx->db.key_name));
1028 if (!NT_STATUS_IS_OK(status)) {
1029 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1030 smb_panic("g_lock_unlock failed");
1032 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1033 return 0;
1036 NTSTATUS netlogon_creds_cli_lck_recv(
1037 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1038 struct netlogon_creds_cli_lck **lck)
1040 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1041 req, struct netlogon_creds_cli_lck_state);
1042 NTSTATUS status;
1044 if (tevent_req_is_nterror(req, &status)) {
1045 return status;
1047 *lck = talloc_move(mem_ctx, &state->lck);
1048 return NT_STATUS_OK;
1051 NTSTATUS netlogon_creds_cli_lck(
1052 struct netlogon_creds_cli_context *context,
1053 enum netlogon_creds_cli_lck_type type,
1054 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1056 TALLOC_CTX *frame = talloc_stackframe();
1057 struct tevent_context *ev;
1058 struct tevent_req *req;
1059 NTSTATUS status = NT_STATUS_NO_MEMORY;
1061 ev = samba_tevent_context_init(frame);
1062 if (ev == NULL) {
1063 goto fail;
1065 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1066 if (req == NULL) {
1067 goto fail;
1069 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1070 goto fail;
1072 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1073 fail:
1074 TALLOC_FREE(frame);
1075 return status;
1078 struct netlogon_creds_cli_auth_state {
1079 struct tevent_context *ev;
1080 struct netlogon_creds_cli_context *context;
1081 struct dcerpc_binding_handle *binding_handle;
1082 uint8_t num_nt_hashes;
1083 uint8_t idx_nt_hashes;
1084 const struct samr_Password * const *nt_hashes;
1085 const struct samr_Password *used_nt_hash;
1086 char *srv_name_slash;
1087 uint32_t current_flags;
1088 struct netr_Credential client_challenge;
1089 struct netr_Credential server_challenge;
1090 struct netlogon_creds_CredentialState *creds;
1091 struct netr_Credential client_credential;
1092 struct netr_Credential server_credential;
1093 uint32_t rid;
1094 bool try_auth3;
1095 bool try_auth2;
1096 bool require_auth2;
1099 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1101 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1102 struct tevent_context *ev,
1103 struct netlogon_creds_cli_context *context,
1104 struct dcerpc_binding_handle *b,
1105 uint8_t num_nt_hashes,
1106 const struct samr_Password * const *nt_hashes)
1108 struct tevent_req *req;
1109 struct netlogon_creds_cli_auth_state *state;
1110 NTSTATUS status;
1112 req = tevent_req_create(mem_ctx, &state,
1113 struct netlogon_creds_cli_auth_state);
1114 if (req == NULL) {
1115 return NULL;
1118 state->ev = ev;
1119 state->context = context;
1120 state->binding_handle = b;
1121 if (num_nt_hashes < 1) {
1122 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1123 return tevent_req_post(req, ev);
1125 if (num_nt_hashes > 4) {
1126 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1127 return tevent_req_post(req, ev);
1130 state->num_nt_hashes = num_nt_hashes;
1131 state->idx_nt_hashes = 0;
1132 state->nt_hashes = nt_hashes;
1134 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1135 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1136 return tevent_req_post(req, ev);
1139 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1140 context->server.computer);
1141 if (tevent_req_nomem(state->srv_name_slash, req)) {
1142 return tevent_req_post(req, ev);
1145 state->try_auth3 = true;
1146 state->try_auth2 = true;
1148 if (context->client.required_flags != 0) {
1149 state->require_auth2 = true;
1152 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1153 state->current_flags = context->client.proposed_flags;
1155 status = dbwrap_purge(state->context->db.ctx,
1156 state->context->db.key_data);
1157 if (tevent_req_nterror(req, status)) {
1158 return tevent_req_post(req, ev);
1161 netlogon_creds_cli_auth_challenge_start(req);
1162 if (!tevent_req_is_in_progress(req)) {
1163 return tevent_req_post(req, ev);
1166 return req;
1169 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1171 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1173 struct netlogon_creds_cli_auth_state *state =
1174 tevent_req_data(req,
1175 struct netlogon_creds_cli_auth_state);
1176 struct tevent_req *subreq;
1178 TALLOC_FREE(state->creds);
1180 generate_random_buffer(state->client_challenge.data,
1181 sizeof(state->client_challenge.data));
1183 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1184 state->binding_handle,
1185 state->srv_name_slash,
1186 state->context->client.computer,
1187 &state->client_challenge,
1188 &state->server_challenge);
1189 if (tevent_req_nomem(subreq, req)) {
1190 return;
1192 tevent_req_set_callback(subreq,
1193 netlogon_creds_cli_auth_challenge_done,
1194 req);
1197 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1199 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1201 struct tevent_req *req =
1202 tevent_req_callback_data(subreq,
1203 struct tevent_req);
1204 struct netlogon_creds_cli_auth_state *state =
1205 tevent_req_data(req,
1206 struct netlogon_creds_cli_auth_state);
1207 NTSTATUS status;
1208 NTSTATUS result;
1210 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1211 TALLOC_FREE(subreq);
1212 if (tevent_req_nterror(req, status)) {
1213 return;
1215 if (tevent_req_nterror(req, result)) {
1216 return;
1219 if (!state->try_auth3 && !state->try_auth2) {
1220 state->current_flags = 0;
1223 /* Calculate the session key and client credentials */
1225 state->creds = netlogon_creds_client_init(state,
1226 state->context->client.account,
1227 state->context->client.computer,
1228 state->context->client.type,
1229 &state->client_challenge,
1230 &state->server_challenge,
1231 state->used_nt_hash,
1232 &state->client_credential,
1233 state->current_flags);
1234 if (tevent_req_nomem(state->creds, req)) {
1235 return;
1238 if (state->try_auth3) {
1239 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1240 state->binding_handle,
1241 state->srv_name_slash,
1242 state->context->client.account,
1243 state->context->client.type,
1244 state->context->client.computer,
1245 &state->client_credential,
1246 &state->server_credential,
1247 &state->creds->negotiate_flags,
1248 &state->rid);
1249 if (tevent_req_nomem(subreq, req)) {
1250 return;
1252 } else if (state->try_auth2) {
1253 state->rid = 0;
1255 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1256 state->binding_handle,
1257 state->srv_name_slash,
1258 state->context->client.account,
1259 state->context->client.type,
1260 state->context->client.computer,
1261 &state->client_credential,
1262 &state->server_credential,
1263 &state->creds->negotiate_flags);
1264 if (tevent_req_nomem(subreq, req)) {
1265 return;
1267 } else {
1268 state->rid = 0;
1270 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1271 state->binding_handle,
1272 state->srv_name_slash,
1273 state->context->client.account,
1274 state->context->client.type,
1275 state->context->client.computer,
1276 &state->client_credential,
1277 &state->server_credential);
1278 if (tevent_req_nomem(subreq, req)) {
1279 return;
1282 tevent_req_set_callback(subreq,
1283 netlogon_creds_cli_auth_srvauth_done,
1284 req);
1287 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1289 struct tevent_req *req =
1290 tevent_req_callback_data(subreq,
1291 struct tevent_req);
1292 struct netlogon_creds_cli_auth_state *state =
1293 tevent_req_data(req,
1294 struct netlogon_creds_cli_auth_state);
1295 NTSTATUS status;
1296 NTSTATUS result;
1297 bool ok;
1298 enum ndr_err_code ndr_err;
1299 DATA_BLOB blob;
1300 TDB_DATA data;
1301 uint32_t tmp_flags;
1303 if (state->try_auth3) {
1304 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1305 &result);
1306 TALLOC_FREE(subreq);
1307 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1308 state->try_auth3 = false;
1309 netlogon_creds_cli_auth_challenge_start(req);
1310 return;
1312 if (tevent_req_nterror(req, status)) {
1313 return;
1315 } else if (state->try_auth2) {
1316 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1317 &result);
1318 TALLOC_FREE(subreq);
1319 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1320 state->try_auth2 = false;
1321 if (state->require_auth2) {
1322 status = NT_STATUS_DOWNGRADE_DETECTED;
1323 tevent_req_nterror(req, status);
1324 return;
1326 netlogon_creds_cli_auth_challenge_start(req);
1327 return;
1329 if (tevent_req_nterror(req, status)) {
1330 return;
1332 } else {
1333 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1334 &result);
1335 TALLOC_FREE(subreq);
1336 if (tevent_req_nterror(req, status)) {
1337 return;
1341 if (!NT_STATUS_IS_OK(result) &&
1342 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1344 tevent_req_nterror(req, result);
1345 return;
1348 tmp_flags = state->creds->negotiate_flags;
1349 tmp_flags &= state->context->client.required_flags;
1350 if (tmp_flags != state->context->client.required_flags) {
1351 if (NT_STATUS_IS_OK(result)) {
1352 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1353 return;
1355 tevent_req_nterror(req, result);
1356 return;
1359 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1361 tmp_flags = state->context->client.proposed_flags;
1362 if ((state->current_flags == tmp_flags) &&
1363 (state->creds->negotiate_flags != tmp_flags))
1366 * lets retry with the negotiated flags
1368 state->current_flags = state->creds->negotiate_flags;
1369 netlogon_creds_cli_auth_challenge_start(req);
1370 return;
1373 state->idx_nt_hashes += 1;
1374 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1376 * we already retried, giving up...
1378 tevent_req_nterror(req, result);
1379 return;
1383 * lets retry with the old nt hash.
1385 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1386 state->current_flags = state->context->client.proposed_flags;
1387 netlogon_creds_cli_auth_challenge_start(req);
1388 return;
1391 ok = netlogon_creds_client_check(state->creds,
1392 &state->server_credential);
1393 if (!ok) {
1394 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1395 return;
1398 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1399 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1400 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1401 status = ndr_map_error2ntstatus(ndr_err);
1402 tevent_req_nterror(req, status);
1403 return;
1406 data.dptr = blob.data;
1407 data.dsize = blob.length;
1409 status = dbwrap_store(state->context->db.ctx,
1410 state->context->db.key_data,
1411 data, TDB_REPLACE);
1412 if (tevent_req_nterror(req, status)) {
1413 return;
1416 tevent_req_done(req);
1419 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1420 uint8_t *idx_nt_hashes)
1422 struct netlogon_creds_cli_auth_state *state =
1423 tevent_req_data(req,
1424 struct netlogon_creds_cli_auth_state);
1425 NTSTATUS status;
1427 *idx_nt_hashes = 0;
1429 if (tevent_req_is_nterror(req, &status)) {
1430 tevent_req_received(req);
1431 return status;
1434 *idx_nt_hashes = state->idx_nt_hashes;
1435 tevent_req_received(req);
1436 return NT_STATUS_OK;
1439 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1440 struct dcerpc_binding_handle *b,
1441 uint8_t num_nt_hashes,
1442 const struct samr_Password * const *nt_hashes,
1443 uint8_t *idx_nt_hashes)
1445 TALLOC_CTX *frame = talloc_stackframe();
1446 struct tevent_context *ev;
1447 struct tevent_req *req;
1448 NTSTATUS status = NT_STATUS_NO_MEMORY;
1450 *idx_nt_hashes = 0;
1452 ev = samba_tevent_context_init(frame);
1453 if (ev == NULL) {
1454 goto fail;
1456 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1457 num_nt_hashes, nt_hashes);
1458 if (req == NULL) {
1459 goto fail;
1461 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1462 goto fail;
1464 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1465 fail:
1466 TALLOC_FREE(frame);
1467 return status;
1470 struct netlogon_creds_cli_check_state {
1471 struct tevent_context *ev;
1472 struct netlogon_creds_cli_context *context;
1473 struct dcerpc_binding_handle *binding_handle;
1475 char *srv_name_slash;
1477 union netr_Capabilities caps;
1479 struct netlogon_creds_CredentialState *creds;
1480 struct netr_Authenticator req_auth;
1481 struct netr_Authenticator rep_auth;
1484 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1485 NTSTATUS status);
1486 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1488 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1489 struct tevent_context *ev,
1490 struct netlogon_creds_cli_context *context,
1491 struct dcerpc_binding_handle *b)
1493 struct tevent_req *req;
1494 struct netlogon_creds_cli_check_state *state;
1495 struct tevent_req *subreq;
1496 enum dcerpc_AuthType auth_type;
1497 enum dcerpc_AuthLevel auth_level;
1498 NTSTATUS status;
1500 req = tevent_req_create(mem_ctx, &state,
1501 struct netlogon_creds_cli_check_state);
1502 if (req == NULL) {
1503 return NULL;
1506 state->ev = ev;
1507 state->context = context;
1508 state->binding_handle = b;
1510 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1511 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1512 return tevent_req_post(req, ev);
1515 status = netlogon_creds_cli_get_internal(context, state,
1516 &state->creds);
1517 if (tevent_req_nterror(req, status)) {
1518 return tevent_req_post(req, ev);
1521 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1522 context->server.computer);
1523 if (tevent_req_nomem(state->srv_name_slash, req)) {
1524 return tevent_req_post(req, ev);
1527 dcerpc_binding_handle_auth_info(state->binding_handle,
1528 &auth_type, &auth_level);
1530 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1531 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1532 return tevent_req_post(req, ev);
1535 switch (auth_level) {
1536 case DCERPC_AUTH_LEVEL_INTEGRITY:
1537 case DCERPC_AUTH_LEVEL_PRIVACY:
1538 break;
1539 default:
1540 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1541 return tevent_req_post(req, ev);
1545 * we defer all callbacks in order to cleanup
1546 * the database record.
1548 tevent_req_defer_callback(req, state->ev);
1550 netlogon_creds_client_authenticator(state->creds, &state->req_auth);
1551 ZERO_STRUCT(state->rep_auth);
1553 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1554 state->binding_handle,
1555 state->srv_name_slash,
1556 state->context->client.computer,
1557 &state->req_auth,
1558 &state->rep_auth,
1560 &state->caps);
1561 if (tevent_req_nomem(subreq, req)) {
1562 return tevent_req_post(req, ev);
1565 tevent_req_set_callback(subreq,
1566 netlogon_creds_cli_check_caps,
1567 req);
1569 return req;
1572 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1573 NTSTATUS status)
1575 struct netlogon_creds_cli_check_state *state =
1576 tevent_req_data(req,
1577 struct netlogon_creds_cli_check_state);
1579 if (state->creds == NULL) {
1580 return;
1583 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1584 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1585 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1586 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1587 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1588 TALLOC_FREE(state->creds);
1589 return;
1592 netlogon_creds_cli_delete_lck(state->context);
1593 TALLOC_FREE(state->creds);
1596 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1598 struct tevent_req *req =
1599 tevent_req_callback_data(subreq,
1600 struct tevent_req);
1601 struct netlogon_creds_cli_check_state *state =
1602 tevent_req_data(req,
1603 struct netlogon_creds_cli_check_state);
1604 NTSTATUS status;
1605 NTSTATUS result;
1606 bool ok;
1608 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1609 &result);
1610 TALLOC_FREE(subreq);
1611 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1613 * Note that the negotiated flags are already checked
1614 * for our required flags after the ServerAuthenticate3/2 call.
1616 uint32_t negotiated = state->creds->negotiate_flags;
1618 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1620 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1621 * already, we expect this to work!
1623 status = NT_STATUS_DOWNGRADE_DETECTED;
1624 tevent_req_nterror(req, status);
1625 netlogon_creds_cli_check_cleanup(req, status);
1626 return;
1629 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1631 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1632 * we expect this to work at least as far as the
1633 * NOT_SUPPORTED error handled below!
1635 * NT 4.0 and Old Samba servers are not
1636 * allowed without "require strong key = no"
1638 status = NT_STATUS_DOWNGRADE_DETECTED;
1639 tevent_req_nterror(req, status);
1640 netlogon_creds_cli_check_cleanup(req, status);
1641 return;
1645 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1646 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1647 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1649 * This is needed against NT 4.0 and old Samba servers.
1651 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1652 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1653 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1654 * with the next request as the sequence number processing
1655 * gets out of sync.
1657 netlogon_creds_cli_check_cleanup(req, status);
1658 tevent_req_done(req);
1659 return;
1661 if (tevent_req_nterror(req, status)) {
1662 netlogon_creds_cli_check_cleanup(req, status);
1663 return;
1666 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1668 * Note that the negotiated flags are already checked
1669 * for our required flags after the ServerAuthenticate3/2 call.
1671 uint32_t negotiated = state->creds->negotiate_flags;
1673 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1675 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1676 * already, we expect this to work!
1678 status = NT_STATUS_DOWNGRADE_DETECTED;
1679 tevent_req_nterror(req, status);
1680 netlogon_creds_cli_check_cleanup(req, status);
1681 return;
1685 * This is ok, the server does not support
1686 * NETLOGON_NEG_SUPPORTS_AES.
1688 * netr_LogonGetCapabilities() was
1689 * netr_LogonDummyRoutine1() before
1690 * NETLOGON_NEG_SUPPORTS_AES was invented.
1692 netlogon_creds_cli_check_cleanup(req, result);
1693 tevent_req_done(req);
1694 return;
1697 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1698 if (!ok) {
1699 status = NT_STATUS_ACCESS_DENIED;
1700 tevent_req_nterror(req, status);
1701 netlogon_creds_cli_check_cleanup(req, status);
1702 return;
1705 if (tevent_req_nterror(req, result)) {
1706 netlogon_creds_cli_check_cleanup(req, result);
1707 return;
1710 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1711 status = NT_STATUS_DOWNGRADE_DETECTED;
1712 tevent_req_nterror(req, status);
1713 netlogon_creds_cli_check_cleanup(req, status);
1714 return;
1718 * This is the key check that makes this check secure. If we
1719 * get OK here (rather than NOT_SUPPORTED), then the server
1720 * did support AES. If the server only proposed STRONG_KEYS
1721 * and not AES, then it should have failed with
1722 * NOT_IMPLEMENTED. We always send AES as a client, so the
1723 * server should always have returned it.
1725 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1726 status = NT_STATUS_DOWNGRADE_DETECTED;
1727 tevent_req_nterror(req, status);
1728 netlogon_creds_cli_check_cleanup(req, status);
1729 return;
1732 status = netlogon_creds_cli_store_internal(state->context,
1733 state->creds);
1734 if (tevent_req_nterror(req, status)) {
1735 return;
1738 tevent_req_done(req);
1741 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1742 union netr_Capabilities *capabilities)
1744 struct netlogon_creds_cli_check_state *state = tevent_req_data(
1745 req, struct netlogon_creds_cli_check_state);
1746 NTSTATUS status;
1748 if (tevent_req_is_nterror(req, &status)) {
1749 netlogon_creds_cli_check_cleanup(req, status);
1750 tevent_req_received(req);
1751 return status;
1754 if (capabilities != NULL) {
1755 *capabilities = state->caps;
1758 tevent_req_received(req);
1759 return NT_STATUS_OK;
1762 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1763 struct dcerpc_binding_handle *b,
1764 union netr_Capabilities *capabilities)
1766 TALLOC_CTX *frame = talloc_stackframe();
1767 struct tevent_context *ev;
1768 struct tevent_req *req;
1769 NTSTATUS status = NT_STATUS_NO_MEMORY;
1771 ev = samba_tevent_context_init(frame);
1772 if (ev == NULL) {
1773 goto fail;
1775 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1776 if (req == NULL) {
1777 goto fail;
1779 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1780 goto fail;
1782 status = netlogon_creds_cli_check_recv(req, capabilities);
1783 fail:
1784 TALLOC_FREE(frame);
1785 return status;
1788 struct netlogon_creds_cli_ServerPasswordSet_state {
1789 struct tevent_context *ev;
1790 struct netlogon_creds_cli_context *context;
1791 struct dcerpc_binding_handle *binding_handle;
1792 uint32_t old_timeout;
1794 char *srv_name_slash;
1795 enum dcerpc_AuthType auth_type;
1796 enum dcerpc_AuthLevel auth_level;
1798 struct samr_CryptPassword samr_crypt_password;
1799 struct netr_CryptPassword netr_crypt_password;
1800 struct samr_Password samr_password;
1802 struct netlogon_creds_CredentialState *creds;
1803 struct netlogon_creds_CredentialState tmp_creds;
1804 struct netr_Authenticator req_auth;
1805 struct netr_Authenticator rep_auth;
1808 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1809 NTSTATUS status);
1810 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1812 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1813 struct tevent_context *ev,
1814 struct netlogon_creds_cli_context *context,
1815 struct dcerpc_binding_handle *b,
1816 const DATA_BLOB *new_password,
1817 const uint32_t *new_version)
1819 struct tevent_req *req;
1820 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1821 struct tevent_req *subreq;
1822 bool ok;
1824 req = tevent_req_create(mem_ctx, &state,
1825 struct netlogon_creds_cli_ServerPasswordSet_state);
1826 if (req == NULL) {
1827 return NULL;
1830 state->ev = ev;
1831 state->context = context;
1832 state->binding_handle = b;
1834 if (new_password->length < 14) {
1835 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1836 return tevent_req_post(req, ev);
1840 * netr_ServerPasswordSet
1842 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1845 * netr_ServerPasswordSet2
1847 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1848 new_password);
1849 if (!ok) {
1850 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1851 return tevent_req_post(req, ev);
1854 if (new_version != NULL) {
1855 struct NL_PASSWORD_VERSION version;
1856 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1857 uint32_t ofs = 512 - len;
1858 uint8_t *p;
1860 if (len > 500) {
1861 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1862 return tevent_req_post(req, ev);
1864 ofs -= 12;
1866 version.ReservedField = 0;
1867 version.PasswordVersionNumber = *new_version;
1868 version.PasswordVersionPresent =
1869 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1871 p = state->samr_crypt_password.data + ofs;
1872 SIVAL(p, 0, version.ReservedField);
1873 SIVAL(p, 4, version.PasswordVersionNumber);
1874 SIVAL(p, 8, version.PasswordVersionPresent);
1877 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1878 context->server.computer);
1879 if (tevent_req_nomem(state->srv_name_slash, req)) {
1880 return tevent_req_post(req, ev);
1883 dcerpc_binding_handle_auth_info(state->binding_handle,
1884 &state->auth_type,
1885 &state->auth_level);
1887 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1888 state->context);
1889 if (tevent_req_nomem(subreq, req)) {
1890 return tevent_req_post(req, ev);
1893 tevent_req_set_callback(subreq,
1894 netlogon_creds_cli_ServerPasswordSet_locked,
1895 req);
1897 return req;
1900 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1901 NTSTATUS status)
1903 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1904 tevent_req_data(req,
1905 struct netlogon_creds_cli_ServerPasswordSet_state);
1907 if (state->creds == NULL) {
1908 return;
1911 dcerpc_binding_handle_set_timeout(state->binding_handle,
1912 state->old_timeout);
1914 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1915 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1916 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1917 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1918 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1919 TALLOC_FREE(state->creds);
1920 return;
1923 netlogon_creds_cli_delete(state->context, state->creds);
1924 TALLOC_FREE(state->creds);
1927 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1929 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1931 struct tevent_req *req =
1932 tevent_req_callback_data(subreq,
1933 struct tevent_req);
1934 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1935 tevent_req_data(req,
1936 struct netlogon_creds_cli_ServerPasswordSet_state);
1937 NTSTATUS status;
1939 status = netlogon_creds_cli_lock_recv(subreq, state,
1940 &state->creds);
1941 TALLOC_FREE(subreq);
1942 if (tevent_req_nterror(req, status)) {
1943 return;
1946 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1947 switch (state->auth_level) {
1948 case DCERPC_AUTH_LEVEL_INTEGRITY:
1949 case DCERPC_AUTH_LEVEL_PRIVACY:
1950 break;
1951 default:
1952 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1953 return;
1955 } else {
1956 uint32_t tmp = state->creds->negotiate_flags;
1958 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1960 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1961 * it should be used, which means
1962 * we had a chance to verify no downgrade
1963 * happened.
1965 * This relies on netlogon_creds_cli_check*
1966 * being called before, as first request after
1967 * the DCERPC bind.
1969 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1970 return;
1974 state->old_timeout = dcerpc_binding_handle_set_timeout(
1975 state->binding_handle, 600000);
1978 * we defer all callbacks in order to cleanup
1979 * the database record.
1981 tevent_req_defer_callback(req, state->ev);
1983 state->tmp_creds = *state->creds;
1984 netlogon_creds_client_authenticator(&state->tmp_creds,
1985 &state->req_auth);
1986 ZERO_STRUCT(state->rep_auth);
1988 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1990 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1991 netlogon_creds_aes_encrypt(&state->tmp_creds,
1992 state->samr_crypt_password.data,
1993 516);
1994 } else {
1995 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
1996 state->samr_crypt_password.data,
1997 516);
1998 if (tevent_req_nterror(req, status)) {
1999 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2000 return;
2004 memcpy(state->netr_crypt_password.data,
2005 state->samr_crypt_password.data, 512);
2006 state->netr_crypt_password.length =
2007 IVAL(state->samr_crypt_password.data, 512);
2009 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2010 state->binding_handle,
2011 state->srv_name_slash,
2012 state->tmp_creds.account_name,
2013 state->tmp_creds.secure_channel_type,
2014 state->tmp_creds.computer_name,
2015 &state->req_auth,
2016 &state->rep_auth,
2017 &state->netr_crypt_password);
2018 if (tevent_req_nomem(subreq, req)) {
2019 status = NT_STATUS_NO_MEMORY;
2020 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2021 return;
2023 } else {
2024 netlogon_creds_des_encrypt(&state->tmp_creds,
2025 &state->samr_password);
2027 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2028 state->binding_handle,
2029 state->srv_name_slash,
2030 state->tmp_creds.account_name,
2031 state->tmp_creds.secure_channel_type,
2032 state->tmp_creds.computer_name,
2033 &state->req_auth,
2034 &state->rep_auth,
2035 &state->samr_password);
2036 if (tevent_req_nomem(subreq, req)) {
2037 status = NT_STATUS_NO_MEMORY;
2038 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2039 return;
2043 tevent_req_set_callback(subreq,
2044 netlogon_creds_cli_ServerPasswordSet_done,
2045 req);
2048 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2050 struct tevent_req *req =
2051 tevent_req_callback_data(subreq,
2052 struct tevent_req);
2053 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2054 tevent_req_data(req,
2055 struct netlogon_creds_cli_ServerPasswordSet_state);
2056 NTSTATUS status;
2057 NTSTATUS result;
2058 bool ok;
2060 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2061 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2062 &result);
2063 TALLOC_FREE(subreq);
2064 if (tevent_req_nterror(req, status)) {
2065 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2066 return;
2068 } else {
2069 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2070 &result);
2071 TALLOC_FREE(subreq);
2072 if (tevent_req_nterror(req, status)) {
2073 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2074 return;
2078 ok = netlogon_creds_client_check(&state->tmp_creds,
2079 &state->rep_auth.cred);
2080 if (!ok) {
2081 status = NT_STATUS_ACCESS_DENIED;
2082 tevent_req_nterror(req, status);
2083 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2084 return;
2087 if (tevent_req_nterror(req, result)) {
2088 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2089 return;
2092 dcerpc_binding_handle_set_timeout(state->binding_handle,
2093 state->old_timeout);
2095 *state->creds = state->tmp_creds;
2096 status = netlogon_creds_cli_store(state->context,
2097 state->creds);
2098 TALLOC_FREE(state->creds);
2099 if (tevent_req_nterror(req, status)) {
2100 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2101 return;
2104 tevent_req_done(req);
2107 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2109 NTSTATUS status;
2111 if (tevent_req_is_nterror(req, &status)) {
2112 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2113 tevent_req_received(req);
2114 return status;
2117 tevent_req_received(req);
2118 return NT_STATUS_OK;
2121 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2122 struct netlogon_creds_cli_context *context,
2123 struct dcerpc_binding_handle *b,
2124 const DATA_BLOB *new_password,
2125 const uint32_t *new_version)
2127 TALLOC_CTX *frame = talloc_stackframe();
2128 struct tevent_context *ev;
2129 struct tevent_req *req;
2130 NTSTATUS status = NT_STATUS_NO_MEMORY;
2132 ev = samba_tevent_context_init(frame);
2133 if (ev == NULL) {
2134 goto fail;
2136 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2137 new_password,
2138 new_version);
2139 if (req == NULL) {
2140 goto fail;
2142 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2143 goto fail;
2145 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2146 fail:
2147 TALLOC_FREE(frame);
2148 return status;
2151 struct netlogon_creds_cli_LogonSamLogon_state {
2152 struct tevent_context *ev;
2153 struct netlogon_creds_cli_context *context;
2154 struct dcerpc_binding_handle *binding_handle;
2156 char *srv_name_slash;
2158 enum netr_LogonInfoClass logon_level;
2159 const union netr_LogonLevel *const_logon;
2160 union netr_LogonLevel *logon;
2161 uint32_t flags;
2163 uint16_t validation_level;
2164 union netr_Validation *validation;
2165 uint8_t authoritative;
2168 * do we need encryption at the application layer?
2170 bool user_encrypt;
2171 bool try_logon_ex;
2172 bool try_validation6;
2175 * the read only credentials before we started the operation
2176 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2178 struct netlogon_creds_CredentialState *ro_creds;
2181 * The (locked) credentials used for the credential chain
2182 * used for netr_LogonSamLogonWithFlags() or
2183 * netr_LogonSamLogonWith().
2185 struct netlogon_creds_CredentialState *lk_creds;
2188 * While we have locked the global credentials (lk_creds above)
2189 * we operate an a temporary copy, because a server
2190 * may not support netr_LogonSamLogonWithFlags() and
2191 * didn't process our netr_Authenticator, so we need to
2192 * restart from lk_creds.
2194 struct netlogon_creds_CredentialState tmp_creds;
2195 struct netr_Authenticator req_auth;
2196 struct netr_Authenticator rep_auth;
2199 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2200 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2201 NTSTATUS status);
2203 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2204 struct tevent_context *ev,
2205 struct netlogon_creds_cli_context *context,
2206 struct dcerpc_binding_handle *b,
2207 enum netr_LogonInfoClass logon_level,
2208 const union netr_LogonLevel *logon,
2209 uint32_t flags)
2211 struct tevent_req *req;
2212 struct netlogon_creds_cli_LogonSamLogon_state *state;
2214 req = tevent_req_create(mem_ctx, &state,
2215 struct netlogon_creds_cli_LogonSamLogon_state);
2216 if (req == NULL) {
2217 return NULL;
2220 state->ev = ev;
2221 state->context = context;
2222 state->binding_handle = b;
2224 state->logon_level = logon_level;
2225 state->const_logon = logon;
2226 state->flags = flags;
2228 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2229 context->server.computer);
2230 if (tevent_req_nomem(state->srv_name_slash, req)) {
2231 return tevent_req_post(req, ev);
2234 switch (logon_level) {
2235 case NetlogonInteractiveInformation:
2236 case NetlogonInteractiveTransitiveInformation:
2237 case NetlogonServiceInformation:
2238 case NetlogonServiceTransitiveInformation:
2239 case NetlogonGenericInformation:
2240 state->user_encrypt = true;
2241 break;
2243 case NetlogonNetworkInformation:
2244 case NetlogonNetworkTransitiveInformation:
2245 break;
2248 state->validation = talloc_zero(state, union netr_Validation);
2249 if (tevent_req_nomem(state->validation, req)) {
2250 return tevent_req_post(req, ev);
2253 netlogon_creds_cli_LogonSamLogon_start(req);
2254 if (!tevent_req_is_in_progress(req)) {
2255 return tevent_req_post(req, ev);
2259 * we defer all callbacks in order to cleanup
2260 * the database record.
2262 tevent_req_defer_callback(req, state->ev);
2263 return req;
2266 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2267 NTSTATUS status)
2269 struct netlogon_creds_cli_LogonSamLogon_state *state =
2270 tevent_req_data(req,
2271 struct netlogon_creds_cli_LogonSamLogon_state);
2273 if (state->lk_creds == NULL) {
2274 return;
2277 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2279 * This is a hack to recover from a bug in old
2280 * Samba servers, when LogonSamLogonEx() fails:
2282 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2284 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2286 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2287 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2288 * If the sign/seal check fails.
2290 * In that case we need to cleanup the netlogon session.
2292 * It's the job of the caller to disconnect the current
2293 * connection, if netlogon_creds_cli_LogonSamLogon()
2294 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2296 if (!state->context->server.try_logon_with) {
2297 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2301 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2302 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2303 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2304 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2305 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2306 TALLOC_FREE(state->lk_creds);
2307 return;
2310 netlogon_creds_cli_delete(state->context, state->lk_creds);
2311 TALLOC_FREE(state->lk_creds);
2314 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2316 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2318 struct netlogon_creds_cli_LogonSamLogon_state *state =
2319 tevent_req_data(req,
2320 struct netlogon_creds_cli_LogonSamLogon_state);
2321 struct tevent_req *subreq;
2322 NTSTATUS status;
2323 enum dcerpc_AuthType auth_type;
2324 enum dcerpc_AuthLevel auth_level;
2326 TALLOC_FREE(state->ro_creds);
2327 TALLOC_FREE(state->logon);
2328 ZERO_STRUCTP(state->validation);
2330 dcerpc_binding_handle_auth_info(state->binding_handle,
2331 &auth_type, &auth_level);
2333 state->try_logon_ex = state->context->server.try_logon_ex;
2334 state->try_validation6 = state->context->server.try_validation6;
2336 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2337 state->try_logon_ex = false;
2340 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2341 state->try_validation6 = false;
2344 if (state->try_logon_ex) {
2345 if (state->try_validation6) {
2346 state->validation_level = 6;
2347 } else {
2348 state->validation_level = 3;
2349 state->user_encrypt = true;
2352 state->logon = netlogon_creds_shallow_copy_logon(state,
2353 state->logon_level,
2354 state->const_logon);
2355 if (tevent_req_nomem(state->logon, req)) {
2356 status = NT_STATUS_NO_MEMORY;
2357 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2358 return;
2361 if (state->user_encrypt) {
2362 status = netlogon_creds_cli_get(state->context,
2363 state,
2364 &state->ro_creds);
2365 if (!NT_STATUS_IS_OK(status)) {
2366 status = NT_STATUS_ACCESS_DENIED;
2367 tevent_req_nterror(req, status);
2368 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2369 return;
2372 status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2373 state->logon_level,
2374 state->logon);
2375 if (!NT_STATUS_IS_OK(status)) {
2376 status = NT_STATUS_ACCESS_DENIED;
2377 tevent_req_nterror(req, status);
2378 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2379 return;
2383 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2384 state->binding_handle,
2385 state->srv_name_slash,
2386 state->context->client.computer,
2387 state->logon_level,
2388 state->logon,
2389 state->validation_level,
2390 state->validation,
2391 &state->authoritative,
2392 &state->flags);
2393 if (tevent_req_nomem(subreq, req)) {
2394 status = NT_STATUS_NO_MEMORY;
2395 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2396 return;
2398 tevent_req_set_callback(subreq,
2399 netlogon_creds_cli_LogonSamLogon_done,
2400 req);
2401 return;
2404 if (state->lk_creds == NULL) {
2405 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2406 state->context);
2407 if (tevent_req_nomem(subreq, req)) {
2408 status = NT_STATUS_NO_MEMORY;
2409 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2410 return;
2412 tevent_req_set_callback(subreq,
2413 netlogon_creds_cli_LogonSamLogon_done,
2414 req);
2415 return;
2418 state->tmp_creds = *state->lk_creds;
2419 netlogon_creds_client_authenticator(&state->tmp_creds,
2420 &state->req_auth);
2421 ZERO_STRUCT(state->rep_auth);
2423 state->logon = netlogon_creds_shallow_copy_logon(state,
2424 state->logon_level,
2425 state->const_logon);
2426 if (tevent_req_nomem(state->logon, req)) {
2427 status = NT_STATUS_NO_MEMORY;
2428 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2429 return;
2432 status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2433 state->logon_level,
2434 state->logon);
2435 if (tevent_req_nterror(req, status)) {
2436 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2437 return;
2440 state->validation_level = 3;
2442 if (state->context->server.try_logon_with) {
2443 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2444 state->binding_handle,
2445 state->srv_name_slash,
2446 state->context->client.computer,
2447 &state->req_auth,
2448 &state->rep_auth,
2449 state->logon_level,
2450 state->logon,
2451 state->validation_level,
2452 state->validation,
2453 &state->authoritative,
2454 &state->flags);
2455 if (tevent_req_nomem(subreq, req)) {
2456 status = NT_STATUS_NO_MEMORY;
2457 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2458 return;
2460 } else {
2461 state->flags = 0;
2463 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2464 state->binding_handle,
2465 state->srv_name_slash,
2466 state->context->client.computer,
2467 &state->req_auth,
2468 &state->rep_auth,
2469 state->logon_level,
2470 state->logon,
2471 state->validation_level,
2472 state->validation,
2473 &state->authoritative);
2474 if (tevent_req_nomem(subreq, req)) {
2475 status = NT_STATUS_NO_MEMORY;
2476 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2477 return;
2481 tevent_req_set_callback(subreq,
2482 netlogon_creds_cli_LogonSamLogon_done,
2483 req);
2486 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2488 struct tevent_req *req =
2489 tevent_req_callback_data(subreq,
2490 struct tevent_req);
2491 struct netlogon_creds_cli_LogonSamLogon_state *state =
2492 tevent_req_data(req,
2493 struct netlogon_creds_cli_LogonSamLogon_state);
2494 NTSTATUS status;
2495 NTSTATUS result;
2496 bool ok;
2498 if (state->try_logon_ex) {
2499 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2500 state->validation,
2501 &result);
2502 TALLOC_FREE(subreq);
2503 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2504 state->context->server.try_validation6 = false;
2505 state->context->server.try_logon_ex = false;
2506 netlogon_creds_cli_LogonSamLogon_start(req);
2507 return;
2509 if (tevent_req_nterror(req, status)) {
2510 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2511 return;
2514 if ((state->validation_level == 6) &&
2515 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2516 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2517 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2519 state->context->server.try_validation6 = false;
2520 netlogon_creds_cli_LogonSamLogon_start(req);
2521 return;
2524 if (tevent_req_nterror(req, result)) {
2525 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2526 return;
2529 if (state->ro_creds == NULL) {
2530 tevent_req_done(req);
2531 return;
2534 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2535 if (!ok) {
2537 * We got a race, lets retry with on authenticator
2538 * protection.
2540 * netlogon_creds_cli_LogonSamLogon_start()
2541 * will TALLOC_FREE(state->ro_creds);
2543 state->try_logon_ex = false;
2544 netlogon_creds_cli_LogonSamLogon_start(req);
2545 return;
2548 status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2549 state->validation_level,
2550 state->validation);
2551 if (tevent_req_nterror(req, status)) {
2552 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2553 return;
2556 tevent_req_done(req);
2557 return;
2560 if (state->lk_creds == NULL) {
2561 status = netlogon_creds_cli_lock_recv(subreq, state,
2562 &state->lk_creds);
2563 TALLOC_FREE(subreq);
2564 if (tevent_req_nterror(req, status)) {
2565 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2566 return;
2569 netlogon_creds_cli_LogonSamLogon_start(req);
2570 return;
2573 if (state->context->server.try_logon_with) {
2574 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2575 state->validation,
2576 &result);
2577 TALLOC_FREE(subreq);
2578 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2579 state->context->server.try_logon_with = false;
2580 netlogon_creds_cli_LogonSamLogon_start(req);
2581 return;
2583 if (tevent_req_nterror(req, status)) {
2584 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2585 return;
2587 } else {
2588 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2589 state->validation,
2590 &result);
2591 TALLOC_FREE(subreq);
2592 if (tevent_req_nterror(req, status)) {
2593 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2594 return;
2598 ok = netlogon_creds_client_check(&state->tmp_creds,
2599 &state->rep_auth.cred);
2600 if (!ok) {
2601 status = NT_STATUS_ACCESS_DENIED;
2602 tevent_req_nterror(req, status);
2603 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2604 return;
2607 *state->lk_creds = state->tmp_creds;
2608 status = netlogon_creds_cli_store(state->context,
2609 state->lk_creds);
2610 TALLOC_FREE(state->lk_creds);
2612 if (tevent_req_nterror(req, status)) {
2613 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2614 return;
2617 if (tevent_req_nterror(req, result)) {
2618 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2619 return;
2622 status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2623 state->validation_level,
2624 state->validation);
2625 if (tevent_req_nterror(req, result)) {
2626 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2627 return;
2630 tevent_req_done(req);
2633 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2634 TALLOC_CTX *mem_ctx,
2635 uint16_t *validation_level,
2636 union netr_Validation **validation,
2637 uint8_t *authoritative,
2638 uint32_t *flags)
2640 struct netlogon_creds_cli_LogonSamLogon_state *state =
2641 tevent_req_data(req,
2642 struct netlogon_creds_cli_LogonSamLogon_state);
2643 NTSTATUS status;
2645 /* authoritative is also returned on error */
2646 *authoritative = state->authoritative;
2648 if (tevent_req_is_nterror(req, &status)) {
2649 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2650 tevent_req_received(req);
2651 return status;
2654 *validation_level = state->validation_level;
2655 *validation = talloc_move(mem_ctx, &state->validation);
2656 *flags = state->flags;
2658 tevent_req_received(req);
2659 return NT_STATUS_OK;
2662 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2663 struct netlogon_creds_cli_context *context,
2664 struct dcerpc_binding_handle *b,
2665 enum netr_LogonInfoClass logon_level,
2666 const union netr_LogonLevel *logon,
2667 TALLOC_CTX *mem_ctx,
2668 uint16_t *validation_level,
2669 union netr_Validation **validation,
2670 uint8_t *authoritative,
2671 uint32_t *flags)
2673 TALLOC_CTX *frame = talloc_stackframe();
2674 struct tevent_context *ev;
2675 struct tevent_req *req;
2676 NTSTATUS status = NT_STATUS_NO_MEMORY;
2678 ev = samba_tevent_context_init(frame);
2679 if (ev == NULL) {
2680 goto fail;
2682 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2683 logon_level, logon,
2684 *flags);
2685 if (req == NULL) {
2686 goto fail;
2688 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2689 goto fail;
2691 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2692 validation_level,
2693 validation,
2694 authoritative,
2695 flags);
2696 fail:
2697 TALLOC_FREE(frame);
2698 return status;
2701 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2702 struct tevent_context *ev;
2703 struct netlogon_creds_cli_context *context;
2704 struct dcerpc_binding_handle *binding_handle;
2706 char *srv_name_slash;
2707 enum dcerpc_AuthType auth_type;
2708 enum dcerpc_AuthLevel auth_level;
2710 const char *site_name;
2711 uint32_t dns_ttl;
2712 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2714 struct netlogon_creds_CredentialState *creds;
2715 struct netlogon_creds_CredentialState tmp_creds;
2716 struct netr_Authenticator req_auth;
2717 struct netr_Authenticator rep_auth;
2720 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2721 NTSTATUS status);
2722 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2724 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2725 struct tevent_context *ev,
2726 struct netlogon_creds_cli_context *context,
2727 struct dcerpc_binding_handle *b,
2728 const char *site_name,
2729 uint32_t dns_ttl,
2730 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2732 struct tevent_req *req;
2733 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2734 struct tevent_req *subreq;
2736 req = tevent_req_create(mem_ctx, &state,
2737 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2738 if (req == NULL) {
2739 return NULL;
2742 state->ev = ev;
2743 state->context = context;
2744 state->binding_handle = b;
2746 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2747 context->server.computer);
2748 if (tevent_req_nomem(state->srv_name_slash, req)) {
2749 return tevent_req_post(req, ev);
2752 state->site_name = site_name;
2753 state->dns_ttl = dns_ttl;
2754 state->dns_names = dns_names;
2756 dcerpc_binding_handle_auth_info(state->binding_handle,
2757 &state->auth_type,
2758 &state->auth_level);
2760 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2761 state->context);
2762 if (tevent_req_nomem(subreq, req)) {
2763 return tevent_req_post(req, ev);
2766 tevent_req_set_callback(subreq,
2767 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2768 req);
2770 return req;
2773 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2774 NTSTATUS status)
2776 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2777 tevent_req_data(req,
2778 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2780 if (state->creds == NULL) {
2781 return;
2784 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2785 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2786 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2787 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2788 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2789 TALLOC_FREE(state->creds);
2790 return;
2793 netlogon_creds_cli_delete(state->context, state->creds);
2794 TALLOC_FREE(state->creds);
2797 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2799 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2801 struct tevent_req *req =
2802 tevent_req_callback_data(subreq,
2803 struct tevent_req);
2804 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2805 tevent_req_data(req,
2806 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2807 NTSTATUS status;
2809 status = netlogon_creds_cli_lock_recv(subreq, state,
2810 &state->creds);
2811 TALLOC_FREE(subreq);
2812 if (tevent_req_nterror(req, status)) {
2813 return;
2816 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2817 switch (state->auth_level) {
2818 case DCERPC_AUTH_LEVEL_INTEGRITY:
2819 case DCERPC_AUTH_LEVEL_PRIVACY:
2820 break;
2821 default:
2822 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2823 return;
2825 } else {
2826 uint32_t tmp = state->creds->negotiate_flags;
2828 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2830 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2831 * it should be used, which means
2832 * we had a chance to verify no downgrade
2833 * happened.
2835 * This relies on netlogon_creds_cli_check*
2836 * being called before, as first request after
2837 * the DCERPC bind.
2839 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2840 return;
2845 * we defer all callbacks in order to cleanup
2846 * the database record.
2848 tevent_req_defer_callback(req, state->ev);
2850 state->tmp_creds = *state->creds;
2851 netlogon_creds_client_authenticator(&state->tmp_creds,
2852 &state->req_auth);
2853 ZERO_STRUCT(state->rep_auth);
2855 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2856 state->binding_handle,
2857 state->srv_name_slash,
2858 state->tmp_creds.computer_name,
2859 &state->req_auth,
2860 &state->rep_auth,
2861 state->site_name,
2862 state->dns_ttl,
2863 state->dns_names);
2864 if (tevent_req_nomem(subreq, req)) {
2865 status = NT_STATUS_NO_MEMORY;
2866 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2867 return;
2870 tevent_req_set_callback(subreq,
2871 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2872 req);
2875 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2877 struct tevent_req *req =
2878 tevent_req_callback_data(subreq,
2879 struct tevent_req);
2880 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2881 tevent_req_data(req,
2882 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2883 NTSTATUS status;
2884 NTSTATUS result;
2885 bool ok;
2888 * We use state->dns_names as the memory context, as this is
2889 * the only in/out variable and it has been overwritten by the
2890 * out parameter from the server.
2892 * We need to preserve the return value until the caller can use it.
2894 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2895 &result);
2896 TALLOC_FREE(subreq);
2897 if (tevent_req_nterror(req, status)) {
2898 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2899 return;
2902 ok = netlogon_creds_client_check(&state->tmp_creds,
2903 &state->rep_auth.cred);
2904 if (!ok) {
2905 status = NT_STATUS_ACCESS_DENIED;
2906 tevent_req_nterror(req, status);
2907 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2908 return;
2911 *state->creds = state->tmp_creds;
2912 status = netlogon_creds_cli_store(state->context,
2913 state->creds);
2914 TALLOC_FREE(state->creds);
2916 if (tevent_req_nterror(req, status)) {
2917 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2918 return;
2921 if (tevent_req_nterror(req, result)) {
2922 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2923 return;
2926 tevent_req_done(req);
2929 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2931 NTSTATUS status;
2933 if (tevent_req_is_nterror(req, &status)) {
2934 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2935 tevent_req_received(req);
2936 return status;
2939 tevent_req_received(req);
2940 return NT_STATUS_OK;
2943 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2944 struct netlogon_creds_cli_context *context,
2945 struct dcerpc_binding_handle *b,
2946 const char *site_name,
2947 uint32_t dns_ttl,
2948 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2950 TALLOC_CTX *frame = talloc_stackframe();
2951 struct tevent_context *ev;
2952 struct tevent_req *req;
2953 NTSTATUS status = NT_STATUS_NO_MEMORY;
2955 ev = samba_tevent_context_init(frame);
2956 if (ev == NULL) {
2957 goto fail;
2959 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2960 site_name,
2961 dns_ttl,
2962 dns_names);
2963 if (req == NULL) {
2964 goto fail;
2966 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2967 goto fail;
2969 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2970 fail:
2971 TALLOC_FREE(frame);
2972 return status;
2975 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2976 struct tevent_context *ev;
2977 struct netlogon_creds_cli_context *context;
2978 struct dcerpc_binding_handle *binding_handle;
2980 char *srv_name_slash;
2981 enum dcerpc_AuthType auth_type;
2982 enum dcerpc_AuthLevel auth_level;
2984 struct samr_Password new_owf_password;
2985 struct samr_Password old_owf_password;
2986 struct netr_TrustInfo *trust_info;
2988 struct netlogon_creds_CredentialState *creds;
2989 struct netlogon_creds_CredentialState tmp_creds;
2990 struct netr_Authenticator req_auth;
2991 struct netr_Authenticator rep_auth;
2994 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2995 NTSTATUS status);
2996 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2998 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2999 struct tevent_context *ev,
3000 struct netlogon_creds_cli_context *context,
3001 struct dcerpc_binding_handle *b)
3003 struct tevent_req *req;
3004 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
3005 struct tevent_req *subreq;
3007 req = tevent_req_create(mem_ctx, &state,
3008 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3009 if (req == NULL) {
3010 return NULL;
3013 state->ev = ev;
3014 state->context = context;
3015 state->binding_handle = b;
3017 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3018 context->server.computer);
3019 if (tevent_req_nomem(state->srv_name_slash, req)) {
3020 return tevent_req_post(req, ev);
3023 dcerpc_binding_handle_auth_info(state->binding_handle,
3024 &state->auth_type,
3025 &state->auth_level);
3027 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3028 state->context);
3029 if (tevent_req_nomem(subreq, req)) {
3030 return tevent_req_post(req, ev);
3033 tevent_req_set_callback(subreq,
3034 netlogon_creds_cli_ServerGetTrustInfo_locked,
3035 req);
3037 return req;
3040 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3041 NTSTATUS status)
3043 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3044 tevent_req_data(req,
3045 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3047 if (state->creds == NULL) {
3048 return;
3051 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3052 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3053 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3054 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3055 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3056 TALLOC_FREE(state->creds);
3057 return;
3060 netlogon_creds_cli_delete(state->context, state->creds);
3061 TALLOC_FREE(state->creds);
3064 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3066 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3068 struct tevent_req *req =
3069 tevent_req_callback_data(subreq,
3070 struct tevent_req);
3071 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3072 tevent_req_data(req,
3073 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3074 NTSTATUS status;
3076 status = netlogon_creds_cli_lock_recv(subreq, state,
3077 &state->creds);
3078 TALLOC_FREE(subreq);
3079 if (tevent_req_nterror(req, status)) {
3080 return;
3083 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3084 switch (state->auth_level) {
3085 case DCERPC_AUTH_LEVEL_PRIVACY:
3086 break;
3087 default:
3088 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3089 return;
3091 } else {
3092 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3093 return;
3097 * we defer all callbacks in order to cleanup
3098 * the database record.
3100 tevent_req_defer_callback(req, state->ev);
3102 state->tmp_creds = *state->creds;
3103 netlogon_creds_client_authenticator(&state->tmp_creds,
3104 &state->req_auth);
3105 ZERO_STRUCT(state->rep_auth);
3107 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3108 state->binding_handle,
3109 state->srv_name_slash,
3110 state->tmp_creds.account_name,
3111 state->tmp_creds.secure_channel_type,
3112 state->tmp_creds.computer_name,
3113 &state->req_auth,
3114 &state->rep_auth,
3115 &state->new_owf_password,
3116 &state->old_owf_password,
3117 &state->trust_info);
3118 if (tevent_req_nomem(subreq, req)) {
3119 status = NT_STATUS_NO_MEMORY;
3120 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3121 return;
3124 tevent_req_set_callback(subreq,
3125 netlogon_creds_cli_ServerGetTrustInfo_done,
3126 req);
3129 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3131 struct tevent_req *req =
3132 tevent_req_callback_data(subreq,
3133 struct tevent_req);
3134 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3135 tevent_req_data(req,
3136 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3137 NTSTATUS status;
3138 NTSTATUS result;
3139 const struct samr_Password zero = {};
3140 int cmp;
3141 bool ok;
3144 * We use state->dns_names as the memory context, as this is
3145 * the only in/out variable and it has been overwritten by the
3146 * out parameter from the server.
3148 * We need to preserve the return value until the caller can use it.
3150 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3151 TALLOC_FREE(subreq);
3152 if (tevent_req_nterror(req, status)) {
3153 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3154 return;
3157 ok = netlogon_creds_client_check(&state->tmp_creds,
3158 &state->rep_auth.cred);
3159 if (!ok) {
3160 status = NT_STATUS_ACCESS_DENIED;
3161 tevent_req_nterror(req, status);
3162 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3163 return;
3166 cmp = memcmp(state->new_owf_password.hash,
3167 zero.hash, sizeof(zero.hash));
3168 if (cmp != 0) {
3169 netlogon_creds_des_decrypt(&state->tmp_creds,
3170 &state->new_owf_password);
3172 cmp = memcmp(state->old_owf_password.hash,
3173 zero.hash, sizeof(zero.hash));
3174 if (cmp != 0) {
3175 netlogon_creds_des_decrypt(&state->tmp_creds,
3176 &state->old_owf_password);
3179 *state->creds = state->tmp_creds;
3180 status = netlogon_creds_cli_store(state->context,
3181 state->creds);
3182 TALLOC_FREE(state->creds);
3183 if (tevent_req_nterror(req, status)) {
3184 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3185 return;
3188 if (tevent_req_nterror(req, result)) {
3189 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3190 return;
3193 tevent_req_done(req);
3196 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3197 TALLOC_CTX *mem_ctx,
3198 struct samr_Password *new_owf_password,
3199 struct samr_Password *old_owf_password,
3200 struct netr_TrustInfo **trust_info)
3202 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3203 tevent_req_data(req,
3204 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3205 NTSTATUS status;
3207 if (tevent_req_is_nterror(req, &status)) {
3208 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3209 tevent_req_received(req);
3210 return status;
3213 if (new_owf_password != NULL) {
3214 *new_owf_password = state->new_owf_password;
3216 if (old_owf_password != NULL) {
3217 *old_owf_password = state->old_owf_password;
3219 if (trust_info != NULL) {
3220 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3223 tevent_req_received(req);
3224 return NT_STATUS_OK;
3227 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3228 struct netlogon_creds_cli_context *context,
3229 struct dcerpc_binding_handle *b,
3230 TALLOC_CTX *mem_ctx,
3231 struct samr_Password *new_owf_password,
3232 struct samr_Password *old_owf_password,
3233 struct netr_TrustInfo **trust_info)
3235 TALLOC_CTX *frame = talloc_stackframe();
3236 struct tevent_context *ev;
3237 struct tevent_req *req;
3238 NTSTATUS status = NT_STATUS_NO_MEMORY;
3240 ev = samba_tevent_context_init(frame);
3241 if (ev == NULL) {
3242 goto fail;
3244 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3245 if (req == NULL) {
3246 goto fail;
3248 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3249 goto fail;
3251 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3252 mem_ctx,
3253 new_owf_password,
3254 old_owf_password,
3255 trust_info);
3256 fail:
3257 TALLOC_FREE(frame);
3258 return status;
3261 struct netlogon_creds_cli_GetForestTrustInformation_state {
3262 struct tevent_context *ev;
3263 struct netlogon_creds_cli_context *context;
3264 struct dcerpc_binding_handle *binding_handle;
3266 char *srv_name_slash;
3267 enum dcerpc_AuthType auth_type;
3268 enum dcerpc_AuthLevel auth_level;
3270 uint32_t flags;
3271 struct lsa_ForestTrustInformation *forest_trust_info;
3273 struct netlogon_creds_CredentialState *creds;
3274 struct netlogon_creds_CredentialState tmp_creds;
3275 struct netr_Authenticator req_auth;
3276 struct netr_Authenticator rep_auth;
3279 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3280 NTSTATUS status);
3281 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3283 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3284 struct tevent_context *ev,
3285 struct netlogon_creds_cli_context *context,
3286 struct dcerpc_binding_handle *b)
3288 struct tevent_req *req;
3289 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3290 struct tevent_req *subreq;
3292 req = tevent_req_create(mem_ctx, &state,
3293 struct netlogon_creds_cli_GetForestTrustInformation_state);
3294 if (req == NULL) {
3295 return NULL;
3298 state->ev = ev;
3299 state->context = context;
3300 state->binding_handle = b;
3302 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3303 context->server.computer);
3304 if (tevent_req_nomem(state->srv_name_slash, req)) {
3305 return tevent_req_post(req, ev);
3308 state->flags = 0;
3310 dcerpc_binding_handle_auth_info(state->binding_handle,
3311 &state->auth_type,
3312 &state->auth_level);
3314 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3315 state->context);
3316 if (tevent_req_nomem(subreq, req)) {
3317 return tevent_req_post(req, ev);
3320 tevent_req_set_callback(subreq,
3321 netlogon_creds_cli_GetForestTrustInformation_locked,
3322 req);
3324 return req;
3327 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3328 NTSTATUS status)
3330 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3331 tevent_req_data(req,
3332 struct netlogon_creds_cli_GetForestTrustInformation_state);
3334 if (state->creds == NULL) {
3335 return;
3338 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3339 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3340 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3341 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3342 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3343 TALLOC_FREE(state->creds);
3344 return;
3347 netlogon_creds_cli_delete(state->context, state->creds);
3348 TALLOC_FREE(state->creds);
3351 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3353 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3355 struct tevent_req *req =
3356 tevent_req_callback_data(subreq,
3357 struct tevent_req);
3358 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3359 tevent_req_data(req,
3360 struct netlogon_creds_cli_GetForestTrustInformation_state);
3361 NTSTATUS status;
3363 status = netlogon_creds_cli_lock_recv(subreq, state,
3364 &state->creds);
3365 TALLOC_FREE(subreq);
3366 if (tevent_req_nterror(req, status)) {
3367 return;
3370 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3371 switch (state->auth_level) {
3372 case DCERPC_AUTH_LEVEL_INTEGRITY:
3373 case DCERPC_AUTH_LEVEL_PRIVACY:
3374 break;
3375 default:
3376 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3377 return;
3379 } else {
3380 uint32_t tmp = state->creds->negotiate_flags;
3382 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3384 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3385 * it should be used, which means
3386 * we had a chance to verify no downgrade
3387 * happened.
3389 * This relies on netlogon_creds_cli_check*
3390 * being called before, as first request after
3391 * the DCERPC bind.
3393 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3394 return;
3399 * we defer all callbacks in order to cleanup
3400 * the database record.
3402 tevent_req_defer_callback(req, state->ev);
3404 state->tmp_creds = *state->creds;
3405 netlogon_creds_client_authenticator(&state->tmp_creds,
3406 &state->req_auth);
3407 ZERO_STRUCT(state->rep_auth);
3409 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3410 state->binding_handle,
3411 state->srv_name_slash,
3412 state->tmp_creds.computer_name,
3413 &state->req_auth,
3414 &state->rep_auth,
3415 state->flags,
3416 &state->forest_trust_info);
3417 if (tevent_req_nomem(subreq, req)) {
3418 status = NT_STATUS_NO_MEMORY;
3419 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3420 return;
3423 tevent_req_set_callback(subreq,
3424 netlogon_creds_cli_GetForestTrustInformation_done,
3425 req);
3428 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3430 struct tevent_req *req =
3431 tevent_req_callback_data(subreq,
3432 struct tevent_req);
3433 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3434 tevent_req_data(req,
3435 struct netlogon_creds_cli_GetForestTrustInformation_state);
3436 NTSTATUS status;
3437 NTSTATUS result;
3438 bool ok;
3441 * We use state->dns_names as the memory context, as this is
3442 * the only in/out variable and it has been overwritten by the
3443 * out parameter from the server.
3445 * We need to preserve the return value until the caller can use it.
3447 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3448 TALLOC_FREE(subreq);
3449 if (tevent_req_nterror(req, status)) {
3450 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3451 return;
3454 ok = netlogon_creds_client_check(&state->tmp_creds,
3455 &state->rep_auth.cred);
3456 if (!ok) {
3457 status = NT_STATUS_ACCESS_DENIED;
3458 tevent_req_nterror(req, status);
3459 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3460 return;
3463 *state->creds = state->tmp_creds;
3464 status = netlogon_creds_cli_store(state->context,
3465 state->creds);
3466 TALLOC_FREE(state->creds);
3468 if (tevent_req_nterror(req, status)) {
3469 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3470 return;
3473 if (tevent_req_nterror(req, result)) {
3474 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3475 return;
3478 tevent_req_done(req);
3481 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3482 TALLOC_CTX *mem_ctx,
3483 struct lsa_ForestTrustInformation **forest_trust_info)
3485 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3486 tevent_req_data(req,
3487 struct netlogon_creds_cli_GetForestTrustInformation_state);
3488 NTSTATUS status;
3490 if (tevent_req_is_nterror(req, &status)) {
3491 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3492 tevent_req_received(req);
3493 return status;
3496 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3498 tevent_req_received(req);
3499 return NT_STATUS_OK;
3502 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3503 struct netlogon_creds_cli_context *context,
3504 struct dcerpc_binding_handle *b,
3505 TALLOC_CTX *mem_ctx,
3506 struct lsa_ForestTrustInformation **forest_trust_info)
3508 TALLOC_CTX *frame = talloc_stackframe();
3509 struct tevent_context *ev;
3510 struct tevent_req *req;
3511 NTSTATUS status = NT_STATUS_NO_MEMORY;
3513 ev = samba_tevent_context_init(frame);
3514 if (ev == NULL) {
3515 goto fail;
3517 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3518 if (req == NULL) {
3519 goto fail;
3521 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3522 goto fail;
3524 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3525 mem_ctx,
3526 forest_trust_info);
3527 fail:
3528 TALLOC_FREE(frame);
3529 return status;
3532 struct netlogon_creds_cli_SendToSam_state {
3533 struct tevent_context *ev;
3534 struct netlogon_creds_cli_context *context;
3535 struct dcerpc_binding_handle *binding_handle;
3537 char *srv_name_slash;
3538 enum dcerpc_AuthType auth_type;
3539 enum dcerpc_AuthLevel auth_level;
3541 DATA_BLOB opaque;
3543 struct netlogon_creds_CredentialState *creds;
3544 struct netlogon_creds_CredentialState tmp_creds;
3545 struct netr_Authenticator req_auth;
3546 struct netr_Authenticator rep_auth;
3549 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3550 NTSTATUS status);
3551 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3553 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3554 struct tevent_context *ev,
3555 struct netlogon_creds_cli_context *context,
3556 struct dcerpc_binding_handle *b,
3557 struct netr_SendToSamBase *message)
3559 struct tevent_req *req;
3560 struct netlogon_creds_cli_SendToSam_state *state;
3561 struct tevent_req *subreq;
3562 enum ndr_err_code ndr_err;
3564 req = tevent_req_create(mem_ctx, &state,
3565 struct netlogon_creds_cli_SendToSam_state);
3566 if (req == NULL) {
3567 return NULL;
3570 state->ev = ev;
3571 state->context = context;
3572 state->binding_handle = b;
3574 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3575 context->server.computer);
3576 if (tevent_req_nomem(state->srv_name_slash, req)) {
3577 return tevent_req_post(req, ev);
3580 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3581 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3582 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3583 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3584 tevent_req_nterror(req, status);
3585 return tevent_req_post(req, ev);
3588 dcerpc_binding_handle_auth_info(state->binding_handle,
3589 &state->auth_type,
3590 &state->auth_level);
3592 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3593 state->context);
3594 if (tevent_req_nomem(subreq, req)) {
3595 return tevent_req_post(req, ev);
3598 tevent_req_set_callback(subreq,
3599 netlogon_creds_cli_SendToSam_locked,
3600 req);
3602 return req;
3605 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3606 NTSTATUS status)
3608 struct netlogon_creds_cli_SendToSam_state *state =
3609 tevent_req_data(req,
3610 struct netlogon_creds_cli_SendToSam_state);
3612 if (state->creds == NULL) {
3613 return;
3616 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3617 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3618 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3619 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3620 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3621 TALLOC_FREE(state->creds);
3622 return;
3625 netlogon_creds_cli_delete(state->context, state->creds);
3626 TALLOC_FREE(state->creds);
3629 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3631 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3633 struct tevent_req *req =
3634 tevent_req_callback_data(subreq,
3635 struct tevent_req);
3636 struct netlogon_creds_cli_SendToSam_state *state =
3637 tevent_req_data(req,
3638 struct netlogon_creds_cli_SendToSam_state);
3639 NTSTATUS status;
3641 status = netlogon_creds_cli_lock_recv(subreq, state,
3642 &state->creds);
3643 TALLOC_FREE(subreq);
3644 if (tevent_req_nterror(req, status)) {
3645 return;
3648 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3649 switch (state->auth_level) {
3650 case DCERPC_AUTH_LEVEL_INTEGRITY:
3651 case DCERPC_AUTH_LEVEL_PRIVACY:
3652 break;
3653 default:
3654 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3655 return;
3657 } else {
3658 uint32_t tmp = state->creds->negotiate_flags;
3660 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3662 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3663 * it should be used, which means
3664 * we had a chance to verify no downgrade
3665 * happened.
3667 * This relies on netlogon_creds_cli_check*
3668 * being called before, as first request after
3669 * the DCERPC bind.
3671 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3672 return;
3677 * we defer all callbacks in order to cleanup
3678 * the database record.
3680 tevent_req_defer_callback(req, state->ev);
3682 state->tmp_creds = *state->creds;
3683 netlogon_creds_client_authenticator(&state->tmp_creds,
3684 &state->req_auth);
3685 ZERO_STRUCT(state->rep_auth);
3687 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3688 netlogon_creds_aes_encrypt(&state->tmp_creds,
3689 state->opaque.data,
3690 state->opaque.length);
3691 } else {
3692 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
3693 state->opaque.data,
3694 state->opaque.length);
3695 if (tevent_req_nterror(req, status)) {
3696 netlogon_creds_cli_SendToSam_cleanup(req, status);
3697 return;
3701 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3702 state->binding_handle,
3703 state->srv_name_slash,
3704 state->tmp_creds.computer_name,
3705 &state->req_auth,
3706 &state->rep_auth,
3707 state->opaque.data,
3708 state->opaque.length);
3709 if (tevent_req_nomem(subreq, req)) {
3710 status = NT_STATUS_NO_MEMORY;
3711 netlogon_creds_cli_SendToSam_cleanup(req, status);
3712 return;
3715 tevent_req_set_callback(subreq,
3716 netlogon_creds_cli_SendToSam_done,
3717 req);
3720 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3722 struct tevent_req *req =
3723 tevent_req_callback_data(subreq,
3724 struct tevent_req);
3725 struct netlogon_creds_cli_SendToSam_state *state =
3726 tevent_req_data(req,
3727 struct netlogon_creds_cli_SendToSam_state);
3728 NTSTATUS status;
3729 NTSTATUS result;
3730 bool ok;
3732 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3733 TALLOC_FREE(subreq);
3734 if (tevent_req_nterror(req, status)) {
3735 netlogon_creds_cli_SendToSam_cleanup(req, status);
3736 return;
3739 ok = netlogon_creds_client_check(&state->tmp_creds,
3740 &state->rep_auth.cred);
3741 if (!ok) {
3742 status = NT_STATUS_ACCESS_DENIED;
3743 tevent_req_nterror(req, status);
3744 netlogon_creds_cli_SendToSam_cleanup(req, status);
3745 return;
3748 *state->creds = state->tmp_creds;
3749 status = netlogon_creds_cli_store(state->context,
3750 state->creds);
3751 TALLOC_FREE(state->creds);
3753 if (tevent_req_nterror(req, status)) {
3754 netlogon_creds_cli_SendToSam_cleanup(req, status);
3755 return;
3759 * Creds must be stored before we send back application errors
3760 * e.g. NT_STATUS_NOT_IMPLEMENTED
3762 if (tevent_req_nterror(req, result)) {
3763 netlogon_creds_cli_SendToSam_cleanup(req, result);
3764 return;
3767 tevent_req_done(req);
3770 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3771 struct dcerpc_binding_handle *b,
3772 struct netr_SendToSamBase *message)
3774 TALLOC_CTX *frame = talloc_stackframe();
3775 struct tevent_context *ev;
3776 struct tevent_req *req;
3777 NTSTATUS status = NT_STATUS_OK;
3779 ev = samba_tevent_context_init(frame);
3780 if (ev == NULL) {
3781 goto fail;
3783 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3784 if (req == NULL) {
3785 goto fail;
3787 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3788 goto fail;
3791 /* Ignore the result */
3792 fail:
3793 TALLOC_FREE(frame);
3794 return status;