s3:vfs_nfs4acl_xattr: make use of lp_parm_substituted_string()
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob6f043d774cd172f0349d700147aaa368dba23a8a
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 status = netlogon_creds_client_authenticator(state->creds,
1551 &state->req_auth);
1552 if (tevent_req_nterror(req, status)) {
1553 return tevent_req_post(req, ev);
1555 ZERO_STRUCT(state->rep_auth);
1557 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1558 state->binding_handle,
1559 state->srv_name_slash,
1560 state->context->client.computer,
1561 &state->req_auth,
1562 &state->rep_auth,
1564 &state->caps);
1565 if (tevent_req_nomem(subreq, req)) {
1566 return tevent_req_post(req, ev);
1569 tevent_req_set_callback(subreq,
1570 netlogon_creds_cli_check_caps,
1571 req);
1573 return req;
1576 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1577 NTSTATUS status)
1579 struct netlogon_creds_cli_check_state *state =
1580 tevent_req_data(req,
1581 struct netlogon_creds_cli_check_state);
1583 if (state->creds == NULL) {
1584 return;
1587 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1588 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1589 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1590 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1591 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1592 TALLOC_FREE(state->creds);
1593 return;
1596 netlogon_creds_cli_delete_lck(state->context);
1597 TALLOC_FREE(state->creds);
1600 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1602 struct tevent_req *req =
1603 tevent_req_callback_data(subreq,
1604 struct tevent_req);
1605 struct netlogon_creds_cli_check_state *state =
1606 tevent_req_data(req,
1607 struct netlogon_creds_cli_check_state);
1608 NTSTATUS status;
1609 NTSTATUS result;
1610 bool ok;
1612 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1613 &result);
1614 TALLOC_FREE(subreq);
1615 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1617 * Note that the negotiated flags are already checked
1618 * for our required flags after the ServerAuthenticate3/2 call.
1620 uint32_t negotiated = state->creds->negotiate_flags;
1622 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1624 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1625 * already, we expect this to work!
1627 status = NT_STATUS_DOWNGRADE_DETECTED;
1628 tevent_req_nterror(req, status);
1629 netlogon_creds_cli_check_cleanup(req, status);
1630 return;
1633 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1635 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1636 * we expect this to work at least as far as the
1637 * NOT_SUPPORTED error handled below!
1639 * NT 4.0 and Old Samba servers are not
1640 * allowed without "require strong key = no"
1642 status = NT_STATUS_DOWNGRADE_DETECTED;
1643 tevent_req_nterror(req, status);
1644 netlogon_creds_cli_check_cleanup(req, status);
1645 return;
1649 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1650 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1651 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1653 * This is needed against NT 4.0 and old Samba servers.
1655 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1656 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1657 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1658 * with the next request as the sequence number processing
1659 * gets out of sync.
1661 netlogon_creds_cli_check_cleanup(req, status);
1662 tevent_req_done(req);
1663 return;
1665 if (tevent_req_nterror(req, status)) {
1666 netlogon_creds_cli_check_cleanup(req, status);
1667 return;
1670 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1672 * Note that the negotiated flags are already checked
1673 * for our required flags after the ServerAuthenticate3/2 call.
1675 uint32_t negotiated = state->creds->negotiate_flags;
1677 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1679 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1680 * already, we expect this to work!
1682 status = NT_STATUS_DOWNGRADE_DETECTED;
1683 tevent_req_nterror(req, status);
1684 netlogon_creds_cli_check_cleanup(req, status);
1685 return;
1689 * This is ok, the server does not support
1690 * NETLOGON_NEG_SUPPORTS_AES.
1692 * netr_LogonGetCapabilities() was
1693 * netr_LogonDummyRoutine1() before
1694 * NETLOGON_NEG_SUPPORTS_AES was invented.
1696 netlogon_creds_cli_check_cleanup(req, result);
1697 tevent_req_done(req);
1698 return;
1701 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1702 if (!ok) {
1703 status = NT_STATUS_ACCESS_DENIED;
1704 tevent_req_nterror(req, status);
1705 netlogon_creds_cli_check_cleanup(req, status);
1706 return;
1709 if (tevent_req_nterror(req, result)) {
1710 netlogon_creds_cli_check_cleanup(req, result);
1711 return;
1714 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1715 status = NT_STATUS_DOWNGRADE_DETECTED;
1716 tevent_req_nterror(req, status);
1717 netlogon_creds_cli_check_cleanup(req, status);
1718 return;
1722 * This is the key check that makes this check secure. If we
1723 * get OK here (rather than NOT_SUPPORTED), then the server
1724 * did support AES. If the server only proposed STRONG_KEYS
1725 * and not AES, then it should have failed with
1726 * NOT_IMPLEMENTED. We always send AES as a client, so the
1727 * server should always have returned it.
1729 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1730 status = NT_STATUS_DOWNGRADE_DETECTED;
1731 tevent_req_nterror(req, status);
1732 netlogon_creds_cli_check_cleanup(req, status);
1733 return;
1736 status = netlogon_creds_cli_store_internal(state->context,
1737 state->creds);
1738 if (tevent_req_nterror(req, status)) {
1739 return;
1742 tevent_req_done(req);
1745 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1746 union netr_Capabilities *capabilities)
1748 struct netlogon_creds_cli_check_state *state = tevent_req_data(
1749 req, struct netlogon_creds_cli_check_state);
1750 NTSTATUS status;
1752 if (tevent_req_is_nterror(req, &status)) {
1753 netlogon_creds_cli_check_cleanup(req, status);
1754 tevent_req_received(req);
1755 return status;
1758 if (capabilities != NULL) {
1759 *capabilities = state->caps;
1762 tevent_req_received(req);
1763 return NT_STATUS_OK;
1766 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1767 struct dcerpc_binding_handle *b,
1768 union netr_Capabilities *capabilities)
1770 TALLOC_CTX *frame = talloc_stackframe();
1771 struct tevent_context *ev;
1772 struct tevent_req *req;
1773 NTSTATUS status = NT_STATUS_NO_MEMORY;
1775 ev = samba_tevent_context_init(frame);
1776 if (ev == NULL) {
1777 goto fail;
1779 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1780 if (req == NULL) {
1781 goto fail;
1783 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1784 goto fail;
1786 status = netlogon_creds_cli_check_recv(req, capabilities);
1787 fail:
1788 TALLOC_FREE(frame);
1789 return status;
1792 struct netlogon_creds_cli_ServerPasswordSet_state {
1793 struct tevent_context *ev;
1794 struct netlogon_creds_cli_context *context;
1795 struct dcerpc_binding_handle *binding_handle;
1796 uint32_t old_timeout;
1798 char *srv_name_slash;
1799 enum dcerpc_AuthType auth_type;
1800 enum dcerpc_AuthLevel auth_level;
1802 struct samr_CryptPassword samr_crypt_password;
1803 struct netr_CryptPassword netr_crypt_password;
1804 struct samr_Password samr_password;
1806 struct netlogon_creds_CredentialState *creds;
1807 struct netlogon_creds_CredentialState tmp_creds;
1808 struct netr_Authenticator req_auth;
1809 struct netr_Authenticator rep_auth;
1812 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1813 NTSTATUS status);
1814 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1816 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1817 struct tevent_context *ev,
1818 struct netlogon_creds_cli_context *context,
1819 struct dcerpc_binding_handle *b,
1820 const DATA_BLOB *new_password,
1821 const uint32_t *new_version)
1823 struct tevent_req *req;
1824 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1825 struct tevent_req *subreq;
1826 bool ok;
1828 req = tevent_req_create(mem_ctx, &state,
1829 struct netlogon_creds_cli_ServerPasswordSet_state);
1830 if (req == NULL) {
1831 return NULL;
1834 state->ev = ev;
1835 state->context = context;
1836 state->binding_handle = b;
1838 if (new_password->length < 14) {
1839 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1840 return tevent_req_post(req, ev);
1844 * netr_ServerPasswordSet
1846 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1849 * netr_ServerPasswordSet2
1851 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1852 new_password);
1853 if (!ok) {
1854 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1855 return tevent_req_post(req, ev);
1858 if (new_version != NULL) {
1859 struct NL_PASSWORD_VERSION version;
1860 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1861 uint32_t ofs = 512 - len;
1862 uint8_t *p;
1864 if (len > 500) {
1865 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1866 return tevent_req_post(req, ev);
1868 ofs -= 12;
1870 version.ReservedField = 0;
1871 version.PasswordVersionNumber = *new_version;
1872 version.PasswordVersionPresent =
1873 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1875 p = state->samr_crypt_password.data + ofs;
1876 SIVAL(p, 0, version.ReservedField);
1877 SIVAL(p, 4, version.PasswordVersionNumber);
1878 SIVAL(p, 8, version.PasswordVersionPresent);
1881 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1882 context->server.computer);
1883 if (tevent_req_nomem(state->srv_name_slash, req)) {
1884 return tevent_req_post(req, ev);
1887 dcerpc_binding_handle_auth_info(state->binding_handle,
1888 &state->auth_type,
1889 &state->auth_level);
1891 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1892 state->context);
1893 if (tevent_req_nomem(subreq, req)) {
1894 return tevent_req_post(req, ev);
1897 tevent_req_set_callback(subreq,
1898 netlogon_creds_cli_ServerPasswordSet_locked,
1899 req);
1901 return req;
1904 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1905 NTSTATUS status)
1907 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1908 tevent_req_data(req,
1909 struct netlogon_creds_cli_ServerPasswordSet_state);
1911 if (state->creds == NULL) {
1912 return;
1915 dcerpc_binding_handle_set_timeout(state->binding_handle,
1916 state->old_timeout);
1918 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1919 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1920 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1921 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1922 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1923 TALLOC_FREE(state->creds);
1924 return;
1927 netlogon_creds_cli_delete(state->context, state->creds);
1928 TALLOC_FREE(state->creds);
1931 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1933 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1935 struct tevent_req *req =
1936 tevent_req_callback_data(subreq,
1937 struct tevent_req);
1938 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1939 tevent_req_data(req,
1940 struct netlogon_creds_cli_ServerPasswordSet_state);
1941 NTSTATUS status;
1943 status = netlogon_creds_cli_lock_recv(subreq, state,
1944 &state->creds);
1945 TALLOC_FREE(subreq);
1946 if (tevent_req_nterror(req, status)) {
1947 return;
1950 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1951 switch (state->auth_level) {
1952 case DCERPC_AUTH_LEVEL_INTEGRITY:
1953 case DCERPC_AUTH_LEVEL_PRIVACY:
1954 break;
1955 default:
1956 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1957 return;
1959 } else {
1960 uint32_t tmp = state->creds->negotiate_flags;
1962 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1964 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1965 * it should be used, which means
1966 * we had a chance to verify no downgrade
1967 * happened.
1969 * This relies on netlogon_creds_cli_check*
1970 * being called before, as first request after
1971 * the DCERPC bind.
1973 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1974 return;
1978 state->old_timeout = dcerpc_binding_handle_set_timeout(
1979 state->binding_handle, 600000);
1982 * we defer all callbacks in order to cleanup
1983 * the database record.
1985 tevent_req_defer_callback(req, state->ev);
1987 state->tmp_creds = *state->creds;
1988 status = netlogon_creds_client_authenticator(&state->tmp_creds,
1989 &state->req_auth);
1990 if (tevent_req_nterror(req, status)) {
1991 return;
1993 ZERO_STRUCT(state->rep_auth);
1995 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1997 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1998 status = netlogon_creds_aes_encrypt(&state->tmp_creds,
1999 state->samr_crypt_password.data,
2000 516);
2001 if (tevent_req_nterror(req, status)) {
2002 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2003 return;
2005 } else {
2006 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
2007 state->samr_crypt_password.data,
2008 516);
2009 if (tevent_req_nterror(req, status)) {
2010 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2011 return;
2015 memcpy(state->netr_crypt_password.data,
2016 state->samr_crypt_password.data, 512);
2017 state->netr_crypt_password.length =
2018 IVAL(state->samr_crypt_password.data, 512);
2020 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2021 state->binding_handle,
2022 state->srv_name_slash,
2023 state->tmp_creds.account_name,
2024 state->tmp_creds.secure_channel_type,
2025 state->tmp_creds.computer_name,
2026 &state->req_auth,
2027 &state->rep_auth,
2028 &state->netr_crypt_password);
2029 if (tevent_req_nomem(subreq, req)) {
2030 status = NT_STATUS_NO_MEMORY;
2031 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2032 return;
2034 } else {
2035 netlogon_creds_des_encrypt(&state->tmp_creds,
2036 &state->samr_password);
2038 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2039 state->binding_handle,
2040 state->srv_name_slash,
2041 state->tmp_creds.account_name,
2042 state->tmp_creds.secure_channel_type,
2043 state->tmp_creds.computer_name,
2044 &state->req_auth,
2045 &state->rep_auth,
2046 &state->samr_password);
2047 if (tevent_req_nomem(subreq, req)) {
2048 status = NT_STATUS_NO_MEMORY;
2049 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2050 return;
2054 tevent_req_set_callback(subreq,
2055 netlogon_creds_cli_ServerPasswordSet_done,
2056 req);
2059 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2061 struct tevent_req *req =
2062 tevent_req_callback_data(subreq,
2063 struct tevent_req);
2064 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2065 tevent_req_data(req,
2066 struct netlogon_creds_cli_ServerPasswordSet_state);
2067 NTSTATUS status;
2068 NTSTATUS result;
2069 bool ok;
2071 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2072 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2073 &result);
2074 TALLOC_FREE(subreq);
2075 if (tevent_req_nterror(req, status)) {
2076 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2077 return;
2079 } else {
2080 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2081 &result);
2082 TALLOC_FREE(subreq);
2083 if (tevent_req_nterror(req, status)) {
2084 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2085 return;
2089 ok = netlogon_creds_client_check(&state->tmp_creds,
2090 &state->rep_auth.cred);
2091 if (!ok) {
2092 status = NT_STATUS_ACCESS_DENIED;
2093 tevent_req_nterror(req, status);
2094 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2095 return;
2098 if (tevent_req_nterror(req, result)) {
2099 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2100 return;
2103 dcerpc_binding_handle_set_timeout(state->binding_handle,
2104 state->old_timeout);
2106 *state->creds = state->tmp_creds;
2107 status = netlogon_creds_cli_store(state->context,
2108 state->creds);
2109 TALLOC_FREE(state->creds);
2110 if (tevent_req_nterror(req, status)) {
2111 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2112 return;
2115 tevent_req_done(req);
2118 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2120 NTSTATUS status;
2122 if (tevent_req_is_nterror(req, &status)) {
2123 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2124 tevent_req_received(req);
2125 return status;
2128 tevent_req_received(req);
2129 return NT_STATUS_OK;
2132 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2133 struct netlogon_creds_cli_context *context,
2134 struct dcerpc_binding_handle *b,
2135 const DATA_BLOB *new_password,
2136 const uint32_t *new_version)
2138 TALLOC_CTX *frame = talloc_stackframe();
2139 struct tevent_context *ev;
2140 struct tevent_req *req;
2141 NTSTATUS status = NT_STATUS_NO_MEMORY;
2143 ev = samba_tevent_context_init(frame);
2144 if (ev == NULL) {
2145 goto fail;
2147 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2148 new_password,
2149 new_version);
2150 if (req == NULL) {
2151 goto fail;
2153 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2154 goto fail;
2156 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2157 fail:
2158 TALLOC_FREE(frame);
2159 return status;
2162 struct netlogon_creds_cli_LogonSamLogon_state {
2163 struct tevent_context *ev;
2164 struct netlogon_creds_cli_context *context;
2165 struct dcerpc_binding_handle *binding_handle;
2167 char *srv_name_slash;
2169 enum netr_LogonInfoClass logon_level;
2170 const union netr_LogonLevel *const_logon;
2171 union netr_LogonLevel *logon;
2172 uint32_t flags;
2174 uint16_t validation_level;
2175 union netr_Validation *validation;
2176 uint8_t authoritative;
2179 * do we need encryption at the application layer?
2181 bool user_encrypt;
2182 bool try_logon_ex;
2183 bool try_validation6;
2186 * the read only credentials before we started the operation
2187 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2189 struct netlogon_creds_CredentialState *ro_creds;
2192 * The (locked) credentials used for the credential chain
2193 * used for netr_LogonSamLogonWithFlags() or
2194 * netr_LogonSamLogonWith().
2196 struct netlogon_creds_CredentialState *lk_creds;
2199 * While we have locked the global credentials (lk_creds above)
2200 * we operate an a temporary copy, because a server
2201 * may not support netr_LogonSamLogonWithFlags() and
2202 * didn't process our netr_Authenticator, so we need to
2203 * restart from lk_creds.
2205 struct netlogon_creds_CredentialState tmp_creds;
2206 struct netr_Authenticator req_auth;
2207 struct netr_Authenticator rep_auth;
2210 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2211 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2212 NTSTATUS status);
2214 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2215 struct tevent_context *ev,
2216 struct netlogon_creds_cli_context *context,
2217 struct dcerpc_binding_handle *b,
2218 enum netr_LogonInfoClass logon_level,
2219 const union netr_LogonLevel *logon,
2220 uint32_t flags)
2222 struct tevent_req *req;
2223 struct netlogon_creds_cli_LogonSamLogon_state *state;
2225 req = tevent_req_create(mem_ctx, &state,
2226 struct netlogon_creds_cli_LogonSamLogon_state);
2227 if (req == NULL) {
2228 return NULL;
2231 state->ev = ev;
2232 state->context = context;
2233 state->binding_handle = b;
2235 state->logon_level = logon_level;
2236 state->const_logon = logon;
2237 state->flags = flags;
2239 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2240 context->server.computer);
2241 if (tevent_req_nomem(state->srv_name_slash, req)) {
2242 return tevent_req_post(req, ev);
2245 switch (logon_level) {
2246 case NetlogonInteractiveInformation:
2247 case NetlogonInteractiveTransitiveInformation:
2248 case NetlogonServiceInformation:
2249 case NetlogonServiceTransitiveInformation:
2250 case NetlogonGenericInformation:
2251 state->user_encrypt = true;
2252 break;
2254 case NetlogonNetworkInformation:
2255 case NetlogonNetworkTransitiveInformation:
2256 break;
2259 state->validation = talloc_zero(state, union netr_Validation);
2260 if (tevent_req_nomem(state->validation, req)) {
2261 return tevent_req_post(req, ev);
2264 netlogon_creds_cli_LogonSamLogon_start(req);
2265 if (!tevent_req_is_in_progress(req)) {
2266 return tevent_req_post(req, ev);
2270 * we defer all callbacks in order to cleanup
2271 * the database record.
2273 tevent_req_defer_callback(req, state->ev);
2274 return req;
2277 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2278 NTSTATUS status)
2280 struct netlogon_creds_cli_LogonSamLogon_state *state =
2281 tevent_req_data(req,
2282 struct netlogon_creds_cli_LogonSamLogon_state);
2284 if (state->lk_creds == NULL) {
2285 return;
2288 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2290 * This is a hack to recover from a bug in old
2291 * Samba servers, when LogonSamLogonEx() fails:
2293 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2295 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2297 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2298 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2299 * If the sign/seal check fails.
2301 * In that case we need to cleanup the netlogon session.
2303 * It's the job of the caller to disconnect the current
2304 * connection, if netlogon_creds_cli_LogonSamLogon()
2305 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2307 if (!state->context->server.try_logon_with) {
2308 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2312 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2313 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2314 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2315 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2316 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2317 TALLOC_FREE(state->lk_creds);
2318 return;
2321 netlogon_creds_cli_delete(state->context, state->lk_creds);
2322 TALLOC_FREE(state->lk_creds);
2325 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2327 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2329 struct netlogon_creds_cli_LogonSamLogon_state *state =
2330 tevent_req_data(req,
2331 struct netlogon_creds_cli_LogonSamLogon_state);
2332 struct tevent_req *subreq;
2333 NTSTATUS status;
2334 enum dcerpc_AuthType auth_type;
2335 enum dcerpc_AuthLevel auth_level;
2337 TALLOC_FREE(state->ro_creds);
2338 TALLOC_FREE(state->logon);
2339 ZERO_STRUCTP(state->validation);
2341 dcerpc_binding_handle_auth_info(state->binding_handle,
2342 &auth_type, &auth_level);
2344 state->try_logon_ex = state->context->server.try_logon_ex;
2345 state->try_validation6 = state->context->server.try_validation6;
2347 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2348 state->try_logon_ex = false;
2351 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2352 state->try_validation6 = false;
2355 if (state->try_logon_ex) {
2356 if (state->try_validation6) {
2357 state->validation_level = 6;
2358 } else {
2359 state->validation_level = 3;
2360 state->user_encrypt = true;
2363 state->logon = netlogon_creds_shallow_copy_logon(state,
2364 state->logon_level,
2365 state->const_logon);
2366 if (tevent_req_nomem(state->logon, req)) {
2367 status = NT_STATUS_NO_MEMORY;
2368 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2369 return;
2372 if (state->user_encrypt) {
2373 status = netlogon_creds_cli_get(state->context,
2374 state,
2375 &state->ro_creds);
2376 if (!NT_STATUS_IS_OK(status)) {
2377 status = NT_STATUS_ACCESS_DENIED;
2378 tevent_req_nterror(req, status);
2379 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2380 return;
2383 status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2384 state->logon_level,
2385 state->logon);
2386 if (!NT_STATUS_IS_OK(status)) {
2387 status = NT_STATUS_ACCESS_DENIED;
2388 tevent_req_nterror(req, status);
2389 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2390 return;
2394 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2395 state->binding_handle,
2396 state->srv_name_slash,
2397 state->context->client.computer,
2398 state->logon_level,
2399 state->logon,
2400 state->validation_level,
2401 state->validation,
2402 &state->authoritative,
2403 &state->flags);
2404 if (tevent_req_nomem(subreq, req)) {
2405 status = NT_STATUS_NO_MEMORY;
2406 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2407 return;
2409 tevent_req_set_callback(subreq,
2410 netlogon_creds_cli_LogonSamLogon_done,
2411 req);
2412 return;
2415 if (state->lk_creds == NULL) {
2416 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2417 state->context);
2418 if (tevent_req_nomem(subreq, req)) {
2419 status = NT_STATUS_NO_MEMORY;
2420 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2421 return;
2423 tevent_req_set_callback(subreq,
2424 netlogon_creds_cli_LogonSamLogon_done,
2425 req);
2426 return;
2429 state->tmp_creds = *state->lk_creds;
2430 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2431 &state->req_auth);
2432 if (tevent_req_nterror(req, status)) {
2433 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2434 return;
2436 ZERO_STRUCT(state->rep_auth);
2438 state->logon = netlogon_creds_shallow_copy_logon(state,
2439 state->logon_level,
2440 state->const_logon);
2441 if (tevent_req_nomem(state->logon, req)) {
2442 status = NT_STATUS_NO_MEMORY;
2443 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2444 return;
2447 status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2448 state->logon_level,
2449 state->logon);
2450 if (tevent_req_nterror(req, status)) {
2451 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2452 return;
2455 state->validation_level = 3;
2457 if (state->context->server.try_logon_with) {
2458 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2459 state->binding_handle,
2460 state->srv_name_slash,
2461 state->context->client.computer,
2462 &state->req_auth,
2463 &state->rep_auth,
2464 state->logon_level,
2465 state->logon,
2466 state->validation_level,
2467 state->validation,
2468 &state->authoritative,
2469 &state->flags);
2470 if (tevent_req_nomem(subreq, req)) {
2471 status = NT_STATUS_NO_MEMORY;
2472 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2473 return;
2475 } else {
2476 state->flags = 0;
2478 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2479 state->binding_handle,
2480 state->srv_name_slash,
2481 state->context->client.computer,
2482 &state->req_auth,
2483 &state->rep_auth,
2484 state->logon_level,
2485 state->logon,
2486 state->validation_level,
2487 state->validation,
2488 &state->authoritative);
2489 if (tevent_req_nomem(subreq, req)) {
2490 status = NT_STATUS_NO_MEMORY;
2491 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2492 return;
2496 tevent_req_set_callback(subreq,
2497 netlogon_creds_cli_LogonSamLogon_done,
2498 req);
2501 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2503 struct tevent_req *req =
2504 tevent_req_callback_data(subreq,
2505 struct tevent_req);
2506 struct netlogon_creds_cli_LogonSamLogon_state *state =
2507 tevent_req_data(req,
2508 struct netlogon_creds_cli_LogonSamLogon_state);
2509 NTSTATUS status;
2510 NTSTATUS result;
2511 bool ok;
2513 if (state->try_logon_ex) {
2514 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2515 state->validation,
2516 &result);
2517 TALLOC_FREE(subreq);
2518 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2519 state->context->server.try_validation6 = false;
2520 state->context->server.try_logon_ex = false;
2521 netlogon_creds_cli_LogonSamLogon_start(req);
2522 return;
2524 if (tevent_req_nterror(req, status)) {
2525 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2526 return;
2529 if ((state->validation_level == 6) &&
2530 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2531 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2532 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2534 state->context->server.try_validation6 = false;
2535 netlogon_creds_cli_LogonSamLogon_start(req);
2536 return;
2539 if (tevent_req_nterror(req, result)) {
2540 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2541 return;
2544 if (state->ro_creds == NULL) {
2545 tevent_req_done(req);
2546 return;
2549 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2550 if (!ok) {
2552 * We got a race, lets retry with on authenticator
2553 * protection.
2555 * netlogon_creds_cli_LogonSamLogon_start()
2556 * will TALLOC_FREE(state->ro_creds);
2558 state->try_logon_ex = false;
2559 netlogon_creds_cli_LogonSamLogon_start(req);
2560 return;
2563 status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2564 state->validation_level,
2565 state->validation);
2566 if (tevent_req_nterror(req, status)) {
2567 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2568 return;
2571 tevent_req_done(req);
2572 return;
2575 if (state->lk_creds == NULL) {
2576 status = netlogon_creds_cli_lock_recv(subreq, state,
2577 &state->lk_creds);
2578 TALLOC_FREE(subreq);
2579 if (tevent_req_nterror(req, status)) {
2580 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2581 return;
2584 netlogon_creds_cli_LogonSamLogon_start(req);
2585 return;
2588 if (state->context->server.try_logon_with) {
2589 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2590 state->validation,
2591 &result);
2592 TALLOC_FREE(subreq);
2593 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2594 state->context->server.try_logon_with = false;
2595 netlogon_creds_cli_LogonSamLogon_start(req);
2596 return;
2598 if (tevent_req_nterror(req, status)) {
2599 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2600 return;
2602 } else {
2603 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2604 state->validation,
2605 &result);
2606 TALLOC_FREE(subreq);
2607 if (tevent_req_nterror(req, status)) {
2608 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2609 return;
2613 ok = netlogon_creds_client_check(&state->tmp_creds,
2614 &state->rep_auth.cred);
2615 if (!ok) {
2616 status = NT_STATUS_ACCESS_DENIED;
2617 tevent_req_nterror(req, status);
2618 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2619 return;
2622 *state->lk_creds = state->tmp_creds;
2623 status = netlogon_creds_cli_store(state->context,
2624 state->lk_creds);
2625 TALLOC_FREE(state->lk_creds);
2627 if (tevent_req_nterror(req, status)) {
2628 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2629 return;
2632 if (tevent_req_nterror(req, result)) {
2633 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2634 return;
2637 status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2638 state->validation_level,
2639 state->validation);
2640 if (tevent_req_nterror(req, status)) {
2641 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2642 return;
2645 tevent_req_done(req);
2648 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2649 TALLOC_CTX *mem_ctx,
2650 uint16_t *validation_level,
2651 union netr_Validation **validation,
2652 uint8_t *authoritative,
2653 uint32_t *flags)
2655 struct netlogon_creds_cli_LogonSamLogon_state *state =
2656 tevent_req_data(req,
2657 struct netlogon_creds_cli_LogonSamLogon_state);
2658 NTSTATUS status;
2660 /* authoritative is also returned on error */
2661 *authoritative = state->authoritative;
2663 if (tevent_req_is_nterror(req, &status)) {
2664 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2665 tevent_req_received(req);
2666 return status;
2669 *validation_level = state->validation_level;
2670 *validation = talloc_move(mem_ctx, &state->validation);
2671 *flags = state->flags;
2673 tevent_req_received(req);
2674 return NT_STATUS_OK;
2677 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2678 struct netlogon_creds_cli_context *context,
2679 struct dcerpc_binding_handle *b,
2680 enum netr_LogonInfoClass logon_level,
2681 const union netr_LogonLevel *logon,
2682 TALLOC_CTX *mem_ctx,
2683 uint16_t *validation_level,
2684 union netr_Validation **validation,
2685 uint8_t *authoritative,
2686 uint32_t *flags)
2688 TALLOC_CTX *frame = talloc_stackframe();
2689 struct tevent_context *ev;
2690 struct tevent_req *req;
2691 NTSTATUS status = NT_STATUS_NO_MEMORY;
2693 ev = samba_tevent_context_init(frame);
2694 if (ev == NULL) {
2695 goto fail;
2697 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2698 logon_level, logon,
2699 *flags);
2700 if (req == NULL) {
2701 goto fail;
2703 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2704 goto fail;
2706 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2707 validation_level,
2708 validation,
2709 authoritative,
2710 flags);
2711 fail:
2712 TALLOC_FREE(frame);
2713 return status;
2716 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2717 struct tevent_context *ev;
2718 struct netlogon_creds_cli_context *context;
2719 struct dcerpc_binding_handle *binding_handle;
2721 char *srv_name_slash;
2722 enum dcerpc_AuthType auth_type;
2723 enum dcerpc_AuthLevel auth_level;
2725 const char *site_name;
2726 uint32_t dns_ttl;
2727 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2729 struct netlogon_creds_CredentialState *creds;
2730 struct netlogon_creds_CredentialState tmp_creds;
2731 struct netr_Authenticator req_auth;
2732 struct netr_Authenticator rep_auth;
2735 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2736 NTSTATUS status);
2737 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2739 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2740 struct tevent_context *ev,
2741 struct netlogon_creds_cli_context *context,
2742 struct dcerpc_binding_handle *b,
2743 const char *site_name,
2744 uint32_t dns_ttl,
2745 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2747 struct tevent_req *req;
2748 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2749 struct tevent_req *subreq;
2751 req = tevent_req_create(mem_ctx, &state,
2752 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2753 if (req == NULL) {
2754 return NULL;
2757 state->ev = ev;
2758 state->context = context;
2759 state->binding_handle = b;
2761 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2762 context->server.computer);
2763 if (tevent_req_nomem(state->srv_name_slash, req)) {
2764 return tevent_req_post(req, ev);
2767 state->site_name = site_name;
2768 state->dns_ttl = dns_ttl;
2769 state->dns_names = dns_names;
2771 dcerpc_binding_handle_auth_info(state->binding_handle,
2772 &state->auth_type,
2773 &state->auth_level);
2775 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2776 state->context);
2777 if (tevent_req_nomem(subreq, req)) {
2778 return tevent_req_post(req, ev);
2781 tevent_req_set_callback(subreq,
2782 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2783 req);
2785 return req;
2788 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2789 NTSTATUS status)
2791 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2792 tevent_req_data(req,
2793 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2795 if (state->creds == NULL) {
2796 return;
2799 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2800 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2801 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2802 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2803 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2804 TALLOC_FREE(state->creds);
2805 return;
2808 netlogon_creds_cli_delete(state->context, state->creds);
2809 TALLOC_FREE(state->creds);
2812 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2814 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2816 struct tevent_req *req =
2817 tevent_req_callback_data(subreq,
2818 struct tevent_req);
2819 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2820 tevent_req_data(req,
2821 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2822 NTSTATUS status;
2824 status = netlogon_creds_cli_lock_recv(subreq, state,
2825 &state->creds);
2826 TALLOC_FREE(subreq);
2827 if (tevent_req_nterror(req, status)) {
2828 return;
2831 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2832 switch (state->auth_level) {
2833 case DCERPC_AUTH_LEVEL_INTEGRITY:
2834 case DCERPC_AUTH_LEVEL_PRIVACY:
2835 break;
2836 default:
2837 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2838 return;
2840 } else {
2841 uint32_t tmp = state->creds->negotiate_flags;
2843 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2845 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2846 * it should be used, which means
2847 * we had a chance to verify no downgrade
2848 * happened.
2850 * This relies on netlogon_creds_cli_check*
2851 * being called before, as first request after
2852 * the DCERPC bind.
2854 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2855 return;
2860 * we defer all callbacks in order to cleanup
2861 * the database record.
2863 tevent_req_defer_callback(req, state->ev);
2865 state->tmp_creds = *state->creds;
2866 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2867 &state->req_auth);
2868 if (tevent_req_nterror(req, status)) {
2869 return;
2871 ZERO_STRUCT(state->rep_auth);
2873 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2874 state->binding_handle,
2875 state->srv_name_slash,
2876 state->tmp_creds.computer_name,
2877 &state->req_auth,
2878 &state->rep_auth,
2879 state->site_name,
2880 state->dns_ttl,
2881 state->dns_names);
2882 if (tevent_req_nomem(subreq, req)) {
2883 status = NT_STATUS_NO_MEMORY;
2884 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2885 return;
2888 tevent_req_set_callback(subreq,
2889 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2890 req);
2893 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2895 struct tevent_req *req =
2896 tevent_req_callback_data(subreq,
2897 struct tevent_req);
2898 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2899 tevent_req_data(req,
2900 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2901 NTSTATUS status;
2902 NTSTATUS result;
2903 bool ok;
2906 * We use state->dns_names as the memory context, as this is
2907 * the only in/out variable and it has been overwritten by the
2908 * out parameter from the server.
2910 * We need to preserve the return value until the caller can use it.
2912 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2913 &result);
2914 TALLOC_FREE(subreq);
2915 if (tevent_req_nterror(req, status)) {
2916 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2917 return;
2920 ok = netlogon_creds_client_check(&state->tmp_creds,
2921 &state->rep_auth.cred);
2922 if (!ok) {
2923 status = NT_STATUS_ACCESS_DENIED;
2924 tevent_req_nterror(req, status);
2925 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2926 return;
2929 *state->creds = state->tmp_creds;
2930 status = netlogon_creds_cli_store(state->context,
2931 state->creds);
2932 TALLOC_FREE(state->creds);
2934 if (tevent_req_nterror(req, status)) {
2935 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2936 return;
2939 if (tevent_req_nterror(req, result)) {
2940 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2941 return;
2944 tevent_req_done(req);
2947 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2949 NTSTATUS status;
2951 if (tevent_req_is_nterror(req, &status)) {
2952 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2953 tevent_req_received(req);
2954 return status;
2957 tevent_req_received(req);
2958 return NT_STATUS_OK;
2961 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2962 struct netlogon_creds_cli_context *context,
2963 struct dcerpc_binding_handle *b,
2964 const char *site_name,
2965 uint32_t dns_ttl,
2966 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2968 TALLOC_CTX *frame = talloc_stackframe();
2969 struct tevent_context *ev;
2970 struct tevent_req *req;
2971 NTSTATUS status = NT_STATUS_NO_MEMORY;
2973 ev = samba_tevent_context_init(frame);
2974 if (ev == NULL) {
2975 goto fail;
2977 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2978 site_name,
2979 dns_ttl,
2980 dns_names);
2981 if (req == NULL) {
2982 goto fail;
2984 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2985 goto fail;
2987 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2988 fail:
2989 TALLOC_FREE(frame);
2990 return status;
2993 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2994 struct tevent_context *ev;
2995 struct netlogon_creds_cli_context *context;
2996 struct dcerpc_binding_handle *binding_handle;
2998 char *srv_name_slash;
2999 enum dcerpc_AuthType auth_type;
3000 enum dcerpc_AuthLevel auth_level;
3002 struct samr_Password new_owf_password;
3003 struct samr_Password old_owf_password;
3004 struct netr_TrustInfo *trust_info;
3006 struct netlogon_creds_CredentialState *creds;
3007 struct netlogon_creds_CredentialState tmp_creds;
3008 struct netr_Authenticator req_auth;
3009 struct netr_Authenticator rep_auth;
3012 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3013 NTSTATUS status);
3014 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
3016 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
3017 struct tevent_context *ev,
3018 struct netlogon_creds_cli_context *context,
3019 struct dcerpc_binding_handle *b)
3021 struct tevent_req *req;
3022 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
3023 struct tevent_req *subreq;
3025 req = tevent_req_create(mem_ctx, &state,
3026 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3027 if (req == NULL) {
3028 return NULL;
3031 state->ev = ev;
3032 state->context = context;
3033 state->binding_handle = b;
3035 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3036 context->server.computer);
3037 if (tevent_req_nomem(state->srv_name_slash, req)) {
3038 return tevent_req_post(req, ev);
3041 dcerpc_binding_handle_auth_info(state->binding_handle,
3042 &state->auth_type,
3043 &state->auth_level);
3045 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3046 state->context);
3047 if (tevent_req_nomem(subreq, req)) {
3048 return tevent_req_post(req, ev);
3051 tevent_req_set_callback(subreq,
3052 netlogon_creds_cli_ServerGetTrustInfo_locked,
3053 req);
3055 return req;
3058 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3059 NTSTATUS status)
3061 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3062 tevent_req_data(req,
3063 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3065 if (state->creds == NULL) {
3066 return;
3069 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3070 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3071 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3072 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3073 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3074 TALLOC_FREE(state->creds);
3075 return;
3078 netlogon_creds_cli_delete(state->context, state->creds);
3079 TALLOC_FREE(state->creds);
3082 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3084 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3086 struct tevent_req *req =
3087 tevent_req_callback_data(subreq,
3088 struct tevent_req);
3089 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3090 tevent_req_data(req,
3091 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3092 NTSTATUS status;
3094 status = netlogon_creds_cli_lock_recv(subreq, state,
3095 &state->creds);
3096 TALLOC_FREE(subreq);
3097 if (tevent_req_nterror(req, status)) {
3098 return;
3101 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3102 switch (state->auth_level) {
3103 case DCERPC_AUTH_LEVEL_PRIVACY:
3104 break;
3105 default:
3106 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3107 return;
3109 } else {
3110 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3111 return;
3115 * we defer all callbacks in order to cleanup
3116 * the database record.
3118 tevent_req_defer_callback(req, state->ev);
3120 state->tmp_creds = *state->creds;
3121 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3122 &state->req_auth);
3123 if (tevent_req_nterror(req, status)) {
3124 return;
3126 ZERO_STRUCT(state->rep_auth);
3128 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3129 state->binding_handle,
3130 state->srv_name_slash,
3131 state->tmp_creds.account_name,
3132 state->tmp_creds.secure_channel_type,
3133 state->tmp_creds.computer_name,
3134 &state->req_auth,
3135 &state->rep_auth,
3136 &state->new_owf_password,
3137 &state->old_owf_password,
3138 &state->trust_info);
3139 if (tevent_req_nomem(subreq, req)) {
3140 status = NT_STATUS_NO_MEMORY;
3141 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3142 return;
3145 tevent_req_set_callback(subreq,
3146 netlogon_creds_cli_ServerGetTrustInfo_done,
3147 req);
3150 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3152 struct tevent_req *req =
3153 tevent_req_callback_data(subreq,
3154 struct tevent_req);
3155 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3156 tevent_req_data(req,
3157 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3158 NTSTATUS status;
3159 NTSTATUS result;
3160 const struct samr_Password zero = {};
3161 int cmp;
3162 bool ok;
3165 * We use state->dns_names as the memory context, as this is
3166 * the only in/out variable and it has been overwritten by the
3167 * out parameter from the server.
3169 * We need to preserve the return value until the caller can use it.
3171 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3172 TALLOC_FREE(subreq);
3173 if (tevent_req_nterror(req, status)) {
3174 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3175 return;
3178 ok = netlogon_creds_client_check(&state->tmp_creds,
3179 &state->rep_auth.cred);
3180 if (!ok) {
3181 status = NT_STATUS_ACCESS_DENIED;
3182 tevent_req_nterror(req, status);
3183 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3184 return;
3187 cmp = memcmp(state->new_owf_password.hash,
3188 zero.hash, sizeof(zero.hash));
3189 if (cmp != 0) {
3190 netlogon_creds_des_decrypt(&state->tmp_creds,
3191 &state->new_owf_password);
3193 cmp = memcmp(state->old_owf_password.hash,
3194 zero.hash, sizeof(zero.hash));
3195 if (cmp != 0) {
3196 netlogon_creds_des_decrypt(&state->tmp_creds,
3197 &state->old_owf_password);
3200 *state->creds = state->tmp_creds;
3201 status = netlogon_creds_cli_store(state->context,
3202 state->creds);
3203 TALLOC_FREE(state->creds);
3204 if (tevent_req_nterror(req, status)) {
3205 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3206 return;
3209 if (tevent_req_nterror(req, result)) {
3210 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3211 return;
3214 tevent_req_done(req);
3217 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3218 TALLOC_CTX *mem_ctx,
3219 struct samr_Password *new_owf_password,
3220 struct samr_Password *old_owf_password,
3221 struct netr_TrustInfo **trust_info)
3223 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3224 tevent_req_data(req,
3225 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3226 NTSTATUS status;
3228 if (tevent_req_is_nterror(req, &status)) {
3229 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3230 tevent_req_received(req);
3231 return status;
3234 if (new_owf_password != NULL) {
3235 *new_owf_password = state->new_owf_password;
3237 if (old_owf_password != NULL) {
3238 *old_owf_password = state->old_owf_password;
3240 if (trust_info != NULL) {
3241 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3244 tevent_req_received(req);
3245 return NT_STATUS_OK;
3248 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3249 struct netlogon_creds_cli_context *context,
3250 struct dcerpc_binding_handle *b,
3251 TALLOC_CTX *mem_ctx,
3252 struct samr_Password *new_owf_password,
3253 struct samr_Password *old_owf_password,
3254 struct netr_TrustInfo **trust_info)
3256 TALLOC_CTX *frame = talloc_stackframe();
3257 struct tevent_context *ev;
3258 struct tevent_req *req;
3259 NTSTATUS status = NT_STATUS_NO_MEMORY;
3261 ev = samba_tevent_context_init(frame);
3262 if (ev == NULL) {
3263 goto fail;
3265 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3266 if (req == NULL) {
3267 goto fail;
3269 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3270 goto fail;
3272 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3273 mem_ctx,
3274 new_owf_password,
3275 old_owf_password,
3276 trust_info);
3277 fail:
3278 TALLOC_FREE(frame);
3279 return status;
3282 struct netlogon_creds_cli_GetForestTrustInformation_state {
3283 struct tevent_context *ev;
3284 struct netlogon_creds_cli_context *context;
3285 struct dcerpc_binding_handle *binding_handle;
3287 char *srv_name_slash;
3288 enum dcerpc_AuthType auth_type;
3289 enum dcerpc_AuthLevel auth_level;
3291 uint32_t flags;
3292 struct lsa_ForestTrustInformation *forest_trust_info;
3294 struct netlogon_creds_CredentialState *creds;
3295 struct netlogon_creds_CredentialState tmp_creds;
3296 struct netr_Authenticator req_auth;
3297 struct netr_Authenticator rep_auth;
3300 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3301 NTSTATUS status);
3302 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3304 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3305 struct tevent_context *ev,
3306 struct netlogon_creds_cli_context *context,
3307 struct dcerpc_binding_handle *b)
3309 struct tevent_req *req;
3310 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3311 struct tevent_req *subreq;
3313 req = tevent_req_create(mem_ctx, &state,
3314 struct netlogon_creds_cli_GetForestTrustInformation_state);
3315 if (req == NULL) {
3316 return NULL;
3319 state->ev = ev;
3320 state->context = context;
3321 state->binding_handle = b;
3323 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3324 context->server.computer);
3325 if (tevent_req_nomem(state->srv_name_slash, req)) {
3326 return tevent_req_post(req, ev);
3329 state->flags = 0;
3331 dcerpc_binding_handle_auth_info(state->binding_handle,
3332 &state->auth_type,
3333 &state->auth_level);
3335 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3336 state->context);
3337 if (tevent_req_nomem(subreq, req)) {
3338 return tevent_req_post(req, ev);
3341 tevent_req_set_callback(subreq,
3342 netlogon_creds_cli_GetForestTrustInformation_locked,
3343 req);
3345 return req;
3348 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3349 NTSTATUS status)
3351 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3352 tevent_req_data(req,
3353 struct netlogon_creds_cli_GetForestTrustInformation_state);
3355 if (state->creds == NULL) {
3356 return;
3359 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3360 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3361 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3362 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3363 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3364 TALLOC_FREE(state->creds);
3365 return;
3368 netlogon_creds_cli_delete(state->context, state->creds);
3369 TALLOC_FREE(state->creds);
3372 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3374 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3376 struct tevent_req *req =
3377 tevent_req_callback_data(subreq,
3378 struct tevent_req);
3379 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3380 tevent_req_data(req,
3381 struct netlogon_creds_cli_GetForestTrustInformation_state);
3382 NTSTATUS status;
3384 status = netlogon_creds_cli_lock_recv(subreq, state,
3385 &state->creds);
3386 TALLOC_FREE(subreq);
3387 if (tevent_req_nterror(req, status)) {
3388 return;
3391 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3392 switch (state->auth_level) {
3393 case DCERPC_AUTH_LEVEL_INTEGRITY:
3394 case DCERPC_AUTH_LEVEL_PRIVACY:
3395 break;
3396 default:
3397 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3398 return;
3400 } else {
3401 uint32_t tmp = state->creds->negotiate_flags;
3403 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3405 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3406 * it should be used, which means
3407 * we had a chance to verify no downgrade
3408 * happened.
3410 * This relies on netlogon_creds_cli_check*
3411 * being called before, as first request after
3412 * the DCERPC bind.
3414 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3415 return;
3420 * we defer all callbacks in order to cleanup
3421 * the database record.
3423 tevent_req_defer_callback(req, state->ev);
3425 state->tmp_creds = *state->creds;
3426 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3427 &state->req_auth);
3428 if (tevent_req_nterror(req, status)) {
3429 return;
3431 ZERO_STRUCT(state->rep_auth);
3433 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3434 state->binding_handle,
3435 state->srv_name_slash,
3436 state->tmp_creds.computer_name,
3437 &state->req_auth,
3438 &state->rep_auth,
3439 state->flags,
3440 &state->forest_trust_info);
3441 if (tevent_req_nomem(subreq, req)) {
3442 status = NT_STATUS_NO_MEMORY;
3443 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3444 return;
3447 tevent_req_set_callback(subreq,
3448 netlogon_creds_cli_GetForestTrustInformation_done,
3449 req);
3452 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3454 struct tevent_req *req =
3455 tevent_req_callback_data(subreq,
3456 struct tevent_req);
3457 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3458 tevent_req_data(req,
3459 struct netlogon_creds_cli_GetForestTrustInformation_state);
3460 NTSTATUS status;
3461 NTSTATUS result;
3462 bool ok;
3465 * We use state->dns_names as the memory context, as this is
3466 * the only in/out variable and it has been overwritten by the
3467 * out parameter from the server.
3469 * We need to preserve the return value until the caller can use it.
3471 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3472 TALLOC_FREE(subreq);
3473 if (tevent_req_nterror(req, status)) {
3474 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3475 return;
3478 ok = netlogon_creds_client_check(&state->tmp_creds,
3479 &state->rep_auth.cred);
3480 if (!ok) {
3481 status = NT_STATUS_ACCESS_DENIED;
3482 tevent_req_nterror(req, status);
3483 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3484 return;
3487 *state->creds = state->tmp_creds;
3488 status = netlogon_creds_cli_store(state->context,
3489 state->creds);
3490 TALLOC_FREE(state->creds);
3492 if (tevent_req_nterror(req, status)) {
3493 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3494 return;
3497 if (tevent_req_nterror(req, result)) {
3498 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3499 return;
3502 tevent_req_done(req);
3505 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3506 TALLOC_CTX *mem_ctx,
3507 struct lsa_ForestTrustInformation **forest_trust_info)
3509 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3510 tevent_req_data(req,
3511 struct netlogon_creds_cli_GetForestTrustInformation_state);
3512 NTSTATUS status;
3514 if (tevent_req_is_nterror(req, &status)) {
3515 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3516 tevent_req_received(req);
3517 return status;
3520 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3522 tevent_req_received(req);
3523 return NT_STATUS_OK;
3526 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3527 struct netlogon_creds_cli_context *context,
3528 struct dcerpc_binding_handle *b,
3529 TALLOC_CTX *mem_ctx,
3530 struct lsa_ForestTrustInformation **forest_trust_info)
3532 TALLOC_CTX *frame = talloc_stackframe();
3533 struct tevent_context *ev;
3534 struct tevent_req *req;
3535 NTSTATUS status = NT_STATUS_NO_MEMORY;
3537 ev = samba_tevent_context_init(frame);
3538 if (ev == NULL) {
3539 goto fail;
3541 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3542 if (req == NULL) {
3543 goto fail;
3545 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3546 goto fail;
3548 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3549 mem_ctx,
3550 forest_trust_info);
3551 fail:
3552 TALLOC_FREE(frame);
3553 return status;
3555 struct netlogon_creds_cli_SendToSam_state {
3556 struct tevent_context *ev;
3557 struct netlogon_creds_cli_context *context;
3558 struct dcerpc_binding_handle *binding_handle;
3560 char *srv_name_slash;
3561 enum dcerpc_AuthType auth_type;
3562 enum dcerpc_AuthLevel auth_level;
3564 DATA_BLOB opaque;
3566 struct netlogon_creds_CredentialState *creds;
3567 struct netlogon_creds_CredentialState tmp_creds;
3568 struct netr_Authenticator req_auth;
3569 struct netr_Authenticator rep_auth;
3572 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3573 NTSTATUS status);
3574 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3576 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3577 struct tevent_context *ev,
3578 struct netlogon_creds_cli_context *context,
3579 struct dcerpc_binding_handle *b,
3580 struct netr_SendToSamBase *message)
3582 struct tevent_req *req;
3583 struct netlogon_creds_cli_SendToSam_state *state;
3584 struct tevent_req *subreq;
3585 enum ndr_err_code ndr_err;
3587 req = tevent_req_create(mem_ctx, &state,
3588 struct netlogon_creds_cli_SendToSam_state);
3589 if (req == NULL) {
3590 return NULL;
3593 state->ev = ev;
3594 state->context = context;
3595 state->binding_handle = b;
3597 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3598 context->server.computer);
3599 if (tevent_req_nomem(state->srv_name_slash, req)) {
3600 return tevent_req_post(req, ev);
3603 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3604 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3605 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3606 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3607 tevent_req_nterror(req, status);
3608 return tevent_req_post(req, ev);
3611 dcerpc_binding_handle_auth_info(state->binding_handle,
3612 &state->auth_type,
3613 &state->auth_level);
3615 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3616 state->context);
3617 if (tevent_req_nomem(subreq, req)) {
3618 return tevent_req_post(req, ev);
3621 tevent_req_set_callback(subreq,
3622 netlogon_creds_cli_SendToSam_locked,
3623 req);
3625 return req;
3628 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3629 NTSTATUS status)
3631 struct netlogon_creds_cli_SendToSam_state *state =
3632 tevent_req_data(req,
3633 struct netlogon_creds_cli_SendToSam_state);
3635 if (state->creds == NULL) {
3636 return;
3639 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3640 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3641 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3642 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3643 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3644 TALLOC_FREE(state->creds);
3645 return;
3648 netlogon_creds_cli_delete(state->context, state->creds);
3649 TALLOC_FREE(state->creds);
3652 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3654 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3656 struct tevent_req *req =
3657 tevent_req_callback_data(subreq,
3658 struct tevent_req);
3659 struct netlogon_creds_cli_SendToSam_state *state =
3660 tevent_req_data(req,
3661 struct netlogon_creds_cli_SendToSam_state);
3662 NTSTATUS status;
3664 status = netlogon_creds_cli_lock_recv(subreq, state,
3665 &state->creds);
3666 TALLOC_FREE(subreq);
3667 if (tevent_req_nterror(req, status)) {
3668 return;
3671 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3672 switch (state->auth_level) {
3673 case DCERPC_AUTH_LEVEL_INTEGRITY:
3674 case DCERPC_AUTH_LEVEL_PRIVACY:
3675 break;
3676 default:
3677 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3678 return;
3680 } else {
3681 uint32_t tmp = state->creds->negotiate_flags;
3683 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3685 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3686 * it should be used, which means
3687 * we had a chance to verify no downgrade
3688 * happened.
3690 * This relies on netlogon_creds_cli_check*
3691 * being called before, as first request after
3692 * the DCERPC bind.
3694 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3695 return;
3700 * we defer all callbacks in order to cleanup
3701 * the database record.
3703 tevent_req_defer_callback(req, state->ev);
3705 state->tmp_creds = *state->creds;
3706 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3707 &state->req_auth);
3708 if (tevent_req_nterror(req, status)) {
3709 return;
3711 ZERO_STRUCT(state->rep_auth);
3713 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3714 status = netlogon_creds_aes_encrypt(&state->tmp_creds,
3715 state->opaque.data,
3716 state->opaque.length);
3717 if (tevent_req_nterror(req, status)) {
3718 netlogon_creds_cli_SendToSam_cleanup(req, status);
3719 return;
3721 } else {
3722 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
3723 state->opaque.data,
3724 state->opaque.length);
3725 if (tevent_req_nterror(req, status)) {
3726 netlogon_creds_cli_SendToSam_cleanup(req, status);
3727 return;
3731 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3732 state->binding_handle,
3733 state->srv_name_slash,
3734 state->tmp_creds.computer_name,
3735 &state->req_auth,
3736 &state->rep_auth,
3737 state->opaque.data,
3738 state->opaque.length);
3739 if (tevent_req_nomem(subreq, req)) {
3740 status = NT_STATUS_NO_MEMORY;
3741 netlogon_creds_cli_SendToSam_cleanup(req, status);
3742 return;
3745 tevent_req_set_callback(subreq,
3746 netlogon_creds_cli_SendToSam_done,
3747 req);
3750 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3752 struct tevent_req *req =
3753 tevent_req_callback_data(subreq,
3754 struct tevent_req);
3755 struct netlogon_creds_cli_SendToSam_state *state =
3756 tevent_req_data(req,
3757 struct netlogon_creds_cli_SendToSam_state);
3758 NTSTATUS status;
3759 NTSTATUS result;
3760 bool ok;
3762 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3763 TALLOC_FREE(subreq);
3764 if (tevent_req_nterror(req, status)) {
3765 netlogon_creds_cli_SendToSam_cleanup(req, status);
3766 return;
3769 ok = netlogon_creds_client_check(&state->tmp_creds,
3770 &state->rep_auth.cred);
3771 if (!ok) {
3772 status = NT_STATUS_ACCESS_DENIED;
3773 tevent_req_nterror(req, status);
3774 netlogon_creds_cli_SendToSam_cleanup(req, status);
3775 return;
3778 *state->creds = state->tmp_creds;
3779 status = netlogon_creds_cli_store(state->context,
3780 state->creds);
3781 TALLOC_FREE(state->creds);
3783 if (tevent_req_nterror(req, status)) {
3784 netlogon_creds_cli_SendToSam_cleanup(req, status);
3785 return;
3789 * Creds must be stored before we send back application errors
3790 * e.g. NT_STATUS_NOT_IMPLEMENTED
3792 if (tevent_req_nterror(req, result)) {
3793 netlogon_creds_cli_SendToSam_cleanup(req, result);
3794 return;
3797 tevent_req_done(req);
3800 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3801 struct dcerpc_binding_handle *b,
3802 struct netr_SendToSamBase *message)
3804 TALLOC_CTX *frame = talloc_stackframe();
3805 struct tevent_context *ev;
3806 struct tevent_req *req;
3807 NTSTATUS status = NT_STATUS_OK;
3809 ev = samba_tevent_context_init(frame);
3810 if (ev == NULL) {
3811 goto fail;
3813 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3814 if (req == NULL) {
3815 goto fail;
3817 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3818 goto fail;
3821 /* Ignore the result */
3822 fail:
3823 TALLOC_FREE(frame);
3824 return status;
3827 struct netlogon_creds_cli_LogonGetDomainInfo_state {
3828 struct tevent_context *ev;
3829 struct netlogon_creds_cli_context *context;
3830 struct dcerpc_binding_handle *binding_handle;
3832 char *srv_name_slash;
3833 enum dcerpc_AuthType auth_type;
3834 enum dcerpc_AuthLevel auth_level;
3836 uint32_t level;
3837 union netr_WorkstationInfo *query;
3838 union netr_DomainInfo *info;
3840 struct netlogon_creds_CredentialState *creds;
3841 struct netlogon_creds_CredentialState tmp_creds;
3842 struct netr_Authenticator req_auth;
3843 struct netr_Authenticator rep_auth;
3846 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
3847 NTSTATUS status);
3848 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq);
3850 struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
3851 struct tevent_context *ev,
3852 struct netlogon_creds_cli_context *context,
3853 struct dcerpc_binding_handle *b,
3854 uint32_t level,
3855 union netr_WorkstationInfo *query)
3857 struct tevent_req *req;
3858 struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
3859 struct tevent_req *subreq;
3861 req = tevent_req_create(mem_ctx, &state,
3862 struct netlogon_creds_cli_LogonGetDomainInfo_state);
3863 if (req == NULL) {
3864 return NULL;
3867 state->ev = ev;
3868 state->context = context;
3869 state->binding_handle = b;
3871 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3872 context->server.computer);
3873 if (tevent_req_nomem(state->srv_name_slash, req)) {
3874 return tevent_req_post(req, ev);
3877 state->level = level;
3878 state->query = query;
3879 state->info = talloc_zero(state, union netr_DomainInfo);
3880 if (tevent_req_nomem(state->info, req)) {
3881 return tevent_req_post(req, ev);
3884 dcerpc_binding_handle_auth_info(state->binding_handle,
3885 &state->auth_type,
3886 &state->auth_level);
3888 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3889 state->context);
3890 if (tevent_req_nomem(subreq, req)) {
3891 return tevent_req_post(req, ev);
3894 tevent_req_set_callback(subreq,
3895 netlogon_creds_cli_LogonGetDomainInfo_locked,
3896 req);
3898 return req;
3901 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
3902 NTSTATUS status)
3904 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
3905 tevent_req_data(req,
3906 struct netlogon_creds_cli_LogonGetDomainInfo_state);
3908 if (state->creds == NULL) {
3909 return;
3912 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3913 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3914 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3915 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3916 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3917 TALLOC_FREE(state->creds);
3918 return;
3921 netlogon_creds_cli_delete(state->context, state->creds);
3924 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq);
3926 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq)
3928 struct tevent_req *req =
3929 tevent_req_callback_data(subreq,
3930 struct tevent_req);
3931 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
3932 tevent_req_data(req,
3933 struct netlogon_creds_cli_LogonGetDomainInfo_state);
3934 NTSTATUS status;
3936 status = netlogon_creds_cli_lock_recv(subreq, state,
3937 &state->creds);
3938 TALLOC_FREE(subreq);
3939 if (tevent_req_nterror(req, status)) {
3940 return;
3943 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3944 switch (state->auth_level) {
3945 case DCERPC_AUTH_LEVEL_INTEGRITY:
3946 case DCERPC_AUTH_LEVEL_PRIVACY:
3947 break;
3948 default:
3949 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3950 return;
3952 } else {
3953 uint32_t tmp = state->creds->negotiate_flags;
3955 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3957 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3958 * it should be used, which means
3959 * we had a chance to verify no downgrade
3960 * happened.
3962 * This relies on netlogon_creds_cli_check*
3963 * being called before, as first request after
3964 * the DCERPC bind.
3966 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3967 return;
3972 * we defer all callbacks in order to cleanup
3973 * the database record.
3975 tevent_req_defer_callback(req, state->ev);
3977 state->tmp_creds = *state->creds;
3978 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3979 &state->req_auth);
3980 if (tevent_req_nterror(req, status)) {
3981 return;
3983 ZERO_STRUCT(state->rep_auth);
3985 subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev,
3986 state->binding_handle,
3987 state->srv_name_slash,
3988 state->tmp_creds.computer_name,
3989 &state->req_auth,
3990 &state->rep_auth,
3991 state->level,
3992 state->query,
3993 state->info);
3994 if (tevent_req_nomem(subreq, req)) {
3995 status = NT_STATUS_NO_MEMORY;
3996 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
3997 return;
4000 tevent_req_set_callback(subreq,
4001 netlogon_creds_cli_LogonGetDomainInfo_done,
4002 req);
4005 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
4007 struct tevent_req *req =
4008 tevent_req_callback_data(subreq,
4009 struct tevent_req);
4010 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4011 tevent_req_data(req,
4012 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4013 NTSTATUS status;
4014 NTSTATUS result;
4015 bool ok;
4018 * We use state->dns_names as the memory context, as this is
4019 * the only in/out variable and it has been overwritten by the
4020 * out parameter from the server.
4022 * We need to preserve the return value until the caller can use it.
4024 status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result);
4025 TALLOC_FREE(subreq);
4026 if (tevent_req_nterror(req, status)) {
4027 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4028 return;
4031 ok = netlogon_creds_client_check(&state->tmp_creds,
4032 &state->rep_auth.cred);
4033 if (!ok) {
4034 status = NT_STATUS_ACCESS_DENIED;
4035 tevent_req_nterror(req, status);
4036 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4037 return;
4040 if (tevent_req_nterror(req, result)) {
4041 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
4042 return;
4045 *state->creds = state->tmp_creds;
4046 status = netlogon_creds_cli_store(state->context,
4047 state->creds);
4048 if (tevent_req_nterror(req, status)) {
4049 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4050 return;
4053 tevent_req_done(req);
4056 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
4057 TALLOC_CTX *mem_ctx,
4058 union netr_DomainInfo **info)
4060 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4061 tevent_req_data(req,
4062 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4063 NTSTATUS status;
4065 if (tevent_req_is_nterror(req, &status)) {
4066 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4067 tevent_req_received(req);
4068 return status;
4071 *info = talloc_move(mem_ctx, &state->info);
4073 tevent_req_received(req);
4074 return NT_STATUS_OK;
4077 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
4078 struct netlogon_creds_cli_context *context,
4079 struct dcerpc_binding_handle *b,
4080 TALLOC_CTX *mem_ctx,
4081 uint32_t level,
4082 union netr_WorkstationInfo *query,
4083 union netr_DomainInfo **info)
4085 TALLOC_CTX *frame = talloc_stackframe();
4086 struct tevent_context *ev;
4087 struct tevent_req *req;
4088 NTSTATUS status = NT_STATUS_OK;
4090 ev = samba_tevent_context_init(frame);
4091 if (ev == NULL) {
4092 goto fail;
4094 req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
4095 level, query);
4096 if (req == NULL) {
4097 goto fail;
4099 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4100 goto fail;
4102 status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,
4103 mem_ctx,
4104 info);
4105 fail:
4106 TALLOC_FREE(frame);
4107 return status;