selftest/tests.py: test pam_winbind with krb5_auth
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob817d2cd041a0e78a1c311c1107eb7c5d57fb6d94
1 /*
2 Unix SMB/CIFS implementation.
4 module to store/fetch session keys for the schannel client
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include <tevent.h>
25 #include "lib/util/tevent_ntstatus.h"
26 #include "lib/dbwrap/dbwrap.h"
27 #include "lib/dbwrap/dbwrap_rbt.h"
28 #include "lib/util/util_tdb.h"
29 #include "libcli/security/security.h"
30 #include "../lib/param/param.h"
31 #include "../libcli/auth/schannel.h"
32 #include "../librpc/gen_ndr/ndr_schannel.h"
33 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
34 #include "../librpc/gen_ndr/ndr_netlogon.h"
35 #include "../librpc/gen_ndr/server_id.h"
36 #include "netlogon_creds_cli.h"
37 #include "source3/include/messages.h"
38 #include "source3/include/g_lock.h"
39 #include "libds/common/roles.h"
40 #include "lib/crypto/crypto.h"
41 #include "auth/credentials/credentials.h"
43 struct netlogon_creds_cli_locked_state;
45 struct netlogon_creds_cli_context {
46 struct {
47 const char *computer;
48 const char *account;
49 uint32_t proposed_flags;
50 uint32_t required_flags;
51 enum netr_SchannelType type;
52 enum dcerpc_AuthLevel auth_level;
53 } client;
55 struct {
56 const char *computer;
57 const char *netbios_domain;
58 const char *dns_domain;
59 uint32_t cached_flags;
60 bool try_validation6;
61 bool try_logon_ex;
62 bool try_logon_with;
63 } server;
65 struct {
66 const char *key_name;
67 TDB_DATA key_data;
68 struct db_context *ctx;
69 struct g_lock_ctx *g_ctx;
70 struct netlogon_creds_cli_locked_state *locked_state;
71 enum netlogon_creds_cli_lck_type lock;
72 } db;
75 struct netlogon_creds_cli_locked_state {
76 struct netlogon_creds_cli_context *context;
77 bool is_glocked;
78 struct netlogon_creds_CredentialState *creds;
81 static int netlogon_creds_cli_locked_state_destructor(
82 struct netlogon_creds_cli_locked_state *state)
84 struct netlogon_creds_cli_context *context = state->context;
86 if (context == NULL) {
87 return 0;
90 if (context->db.locked_state == state) {
91 context->db.locked_state = NULL;
94 if (state->is_glocked) {
95 g_lock_unlock(context->db.g_ctx,
96 string_term_tdb_data(context->db.key_name));
99 return 0;
102 static NTSTATUS netlogon_creds_cli_context_common(
103 const char *client_computer,
104 const char *client_account,
105 enum netr_SchannelType type,
106 enum dcerpc_AuthLevel auth_level,
107 uint32_t proposed_flags,
108 uint32_t required_flags,
109 const char *server_computer,
110 const char *server_netbios_domain,
111 const char *server_dns_domain,
112 TALLOC_CTX *mem_ctx,
113 struct netlogon_creds_cli_context **_context)
115 struct netlogon_creds_cli_context *context = NULL;
116 char *_key_name = NULL;
117 size_t server_netbios_name_len;
118 char *p = NULL;
120 *_context = NULL;
122 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
123 if (context == NULL) {
124 return NT_STATUS_NO_MEMORY;
127 context->client.computer = talloc_strdup(context, client_computer);
128 if (context->client.computer == NULL) {
129 TALLOC_FREE(context);
130 return NT_STATUS_NO_MEMORY;
133 context->client.account = talloc_strdup(context, client_account);
134 if (context->client.account == NULL) {
135 TALLOC_FREE(context);
136 return NT_STATUS_NO_MEMORY;
139 context->client.proposed_flags = proposed_flags;
140 context->client.required_flags = required_flags;
141 context->client.type = type;
142 context->client.auth_level = auth_level;
144 context->server.computer = talloc_strdup(context, server_computer);
145 if (context->server.computer == NULL) {
146 TALLOC_FREE(context);
147 return NT_STATUS_NO_MEMORY;
150 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
151 if (context->server.netbios_domain == NULL) {
152 TALLOC_FREE(context);
153 return NT_STATUS_NO_MEMORY;
156 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
157 if (context->server.dns_domain == NULL) {
158 TALLOC_FREE(context);
159 return NT_STATUS_NO_MEMORY;
163 * TODO:
164 * Force the callers to provide a unique
165 * value for server_computer and use this directly.
167 * For now we have to deal with
168 * "HOSTNAME" vs. "hostname.example.com".
171 p = strchr(server_computer, '.');
172 if (p != NULL) {
173 server_netbios_name_len = p-server_computer;
174 } else {
175 server_netbios_name_len = strlen(server_computer);
178 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
179 client_computer,
180 client_account,
181 (int)server_netbios_name_len,
182 server_computer,
183 server_netbios_domain);
184 if (_key_name == NULL) {
185 TALLOC_FREE(context);
186 return NT_STATUS_NO_MEMORY;
189 context->db.key_name = talloc_strdup_upper(context, _key_name);
190 TALLOC_FREE(_key_name);
191 if (context->db.key_name == NULL) {
192 TALLOC_FREE(context);
193 return NT_STATUS_NO_MEMORY;
196 context->db.key_data = string_term_tdb_data(context->db.key_name);
198 *_context = context;
199 return NT_STATUS_OK;
202 static struct db_context *netlogon_creds_cli_global_db;
204 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
206 if (netlogon_creds_cli_global_db != NULL) {
207 return NT_STATUS_INVALID_PARAMETER_MIX;
210 netlogon_creds_cli_global_db = talloc_move(NULL, db);
211 return NT_STATUS_OK;
214 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
216 char *fname;
217 struct db_context *global_db;
218 int hash_size, tdb_flags;
220 if (netlogon_creds_cli_global_db != NULL) {
221 return NT_STATUS_OK;
224 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
225 if (fname == NULL) {
226 return NT_STATUS_NO_MEMORY;
229 hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
230 tdb_flags = lpcfg_tdb_flags(
231 lp_ctx,
232 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
234 global_db = dbwrap_local_open(
235 NULL,
236 fname,
237 hash_size,
238 tdb_flags,
239 O_RDWR|O_CREAT,
240 0600,
241 DBWRAP_LOCK_ORDER_2,
242 DBWRAP_FLAG_NONE);
243 if (global_db == NULL) {
244 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
245 fname, strerror(errno)));
246 talloc_free(fname);
247 return NT_STATUS_NO_MEMORY;
249 TALLOC_FREE(fname);
251 netlogon_creds_cli_global_db = global_db;
252 return NT_STATUS_OK;
255 void netlogon_creds_cli_close_global_db(void)
257 TALLOC_FREE(netlogon_creds_cli_global_db);
260 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
261 struct messaging_context *msg_ctx,
262 const char *client_account,
263 enum netr_SchannelType type,
264 const char *server_computer,
265 const char *server_netbios_domain,
266 const char *server_dns_domain,
267 TALLOC_CTX *mem_ctx,
268 struct netlogon_creds_cli_context **_context)
270 TALLOC_CTX *frame = talloc_stackframe();
271 NTSTATUS status;
272 struct netlogon_creds_cli_context *context = NULL;
273 const char *client_computer;
274 uint32_t proposed_flags;
275 uint32_t required_flags = 0;
276 bool reject_md5_servers = false;
277 bool require_strong_key = false;
278 int require_sign_or_seal = true;
279 bool seal_secure_channel = true;
280 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
281 bool neutralize_nt4_emulation = false;
283 *_context = NULL;
285 if (msg_ctx == NULL) {
286 TALLOC_FREE(frame);
287 return NT_STATUS_INVALID_PARAMETER_MIX;
290 client_computer = lpcfg_netbios_name(lp_ctx);
291 if (strlen(client_computer) > 15) {
292 TALLOC_FREE(frame);
293 return NT_STATUS_INVALID_PARAMETER_MIX;
297 * allow overwrite per domain
298 * reject md5 servers:<netbios_domain>
300 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
301 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
302 "reject md5 servers",
303 server_netbios_domain,
304 reject_md5_servers);
307 * allow overwrite per domain
308 * require strong key:<netbios_domain>
310 require_strong_key = lpcfg_require_strong_key(lp_ctx);
311 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
312 "require strong key",
313 server_netbios_domain,
314 require_strong_key);
317 * allow overwrite per domain
318 * client schannel:<netbios_domain>
320 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
321 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
322 "client schannel",
323 server_netbios_domain,
324 require_sign_or_seal);
327 * allow overwrite per domain
328 * winbind sealed pipes:<netbios_domain>
330 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
331 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
332 "winbind sealed pipes",
333 server_netbios_domain,
334 seal_secure_channel);
337 * allow overwrite per domain
338 * neutralize nt4 emulation:<netbios_domain>
340 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
341 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
342 "neutralize nt4 emulation",
343 server_netbios_domain,
344 neutralize_nt4_emulation);
346 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
347 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
349 switch (type) {
350 case SEC_CHAN_WKSTA:
351 if (lpcfg_security(lp_ctx) == SEC_ADS) {
353 * AD domains should be secure
355 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
356 require_sign_or_seal = true;
357 require_strong_key = true;
359 break;
361 case SEC_CHAN_DOMAIN:
362 break;
364 case SEC_CHAN_DNS_DOMAIN:
366 * AD domains should be secure
368 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
369 require_sign_or_seal = true;
370 require_strong_key = true;
371 neutralize_nt4_emulation = true;
372 break;
374 case SEC_CHAN_BDC:
375 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
376 require_sign_or_seal = true;
377 require_strong_key = true;
378 break;
380 case SEC_CHAN_RODC:
381 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
382 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
383 require_sign_or_seal = true;
384 require_strong_key = true;
385 neutralize_nt4_emulation = true;
386 break;
388 default:
389 TALLOC_FREE(frame);
390 return NT_STATUS_INVALID_PARAMETER;
393 if (neutralize_nt4_emulation) {
394 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
397 if (require_sign_or_seal) {
398 required_flags |= NETLOGON_NEG_ARCFOUR;
399 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
400 } else {
401 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
404 if (reject_md5_servers) {
405 required_flags |= NETLOGON_NEG_ARCFOUR;
406 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
407 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
408 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
411 if (require_strong_key) {
412 required_flags |= NETLOGON_NEG_ARCFOUR;
413 required_flags |= NETLOGON_NEG_STRONG_KEYS;
414 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
417 proposed_flags |= required_flags;
419 if (seal_secure_channel) {
420 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
421 } else {
422 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
425 status = netlogon_creds_cli_context_common(client_computer,
426 client_account,
427 type,
428 auth_level,
429 proposed_flags,
430 required_flags,
431 server_computer,
432 server_netbios_domain,
434 mem_ctx,
435 &context);
436 if (!NT_STATUS_IS_OK(status)) {
437 TALLOC_FREE(frame);
438 return status;
441 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
442 if (context->db.g_ctx == NULL) {
443 TALLOC_FREE(context);
444 TALLOC_FREE(frame);
445 return NT_STATUS_NO_MEMORY;
448 status = netlogon_creds_cli_open_global_db(lp_ctx);
449 if (!NT_STATUS_IS_OK(status)) {
450 TALLOC_FREE(context);
451 TALLOC_FREE(frame);
452 return NT_STATUS_NO_MEMORY;
455 context->db.ctx = netlogon_creds_cli_global_db;
456 *_context = context;
457 TALLOC_FREE(frame);
458 return NT_STATUS_OK;
461 NTSTATUS netlogon_creds_bind_cli_credentials(
462 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
463 struct cli_credentials **pcli_creds)
465 struct cli_credentials *cli_creds;
466 struct netlogon_creds_CredentialState *ncreds;
467 NTSTATUS status;
469 cli_creds = cli_credentials_init(mem_ctx);
470 if (cli_creds == NULL) {
471 return NT_STATUS_NO_MEMORY;
473 cli_credentials_set_secure_channel_type(cli_creds,
474 context->client.type);
475 cli_credentials_set_username(cli_creds, context->client.account,
476 CRED_SPECIFIED);
477 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
478 CRED_SPECIFIED);
479 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
480 CRED_SPECIFIED);
482 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
483 if (!NT_STATUS_IS_OK(status)) {
484 TALLOC_FREE(cli_creds);
485 return status;
487 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
489 *pcli_creds = cli_creds;
490 return NT_STATUS_OK;
493 char *netlogon_creds_cli_debug_string(
494 const struct netlogon_creds_cli_context *context,
495 TALLOC_CTX *mem_ctx)
497 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
498 context->db.key_name);
501 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
502 struct netlogon_creds_cli_context *context)
504 return context->client.auth_level;
507 struct netlogon_creds_cli_fetch_state {
508 TALLOC_CTX *mem_ctx;
509 struct netlogon_creds_CredentialState *creds;
510 uint32_t required_flags;
511 NTSTATUS status;
514 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
515 void *private_data)
517 struct netlogon_creds_cli_fetch_state *state =
518 (struct netlogon_creds_cli_fetch_state *)private_data;
519 enum ndr_err_code ndr_err;
520 DATA_BLOB blob;
521 uint32_t tmp_flags;
523 state->creds = talloc_zero(state->mem_ctx,
524 struct netlogon_creds_CredentialState);
525 if (state->creds == NULL) {
526 state->status = NT_STATUS_NO_MEMORY;
527 return;
530 blob.data = data.dptr;
531 blob.length = data.dsize;
533 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
534 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
535 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
536 TALLOC_FREE(state->creds);
537 state->status = ndr_map_error2ntstatus(ndr_err);
538 return;
541 if (DEBUGLEVEL >= 10) {
542 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
545 tmp_flags = state->creds->negotiate_flags;
546 tmp_flags &= state->required_flags;
547 if (tmp_flags != state->required_flags) {
548 TALLOC_FREE(state->creds);
549 state->status = NT_STATUS_DOWNGRADE_DETECTED;
550 return;
553 state->status = NT_STATUS_OK;
556 static NTSTATUS netlogon_creds_cli_get_internal(
557 struct netlogon_creds_cli_context *context,
558 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
560 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
561 TALLOC_CTX *mem_ctx,
562 struct netlogon_creds_CredentialState **_creds)
564 NTSTATUS status;
565 struct netlogon_creds_CredentialState *creds;
567 *_creds = NULL;
569 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
570 if (!NT_STATUS_IS_OK(status)) {
571 return status;
575 * mark it as invalid for step operations.
577 creds->sequence = 0;
578 creds->seed = (struct netr_Credential) {{0}};
579 creds->client = (struct netr_Credential) {{0}};
580 creds->server = (struct netr_Credential) {{0}};
582 *_creds = creds;
583 return NT_STATUS_OK;
586 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
587 const struct netlogon_creds_CredentialState *creds1)
589 TALLOC_CTX *frame = talloc_stackframe();
590 struct netlogon_creds_CredentialState *creds2;
591 DATA_BLOB blob1;
592 DATA_BLOB blob2;
593 NTSTATUS status;
594 enum ndr_err_code ndr_err;
595 int cmp;
597 status = netlogon_creds_cli_get(context, frame, &creds2);
598 if (!NT_STATUS_IS_OK(status)) {
599 TALLOC_FREE(frame);
600 return false;
603 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
604 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
605 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
606 TALLOC_FREE(frame);
607 return false;
610 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
611 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
612 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
613 TALLOC_FREE(frame);
614 return false;
617 cmp = data_blob_cmp(&blob1, &blob2);
619 TALLOC_FREE(frame);
621 return (cmp == 0);
624 static NTSTATUS netlogon_creds_cli_store_internal(
625 struct netlogon_creds_cli_context *context,
626 struct netlogon_creds_CredentialState *creds)
628 NTSTATUS status;
629 enum ndr_err_code ndr_err;
630 DATA_BLOB blob;
631 TDB_DATA data;
633 if (DEBUGLEVEL >= 10) {
634 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
637 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
638 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
639 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
640 status = ndr_map_error2ntstatus(ndr_err);
641 return status;
644 data.dptr = blob.data;
645 data.dsize = blob.length;
647 status = dbwrap_store(context->db.ctx,
648 context->db.key_data,
649 data, TDB_REPLACE);
650 TALLOC_FREE(data.dptr);
651 if (!NT_STATUS_IS_OK(status)) {
652 return status;
655 return NT_STATUS_OK;
658 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
659 struct netlogon_creds_CredentialState *creds)
661 NTSTATUS status;
663 if (context->db.locked_state == NULL) {
665 * this was not the result of netlogon_creds_cli_lock*()
667 return NT_STATUS_INVALID_PAGE_PROTECTION;
670 if (context->db.locked_state->creds != creds) {
672 * this was not the result of netlogon_creds_cli_lock*()
674 return NT_STATUS_INVALID_PAGE_PROTECTION;
677 status = netlogon_creds_cli_store_internal(context, creds);
678 return status;
681 static NTSTATUS netlogon_creds_cli_delete_internal(
682 struct netlogon_creds_cli_context *context)
684 NTSTATUS status;
685 status = dbwrap_delete(context->db.ctx, context->db.key_data);
686 return status;
689 NTSTATUS netlogon_creds_cli_delete_lck(
690 struct netlogon_creds_cli_context *context)
692 NTSTATUS status;
694 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
695 return NT_STATUS_NOT_LOCKED;
698 status = netlogon_creds_cli_delete_internal(context);
699 return status;
702 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
703 struct netlogon_creds_CredentialState *creds)
705 NTSTATUS status;
707 if (context->db.locked_state == NULL) {
709 * this was not the result of netlogon_creds_cli_lock*()
711 return NT_STATUS_INVALID_PAGE_PROTECTION;
714 if (context->db.locked_state->creds != creds) {
716 * this was not the result of netlogon_creds_cli_lock*()
718 return NT_STATUS_INVALID_PAGE_PROTECTION;
721 status = netlogon_creds_cli_delete_internal(context);
722 return status;
725 struct netlogon_creds_cli_lock_state {
726 struct netlogon_creds_cli_locked_state *locked_state;
727 struct netlogon_creds_CredentialState *creds;
730 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
732 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
733 struct tevent_context *ev,
734 struct netlogon_creds_cli_context *context)
736 struct tevent_req *req;
737 struct netlogon_creds_cli_lock_state *state;
738 struct netlogon_creds_cli_locked_state *locked_state;
739 struct tevent_req *subreq;
741 req = tevent_req_create(mem_ctx, &state,
742 struct netlogon_creds_cli_lock_state);
743 if (req == NULL) {
744 return NULL;
747 if (context->db.locked_state != NULL) {
748 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
749 return tevent_req_post(req, ev);
752 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
753 if (tevent_req_nomem(locked_state, req)) {
754 return tevent_req_post(req, ev);
756 talloc_set_destructor(locked_state,
757 netlogon_creds_cli_locked_state_destructor);
758 locked_state->context = context;
760 context->db.locked_state = locked_state;
761 state->locked_state = locked_state;
763 if (context->db.g_ctx == NULL) {
764 NTSTATUS status;
766 status = netlogon_creds_cli_get_internal(
767 context, state, &state->creds);
768 if (tevent_req_nterror(req, status)) {
769 return tevent_req_post(req, ev);
772 return req;
775 subreq = g_lock_lock_send(state, ev,
776 context->db.g_ctx,
777 string_term_tdb_data(context->db.key_name),
778 G_LOCK_WRITE);
779 if (tevent_req_nomem(subreq, req)) {
780 return tevent_req_post(req, ev);
782 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
784 return req;
787 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
789 struct tevent_req *req =
790 tevent_req_callback_data(subreq,
791 struct tevent_req);
792 struct netlogon_creds_cli_lock_state *state =
793 tevent_req_data(req,
794 struct netlogon_creds_cli_lock_state);
795 NTSTATUS status;
797 status = g_lock_lock_recv(subreq);
798 TALLOC_FREE(subreq);
799 if (tevent_req_nterror(req, status)) {
800 return;
802 state->locked_state->is_glocked = true;
804 status = netlogon_creds_cli_get_internal(state->locked_state->context,
805 state, &state->creds);
806 if (tevent_req_nterror(req, status)) {
807 return;
809 tevent_req_done(req);
812 static NTSTATUS netlogon_creds_cli_get_internal(
813 struct netlogon_creds_cli_context *context,
814 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
816 struct netlogon_creds_cli_fetch_state fstate = {
817 .status = NT_STATUS_INTERNAL_ERROR,
818 .required_flags = context->client.required_flags,
820 NTSTATUS status;
822 fstate.mem_ctx = mem_ctx;
823 status = dbwrap_parse_record(context->db.ctx,
824 context->db.key_data,
825 netlogon_creds_cli_fetch_parser,
826 &fstate);
827 if (!NT_STATUS_IS_OK(status)) {
828 return status;
830 if (!NT_STATUS_IS_OK(fstate.status)) {
831 return fstate.status;
834 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
835 *pcreds = fstate.creds;
836 return NT_STATUS_OK;
840 * It is really important to try SamLogonEx here,
841 * because multiple processes can talk to the same
842 * domain controller, without using the credential
843 * chain.
845 * With a normal SamLogon call, we must keep the
846 * credentials chain updated and intact between all
847 * users of the machine account (which would imply
848 * cross-node communication for every NTLM logon).
850 * The credentials chain is not per NETLOGON pipe
851 * connection, but globally on the server/client pair
852 * by computer name.
854 * It's also important to use NetlogonValidationSamInfo4 (6),
855 * because it relies on the rpc transport encryption
856 * and avoids using the global netlogon schannel
857 * session key to en/decrypt secret information
858 * like the user_session_key for network logons.
860 * [MS-APDS] 3.1.5.2 NTLM Network Logon
861 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
862 * NETLOGON_NEG_AUTHENTICATED_RPC set together
863 * are the indication that the server supports
864 * NetlogonValidationSamInfo4 (6). And it must only
865 * be used if "SealSecureChannel" is used.
867 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
868 * check is done in netlogon_creds_cli_LogonSamLogon*().
871 context->server.cached_flags = fstate.creds->negotiate_flags;
872 context->server.try_validation6 = true;
873 context->server.try_logon_ex = true;
874 context->server.try_logon_with = true;
876 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
877 context->server.try_validation6 = false;
878 context->server.try_logon_ex = false;
880 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
881 context->server.try_validation6 = false;
884 *pcreds = fstate.creds;
885 return NT_STATUS_OK;
888 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
889 TALLOC_CTX *mem_ctx,
890 struct netlogon_creds_CredentialState **creds)
892 struct netlogon_creds_cli_lock_state *state =
893 tevent_req_data(req,
894 struct netlogon_creds_cli_lock_state);
895 NTSTATUS status;
897 if (tevent_req_is_nterror(req, &status)) {
898 tevent_req_received(req);
899 return status;
902 talloc_steal(state->creds, state->locked_state);
903 state->locked_state->creds = state->creds;
904 *creds = talloc_move(mem_ctx, &state->creds);
905 tevent_req_received(req);
906 return NT_STATUS_OK;
909 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
910 TALLOC_CTX *mem_ctx,
911 struct netlogon_creds_CredentialState **creds)
913 TALLOC_CTX *frame = talloc_stackframe();
914 struct tevent_context *ev;
915 struct tevent_req *req;
916 NTSTATUS status = NT_STATUS_NO_MEMORY;
918 ev = samba_tevent_context_init(frame);
919 if (ev == NULL) {
920 goto fail;
922 req = netlogon_creds_cli_lock_send(frame, ev, context);
923 if (req == NULL) {
924 goto fail;
926 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
927 goto fail;
929 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
930 fail:
931 TALLOC_FREE(frame);
932 return status;
935 struct netlogon_creds_cli_lck {
936 struct netlogon_creds_cli_context *context;
939 struct netlogon_creds_cli_lck_state {
940 struct netlogon_creds_cli_lck *lck;
941 enum netlogon_creds_cli_lck_type type;
944 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
945 static int netlogon_creds_cli_lck_destructor(
946 struct netlogon_creds_cli_lck *lck);
948 struct tevent_req *netlogon_creds_cli_lck_send(
949 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
950 struct netlogon_creds_cli_context *context,
951 enum netlogon_creds_cli_lck_type type)
953 struct tevent_req *req, *subreq;
954 struct netlogon_creds_cli_lck_state *state;
955 enum g_lock_type gtype;
957 req = tevent_req_create(mem_ctx, &state,
958 struct netlogon_creds_cli_lck_state);
959 if (req == NULL) {
960 return NULL;
963 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
964 DBG_DEBUG("context already locked\n");
965 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
966 return tevent_req_post(req, ev);
969 switch (type) {
970 case NETLOGON_CREDS_CLI_LCK_SHARED:
971 gtype = G_LOCK_READ;
972 break;
973 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
974 gtype = G_LOCK_WRITE;
975 break;
976 default:
977 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
978 return tevent_req_post(req, ev);
981 state->lck = talloc(state, struct netlogon_creds_cli_lck);
982 if (tevent_req_nomem(state->lck, req)) {
983 return tevent_req_post(req, ev);
985 state->lck->context = context;
986 state->type = type;
988 subreq = g_lock_lock_send(state, ev,
989 context->db.g_ctx,
990 string_term_tdb_data(context->db.key_name),
991 gtype);
992 if (tevent_req_nomem(subreq, req)) {
993 return tevent_req_post(req, ev);
995 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
997 return req;
1000 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
1002 struct tevent_req *req = tevent_req_callback_data(
1003 subreq, struct tevent_req);
1004 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1005 req, struct netlogon_creds_cli_lck_state);
1006 NTSTATUS status;
1008 status = g_lock_lock_recv(subreq);
1009 TALLOC_FREE(subreq);
1010 if (tevent_req_nterror(req, status)) {
1011 return;
1014 state->lck->context->db.lock = state->type;
1015 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1017 tevent_req_done(req);
1020 static int netlogon_creds_cli_lck_destructor(
1021 struct netlogon_creds_cli_lck *lck)
1023 struct netlogon_creds_cli_context *ctx = lck->context;
1024 NTSTATUS status;
1026 status = g_lock_unlock(ctx->db.g_ctx,
1027 string_term_tdb_data(ctx->db.key_name));
1028 if (!NT_STATUS_IS_OK(status)) {
1029 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1030 smb_panic("g_lock_unlock failed");
1032 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1033 return 0;
1036 NTSTATUS netlogon_creds_cli_lck_recv(
1037 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1038 struct netlogon_creds_cli_lck **lck)
1040 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1041 req, struct netlogon_creds_cli_lck_state);
1042 NTSTATUS status;
1044 if (tevent_req_is_nterror(req, &status)) {
1045 return status;
1047 *lck = talloc_move(mem_ctx, &state->lck);
1048 return NT_STATUS_OK;
1051 NTSTATUS netlogon_creds_cli_lck(
1052 struct netlogon_creds_cli_context *context,
1053 enum netlogon_creds_cli_lck_type type,
1054 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1056 TALLOC_CTX *frame = talloc_stackframe();
1057 struct tevent_context *ev;
1058 struct tevent_req *req;
1059 NTSTATUS status = NT_STATUS_NO_MEMORY;
1061 ev = samba_tevent_context_init(frame);
1062 if (ev == NULL) {
1063 goto fail;
1065 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1066 if (req == NULL) {
1067 goto fail;
1069 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1070 goto fail;
1072 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1073 fail:
1074 TALLOC_FREE(frame);
1075 return status;
1078 struct netlogon_creds_cli_auth_state {
1079 struct tevent_context *ev;
1080 struct netlogon_creds_cli_context *context;
1081 struct dcerpc_binding_handle *binding_handle;
1082 uint8_t num_nt_hashes;
1083 uint8_t idx_nt_hashes;
1084 const struct samr_Password * const *nt_hashes;
1085 const struct samr_Password *used_nt_hash;
1086 char *srv_name_slash;
1087 uint32_t current_flags;
1088 struct netr_Credential client_challenge;
1089 struct netr_Credential server_challenge;
1090 struct netlogon_creds_CredentialState *creds;
1091 struct netr_Credential client_credential;
1092 struct netr_Credential server_credential;
1093 uint32_t rid;
1094 bool try_auth3;
1095 bool try_auth2;
1096 bool require_auth2;
1099 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1101 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1102 struct tevent_context *ev,
1103 struct netlogon_creds_cli_context *context,
1104 struct dcerpc_binding_handle *b,
1105 uint8_t num_nt_hashes,
1106 const struct samr_Password * const *nt_hashes)
1108 struct tevent_req *req;
1109 struct netlogon_creds_cli_auth_state *state;
1110 NTSTATUS status;
1112 req = tevent_req_create(mem_ctx, &state,
1113 struct netlogon_creds_cli_auth_state);
1114 if (req == NULL) {
1115 return NULL;
1118 state->ev = ev;
1119 state->context = context;
1120 state->binding_handle = b;
1121 if (num_nt_hashes < 1) {
1122 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1123 return tevent_req_post(req, ev);
1125 if (num_nt_hashes > 4) {
1126 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1127 return tevent_req_post(req, ev);
1130 state->num_nt_hashes = num_nt_hashes;
1131 state->idx_nt_hashes = 0;
1132 state->nt_hashes = nt_hashes;
1134 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1135 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1136 return tevent_req_post(req, ev);
1139 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1140 context->server.computer);
1141 if (tevent_req_nomem(state->srv_name_slash, req)) {
1142 return tevent_req_post(req, ev);
1145 state->try_auth3 = true;
1146 state->try_auth2 = true;
1148 if (context->client.required_flags != 0) {
1149 state->require_auth2 = true;
1152 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1153 state->current_flags = context->client.proposed_flags;
1155 status = dbwrap_purge(state->context->db.ctx,
1156 state->context->db.key_data);
1157 if (tevent_req_nterror(req, status)) {
1158 return tevent_req_post(req, ev);
1161 netlogon_creds_cli_auth_challenge_start(req);
1162 if (!tevent_req_is_in_progress(req)) {
1163 return tevent_req_post(req, ev);
1166 return req;
1169 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1171 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1173 struct netlogon_creds_cli_auth_state *state =
1174 tevent_req_data(req,
1175 struct netlogon_creds_cli_auth_state);
1176 struct tevent_req *subreq;
1178 TALLOC_FREE(state->creds);
1180 generate_random_buffer(state->client_challenge.data,
1181 sizeof(state->client_challenge.data));
1183 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1184 state->binding_handle,
1185 state->srv_name_slash,
1186 state->context->client.computer,
1187 &state->client_challenge,
1188 &state->server_challenge);
1189 if (tevent_req_nomem(subreq, req)) {
1190 return;
1192 tevent_req_set_callback(subreq,
1193 netlogon_creds_cli_auth_challenge_done,
1194 req);
1197 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1199 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1201 struct tevent_req *req =
1202 tevent_req_callback_data(subreq,
1203 struct tevent_req);
1204 struct netlogon_creds_cli_auth_state *state =
1205 tevent_req_data(req,
1206 struct netlogon_creds_cli_auth_state);
1207 NTSTATUS status;
1208 NTSTATUS result;
1210 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1211 TALLOC_FREE(subreq);
1212 if (tevent_req_nterror(req, status)) {
1213 return;
1215 if (tevent_req_nterror(req, result)) {
1216 return;
1219 if (!state->try_auth3 && !state->try_auth2) {
1220 state->current_flags = 0;
1223 /* Calculate the session key and client credentials */
1225 state->creds = netlogon_creds_client_init(state,
1226 state->context->client.account,
1227 state->context->client.computer,
1228 state->context->client.type,
1229 &state->client_challenge,
1230 &state->server_challenge,
1231 state->used_nt_hash,
1232 &state->client_credential,
1233 state->current_flags);
1234 if (tevent_req_nomem(state->creds, req)) {
1235 return;
1238 if (state->try_auth3) {
1239 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1240 state->binding_handle,
1241 state->srv_name_slash,
1242 state->context->client.account,
1243 state->context->client.type,
1244 state->context->client.computer,
1245 &state->client_credential,
1246 &state->server_credential,
1247 &state->creds->negotiate_flags,
1248 &state->rid);
1249 if (tevent_req_nomem(subreq, req)) {
1250 return;
1252 } else if (state->try_auth2) {
1253 state->rid = 0;
1255 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1256 state->binding_handle,
1257 state->srv_name_slash,
1258 state->context->client.account,
1259 state->context->client.type,
1260 state->context->client.computer,
1261 &state->client_credential,
1262 &state->server_credential,
1263 &state->creds->negotiate_flags);
1264 if (tevent_req_nomem(subreq, req)) {
1265 return;
1267 } else {
1268 state->rid = 0;
1270 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1271 state->binding_handle,
1272 state->srv_name_slash,
1273 state->context->client.account,
1274 state->context->client.type,
1275 state->context->client.computer,
1276 &state->client_credential,
1277 &state->server_credential);
1278 if (tevent_req_nomem(subreq, req)) {
1279 return;
1282 tevent_req_set_callback(subreq,
1283 netlogon_creds_cli_auth_srvauth_done,
1284 req);
1287 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1289 struct tevent_req *req =
1290 tevent_req_callback_data(subreq,
1291 struct tevent_req);
1292 struct netlogon_creds_cli_auth_state *state =
1293 tevent_req_data(req,
1294 struct netlogon_creds_cli_auth_state);
1295 NTSTATUS status;
1296 NTSTATUS result;
1297 bool ok;
1298 enum ndr_err_code ndr_err;
1299 DATA_BLOB blob;
1300 TDB_DATA data;
1301 uint32_t tmp_flags;
1303 if (state->try_auth3) {
1304 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1305 &result);
1306 TALLOC_FREE(subreq);
1307 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1308 state->try_auth3 = false;
1309 netlogon_creds_cli_auth_challenge_start(req);
1310 return;
1312 if (tevent_req_nterror(req, status)) {
1313 return;
1315 } else if (state->try_auth2) {
1316 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1317 &result);
1318 TALLOC_FREE(subreq);
1319 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1320 state->try_auth2 = false;
1321 if (state->require_auth2) {
1322 status = NT_STATUS_DOWNGRADE_DETECTED;
1323 tevent_req_nterror(req, status);
1324 return;
1326 netlogon_creds_cli_auth_challenge_start(req);
1327 return;
1329 if (tevent_req_nterror(req, status)) {
1330 return;
1332 } else {
1333 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1334 &result);
1335 TALLOC_FREE(subreq);
1336 if (tevent_req_nterror(req, status)) {
1337 return;
1341 if (!NT_STATUS_IS_OK(result) &&
1342 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1344 tevent_req_nterror(req, result);
1345 return;
1348 tmp_flags = state->creds->negotiate_flags;
1349 tmp_flags &= state->context->client.required_flags;
1350 if (tmp_flags != state->context->client.required_flags) {
1351 if (NT_STATUS_IS_OK(result)) {
1352 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1353 return;
1355 tevent_req_nterror(req, result);
1356 return;
1359 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1361 tmp_flags = state->context->client.proposed_flags;
1362 if ((state->current_flags == tmp_flags) &&
1363 (state->creds->negotiate_flags != tmp_flags))
1366 * lets retry with the negotiated flags
1368 state->current_flags = state->creds->negotiate_flags;
1369 netlogon_creds_cli_auth_challenge_start(req);
1370 return;
1373 state->idx_nt_hashes += 1;
1374 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1376 * we already retried, giving up...
1378 tevent_req_nterror(req, result);
1379 return;
1383 * lets retry with the old nt hash.
1385 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1386 state->current_flags = state->context->client.proposed_flags;
1387 netlogon_creds_cli_auth_challenge_start(req);
1388 return;
1391 ok = netlogon_creds_client_check(state->creds,
1392 &state->server_credential);
1393 if (!ok) {
1394 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1395 return;
1398 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1399 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1400 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1401 status = ndr_map_error2ntstatus(ndr_err);
1402 tevent_req_nterror(req, status);
1403 return;
1406 data.dptr = blob.data;
1407 data.dsize = blob.length;
1409 status = dbwrap_store(state->context->db.ctx,
1410 state->context->db.key_data,
1411 data, TDB_REPLACE);
1412 if (tevent_req_nterror(req, status)) {
1413 return;
1416 tevent_req_done(req);
1419 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1420 uint8_t *idx_nt_hashes)
1422 struct netlogon_creds_cli_auth_state *state =
1423 tevent_req_data(req,
1424 struct netlogon_creds_cli_auth_state);
1425 NTSTATUS status;
1427 *idx_nt_hashes = 0;
1429 if (tevent_req_is_nterror(req, &status)) {
1430 tevent_req_received(req);
1431 return status;
1434 *idx_nt_hashes = state->idx_nt_hashes;
1435 tevent_req_received(req);
1436 return NT_STATUS_OK;
1439 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1440 struct dcerpc_binding_handle *b,
1441 uint8_t num_nt_hashes,
1442 const struct samr_Password * const *nt_hashes,
1443 uint8_t *idx_nt_hashes)
1445 TALLOC_CTX *frame = talloc_stackframe();
1446 struct tevent_context *ev;
1447 struct tevent_req *req;
1448 NTSTATUS status = NT_STATUS_NO_MEMORY;
1450 *idx_nt_hashes = 0;
1452 ev = samba_tevent_context_init(frame);
1453 if (ev == NULL) {
1454 goto fail;
1456 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1457 num_nt_hashes, nt_hashes);
1458 if (req == NULL) {
1459 goto fail;
1461 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1462 goto fail;
1464 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1465 fail:
1466 TALLOC_FREE(frame);
1467 return status;
1470 struct netlogon_creds_cli_check_state {
1471 struct tevent_context *ev;
1472 struct netlogon_creds_cli_context *context;
1473 struct dcerpc_binding_handle *binding_handle;
1475 char *srv_name_slash;
1477 union netr_Capabilities caps;
1479 struct netlogon_creds_CredentialState *creds;
1480 struct netr_Authenticator req_auth;
1481 struct netr_Authenticator rep_auth;
1484 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1485 NTSTATUS status);
1486 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1488 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1489 struct tevent_context *ev,
1490 struct netlogon_creds_cli_context *context,
1491 struct dcerpc_binding_handle *b)
1493 struct tevent_req *req;
1494 struct netlogon_creds_cli_check_state *state;
1495 struct tevent_req *subreq;
1496 enum dcerpc_AuthType auth_type;
1497 enum dcerpc_AuthLevel auth_level;
1498 NTSTATUS status;
1500 req = tevent_req_create(mem_ctx, &state,
1501 struct netlogon_creds_cli_check_state);
1502 if (req == NULL) {
1503 return NULL;
1506 state->ev = ev;
1507 state->context = context;
1508 state->binding_handle = b;
1510 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1511 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1512 return tevent_req_post(req, ev);
1515 status = netlogon_creds_cli_get_internal(context, state,
1516 &state->creds);
1517 if (tevent_req_nterror(req, status)) {
1518 return tevent_req_post(req, ev);
1521 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1522 context->server.computer);
1523 if (tevent_req_nomem(state->srv_name_slash, req)) {
1524 return tevent_req_post(req, ev);
1527 dcerpc_binding_handle_auth_info(state->binding_handle,
1528 &auth_type, &auth_level);
1530 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1531 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1532 return tevent_req_post(req, ev);
1535 switch (auth_level) {
1536 case DCERPC_AUTH_LEVEL_INTEGRITY:
1537 case DCERPC_AUTH_LEVEL_PRIVACY:
1538 break;
1539 default:
1540 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1541 return tevent_req_post(req, ev);
1545 * we defer all callbacks in order to cleanup
1546 * the database record.
1548 tevent_req_defer_callback(req, state->ev);
1550 netlogon_creds_client_authenticator(state->creds, &state->req_auth);
1551 ZERO_STRUCT(state->rep_auth);
1553 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1554 state->binding_handle,
1555 state->srv_name_slash,
1556 state->context->client.computer,
1557 &state->req_auth,
1558 &state->rep_auth,
1560 &state->caps);
1561 if (tevent_req_nomem(subreq, req)) {
1562 return tevent_req_post(req, ev);
1565 tevent_req_set_callback(subreq,
1566 netlogon_creds_cli_check_caps,
1567 req);
1569 return req;
1572 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1573 NTSTATUS status)
1575 struct netlogon_creds_cli_check_state *state =
1576 tevent_req_data(req,
1577 struct netlogon_creds_cli_check_state);
1579 if (state->creds == NULL) {
1580 return;
1583 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1584 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1585 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1586 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1587 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1588 TALLOC_FREE(state->creds);
1589 return;
1592 netlogon_creds_cli_delete_lck(state->context);
1593 TALLOC_FREE(state->creds);
1596 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1598 struct tevent_req *req =
1599 tevent_req_callback_data(subreq,
1600 struct tevent_req);
1601 struct netlogon_creds_cli_check_state *state =
1602 tevent_req_data(req,
1603 struct netlogon_creds_cli_check_state);
1604 NTSTATUS status;
1605 NTSTATUS result;
1606 bool ok;
1608 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1609 &result);
1610 TALLOC_FREE(subreq);
1611 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1613 * Note that the negotiated flags are already checked
1614 * for our required flags after the ServerAuthenticate3/2 call.
1616 uint32_t negotiated = state->creds->negotiate_flags;
1618 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1620 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1621 * already, we expect this to work!
1623 status = NT_STATUS_DOWNGRADE_DETECTED;
1624 tevent_req_nterror(req, status);
1625 netlogon_creds_cli_check_cleanup(req, status);
1626 return;
1629 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1631 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1632 * we expect this to work at least as far as the
1633 * NOT_SUPPORTED error handled below!
1635 * NT 4.0 and Old Samba servers are not
1636 * allowed without "require strong key = no"
1638 status = NT_STATUS_DOWNGRADE_DETECTED;
1639 tevent_req_nterror(req, status);
1640 netlogon_creds_cli_check_cleanup(req, status);
1641 return;
1645 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1646 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1647 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1649 * This is needed against NT 4.0 and old Samba servers.
1651 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1652 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1653 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1654 * with the next request as the sequence number processing
1655 * gets out of sync.
1657 netlogon_creds_cli_check_cleanup(req, status);
1658 tevent_req_done(req);
1659 return;
1661 if (tevent_req_nterror(req, status)) {
1662 netlogon_creds_cli_check_cleanup(req, status);
1663 return;
1666 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1668 * Note that the negotiated flags are already checked
1669 * for our required flags after the ServerAuthenticate3/2 call.
1671 uint32_t negotiated = state->creds->negotiate_flags;
1673 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1675 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1676 * already, we expect this to work!
1678 status = NT_STATUS_DOWNGRADE_DETECTED;
1679 tevent_req_nterror(req, status);
1680 netlogon_creds_cli_check_cleanup(req, status);
1681 return;
1685 * This is ok, the server does not support
1686 * NETLOGON_NEG_SUPPORTS_AES.
1688 * netr_LogonGetCapabilities() was
1689 * netr_LogonDummyRoutine1() before
1690 * NETLOGON_NEG_SUPPORTS_AES was invented.
1692 netlogon_creds_cli_check_cleanup(req, result);
1693 tevent_req_done(req);
1694 return;
1697 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1698 if (!ok) {
1699 status = NT_STATUS_ACCESS_DENIED;
1700 tevent_req_nterror(req, status);
1701 netlogon_creds_cli_check_cleanup(req, status);
1702 return;
1705 if (tevent_req_nterror(req, result)) {
1706 netlogon_creds_cli_check_cleanup(req, result);
1707 return;
1710 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1711 status = NT_STATUS_DOWNGRADE_DETECTED;
1712 tevent_req_nterror(req, status);
1713 netlogon_creds_cli_check_cleanup(req, status);
1714 return;
1718 * This is the key check that makes this check secure. If we
1719 * get OK here (rather than NOT_SUPPORTED), then the server
1720 * did support AES. If the server only proposed STRONG_KEYS
1721 * and not AES, then it should have failed with
1722 * NOT_IMPLEMENTED. We always send AES as a client, so the
1723 * server should always have returned it.
1725 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1726 status = NT_STATUS_DOWNGRADE_DETECTED;
1727 tevent_req_nterror(req, status);
1728 netlogon_creds_cli_check_cleanup(req, status);
1729 return;
1732 status = netlogon_creds_cli_store_internal(state->context,
1733 state->creds);
1734 if (tevent_req_nterror(req, status)) {
1735 return;
1738 tevent_req_done(req);
1741 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1742 union netr_Capabilities *capabilities)
1744 struct netlogon_creds_cli_check_state *state = tevent_req_data(
1745 req, struct netlogon_creds_cli_check_state);
1746 NTSTATUS status;
1748 if (tevent_req_is_nterror(req, &status)) {
1749 netlogon_creds_cli_check_cleanup(req, status);
1750 tevent_req_received(req);
1751 return status;
1754 if (capabilities != NULL) {
1755 *capabilities = state->caps;
1758 tevent_req_received(req);
1759 return NT_STATUS_OK;
1762 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1763 struct dcerpc_binding_handle *b,
1764 union netr_Capabilities *capabilities)
1766 TALLOC_CTX *frame = talloc_stackframe();
1767 struct tevent_context *ev;
1768 struct tevent_req *req;
1769 NTSTATUS status = NT_STATUS_NO_MEMORY;
1771 ev = samba_tevent_context_init(frame);
1772 if (ev == NULL) {
1773 goto fail;
1775 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1776 if (req == NULL) {
1777 goto fail;
1779 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1780 goto fail;
1782 status = netlogon_creds_cli_check_recv(req, capabilities);
1783 fail:
1784 TALLOC_FREE(frame);
1785 return status;
1788 struct netlogon_creds_cli_ServerPasswordSet_state {
1789 struct tevent_context *ev;
1790 struct netlogon_creds_cli_context *context;
1791 struct dcerpc_binding_handle *binding_handle;
1792 uint32_t old_timeout;
1794 char *srv_name_slash;
1795 enum dcerpc_AuthType auth_type;
1796 enum dcerpc_AuthLevel auth_level;
1798 struct samr_CryptPassword samr_crypt_password;
1799 struct netr_CryptPassword netr_crypt_password;
1800 struct samr_Password samr_password;
1802 struct netlogon_creds_CredentialState *creds;
1803 struct netlogon_creds_CredentialState tmp_creds;
1804 struct netr_Authenticator req_auth;
1805 struct netr_Authenticator rep_auth;
1808 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1809 NTSTATUS status);
1810 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1812 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1813 struct tevent_context *ev,
1814 struct netlogon_creds_cli_context *context,
1815 struct dcerpc_binding_handle *b,
1816 const DATA_BLOB *new_password,
1817 const uint32_t *new_version)
1819 struct tevent_req *req;
1820 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1821 struct tevent_req *subreq;
1822 bool ok;
1824 req = tevent_req_create(mem_ctx, &state,
1825 struct netlogon_creds_cli_ServerPasswordSet_state);
1826 if (req == NULL) {
1827 return NULL;
1830 state->ev = ev;
1831 state->context = context;
1832 state->binding_handle = b;
1834 if (new_password->length < 14) {
1835 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1836 return tevent_req_post(req, ev);
1840 * netr_ServerPasswordSet
1842 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1845 * netr_ServerPasswordSet2
1847 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1848 new_password);
1849 if (!ok) {
1850 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1851 return tevent_req_post(req, ev);
1854 if (new_version != NULL) {
1855 struct NL_PASSWORD_VERSION version;
1856 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1857 uint32_t ofs = 512 - len;
1858 uint8_t *p;
1860 if (len > 500) {
1861 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1862 return tevent_req_post(req, ev);
1864 ofs -= 12;
1866 version.ReservedField = 0;
1867 version.PasswordVersionNumber = *new_version;
1868 version.PasswordVersionPresent =
1869 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1871 p = state->samr_crypt_password.data + ofs;
1872 SIVAL(p, 0, version.ReservedField);
1873 SIVAL(p, 4, version.PasswordVersionNumber);
1874 SIVAL(p, 8, version.PasswordVersionPresent);
1877 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1878 context->server.computer);
1879 if (tevent_req_nomem(state->srv_name_slash, req)) {
1880 return tevent_req_post(req, ev);
1883 dcerpc_binding_handle_auth_info(state->binding_handle,
1884 &state->auth_type,
1885 &state->auth_level);
1887 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1888 state->context);
1889 if (tevent_req_nomem(subreq, req)) {
1890 return tevent_req_post(req, ev);
1893 tevent_req_set_callback(subreq,
1894 netlogon_creds_cli_ServerPasswordSet_locked,
1895 req);
1897 return req;
1900 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1901 NTSTATUS status)
1903 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1904 tevent_req_data(req,
1905 struct netlogon_creds_cli_ServerPasswordSet_state);
1907 if (state->creds == NULL) {
1908 return;
1911 dcerpc_binding_handle_set_timeout(state->binding_handle,
1912 state->old_timeout);
1914 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1915 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1916 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1917 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1918 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1919 TALLOC_FREE(state->creds);
1920 return;
1923 netlogon_creds_cli_delete(state->context, state->creds);
1924 TALLOC_FREE(state->creds);
1927 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1929 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1931 struct tevent_req *req =
1932 tevent_req_callback_data(subreq,
1933 struct tevent_req);
1934 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1935 tevent_req_data(req,
1936 struct netlogon_creds_cli_ServerPasswordSet_state);
1937 NTSTATUS status;
1939 status = netlogon_creds_cli_lock_recv(subreq, state,
1940 &state->creds);
1941 TALLOC_FREE(subreq);
1942 if (tevent_req_nterror(req, status)) {
1943 return;
1946 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1947 switch (state->auth_level) {
1948 case DCERPC_AUTH_LEVEL_INTEGRITY:
1949 case DCERPC_AUTH_LEVEL_PRIVACY:
1950 break;
1951 default:
1952 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1953 return;
1955 } else {
1956 uint32_t tmp = state->creds->negotiate_flags;
1958 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1960 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1961 * it should be used, which means
1962 * we had a chance to verify no downgrade
1963 * happened.
1965 * This relies on netlogon_creds_cli_check*
1966 * being called before, as first request after
1967 * the DCERPC bind.
1969 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1970 return;
1974 state->old_timeout = dcerpc_binding_handle_set_timeout(
1975 state->binding_handle, 600000);
1978 * we defer all callbacks in order to cleanup
1979 * the database record.
1981 tevent_req_defer_callback(req, state->ev);
1983 state->tmp_creds = *state->creds;
1984 netlogon_creds_client_authenticator(&state->tmp_creds,
1985 &state->req_auth);
1986 ZERO_STRUCT(state->rep_auth);
1988 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1990 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1991 netlogon_creds_aes_encrypt(&state->tmp_creds,
1992 state->samr_crypt_password.data,
1993 516);
1994 } else {
1995 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1996 state->samr_crypt_password.data,
1997 516);
2000 memcpy(state->netr_crypt_password.data,
2001 state->samr_crypt_password.data, 512);
2002 state->netr_crypt_password.length =
2003 IVAL(state->samr_crypt_password.data, 512);
2005 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2006 state->binding_handle,
2007 state->srv_name_slash,
2008 state->tmp_creds.account_name,
2009 state->tmp_creds.secure_channel_type,
2010 state->tmp_creds.computer_name,
2011 &state->req_auth,
2012 &state->rep_auth,
2013 &state->netr_crypt_password);
2014 if (tevent_req_nomem(subreq, req)) {
2015 status = NT_STATUS_NO_MEMORY;
2016 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2017 return;
2019 } else {
2020 netlogon_creds_des_encrypt(&state->tmp_creds,
2021 &state->samr_password);
2023 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2024 state->binding_handle,
2025 state->srv_name_slash,
2026 state->tmp_creds.account_name,
2027 state->tmp_creds.secure_channel_type,
2028 state->tmp_creds.computer_name,
2029 &state->req_auth,
2030 &state->rep_auth,
2031 &state->samr_password);
2032 if (tevent_req_nomem(subreq, req)) {
2033 status = NT_STATUS_NO_MEMORY;
2034 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2035 return;
2039 tevent_req_set_callback(subreq,
2040 netlogon_creds_cli_ServerPasswordSet_done,
2041 req);
2044 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2046 struct tevent_req *req =
2047 tevent_req_callback_data(subreq,
2048 struct tevent_req);
2049 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2050 tevent_req_data(req,
2051 struct netlogon_creds_cli_ServerPasswordSet_state);
2052 NTSTATUS status;
2053 NTSTATUS result;
2054 bool ok;
2056 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2057 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2058 &result);
2059 TALLOC_FREE(subreq);
2060 if (tevent_req_nterror(req, status)) {
2061 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2062 return;
2064 } else {
2065 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2066 &result);
2067 TALLOC_FREE(subreq);
2068 if (tevent_req_nterror(req, status)) {
2069 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2070 return;
2074 ok = netlogon_creds_client_check(&state->tmp_creds,
2075 &state->rep_auth.cred);
2076 if (!ok) {
2077 status = NT_STATUS_ACCESS_DENIED;
2078 tevent_req_nterror(req, status);
2079 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2080 return;
2083 if (tevent_req_nterror(req, result)) {
2084 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2085 return;
2088 dcerpc_binding_handle_set_timeout(state->binding_handle,
2089 state->old_timeout);
2091 *state->creds = state->tmp_creds;
2092 status = netlogon_creds_cli_store(state->context,
2093 state->creds);
2094 TALLOC_FREE(state->creds);
2095 if (tevent_req_nterror(req, status)) {
2096 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2097 return;
2100 tevent_req_done(req);
2103 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2105 NTSTATUS status;
2107 if (tevent_req_is_nterror(req, &status)) {
2108 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2109 tevent_req_received(req);
2110 return status;
2113 tevent_req_received(req);
2114 return NT_STATUS_OK;
2117 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2118 struct netlogon_creds_cli_context *context,
2119 struct dcerpc_binding_handle *b,
2120 const DATA_BLOB *new_password,
2121 const uint32_t *new_version)
2123 TALLOC_CTX *frame = talloc_stackframe();
2124 struct tevent_context *ev;
2125 struct tevent_req *req;
2126 NTSTATUS status = NT_STATUS_NO_MEMORY;
2128 ev = samba_tevent_context_init(frame);
2129 if (ev == NULL) {
2130 goto fail;
2132 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2133 new_password,
2134 new_version);
2135 if (req == NULL) {
2136 goto fail;
2138 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2139 goto fail;
2141 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2142 fail:
2143 TALLOC_FREE(frame);
2144 return status;
2147 struct netlogon_creds_cli_LogonSamLogon_state {
2148 struct tevent_context *ev;
2149 struct netlogon_creds_cli_context *context;
2150 struct dcerpc_binding_handle *binding_handle;
2152 char *srv_name_slash;
2154 enum netr_LogonInfoClass logon_level;
2155 const union netr_LogonLevel *const_logon;
2156 union netr_LogonLevel *logon;
2157 uint32_t flags;
2159 uint16_t validation_level;
2160 union netr_Validation *validation;
2161 uint8_t authoritative;
2164 * do we need encryption at the application layer?
2166 bool user_encrypt;
2167 bool try_logon_ex;
2168 bool try_validation6;
2171 * the read only credentials before we started the operation
2172 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2174 struct netlogon_creds_CredentialState *ro_creds;
2177 * The (locked) credentials used for the credential chain
2178 * used for netr_LogonSamLogonWithFlags() or
2179 * netr_LogonSamLogonWith().
2181 struct netlogon_creds_CredentialState *lk_creds;
2184 * While we have locked the global credentials (lk_creds above)
2185 * we operate an a temporary copy, because a server
2186 * may not support netr_LogonSamLogonWithFlags() and
2187 * didn't process our netr_Authenticator, so we need to
2188 * restart from lk_creds.
2190 struct netlogon_creds_CredentialState tmp_creds;
2191 struct netr_Authenticator req_auth;
2192 struct netr_Authenticator rep_auth;
2195 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2196 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2197 NTSTATUS status);
2199 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2200 struct tevent_context *ev,
2201 struct netlogon_creds_cli_context *context,
2202 struct dcerpc_binding_handle *b,
2203 enum netr_LogonInfoClass logon_level,
2204 const union netr_LogonLevel *logon,
2205 uint32_t flags)
2207 struct tevent_req *req;
2208 struct netlogon_creds_cli_LogonSamLogon_state *state;
2210 req = tevent_req_create(mem_ctx, &state,
2211 struct netlogon_creds_cli_LogonSamLogon_state);
2212 if (req == NULL) {
2213 return NULL;
2216 state->ev = ev;
2217 state->context = context;
2218 state->binding_handle = b;
2220 state->logon_level = logon_level;
2221 state->const_logon = logon;
2222 state->flags = flags;
2224 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2225 context->server.computer);
2226 if (tevent_req_nomem(state->srv_name_slash, req)) {
2227 return tevent_req_post(req, ev);
2230 switch (logon_level) {
2231 case NetlogonInteractiveInformation:
2232 case NetlogonInteractiveTransitiveInformation:
2233 case NetlogonServiceInformation:
2234 case NetlogonServiceTransitiveInformation:
2235 case NetlogonGenericInformation:
2236 state->user_encrypt = true;
2237 break;
2239 case NetlogonNetworkInformation:
2240 case NetlogonNetworkTransitiveInformation:
2241 break;
2244 state->validation = talloc_zero(state, union netr_Validation);
2245 if (tevent_req_nomem(state->validation, req)) {
2246 return tevent_req_post(req, ev);
2249 netlogon_creds_cli_LogonSamLogon_start(req);
2250 if (!tevent_req_is_in_progress(req)) {
2251 return tevent_req_post(req, ev);
2255 * we defer all callbacks in order to cleanup
2256 * the database record.
2258 tevent_req_defer_callback(req, state->ev);
2259 return req;
2262 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2263 NTSTATUS status)
2265 struct netlogon_creds_cli_LogonSamLogon_state *state =
2266 tevent_req_data(req,
2267 struct netlogon_creds_cli_LogonSamLogon_state);
2269 if (state->lk_creds == NULL) {
2270 return;
2273 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2275 * This is a hack to recover from a bug in old
2276 * Samba servers, when LogonSamLogonEx() fails:
2278 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2280 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2282 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2283 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2284 * If the sign/seal check fails.
2286 * In that case we need to cleanup the netlogon session.
2288 * It's the job of the caller to disconnect the current
2289 * connection, if netlogon_creds_cli_LogonSamLogon()
2290 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2292 if (!state->context->server.try_logon_with) {
2293 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2297 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2298 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2299 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2300 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2301 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2302 TALLOC_FREE(state->lk_creds);
2303 return;
2306 netlogon_creds_cli_delete(state->context, state->lk_creds);
2307 TALLOC_FREE(state->lk_creds);
2310 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2312 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2314 struct netlogon_creds_cli_LogonSamLogon_state *state =
2315 tevent_req_data(req,
2316 struct netlogon_creds_cli_LogonSamLogon_state);
2317 struct tevent_req *subreq;
2318 NTSTATUS status;
2319 enum dcerpc_AuthType auth_type;
2320 enum dcerpc_AuthLevel auth_level;
2322 TALLOC_FREE(state->ro_creds);
2323 TALLOC_FREE(state->logon);
2324 ZERO_STRUCTP(state->validation);
2326 dcerpc_binding_handle_auth_info(state->binding_handle,
2327 &auth_type, &auth_level);
2329 state->try_logon_ex = state->context->server.try_logon_ex;
2330 state->try_validation6 = state->context->server.try_validation6;
2332 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2333 state->try_logon_ex = false;
2336 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2337 state->try_validation6 = false;
2340 if (state->try_logon_ex) {
2341 if (state->try_validation6) {
2342 state->validation_level = 6;
2343 } else {
2344 state->validation_level = 3;
2345 state->user_encrypt = true;
2348 state->logon = netlogon_creds_shallow_copy_logon(state,
2349 state->logon_level,
2350 state->const_logon);
2351 if (tevent_req_nomem(state->logon, req)) {
2352 status = NT_STATUS_NO_MEMORY;
2353 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2354 return;
2357 if (state->user_encrypt) {
2358 status = netlogon_creds_cli_get(state->context,
2359 state,
2360 &state->ro_creds);
2361 if (!NT_STATUS_IS_OK(status)) {
2362 status = NT_STATUS_ACCESS_DENIED;
2363 tevent_req_nterror(req, status);
2364 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2365 return;
2368 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2369 state->logon_level,
2370 state->logon);
2373 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2374 state->binding_handle,
2375 state->srv_name_slash,
2376 state->context->client.computer,
2377 state->logon_level,
2378 state->logon,
2379 state->validation_level,
2380 state->validation,
2381 &state->authoritative,
2382 &state->flags);
2383 if (tevent_req_nomem(subreq, req)) {
2384 status = NT_STATUS_NO_MEMORY;
2385 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2386 return;
2388 tevent_req_set_callback(subreq,
2389 netlogon_creds_cli_LogonSamLogon_done,
2390 req);
2391 return;
2394 if (state->lk_creds == NULL) {
2395 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2396 state->context);
2397 if (tevent_req_nomem(subreq, req)) {
2398 status = NT_STATUS_NO_MEMORY;
2399 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2400 return;
2402 tevent_req_set_callback(subreq,
2403 netlogon_creds_cli_LogonSamLogon_done,
2404 req);
2405 return;
2408 state->tmp_creds = *state->lk_creds;
2409 netlogon_creds_client_authenticator(&state->tmp_creds,
2410 &state->req_auth);
2411 ZERO_STRUCT(state->rep_auth);
2413 state->logon = netlogon_creds_shallow_copy_logon(state,
2414 state->logon_level,
2415 state->const_logon);
2416 if (tevent_req_nomem(state->logon, req)) {
2417 status = NT_STATUS_NO_MEMORY;
2418 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2419 return;
2422 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2423 state->logon_level,
2424 state->logon);
2426 state->validation_level = 3;
2428 if (state->context->server.try_logon_with) {
2429 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2430 state->binding_handle,
2431 state->srv_name_slash,
2432 state->context->client.computer,
2433 &state->req_auth,
2434 &state->rep_auth,
2435 state->logon_level,
2436 state->logon,
2437 state->validation_level,
2438 state->validation,
2439 &state->authoritative,
2440 &state->flags);
2441 if (tevent_req_nomem(subreq, req)) {
2442 status = NT_STATUS_NO_MEMORY;
2443 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2444 return;
2446 } else {
2447 state->flags = 0;
2449 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2450 state->binding_handle,
2451 state->srv_name_slash,
2452 state->context->client.computer,
2453 &state->req_auth,
2454 &state->rep_auth,
2455 state->logon_level,
2456 state->logon,
2457 state->validation_level,
2458 state->validation,
2459 &state->authoritative);
2460 if (tevent_req_nomem(subreq, req)) {
2461 status = NT_STATUS_NO_MEMORY;
2462 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2463 return;
2467 tevent_req_set_callback(subreq,
2468 netlogon_creds_cli_LogonSamLogon_done,
2469 req);
2472 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2474 struct tevent_req *req =
2475 tevent_req_callback_data(subreq,
2476 struct tevent_req);
2477 struct netlogon_creds_cli_LogonSamLogon_state *state =
2478 tevent_req_data(req,
2479 struct netlogon_creds_cli_LogonSamLogon_state);
2480 NTSTATUS status;
2481 NTSTATUS result;
2482 bool ok;
2484 if (state->try_logon_ex) {
2485 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2486 state->validation,
2487 &result);
2488 TALLOC_FREE(subreq);
2489 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2490 state->context->server.try_validation6 = false;
2491 state->context->server.try_logon_ex = false;
2492 netlogon_creds_cli_LogonSamLogon_start(req);
2493 return;
2495 if (tevent_req_nterror(req, status)) {
2496 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2497 return;
2500 if ((state->validation_level == 6) &&
2501 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2502 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2503 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2505 state->context->server.try_validation6 = false;
2506 netlogon_creds_cli_LogonSamLogon_start(req);
2507 return;
2510 if (tevent_req_nterror(req, result)) {
2511 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2512 return;
2515 if (state->ro_creds == NULL) {
2516 tevent_req_done(req);
2517 return;
2520 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2521 if (!ok) {
2523 * We got a race, lets retry with on authenticator
2524 * protection.
2526 * netlogon_creds_cli_LogonSamLogon_start()
2527 * will TALLOC_FREE(state->ro_creds);
2529 state->try_logon_ex = false;
2530 netlogon_creds_cli_LogonSamLogon_start(req);
2531 return;
2534 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2535 state->validation_level,
2536 state->validation);
2538 tevent_req_done(req);
2539 return;
2542 if (state->lk_creds == NULL) {
2543 status = netlogon_creds_cli_lock_recv(subreq, state,
2544 &state->lk_creds);
2545 TALLOC_FREE(subreq);
2546 if (tevent_req_nterror(req, status)) {
2547 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2548 return;
2551 netlogon_creds_cli_LogonSamLogon_start(req);
2552 return;
2555 if (state->context->server.try_logon_with) {
2556 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2557 state->validation,
2558 &result);
2559 TALLOC_FREE(subreq);
2560 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2561 state->context->server.try_logon_with = false;
2562 netlogon_creds_cli_LogonSamLogon_start(req);
2563 return;
2565 if (tevent_req_nterror(req, status)) {
2566 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2567 return;
2569 } else {
2570 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2571 state->validation,
2572 &result);
2573 TALLOC_FREE(subreq);
2574 if (tevent_req_nterror(req, status)) {
2575 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2576 return;
2580 ok = netlogon_creds_client_check(&state->tmp_creds,
2581 &state->rep_auth.cred);
2582 if (!ok) {
2583 status = NT_STATUS_ACCESS_DENIED;
2584 tevent_req_nterror(req, status);
2585 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2586 return;
2589 *state->lk_creds = state->tmp_creds;
2590 status = netlogon_creds_cli_store(state->context,
2591 state->lk_creds);
2592 TALLOC_FREE(state->lk_creds);
2594 if (tevent_req_nterror(req, status)) {
2595 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2596 return;
2599 if (tevent_req_nterror(req, result)) {
2600 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2601 return;
2604 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2605 state->validation_level,
2606 state->validation);
2608 tevent_req_done(req);
2611 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2612 TALLOC_CTX *mem_ctx,
2613 uint16_t *validation_level,
2614 union netr_Validation **validation,
2615 uint8_t *authoritative,
2616 uint32_t *flags)
2618 struct netlogon_creds_cli_LogonSamLogon_state *state =
2619 tevent_req_data(req,
2620 struct netlogon_creds_cli_LogonSamLogon_state);
2621 NTSTATUS status;
2623 /* authoritative is also returned on error */
2624 *authoritative = state->authoritative;
2626 if (tevent_req_is_nterror(req, &status)) {
2627 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2628 tevent_req_received(req);
2629 return status;
2632 *validation_level = state->validation_level;
2633 *validation = talloc_move(mem_ctx, &state->validation);
2634 *flags = state->flags;
2636 tevent_req_received(req);
2637 return NT_STATUS_OK;
2640 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2641 struct netlogon_creds_cli_context *context,
2642 struct dcerpc_binding_handle *b,
2643 enum netr_LogonInfoClass logon_level,
2644 const union netr_LogonLevel *logon,
2645 TALLOC_CTX *mem_ctx,
2646 uint16_t *validation_level,
2647 union netr_Validation **validation,
2648 uint8_t *authoritative,
2649 uint32_t *flags)
2651 TALLOC_CTX *frame = talloc_stackframe();
2652 struct tevent_context *ev;
2653 struct tevent_req *req;
2654 NTSTATUS status = NT_STATUS_NO_MEMORY;
2656 ev = samba_tevent_context_init(frame);
2657 if (ev == NULL) {
2658 goto fail;
2660 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2661 logon_level, logon,
2662 *flags);
2663 if (req == NULL) {
2664 goto fail;
2666 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2667 goto fail;
2669 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2670 validation_level,
2671 validation,
2672 authoritative,
2673 flags);
2674 fail:
2675 TALLOC_FREE(frame);
2676 return status;
2679 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2680 struct tevent_context *ev;
2681 struct netlogon_creds_cli_context *context;
2682 struct dcerpc_binding_handle *binding_handle;
2684 char *srv_name_slash;
2685 enum dcerpc_AuthType auth_type;
2686 enum dcerpc_AuthLevel auth_level;
2688 const char *site_name;
2689 uint32_t dns_ttl;
2690 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2692 struct netlogon_creds_CredentialState *creds;
2693 struct netlogon_creds_CredentialState tmp_creds;
2694 struct netr_Authenticator req_auth;
2695 struct netr_Authenticator rep_auth;
2698 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2699 NTSTATUS status);
2700 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2702 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2703 struct tevent_context *ev,
2704 struct netlogon_creds_cli_context *context,
2705 struct dcerpc_binding_handle *b,
2706 const char *site_name,
2707 uint32_t dns_ttl,
2708 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2710 struct tevent_req *req;
2711 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2712 struct tevent_req *subreq;
2714 req = tevent_req_create(mem_ctx, &state,
2715 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2716 if (req == NULL) {
2717 return NULL;
2720 state->ev = ev;
2721 state->context = context;
2722 state->binding_handle = b;
2724 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2725 context->server.computer);
2726 if (tevent_req_nomem(state->srv_name_slash, req)) {
2727 return tevent_req_post(req, ev);
2730 state->site_name = site_name;
2731 state->dns_ttl = dns_ttl;
2732 state->dns_names = dns_names;
2734 dcerpc_binding_handle_auth_info(state->binding_handle,
2735 &state->auth_type,
2736 &state->auth_level);
2738 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2739 state->context);
2740 if (tevent_req_nomem(subreq, req)) {
2741 return tevent_req_post(req, ev);
2744 tevent_req_set_callback(subreq,
2745 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2746 req);
2748 return req;
2751 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2752 NTSTATUS status)
2754 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2755 tevent_req_data(req,
2756 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2758 if (state->creds == NULL) {
2759 return;
2762 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2763 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2764 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2765 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2766 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2767 TALLOC_FREE(state->creds);
2768 return;
2771 netlogon_creds_cli_delete(state->context, state->creds);
2772 TALLOC_FREE(state->creds);
2775 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2777 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2779 struct tevent_req *req =
2780 tevent_req_callback_data(subreq,
2781 struct tevent_req);
2782 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2783 tevent_req_data(req,
2784 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2785 NTSTATUS status;
2787 status = netlogon_creds_cli_lock_recv(subreq, state,
2788 &state->creds);
2789 TALLOC_FREE(subreq);
2790 if (tevent_req_nterror(req, status)) {
2791 return;
2794 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2795 switch (state->auth_level) {
2796 case DCERPC_AUTH_LEVEL_INTEGRITY:
2797 case DCERPC_AUTH_LEVEL_PRIVACY:
2798 break;
2799 default:
2800 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2801 return;
2803 } else {
2804 uint32_t tmp = state->creds->negotiate_flags;
2806 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2808 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2809 * it should be used, which means
2810 * we had a chance to verify no downgrade
2811 * happened.
2813 * This relies on netlogon_creds_cli_check*
2814 * being called before, as first request after
2815 * the DCERPC bind.
2817 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2818 return;
2823 * we defer all callbacks in order to cleanup
2824 * the database record.
2826 tevent_req_defer_callback(req, state->ev);
2828 state->tmp_creds = *state->creds;
2829 netlogon_creds_client_authenticator(&state->tmp_creds,
2830 &state->req_auth);
2831 ZERO_STRUCT(state->rep_auth);
2833 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2834 state->binding_handle,
2835 state->srv_name_slash,
2836 state->tmp_creds.computer_name,
2837 &state->req_auth,
2838 &state->rep_auth,
2839 state->site_name,
2840 state->dns_ttl,
2841 state->dns_names);
2842 if (tevent_req_nomem(subreq, req)) {
2843 status = NT_STATUS_NO_MEMORY;
2844 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2845 return;
2848 tevent_req_set_callback(subreq,
2849 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2850 req);
2853 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2855 struct tevent_req *req =
2856 tevent_req_callback_data(subreq,
2857 struct tevent_req);
2858 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2859 tevent_req_data(req,
2860 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2861 NTSTATUS status;
2862 NTSTATUS result;
2863 bool ok;
2866 * We use state->dns_names as the memory context, as this is
2867 * the only in/out variable and it has been overwritten by the
2868 * out parameter from the server.
2870 * We need to preserve the return value until the caller can use it.
2872 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2873 &result);
2874 TALLOC_FREE(subreq);
2875 if (tevent_req_nterror(req, status)) {
2876 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2877 return;
2880 ok = netlogon_creds_client_check(&state->tmp_creds,
2881 &state->rep_auth.cred);
2882 if (!ok) {
2883 status = NT_STATUS_ACCESS_DENIED;
2884 tevent_req_nterror(req, status);
2885 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2886 return;
2889 *state->creds = state->tmp_creds;
2890 status = netlogon_creds_cli_store(state->context,
2891 state->creds);
2892 TALLOC_FREE(state->creds);
2894 if (tevent_req_nterror(req, status)) {
2895 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2896 return;
2899 if (tevent_req_nterror(req, result)) {
2900 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2901 return;
2904 tevent_req_done(req);
2907 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2909 NTSTATUS status;
2911 if (tevent_req_is_nterror(req, &status)) {
2912 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2913 tevent_req_received(req);
2914 return status;
2917 tevent_req_received(req);
2918 return NT_STATUS_OK;
2921 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2922 struct netlogon_creds_cli_context *context,
2923 struct dcerpc_binding_handle *b,
2924 const char *site_name,
2925 uint32_t dns_ttl,
2926 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2928 TALLOC_CTX *frame = talloc_stackframe();
2929 struct tevent_context *ev;
2930 struct tevent_req *req;
2931 NTSTATUS status = NT_STATUS_NO_MEMORY;
2933 ev = samba_tevent_context_init(frame);
2934 if (ev == NULL) {
2935 goto fail;
2937 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2938 site_name,
2939 dns_ttl,
2940 dns_names);
2941 if (req == NULL) {
2942 goto fail;
2944 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2945 goto fail;
2947 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2948 fail:
2949 TALLOC_FREE(frame);
2950 return status;
2953 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2954 struct tevent_context *ev;
2955 struct netlogon_creds_cli_context *context;
2956 struct dcerpc_binding_handle *binding_handle;
2958 char *srv_name_slash;
2959 enum dcerpc_AuthType auth_type;
2960 enum dcerpc_AuthLevel auth_level;
2962 struct samr_Password new_owf_password;
2963 struct samr_Password old_owf_password;
2964 struct netr_TrustInfo *trust_info;
2966 struct netlogon_creds_CredentialState *creds;
2967 struct netlogon_creds_CredentialState tmp_creds;
2968 struct netr_Authenticator req_auth;
2969 struct netr_Authenticator rep_auth;
2972 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2973 NTSTATUS status);
2974 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2976 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2977 struct tevent_context *ev,
2978 struct netlogon_creds_cli_context *context,
2979 struct dcerpc_binding_handle *b)
2981 struct tevent_req *req;
2982 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2983 struct tevent_req *subreq;
2985 req = tevent_req_create(mem_ctx, &state,
2986 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2987 if (req == NULL) {
2988 return NULL;
2991 state->ev = ev;
2992 state->context = context;
2993 state->binding_handle = b;
2995 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2996 context->server.computer);
2997 if (tevent_req_nomem(state->srv_name_slash, req)) {
2998 return tevent_req_post(req, ev);
3001 dcerpc_binding_handle_auth_info(state->binding_handle,
3002 &state->auth_type,
3003 &state->auth_level);
3005 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3006 state->context);
3007 if (tevent_req_nomem(subreq, req)) {
3008 return tevent_req_post(req, ev);
3011 tevent_req_set_callback(subreq,
3012 netlogon_creds_cli_ServerGetTrustInfo_locked,
3013 req);
3015 return req;
3018 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3019 NTSTATUS status)
3021 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3022 tevent_req_data(req,
3023 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3025 if (state->creds == NULL) {
3026 return;
3029 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3030 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3031 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3032 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3033 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3034 TALLOC_FREE(state->creds);
3035 return;
3038 netlogon_creds_cli_delete(state->context, state->creds);
3039 TALLOC_FREE(state->creds);
3042 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3044 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3046 struct tevent_req *req =
3047 tevent_req_callback_data(subreq,
3048 struct tevent_req);
3049 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3050 tevent_req_data(req,
3051 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3052 NTSTATUS status;
3054 status = netlogon_creds_cli_lock_recv(subreq, state,
3055 &state->creds);
3056 TALLOC_FREE(subreq);
3057 if (tevent_req_nterror(req, status)) {
3058 return;
3061 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3062 switch (state->auth_level) {
3063 case DCERPC_AUTH_LEVEL_PRIVACY:
3064 break;
3065 default:
3066 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3067 return;
3069 } else {
3070 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3071 return;
3075 * we defer all callbacks in order to cleanup
3076 * the database record.
3078 tevent_req_defer_callback(req, state->ev);
3080 state->tmp_creds = *state->creds;
3081 netlogon_creds_client_authenticator(&state->tmp_creds,
3082 &state->req_auth);
3083 ZERO_STRUCT(state->rep_auth);
3085 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3086 state->binding_handle,
3087 state->srv_name_slash,
3088 state->tmp_creds.account_name,
3089 state->tmp_creds.secure_channel_type,
3090 state->tmp_creds.computer_name,
3091 &state->req_auth,
3092 &state->rep_auth,
3093 &state->new_owf_password,
3094 &state->old_owf_password,
3095 &state->trust_info);
3096 if (tevent_req_nomem(subreq, req)) {
3097 status = NT_STATUS_NO_MEMORY;
3098 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3099 return;
3102 tevent_req_set_callback(subreq,
3103 netlogon_creds_cli_ServerGetTrustInfo_done,
3104 req);
3107 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3109 struct tevent_req *req =
3110 tevent_req_callback_data(subreq,
3111 struct tevent_req);
3112 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3113 tevent_req_data(req,
3114 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3115 NTSTATUS status;
3116 NTSTATUS result;
3117 const struct samr_Password zero = {};
3118 int cmp;
3119 bool ok;
3122 * We use state->dns_names as the memory context, as this is
3123 * the only in/out variable and it has been overwritten by the
3124 * out parameter from the server.
3126 * We need to preserve the return value until the caller can use it.
3128 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3129 TALLOC_FREE(subreq);
3130 if (tevent_req_nterror(req, status)) {
3131 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3132 return;
3135 ok = netlogon_creds_client_check(&state->tmp_creds,
3136 &state->rep_auth.cred);
3137 if (!ok) {
3138 status = NT_STATUS_ACCESS_DENIED;
3139 tevent_req_nterror(req, status);
3140 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3141 return;
3144 cmp = memcmp(state->new_owf_password.hash,
3145 zero.hash, sizeof(zero.hash));
3146 if (cmp != 0) {
3147 netlogon_creds_des_decrypt(&state->tmp_creds,
3148 &state->new_owf_password);
3150 cmp = memcmp(state->old_owf_password.hash,
3151 zero.hash, sizeof(zero.hash));
3152 if (cmp != 0) {
3153 netlogon_creds_des_decrypt(&state->tmp_creds,
3154 &state->old_owf_password);
3157 *state->creds = state->tmp_creds;
3158 status = netlogon_creds_cli_store(state->context,
3159 state->creds);
3160 TALLOC_FREE(state->creds);
3161 if (tevent_req_nterror(req, status)) {
3162 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3163 return;
3166 if (tevent_req_nterror(req, result)) {
3167 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3168 return;
3171 tevent_req_done(req);
3174 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3175 TALLOC_CTX *mem_ctx,
3176 struct samr_Password *new_owf_password,
3177 struct samr_Password *old_owf_password,
3178 struct netr_TrustInfo **trust_info)
3180 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3181 tevent_req_data(req,
3182 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3183 NTSTATUS status;
3185 if (tevent_req_is_nterror(req, &status)) {
3186 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3187 tevent_req_received(req);
3188 return status;
3191 if (new_owf_password != NULL) {
3192 *new_owf_password = state->new_owf_password;
3194 if (old_owf_password != NULL) {
3195 *old_owf_password = state->old_owf_password;
3197 if (trust_info != NULL) {
3198 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3201 tevent_req_received(req);
3202 return NT_STATUS_OK;
3205 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3206 struct netlogon_creds_cli_context *context,
3207 struct dcerpc_binding_handle *b,
3208 TALLOC_CTX *mem_ctx,
3209 struct samr_Password *new_owf_password,
3210 struct samr_Password *old_owf_password,
3211 struct netr_TrustInfo **trust_info)
3213 TALLOC_CTX *frame = talloc_stackframe();
3214 struct tevent_context *ev;
3215 struct tevent_req *req;
3216 NTSTATUS status = NT_STATUS_NO_MEMORY;
3218 ev = samba_tevent_context_init(frame);
3219 if (ev == NULL) {
3220 goto fail;
3222 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3223 if (req == NULL) {
3224 goto fail;
3226 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3227 goto fail;
3229 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3230 mem_ctx,
3231 new_owf_password,
3232 old_owf_password,
3233 trust_info);
3234 fail:
3235 TALLOC_FREE(frame);
3236 return status;
3239 struct netlogon_creds_cli_GetForestTrustInformation_state {
3240 struct tevent_context *ev;
3241 struct netlogon_creds_cli_context *context;
3242 struct dcerpc_binding_handle *binding_handle;
3244 char *srv_name_slash;
3245 enum dcerpc_AuthType auth_type;
3246 enum dcerpc_AuthLevel auth_level;
3248 uint32_t flags;
3249 struct lsa_ForestTrustInformation *forest_trust_info;
3251 struct netlogon_creds_CredentialState *creds;
3252 struct netlogon_creds_CredentialState tmp_creds;
3253 struct netr_Authenticator req_auth;
3254 struct netr_Authenticator rep_auth;
3257 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3258 NTSTATUS status);
3259 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3261 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3262 struct tevent_context *ev,
3263 struct netlogon_creds_cli_context *context,
3264 struct dcerpc_binding_handle *b)
3266 struct tevent_req *req;
3267 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3268 struct tevent_req *subreq;
3270 req = tevent_req_create(mem_ctx, &state,
3271 struct netlogon_creds_cli_GetForestTrustInformation_state);
3272 if (req == NULL) {
3273 return NULL;
3276 state->ev = ev;
3277 state->context = context;
3278 state->binding_handle = b;
3280 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3281 context->server.computer);
3282 if (tevent_req_nomem(state->srv_name_slash, req)) {
3283 return tevent_req_post(req, ev);
3286 state->flags = 0;
3288 dcerpc_binding_handle_auth_info(state->binding_handle,
3289 &state->auth_type,
3290 &state->auth_level);
3292 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3293 state->context);
3294 if (tevent_req_nomem(subreq, req)) {
3295 return tevent_req_post(req, ev);
3298 tevent_req_set_callback(subreq,
3299 netlogon_creds_cli_GetForestTrustInformation_locked,
3300 req);
3302 return req;
3305 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3306 NTSTATUS status)
3308 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3309 tevent_req_data(req,
3310 struct netlogon_creds_cli_GetForestTrustInformation_state);
3312 if (state->creds == NULL) {
3313 return;
3316 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3317 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3318 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3319 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3320 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3321 TALLOC_FREE(state->creds);
3322 return;
3325 netlogon_creds_cli_delete(state->context, state->creds);
3326 TALLOC_FREE(state->creds);
3329 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3331 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3333 struct tevent_req *req =
3334 tevent_req_callback_data(subreq,
3335 struct tevent_req);
3336 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3337 tevent_req_data(req,
3338 struct netlogon_creds_cli_GetForestTrustInformation_state);
3339 NTSTATUS status;
3341 status = netlogon_creds_cli_lock_recv(subreq, state,
3342 &state->creds);
3343 TALLOC_FREE(subreq);
3344 if (tevent_req_nterror(req, status)) {
3345 return;
3348 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3349 switch (state->auth_level) {
3350 case DCERPC_AUTH_LEVEL_INTEGRITY:
3351 case DCERPC_AUTH_LEVEL_PRIVACY:
3352 break;
3353 default:
3354 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3355 return;
3357 } else {
3358 uint32_t tmp = state->creds->negotiate_flags;
3360 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3362 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3363 * it should be used, which means
3364 * we had a chance to verify no downgrade
3365 * happened.
3367 * This relies on netlogon_creds_cli_check*
3368 * being called before, as first request after
3369 * the DCERPC bind.
3371 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3372 return;
3377 * we defer all callbacks in order to cleanup
3378 * the database record.
3380 tevent_req_defer_callback(req, state->ev);
3382 state->tmp_creds = *state->creds;
3383 netlogon_creds_client_authenticator(&state->tmp_creds,
3384 &state->req_auth);
3385 ZERO_STRUCT(state->rep_auth);
3387 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3388 state->binding_handle,
3389 state->srv_name_slash,
3390 state->tmp_creds.computer_name,
3391 &state->req_auth,
3392 &state->rep_auth,
3393 state->flags,
3394 &state->forest_trust_info);
3395 if (tevent_req_nomem(subreq, req)) {
3396 status = NT_STATUS_NO_MEMORY;
3397 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3398 return;
3401 tevent_req_set_callback(subreq,
3402 netlogon_creds_cli_GetForestTrustInformation_done,
3403 req);
3406 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3408 struct tevent_req *req =
3409 tevent_req_callback_data(subreq,
3410 struct tevent_req);
3411 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3412 tevent_req_data(req,
3413 struct netlogon_creds_cli_GetForestTrustInformation_state);
3414 NTSTATUS status;
3415 NTSTATUS result;
3416 bool ok;
3419 * We use state->dns_names as the memory context, as this is
3420 * the only in/out variable and it has been overwritten by the
3421 * out parameter from the server.
3423 * We need to preserve the return value until the caller can use it.
3425 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3426 TALLOC_FREE(subreq);
3427 if (tevent_req_nterror(req, status)) {
3428 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3429 return;
3432 ok = netlogon_creds_client_check(&state->tmp_creds,
3433 &state->rep_auth.cred);
3434 if (!ok) {
3435 status = NT_STATUS_ACCESS_DENIED;
3436 tevent_req_nterror(req, status);
3437 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3438 return;
3441 *state->creds = state->tmp_creds;
3442 status = netlogon_creds_cli_store(state->context,
3443 state->creds);
3444 TALLOC_FREE(state->creds);
3446 if (tevent_req_nterror(req, status)) {
3447 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3448 return;
3451 if (tevent_req_nterror(req, result)) {
3452 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3453 return;
3456 tevent_req_done(req);
3459 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3460 TALLOC_CTX *mem_ctx,
3461 struct lsa_ForestTrustInformation **forest_trust_info)
3463 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3464 tevent_req_data(req,
3465 struct netlogon_creds_cli_GetForestTrustInformation_state);
3466 NTSTATUS status;
3468 if (tevent_req_is_nterror(req, &status)) {
3469 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3470 tevent_req_received(req);
3471 return status;
3474 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3476 tevent_req_received(req);
3477 return NT_STATUS_OK;
3480 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3481 struct netlogon_creds_cli_context *context,
3482 struct dcerpc_binding_handle *b,
3483 TALLOC_CTX *mem_ctx,
3484 struct lsa_ForestTrustInformation **forest_trust_info)
3486 TALLOC_CTX *frame = talloc_stackframe();
3487 struct tevent_context *ev;
3488 struct tevent_req *req;
3489 NTSTATUS status = NT_STATUS_NO_MEMORY;
3491 ev = samba_tevent_context_init(frame);
3492 if (ev == NULL) {
3493 goto fail;
3495 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3496 if (req == NULL) {
3497 goto fail;
3499 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3500 goto fail;
3502 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3503 mem_ctx,
3504 forest_trust_info);
3505 fail:
3506 TALLOC_FREE(frame);
3507 return status;
3510 struct netlogon_creds_cli_SendToSam_state {
3511 struct tevent_context *ev;
3512 struct netlogon_creds_cli_context *context;
3513 struct dcerpc_binding_handle *binding_handle;
3515 char *srv_name_slash;
3516 enum dcerpc_AuthType auth_type;
3517 enum dcerpc_AuthLevel auth_level;
3519 DATA_BLOB opaque;
3521 struct netlogon_creds_CredentialState *creds;
3522 struct netlogon_creds_CredentialState tmp_creds;
3523 struct netr_Authenticator req_auth;
3524 struct netr_Authenticator rep_auth;
3527 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3528 NTSTATUS status);
3529 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3531 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3532 struct tevent_context *ev,
3533 struct netlogon_creds_cli_context *context,
3534 struct dcerpc_binding_handle *b,
3535 struct netr_SendToSamBase *message)
3537 struct tevent_req *req;
3538 struct netlogon_creds_cli_SendToSam_state *state;
3539 struct tevent_req *subreq;
3540 enum ndr_err_code ndr_err;
3542 req = tevent_req_create(mem_ctx, &state,
3543 struct netlogon_creds_cli_SendToSam_state);
3544 if (req == NULL) {
3545 return NULL;
3548 state->ev = ev;
3549 state->context = context;
3550 state->binding_handle = b;
3552 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3553 context->server.computer);
3554 if (tevent_req_nomem(state->srv_name_slash, req)) {
3555 return tevent_req_post(req, ev);
3558 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3559 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3560 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3561 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3562 tevent_req_nterror(req, status);
3563 return tevent_req_post(req, ev);
3566 dcerpc_binding_handle_auth_info(state->binding_handle,
3567 &state->auth_type,
3568 &state->auth_level);
3570 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3571 state->context);
3572 if (tevent_req_nomem(subreq, req)) {
3573 return tevent_req_post(req, ev);
3576 tevent_req_set_callback(subreq,
3577 netlogon_creds_cli_SendToSam_locked,
3578 req);
3580 return req;
3583 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3584 NTSTATUS status)
3586 struct netlogon_creds_cli_SendToSam_state *state =
3587 tevent_req_data(req,
3588 struct netlogon_creds_cli_SendToSam_state);
3590 if (state->creds == NULL) {
3591 return;
3594 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3595 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3596 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3597 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3598 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3599 TALLOC_FREE(state->creds);
3600 return;
3603 netlogon_creds_cli_delete(state->context, state->creds);
3604 TALLOC_FREE(state->creds);
3607 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3609 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3611 struct tevent_req *req =
3612 tevent_req_callback_data(subreq,
3613 struct tevent_req);
3614 struct netlogon_creds_cli_SendToSam_state *state =
3615 tevent_req_data(req,
3616 struct netlogon_creds_cli_SendToSam_state);
3617 NTSTATUS status;
3619 status = netlogon_creds_cli_lock_recv(subreq, state,
3620 &state->creds);
3621 TALLOC_FREE(subreq);
3622 if (tevent_req_nterror(req, status)) {
3623 return;
3626 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3627 switch (state->auth_level) {
3628 case DCERPC_AUTH_LEVEL_INTEGRITY:
3629 case DCERPC_AUTH_LEVEL_PRIVACY:
3630 break;
3631 default:
3632 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3633 return;
3635 } else {
3636 uint32_t tmp = state->creds->negotiate_flags;
3638 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3640 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3641 * it should be used, which means
3642 * we had a chance to verify no downgrade
3643 * happened.
3645 * This relies on netlogon_creds_cli_check*
3646 * being called before, as first request after
3647 * the DCERPC bind.
3649 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3650 return;
3655 * we defer all callbacks in order to cleanup
3656 * the database record.
3658 tevent_req_defer_callback(req, state->ev);
3660 state->tmp_creds = *state->creds;
3661 netlogon_creds_client_authenticator(&state->tmp_creds,
3662 &state->req_auth);
3663 ZERO_STRUCT(state->rep_auth);
3665 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3666 netlogon_creds_aes_encrypt(&state->tmp_creds,
3667 state->opaque.data,
3668 state->opaque.length);
3669 } else {
3670 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3671 state->opaque.data,
3672 state->opaque.length);
3675 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3676 state->binding_handle,
3677 state->srv_name_slash,
3678 state->tmp_creds.computer_name,
3679 &state->req_auth,
3680 &state->rep_auth,
3681 state->opaque.data,
3682 state->opaque.length);
3683 if (tevent_req_nomem(subreq, req)) {
3684 status = NT_STATUS_NO_MEMORY;
3685 netlogon_creds_cli_SendToSam_cleanup(req, status);
3686 return;
3689 tevent_req_set_callback(subreq,
3690 netlogon_creds_cli_SendToSam_done,
3691 req);
3694 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3696 struct tevent_req *req =
3697 tevent_req_callback_data(subreq,
3698 struct tevent_req);
3699 struct netlogon_creds_cli_SendToSam_state *state =
3700 tevent_req_data(req,
3701 struct netlogon_creds_cli_SendToSam_state);
3702 NTSTATUS status;
3703 NTSTATUS result;
3704 bool ok;
3706 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3707 TALLOC_FREE(subreq);
3708 if (tevent_req_nterror(req, status)) {
3709 netlogon_creds_cli_SendToSam_cleanup(req, status);
3710 return;
3713 ok = netlogon_creds_client_check(&state->tmp_creds,
3714 &state->rep_auth.cred);
3715 if (!ok) {
3716 status = NT_STATUS_ACCESS_DENIED;
3717 tevent_req_nterror(req, status);
3718 netlogon_creds_cli_SendToSam_cleanup(req, status);
3719 return;
3722 *state->creds = state->tmp_creds;
3723 status = netlogon_creds_cli_store(state->context,
3724 state->creds);
3725 TALLOC_FREE(state->creds);
3727 if (tevent_req_nterror(req, status)) {
3728 netlogon_creds_cli_SendToSam_cleanup(req, status);
3729 return;
3733 * Creds must be stored before we send back application errors
3734 * e.g. NT_STATUS_NOT_IMPLEMENTED
3736 if (tevent_req_nterror(req, result)) {
3737 netlogon_creds_cli_SendToSam_cleanup(req, result);
3738 return;
3741 tevent_req_done(req);
3744 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3745 struct dcerpc_binding_handle *b,
3746 struct netr_SendToSamBase *message)
3748 TALLOC_CTX *frame = talloc_stackframe();
3749 struct tevent_context *ev;
3750 struct tevent_req *req;
3751 NTSTATUS status = NT_STATUS_OK;
3753 ev = samba_tevent_context_init(frame);
3754 if (ev == NULL) {
3755 goto fail;
3757 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3758 if (req == NULL) {
3759 goto fail;
3761 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3762 goto fail;
3765 /* Ignore the result */
3766 fail:
3767 TALLOC_FREE(frame);
3768 return status;