libcli/auth: add netlogon_creds_cli_GetForestTrustInformation*()
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob1ea2f754762142ee549be5b758407f6e18e4f14a
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/server_id.h"
35 #include "netlogon_creds_cli.h"
36 #include "source3/include/messages.h"
37 #include "source3/include/g_lock.h"
39 struct netlogon_creds_cli_locked_state;
41 struct netlogon_creds_cli_context {
42 struct {
43 const char *computer;
44 const char *account;
45 uint32_t proposed_flags;
46 uint32_t required_flags;
47 enum netr_SchannelType type;
48 enum dcerpc_AuthLevel auth_level;
49 } client;
51 struct {
52 const char *computer;
53 const char *netbios_domain;
54 uint32_t cached_flags;
55 bool try_validation6;
56 bool try_logon_ex;
57 bool try_logon_with;
58 } server;
60 struct {
61 const char *key_name;
62 TDB_DATA key_data;
63 struct db_context *ctx;
64 struct g_lock_ctx *g_ctx;
65 struct netlogon_creds_cli_locked_state *locked_state;
66 } db;
69 struct netlogon_creds_cli_locked_state {
70 struct netlogon_creds_cli_context *context;
71 bool is_glocked;
72 struct netlogon_creds_CredentialState *creds;
75 static int netlogon_creds_cli_locked_state_destructor(
76 struct netlogon_creds_cli_locked_state *state)
78 struct netlogon_creds_cli_context *context = state->context;
80 if (context == NULL) {
81 return 0;
84 if (context->db.locked_state == state) {
85 context->db.locked_state = NULL;
88 if (state->is_glocked) {
89 g_lock_unlock(context->db.g_ctx,
90 context->db.key_name);
93 return 0;
96 static NTSTATUS netlogon_creds_cli_context_common(
97 const char *client_computer,
98 const char *client_account,
99 enum netr_SchannelType type,
100 enum dcerpc_AuthLevel auth_level,
101 uint32_t proposed_flags,
102 uint32_t required_flags,
103 const char *server_computer,
104 const char *server_netbios_domain,
105 TALLOC_CTX *mem_ctx,
106 struct netlogon_creds_cli_context **_context)
108 struct netlogon_creds_cli_context *context = NULL;
109 TALLOC_CTX *frame = talloc_stackframe();
110 char *_key_name = NULL;
111 char *server_netbios_name = NULL;
112 char *p = NULL;
114 *_context = NULL;
116 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
117 if (context == NULL) {
118 TALLOC_FREE(frame);
119 return NT_STATUS_NO_MEMORY;
122 context->client.computer = talloc_strdup(context, client_computer);
123 if (context->client.computer == NULL) {
124 TALLOC_FREE(context);
125 TALLOC_FREE(frame);
126 return NT_STATUS_NO_MEMORY;
129 context->client.account = talloc_strdup(context, client_account);
130 if (context->client.account == NULL) {
131 TALLOC_FREE(context);
132 TALLOC_FREE(frame);
133 return NT_STATUS_NO_MEMORY;
136 context->client.proposed_flags = proposed_flags;
137 context->client.required_flags = required_flags;
138 context->client.type = type;
139 context->client.auth_level = auth_level;
141 context->server.computer = talloc_strdup(context, server_computer);
142 if (context->server.computer == NULL) {
143 TALLOC_FREE(context);
144 TALLOC_FREE(frame);
145 return NT_STATUS_NO_MEMORY;
148 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
149 if (context->server.netbios_domain == NULL) {
150 TALLOC_FREE(context);
151 TALLOC_FREE(frame);
152 return NT_STATUS_NO_MEMORY;
156 * TODO:
157 * Force the callers to provide a unique
158 * value for server_computer and use this directly.
160 * For now we have to deal with
161 * "HOSTNAME" vs. "hostname.example.com".
163 server_netbios_name = talloc_strdup(frame, server_computer);
164 if (server_netbios_name == NULL) {
165 TALLOC_FREE(context);
166 TALLOC_FREE(frame);
167 return NT_STATUS_NO_MEMORY;
170 p = strchr(server_netbios_name, '.');
171 if (p != NULL) {
172 p[0] = '\0';
175 _key_name = talloc_asprintf(frame, "CLI[%s/%s]/SRV[%s/%s]",
176 client_computer,
177 client_account,
178 server_netbios_name,
179 server_netbios_domain);
180 if (_key_name == NULL) {
181 TALLOC_FREE(context);
182 TALLOC_FREE(frame);
183 return NT_STATUS_NO_MEMORY;
186 context->db.key_name = talloc_strdup_upper(context, _key_name);
187 if (context->db.key_name == NULL) {
188 TALLOC_FREE(context);
189 TALLOC_FREE(frame);
190 return NT_STATUS_NO_MEMORY;
193 context->db.key_data = string_term_tdb_data(context->db.key_name);
195 *_context = context;
196 TALLOC_FREE(frame);
197 return NT_STATUS_OK;
200 static struct db_context *netlogon_creds_cli_global_db;
202 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
204 if (netlogon_creds_cli_global_db != NULL) {
205 return NT_STATUS_INVALID_PARAMETER_MIX;
208 netlogon_creds_cli_global_db = talloc_move(talloc_autofree_context(), db);
209 return NT_STATUS_OK;
212 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
214 char *fname;
215 struct db_context *global_db;
217 if (netlogon_creds_cli_global_db != NULL) {
218 return NT_STATUS_OK;
221 fname = lpcfg_private_db_path(talloc_autofree_context(), lp_ctx, "netlogon_creds_cli");
222 if (fname == NULL) {
223 return NT_STATUS_NO_MEMORY;
226 global_db = dbwrap_local_open(talloc_autofree_context(), lp_ctx,
227 fname, 0,
228 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
229 O_RDWR|O_CREAT,
230 0600, DBWRAP_LOCK_ORDER_2,
231 DBWRAP_FLAG_NONE);
232 if (global_db == NULL) {
233 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
234 fname, strerror(errno)));
235 talloc_free(fname);
236 return NT_STATUS_NO_MEMORY;
238 TALLOC_FREE(fname);
240 netlogon_creds_cli_global_db = global_db;
241 return NT_STATUS_OK;
244 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
245 struct messaging_context *msg_ctx,
246 const char *client_account,
247 enum netr_SchannelType type,
248 const char *server_computer,
249 const char *server_netbios_domain,
250 TALLOC_CTX *mem_ctx,
251 struct netlogon_creds_cli_context **_context)
253 TALLOC_CTX *frame = talloc_stackframe();
254 NTSTATUS status;
255 struct netlogon_creds_cli_context *context = NULL;
256 const char *client_computer;
257 uint32_t proposed_flags;
258 uint32_t required_flags = 0;
259 bool reject_md5_servers = false;
260 bool require_strong_key = false;
261 int require_sign_or_seal = true;
262 bool seal_secure_channel = true;
263 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
264 bool neutralize_nt4_emulation = false;
266 *_context = NULL;
268 client_computer = lpcfg_netbios_name(lp_ctx);
269 if (strlen(client_computer) > 15) {
270 return NT_STATUS_INVALID_PARAMETER_MIX;
274 * allow overwrite per domain
275 * reject md5 servers:<netbios_domain>
277 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
278 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
279 "reject md5 servers",
280 server_netbios_domain,
281 reject_md5_servers);
284 * allow overwrite per domain
285 * require strong key:<netbios_domain>
287 require_strong_key = lpcfg_require_strong_key(lp_ctx);
288 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
289 "require strong key",
290 server_netbios_domain,
291 require_strong_key);
294 * allow overwrite per domain
295 * client schannel:<netbios_domain>
297 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
298 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
299 "client schannel",
300 server_netbios_domain,
301 require_sign_or_seal);
304 * allow overwrite per domain
305 * winbind sealed pipes:<netbios_domain>
307 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
308 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
309 "winbind sealed pipes",
310 server_netbios_domain,
311 seal_secure_channel);
314 * allow overwrite per domain
315 * neutralize nt4 emulation:<netbios_domain>
317 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
318 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
319 "neutralize nt4 emulation",
320 server_netbios_domain,
321 neutralize_nt4_emulation);
323 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
324 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
326 switch (type) {
327 case SEC_CHAN_WKSTA:
328 if (lpcfg_security(lp_ctx) == SEC_ADS) {
330 * AD domains should be secure
332 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
333 require_sign_or_seal = true;
334 require_strong_key = true;
336 break;
338 case SEC_CHAN_DOMAIN:
339 break;
341 case SEC_CHAN_DNS_DOMAIN:
343 * AD domains should be secure
345 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
346 require_sign_or_seal = true;
347 require_strong_key = true;
348 neutralize_nt4_emulation = true;
349 break;
351 case SEC_CHAN_BDC:
352 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
353 require_sign_or_seal = true;
354 require_strong_key = true;
355 break;
357 case SEC_CHAN_RODC:
358 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
359 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
360 require_sign_or_seal = true;
361 require_strong_key = true;
362 neutralize_nt4_emulation = true;
363 break;
365 default:
366 TALLOC_FREE(frame);
367 return NT_STATUS_INVALID_PARAMETER;
370 if (neutralize_nt4_emulation) {
371 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
374 if (require_sign_or_seal == false) {
375 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
376 } else {
377 required_flags |= NETLOGON_NEG_ARCFOUR;
378 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
381 if (reject_md5_servers) {
382 required_flags |= NETLOGON_NEG_ARCFOUR;
383 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
384 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
385 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
388 if (require_strong_key) {
389 required_flags |= NETLOGON_NEG_ARCFOUR;
390 required_flags |= NETLOGON_NEG_STRONG_KEYS;
391 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
394 proposed_flags |= required_flags;
396 if (seal_secure_channel) {
397 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
398 } else {
399 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
402 status = netlogon_creds_cli_context_common(client_computer,
403 client_account,
404 type,
405 auth_level,
406 proposed_flags,
407 required_flags,
408 server_computer,
409 server_netbios_domain,
410 mem_ctx,
411 &context);
412 if (!NT_STATUS_IS_OK(status)) {
413 TALLOC_FREE(frame);
414 return status;
417 if (msg_ctx != NULL) {
418 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
419 if (context->db.g_ctx == NULL) {
420 TALLOC_FREE(context);
421 TALLOC_FREE(frame);
422 return NT_STATUS_NO_MEMORY;
426 if (netlogon_creds_cli_global_db != NULL) {
427 context->db.ctx = netlogon_creds_cli_global_db;
428 *_context = context;
429 TALLOC_FREE(frame);
430 return NT_STATUS_OK;
433 status = netlogon_creds_cli_open_global_db(lp_ctx);
434 if (!NT_STATUS_IS_OK(status)) {
435 TALLOC_FREE(context);
436 TALLOC_FREE(frame);
437 return NT_STATUS_NO_MEMORY;
440 context->db.ctx = netlogon_creds_cli_global_db;
441 *_context = context;
442 TALLOC_FREE(frame);
443 return NT_STATUS_OK;
446 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
447 const char *client_account,
448 enum netr_SchannelType type,
449 uint32_t proposed_flags,
450 uint32_t required_flags,
451 enum dcerpc_AuthLevel auth_level,
452 const char *server_computer,
453 const char *server_netbios_domain,
454 TALLOC_CTX *mem_ctx,
455 struct netlogon_creds_cli_context **_context)
457 NTSTATUS status;
458 struct netlogon_creds_cli_context *context = NULL;
460 *_context = NULL;
462 status = netlogon_creds_cli_context_common(client_computer,
463 client_account,
464 type,
465 auth_level,
466 proposed_flags,
467 required_flags,
468 server_computer,
469 server_netbios_domain,
470 mem_ctx,
471 &context);
472 if (!NT_STATUS_IS_OK(status)) {
473 return status;
476 context->db.ctx = db_open_rbt(context);
477 if (context->db.ctx == NULL) {
478 talloc_free(context);
479 return NT_STATUS_NO_MEMORY;
482 *_context = context;
483 return NT_STATUS_OK;
486 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
487 struct netlogon_creds_cli_context *context)
489 return context->client.auth_level;
492 struct netlogon_creds_cli_fetch_state {
493 TALLOC_CTX *mem_ctx;
494 struct netlogon_creds_CredentialState *creds;
495 uint32_t required_flags;
496 NTSTATUS status;
499 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
500 void *private_data)
502 struct netlogon_creds_cli_fetch_state *state =
503 (struct netlogon_creds_cli_fetch_state *)private_data;
504 enum ndr_err_code ndr_err;
505 DATA_BLOB blob;
506 uint32_t tmp_flags;
508 state->creds = talloc_zero(state->mem_ctx,
509 struct netlogon_creds_CredentialState);
510 if (state->creds == NULL) {
511 state->status = NT_STATUS_NO_MEMORY;
512 return;
515 blob.data = data.dptr;
516 blob.length = data.dsize;
518 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
519 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
520 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
521 TALLOC_FREE(state->creds);
522 state->status = ndr_map_error2ntstatus(ndr_err);
523 return;
526 tmp_flags = state->creds->negotiate_flags;
527 tmp_flags &= state->required_flags;
528 if (tmp_flags != state->required_flags) {
529 TALLOC_FREE(state->creds);
530 state->status = NT_STATUS_DOWNGRADE_DETECTED;
531 return;
534 state->status = NT_STATUS_OK;
537 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
538 TALLOC_CTX *mem_ctx,
539 struct netlogon_creds_CredentialState **_creds)
541 NTSTATUS status;
542 struct netlogon_creds_cli_fetch_state fstate = {
543 .mem_ctx = mem_ctx,
544 .status = NT_STATUS_INTERNAL_ERROR,
545 .required_flags = context->client.required_flags,
547 static const struct netr_Credential zero_creds;
549 *_creds = NULL;
551 status = dbwrap_parse_record(context->db.ctx,
552 context->db.key_data,
553 netlogon_creds_cli_fetch_parser,
554 &fstate);
555 if (!NT_STATUS_IS_OK(status)) {
556 return status;
558 status = fstate.status;
559 if (!NT_STATUS_IS_OK(status)) {
560 return status;
564 * mark it as invalid for step operations.
566 fstate.creds->sequence = 0;
567 fstate.creds->seed = zero_creds;
568 fstate.creds->client = zero_creds;
569 fstate.creds->server = zero_creds;
571 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
572 *_creds = fstate.creds;
573 return NT_STATUS_OK;
577 * It is really important to try SamLogonEx here,
578 * because multiple processes can talk to the same
579 * domain controller, without using the credential
580 * chain.
582 * With a normal SamLogon call, we must keep the
583 * credentials chain updated and intact between all
584 * users of the machine account (which would imply
585 * cross-node communication for every NTLM logon).
587 * The credentials chain is not per NETLOGON pipe
588 * connection, but globally on the server/client pair
589 * by computer name, while the client is free to use
590 * any computer name. We include the cluster node number
591 * in our computer name in order to avoid cross node
592 * coordination of the credential chain.
594 * It's also important to use NetlogonValidationSamInfo4 (6),
595 * because it relies on the rpc transport encryption
596 * and avoids using the global netlogon schannel
597 * session key to en/decrypt secret information
598 * like the user_session_key for network logons.
600 * [MS-APDS] 3.1.5.2 NTLM Network Logon
601 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
602 * NETLOGON_NEG_AUTHENTICATED_RPC set together
603 * are the indication that the server supports
604 * NetlogonValidationSamInfo4 (6). And it must only
605 * be used if "SealSecureChannel" is used.
607 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
608 * check is done in netlogon_creds_cli_LogonSamLogon*().
610 context->server.cached_flags = fstate.creds->negotiate_flags;
611 context->server.try_validation6 = true;
612 context->server.try_logon_ex = true;
613 context->server.try_logon_with = true;
615 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
616 context->server.try_validation6 = false;
617 context->server.try_logon_ex = false;
619 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
620 context->server.try_validation6 = false;
623 *_creds = fstate.creds;
624 return NT_STATUS_OK;
627 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
628 const struct netlogon_creds_CredentialState *creds1)
630 TALLOC_CTX *frame = talloc_stackframe();
631 struct netlogon_creds_CredentialState *creds2;
632 DATA_BLOB blob1;
633 DATA_BLOB blob2;
634 NTSTATUS status;
635 enum ndr_err_code ndr_err;
636 int cmp;
638 status = netlogon_creds_cli_get(context, frame, &creds2);
639 if (!NT_STATUS_IS_OK(status)) {
640 TALLOC_FREE(frame);
641 return false;
644 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
645 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
646 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
647 TALLOC_FREE(frame);
648 return false;
651 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
652 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
653 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
654 TALLOC_FREE(frame);
655 return false;
658 if (blob1.length != blob2.length) {
659 TALLOC_FREE(frame);
660 return false;
663 cmp = memcmp(blob1.data, blob2.data, blob1.length);
664 if (cmp != 0) {
665 TALLOC_FREE(frame);
666 return false;
669 TALLOC_FREE(frame);
670 return true;
673 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
674 struct netlogon_creds_CredentialState **_creds)
676 struct netlogon_creds_CredentialState *creds = *_creds;
677 NTSTATUS status;
678 enum ndr_err_code ndr_err;
679 DATA_BLOB blob;
680 TDB_DATA data;
682 *_creds = NULL;
684 if (context->db.locked_state == NULL) {
686 * this was not the result of netlogon_creds_cli_lock*()
688 TALLOC_FREE(creds);
689 return NT_STATUS_INVALID_PAGE_PROTECTION;
692 if (context->db.locked_state->creds != creds) {
694 * this was not the result of netlogon_creds_cli_lock*()
696 TALLOC_FREE(creds);
697 return NT_STATUS_INVALID_PAGE_PROTECTION;
700 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
701 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
702 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
703 TALLOC_FREE(creds);
704 status = ndr_map_error2ntstatus(ndr_err);
705 return status;
708 data.dptr = blob.data;
709 data.dsize = blob.length;
711 status = dbwrap_store(context->db.ctx,
712 context->db.key_data,
713 data, TDB_REPLACE);
714 TALLOC_FREE(creds);
715 if (!NT_STATUS_IS_OK(status)) {
716 return status;
719 return NT_STATUS_OK;
722 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
723 struct netlogon_creds_CredentialState **_creds)
725 struct netlogon_creds_CredentialState *creds = *_creds;
726 NTSTATUS status;
728 *_creds = NULL;
730 if (context->db.locked_state == NULL) {
732 * this was not the result of netlogon_creds_cli_lock*()
734 TALLOC_FREE(creds);
735 return NT_STATUS_INVALID_PAGE_PROTECTION;
738 if (context->db.locked_state->creds != creds) {
740 * this was not the result of netlogon_creds_cli_lock*()
742 TALLOC_FREE(creds);
743 return NT_STATUS_INVALID_PAGE_PROTECTION;
746 status = dbwrap_delete(context->db.ctx,
747 context->db.key_data);
748 TALLOC_FREE(creds);
749 if (!NT_STATUS_IS_OK(status)) {
750 return status;
753 return NT_STATUS_OK;
756 struct netlogon_creds_cli_lock_state {
757 struct netlogon_creds_cli_locked_state *locked_state;
758 struct netlogon_creds_CredentialState *creds;
761 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
762 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
764 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
765 struct tevent_context *ev,
766 struct netlogon_creds_cli_context *context)
768 struct tevent_req *req;
769 struct netlogon_creds_cli_lock_state *state;
770 struct netlogon_creds_cli_locked_state *locked_state;
771 struct tevent_req *subreq;
773 req = tevent_req_create(mem_ctx, &state,
774 struct netlogon_creds_cli_lock_state);
775 if (req == NULL) {
776 return NULL;
779 if (context->db.locked_state != NULL) {
780 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
781 return tevent_req_post(req, ev);
784 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
785 if (tevent_req_nomem(locked_state, req)) {
786 return tevent_req_post(req, ev);
788 talloc_set_destructor(locked_state,
789 netlogon_creds_cli_locked_state_destructor);
790 locked_state->context = context;
792 context->db.locked_state = locked_state;
793 state->locked_state = locked_state;
795 if (context->db.g_ctx == NULL) {
796 netlogon_creds_cli_lock_fetch(req);
797 if (!tevent_req_is_in_progress(req)) {
798 return tevent_req_post(req, ev);
801 return req;
804 subreq = g_lock_lock_send(state, ev,
805 context->db.g_ctx,
806 context->db.key_name,
807 G_LOCK_WRITE);
808 if (tevent_req_nomem(subreq, req)) {
809 return tevent_req_post(req, ev);
811 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
813 return req;
816 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
818 struct tevent_req *req =
819 tevent_req_callback_data(subreq,
820 struct tevent_req);
821 struct netlogon_creds_cli_lock_state *state =
822 tevent_req_data(req,
823 struct netlogon_creds_cli_lock_state);
824 NTSTATUS status;
826 status = g_lock_lock_recv(subreq);
827 TALLOC_FREE(subreq);
828 if (tevent_req_nterror(req, status)) {
829 return;
831 state->locked_state->is_glocked = true;
833 netlogon_creds_cli_lock_fetch(req);
836 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
838 struct netlogon_creds_cli_lock_state *state =
839 tevent_req_data(req,
840 struct netlogon_creds_cli_lock_state);
841 struct netlogon_creds_cli_context *context = state->locked_state->context;
842 struct netlogon_creds_cli_fetch_state fstate = {
843 .status = NT_STATUS_INTERNAL_ERROR,
844 .required_flags = context->client.required_flags,
846 NTSTATUS status;
848 fstate.mem_ctx = state;
849 status = dbwrap_parse_record(context->db.ctx,
850 context->db.key_data,
851 netlogon_creds_cli_fetch_parser,
852 &fstate);
853 if (tevent_req_nterror(req, status)) {
854 return;
856 status = fstate.status;
857 if (tevent_req_nterror(req, status)) {
858 return;
861 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
862 state->creds = fstate.creds;
863 tevent_req_done(req);
864 return;
867 context->server.cached_flags = fstate.creds->negotiate_flags;
868 context->server.try_validation6 = true;
869 context->server.try_logon_ex = true;
870 context->server.try_logon_with = true;
872 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
873 context->server.try_validation6 = false;
874 context->server.try_logon_ex = false;
876 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
877 context->server.try_validation6 = false;
880 state->creds = fstate.creds;
881 tevent_req_done(req);
882 return;
885 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
886 TALLOC_CTX *mem_ctx,
887 struct netlogon_creds_CredentialState **creds)
889 struct netlogon_creds_cli_lock_state *state =
890 tevent_req_data(req,
891 struct netlogon_creds_cli_lock_state);
892 NTSTATUS status;
894 if (tevent_req_is_nterror(req, &status)) {
895 tevent_req_received(req);
896 return status;
899 talloc_steal(state->creds, state->locked_state);
900 state->locked_state->creds = state->creds;
901 *creds = talloc_move(mem_ctx, &state->creds);
902 tevent_req_received(req);
903 return NT_STATUS_OK;
906 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
907 TALLOC_CTX *mem_ctx,
908 struct netlogon_creds_CredentialState **creds)
910 TALLOC_CTX *frame = talloc_stackframe();
911 struct tevent_context *ev;
912 struct tevent_req *req;
913 NTSTATUS status = NT_STATUS_NO_MEMORY;
915 ev = samba_tevent_context_init(frame);
916 if (ev == NULL) {
917 goto fail;
919 req = netlogon_creds_cli_lock_send(frame, ev, context);
920 if (req == NULL) {
921 goto fail;
923 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
924 goto fail;
926 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
927 fail:
928 TALLOC_FREE(frame);
929 return status;
932 struct netlogon_creds_cli_auth_state {
933 struct tevent_context *ev;
934 struct netlogon_creds_cli_context *context;
935 struct dcerpc_binding_handle *binding_handle;
936 struct samr_Password current_nt_hash;
937 struct samr_Password previous_nt_hash;
938 struct samr_Password used_nt_hash;
939 char *srv_name_slash;
940 uint32_t current_flags;
941 struct netr_Credential client_challenge;
942 struct netr_Credential server_challenge;
943 struct netlogon_creds_CredentialState *creds;
944 struct netr_Credential client_credential;
945 struct netr_Credential server_credential;
946 uint32_t rid;
947 bool try_auth3;
948 bool try_auth2;
949 bool require_auth2;
950 bool try_previous_nt_hash;
951 struct netlogon_creds_cli_locked_state *locked_state;
954 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
955 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
957 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
958 struct tevent_context *ev,
959 struct netlogon_creds_cli_context *context,
960 struct dcerpc_binding_handle *b,
961 struct samr_Password current_nt_hash,
962 const struct samr_Password *previous_nt_hash)
964 struct tevent_req *req;
965 struct netlogon_creds_cli_auth_state *state;
966 struct netlogon_creds_cli_locked_state *locked_state;
967 NTSTATUS status;
969 req = tevent_req_create(mem_ctx, &state,
970 struct netlogon_creds_cli_auth_state);
971 if (req == NULL) {
972 return NULL;
975 state->ev = ev;
976 state->context = context;
977 state->binding_handle = b;
978 state->current_nt_hash = current_nt_hash;
979 if (previous_nt_hash != NULL) {
980 state->previous_nt_hash = *previous_nt_hash;
981 state->try_previous_nt_hash = true;
984 if (context->db.locked_state != NULL) {
985 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
986 return tevent_req_post(req, ev);
989 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
990 if (tevent_req_nomem(locked_state, req)) {
991 return tevent_req_post(req, ev);
993 talloc_set_destructor(locked_state,
994 netlogon_creds_cli_locked_state_destructor);
995 locked_state->context = context;
997 context->db.locked_state = locked_state;
998 state->locked_state = locked_state;
1000 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1001 context->server.computer);
1002 if (tevent_req_nomem(state->srv_name_slash, req)) {
1003 return tevent_req_post(req, ev);
1006 state->try_auth3 = true;
1007 state->try_auth2 = true;
1009 if (context->client.required_flags != 0) {
1010 state->require_auth2 = true;
1013 state->used_nt_hash = state->current_nt_hash;
1014 state->current_flags = context->client.proposed_flags;
1016 if (context->db.g_ctx != NULL) {
1017 struct tevent_req *subreq;
1019 subreq = g_lock_lock_send(state, ev,
1020 context->db.g_ctx,
1021 context->db.key_name,
1022 G_LOCK_WRITE);
1023 if (tevent_req_nomem(subreq, req)) {
1024 return tevent_req_post(req, ev);
1026 tevent_req_set_callback(subreq,
1027 netlogon_creds_cli_auth_locked,
1028 req);
1030 return req;
1033 status = dbwrap_delete(state->context->db.ctx,
1034 state->context->db.key_data);
1035 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1036 status = NT_STATUS_OK;
1038 if (tevent_req_nterror(req, status)) {
1039 return tevent_req_post(req, ev);
1042 netlogon_creds_cli_auth_challenge_start(req);
1043 if (!tevent_req_is_in_progress(req)) {
1044 return tevent_req_post(req, ev);
1047 return req;
1050 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1052 struct tevent_req *req =
1053 tevent_req_callback_data(subreq,
1054 struct tevent_req);
1055 struct netlogon_creds_cli_auth_state *state =
1056 tevent_req_data(req,
1057 struct netlogon_creds_cli_auth_state);
1058 NTSTATUS status;
1060 status = g_lock_lock_recv(subreq);
1061 TALLOC_FREE(subreq);
1062 if (tevent_req_nterror(req, status)) {
1063 return;
1065 state->locked_state->is_glocked = true;
1067 status = dbwrap_delete(state->context->db.ctx,
1068 state->context->db.key_data);
1069 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1070 status = NT_STATUS_OK;
1072 if (tevent_req_nterror(req, status)) {
1073 return;
1076 netlogon_creds_cli_auth_challenge_start(req);
1079 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1081 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1083 struct netlogon_creds_cli_auth_state *state =
1084 tevent_req_data(req,
1085 struct netlogon_creds_cli_auth_state);
1086 struct tevent_req *subreq;
1088 TALLOC_FREE(state->creds);
1090 generate_random_buffer(state->client_challenge.data,
1091 sizeof(state->client_challenge.data));
1093 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1094 state->binding_handle,
1095 state->srv_name_slash,
1096 state->context->client.computer,
1097 &state->client_challenge,
1098 &state->server_challenge);
1099 if (tevent_req_nomem(subreq, req)) {
1100 return;
1102 tevent_req_set_callback(subreq,
1103 netlogon_creds_cli_auth_challenge_done,
1104 req);
1107 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1109 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1111 struct tevent_req *req =
1112 tevent_req_callback_data(subreq,
1113 struct tevent_req);
1114 struct netlogon_creds_cli_auth_state *state =
1115 tevent_req_data(req,
1116 struct netlogon_creds_cli_auth_state);
1117 NTSTATUS status;
1118 NTSTATUS result;
1120 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1121 TALLOC_FREE(subreq);
1122 if (tevent_req_nterror(req, status)) {
1123 return;
1125 if (tevent_req_nterror(req, result)) {
1126 return;
1129 if (!state->try_auth3 && !state->try_auth2) {
1130 state->current_flags = 0;
1133 /* Calculate the session key and client credentials */
1135 state->creds = netlogon_creds_client_init(state,
1136 state->context->client.account,
1137 state->context->client.computer,
1138 state->context->client.type,
1139 &state->client_challenge,
1140 &state->server_challenge,
1141 &state->used_nt_hash,
1142 &state->client_credential,
1143 state->current_flags);
1144 if (tevent_req_nomem(state->creds, req)) {
1145 return;
1148 if (state->try_auth3) {
1149 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1150 state->binding_handle,
1151 state->srv_name_slash,
1152 state->context->client.account,
1153 state->context->client.type,
1154 state->context->client.computer,
1155 &state->client_credential,
1156 &state->server_credential,
1157 &state->creds->negotiate_flags,
1158 &state->rid);
1159 if (tevent_req_nomem(subreq, req)) {
1160 return;
1162 } else if (state->try_auth2) {
1163 state->rid = 0;
1165 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1166 state->binding_handle,
1167 state->srv_name_slash,
1168 state->context->client.account,
1169 state->context->client.type,
1170 state->context->client.computer,
1171 &state->client_credential,
1172 &state->server_credential,
1173 &state->creds->negotiate_flags);
1174 if (tevent_req_nomem(subreq, req)) {
1175 return;
1177 } else {
1178 state->rid = 0;
1180 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1181 state->binding_handle,
1182 state->srv_name_slash,
1183 state->context->client.account,
1184 state->context->client.type,
1185 state->context->client.computer,
1186 &state->client_credential,
1187 &state->server_credential);
1188 if (tevent_req_nomem(subreq, req)) {
1189 return;
1192 tevent_req_set_callback(subreq,
1193 netlogon_creds_cli_auth_srvauth_done,
1194 req);
1197 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1199 struct tevent_req *req =
1200 tevent_req_callback_data(subreq,
1201 struct tevent_req);
1202 struct netlogon_creds_cli_auth_state *state =
1203 tevent_req_data(req,
1204 struct netlogon_creds_cli_auth_state);
1205 NTSTATUS status;
1206 NTSTATUS result;
1207 bool ok;
1208 enum ndr_err_code ndr_err;
1209 DATA_BLOB blob;
1210 TDB_DATA data;
1211 uint32_t tmp_flags;
1213 if (state->try_auth3) {
1214 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1215 &result);
1216 TALLOC_FREE(subreq);
1217 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1218 state->try_auth3 = false;
1219 netlogon_creds_cli_auth_challenge_start(req);
1220 return;
1222 if (tevent_req_nterror(req, status)) {
1223 return;
1225 } else if (state->try_auth2) {
1226 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1227 &result);
1228 TALLOC_FREE(subreq);
1229 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1230 state->try_auth2 = false;
1231 if (state->require_auth2) {
1232 status = NT_STATUS_DOWNGRADE_DETECTED;
1233 tevent_req_nterror(req, status);
1234 return;
1236 netlogon_creds_cli_auth_challenge_start(req);
1237 return;
1239 if (tevent_req_nterror(req, status)) {
1240 return;
1242 } else {
1243 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1244 &result);
1245 TALLOC_FREE(subreq);
1246 if (tevent_req_nterror(req, status)) {
1247 return;
1251 if (!NT_STATUS_IS_OK(result) &&
1252 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1254 tevent_req_nterror(req, result);
1255 return;
1258 tmp_flags = state->creds->negotiate_flags;
1259 tmp_flags &= state->context->client.required_flags;
1260 if (tmp_flags != state->context->client.required_flags) {
1261 if (NT_STATUS_IS_OK(result)) {
1262 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1263 return;
1265 tevent_req_nterror(req, result);
1266 return;
1269 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1271 tmp_flags = state->context->client.proposed_flags;
1272 if ((state->current_flags == tmp_flags) &&
1273 (state->creds->negotiate_flags != tmp_flags))
1276 * lets retry with the negotiated flags
1278 state->current_flags = state->creds->negotiate_flags;
1279 netlogon_creds_cli_auth_challenge_start(req);
1280 return;
1283 if (!state->try_previous_nt_hash) {
1285 * we already retried, giving up...
1287 tevent_req_nterror(req, result);
1288 return;
1292 * lets retry with the old nt hash.
1294 state->try_previous_nt_hash = false;
1295 state->used_nt_hash = state->previous_nt_hash;
1296 state->current_flags = state->context->client.proposed_flags;
1297 netlogon_creds_cli_auth_challenge_start(req);
1298 return;
1301 ok = netlogon_creds_client_check(state->creds,
1302 &state->server_credential);
1303 if (!ok) {
1304 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1305 return;
1308 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1309 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1310 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1311 status = ndr_map_error2ntstatus(ndr_err);
1312 tevent_req_nterror(req, status);
1313 return;
1316 data.dptr = blob.data;
1317 data.dsize = blob.length;
1319 status = dbwrap_store(state->context->db.ctx,
1320 state->context->db.key_data,
1321 data, TDB_REPLACE);
1322 TALLOC_FREE(state->locked_state);
1323 if (tevent_req_nterror(req, status)) {
1324 return;
1327 tevent_req_done(req);
1330 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req)
1332 NTSTATUS status;
1334 if (tevent_req_is_nterror(req, &status)) {
1335 tevent_req_received(req);
1336 return status;
1339 tevent_req_received(req);
1340 return NT_STATUS_OK;
1343 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1344 struct dcerpc_binding_handle *b,
1345 struct samr_Password current_nt_hash,
1346 const struct samr_Password *previous_nt_hash)
1348 TALLOC_CTX *frame = talloc_stackframe();
1349 struct tevent_context *ev;
1350 struct tevent_req *req;
1351 NTSTATUS status = NT_STATUS_NO_MEMORY;
1353 ev = samba_tevent_context_init(frame);
1354 if (ev == NULL) {
1355 goto fail;
1357 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1358 current_nt_hash,
1359 previous_nt_hash);
1360 if (req == NULL) {
1361 goto fail;
1363 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1364 goto fail;
1366 status = netlogon_creds_cli_auth_recv(req);
1367 fail:
1368 TALLOC_FREE(frame);
1369 return status;
1372 struct netlogon_creds_cli_check_state {
1373 struct tevent_context *ev;
1374 struct netlogon_creds_cli_context *context;
1375 struct dcerpc_binding_handle *binding_handle;
1377 char *srv_name_slash;
1379 union netr_Capabilities caps;
1381 struct netlogon_creds_CredentialState *creds;
1382 struct netlogon_creds_CredentialState tmp_creds;
1383 struct netr_Authenticator req_auth;
1384 struct netr_Authenticator rep_auth;
1387 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1388 NTSTATUS status);
1389 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1391 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1392 struct tevent_context *ev,
1393 struct netlogon_creds_cli_context *context,
1394 struct dcerpc_binding_handle *b)
1396 struct tevent_req *req;
1397 struct netlogon_creds_cli_check_state *state;
1398 struct tevent_req *subreq;
1399 enum dcerpc_AuthType auth_type;
1400 enum dcerpc_AuthLevel auth_level;
1402 req = tevent_req_create(mem_ctx, &state,
1403 struct netlogon_creds_cli_check_state);
1404 if (req == NULL) {
1405 return NULL;
1408 state->ev = ev;
1409 state->context = context;
1410 state->binding_handle = b;
1412 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1413 context->server.computer);
1414 if (tevent_req_nomem(state->srv_name_slash, req)) {
1415 return tevent_req_post(req, ev);
1418 dcerpc_binding_handle_auth_info(state->binding_handle,
1419 &auth_type, &auth_level);
1421 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1422 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1423 return tevent_req_post(req, ev);
1426 switch (auth_level) {
1427 case DCERPC_AUTH_LEVEL_INTEGRITY:
1428 case DCERPC_AUTH_LEVEL_PRIVACY:
1429 break;
1430 default:
1431 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1432 return tevent_req_post(req, ev);
1435 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1436 state->context);
1437 if (tevent_req_nomem(subreq, req)) {
1438 return tevent_req_post(req, ev);
1441 tevent_req_set_callback(subreq,
1442 netlogon_creds_cli_check_locked,
1443 req);
1445 return req;
1448 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1449 NTSTATUS status)
1451 struct netlogon_creds_cli_check_state *state =
1452 tevent_req_data(req,
1453 struct netlogon_creds_cli_check_state);
1455 if (state->creds == NULL) {
1456 return;
1459 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1460 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1461 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1462 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1463 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1464 TALLOC_FREE(state->creds);
1465 return;
1468 netlogon_creds_cli_delete(state->context, &state->creds);
1471 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1473 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1475 struct tevent_req *req =
1476 tevent_req_callback_data(subreq,
1477 struct tevent_req);
1478 struct netlogon_creds_cli_check_state *state =
1479 tevent_req_data(req,
1480 struct netlogon_creds_cli_check_state);
1481 NTSTATUS status;
1483 status = netlogon_creds_cli_lock_recv(subreq, state,
1484 &state->creds);
1485 TALLOC_FREE(subreq);
1486 if (tevent_req_nterror(req, status)) {
1487 return;
1491 * we defer all callbacks in order to cleanup
1492 * the database record.
1494 tevent_req_defer_callback(req, state->ev);
1496 state->tmp_creds = *state->creds;
1497 netlogon_creds_client_authenticator(&state->tmp_creds,
1498 &state->req_auth);
1499 ZERO_STRUCT(state->rep_auth);
1501 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1502 state->binding_handle,
1503 state->srv_name_slash,
1504 state->context->client.computer,
1505 &state->req_auth,
1506 &state->rep_auth,
1508 &state->caps);
1509 if (tevent_req_nomem(subreq, req)) {
1510 status = NT_STATUS_NO_MEMORY;
1511 netlogon_creds_cli_check_cleanup(req, status);
1512 return;
1514 tevent_req_set_callback(subreq,
1515 netlogon_creds_cli_check_caps,
1516 req);
1519 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1521 struct tevent_req *req =
1522 tevent_req_callback_data(subreq,
1523 struct tevent_req);
1524 struct netlogon_creds_cli_check_state *state =
1525 tevent_req_data(req,
1526 struct netlogon_creds_cli_check_state);
1527 NTSTATUS status;
1528 NTSTATUS result;
1529 bool ok;
1531 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1532 &result);
1533 TALLOC_FREE(subreq);
1534 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1536 * Note that the negotiated flags are already checked
1537 * for our required flags after the ServerAuthenticate3/2 call.
1539 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1541 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1543 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1544 * already, we expect this to work!
1546 status = NT_STATUS_DOWNGRADE_DETECTED;
1547 tevent_req_nterror(req, status);
1548 netlogon_creds_cli_check_cleanup(req, status);
1549 return;
1552 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1554 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1555 * we expect this to work at least as far as the
1556 * NOT_SUPPORTED error handled below!
1558 * NT 4.0 and Old Samba servers are not
1559 * allowed without "require strong key = no"
1561 status = NT_STATUS_DOWNGRADE_DETECTED;
1562 tevent_req_nterror(req, status);
1563 netlogon_creds_cli_check_cleanup(req, status);
1564 return;
1568 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1569 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1570 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1572 * This is needed against NT 4.0 and old Samba servers.
1574 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1575 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1576 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1577 * with the next request as the sequence number processing
1578 * gets out of sync.
1580 netlogon_creds_cli_check_cleanup(req, status);
1581 tevent_req_done(req);
1582 return;
1584 if (tevent_req_nterror(req, status)) {
1585 netlogon_creds_cli_check_cleanup(req, status);
1586 return;
1589 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1591 * Note that the negotiated flags are already checked
1592 * for our required flags after the ServerAuthenticate3/2 call.
1594 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1596 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1598 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1599 * already, we expect this to work!
1601 status = NT_STATUS_DOWNGRADE_DETECTED;
1602 tevent_req_nterror(req, status);
1603 netlogon_creds_cli_check_cleanup(req, status);
1604 return;
1608 * This is ok, the server does not support
1609 * NETLOGON_NEG_SUPPORTS_AES.
1611 * netr_LogonGetCapabilities() was
1612 * netr_LogonDummyRoutine1() before
1613 * NETLOGON_NEG_SUPPORTS_AES was invented.
1615 netlogon_creds_cli_check_cleanup(req, result);
1616 tevent_req_done(req);
1617 return;
1620 ok = netlogon_creds_client_check(&state->tmp_creds,
1621 &state->rep_auth.cred);
1622 if (!ok) {
1623 status = NT_STATUS_ACCESS_DENIED;
1624 tevent_req_nterror(req, status);
1625 netlogon_creds_cli_check_cleanup(req, status);
1626 return;
1629 if (tevent_req_nterror(req, result)) {
1630 netlogon_creds_cli_check_cleanup(req, result);
1631 return;
1634 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1635 status = NT_STATUS_DOWNGRADE_DETECTED;
1636 tevent_req_nterror(req, status);
1637 netlogon_creds_cli_check_cleanup(req, status);
1638 return;
1642 * This is the key check that makes this check secure. If we
1643 * get OK here (rather than NOT_SUPPORTED), then the server
1644 * did support AES. If the server only proposed STRONG_KEYS
1645 * and not AES, then it should have failed with
1646 * NOT_IMPLEMENTED. We always send AES as a client, so the
1647 * server should always have returned it.
1649 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1650 status = NT_STATUS_DOWNGRADE_DETECTED;
1651 tevent_req_nterror(req, status);
1652 netlogon_creds_cli_check_cleanup(req, status);
1653 return;
1656 *state->creds = state->tmp_creds;
1657 status = netlogon_creds_cli_store(state->context,
1658 &state->creds);
1659 netlogon_creds_cli_check_cleanup(req, status);
1660 if (tevent_req_nterror(req, status)) {
1661 return;
1664 tevent_req_done(req);
1667 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1669 NTSTATUS status;
1671 if (tevent_req_is_nterror(req, &status)) {
1672 netlogon_creds_cli_check_cleanup(req, status);
1673 tevent_req_received(req);
1674 return status;
1677 tevent_req_received(req);
1678 return NT_STATUS_OK;
1681 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1682 struct dcerpc_binding_handle *b)
1684 TALLOC_CTX *frame = talloc_stackframe();
1685 struct tevent_context *ev;
1686 struct tevent_req *req;
1687 NTSTATUS status = NT_STATUS_NO_MEMORY;
1689 ev = samba_tevent_context_init(frame);
1690 if (ev == NULL) {
1691 goto fail;
1693 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1694 if (req == NULL) {
1695 goto fail;
1697 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1698 goto fail;
1700 status = netlogon_creds_cli_check_recv(req);
1701 fail:
1702 TALLOC_FREE(frame);
1703 return status;
1706 struct netlogon_creds_cli_ServerPasswordSet_state {
1707 struct tevent_context *ev;
1708 struct netlogon_creds_cli_context *context;
1709 struct dcerpc_binding_handle *binding_handle;
1710 uint32_t old_timeout;
1712 char *srv_name_slash;
1713 enum dcerpc_AuthType auth_type;
1714 enum dcerpc_AuthLevel auth_level;
1716 struct samr_CryptPassword samr_crypt_password;
1717 struct netr_CryptPassword netr_crypt_password;
1718 struct samr_Password samr_password;
1720 struct netlogon_creds_CredentialState *creds;
1721 struct netlogon_creds_CredentialState tmp_creds;
1722 struct netr_Authenticator req_auth;
1723 struct netr_Authenticator rep_auth;
1726 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1727 NTSTATUS status);
1728 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1730 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1731 struct tevent_context *ev,
1732 struct netlogon_creds_cli_context *context,
1733 struct dcerpc_binding_handle *b,
1734 const char *new_password,
1735 const uint32_t *new_version)
1737 struct tevent_req *req;
1738 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1739 struct tevent_req *subreq;
1740 bool ok;
1742 req = tevent_req_create(mem_ctx, &state,
1743 struct netlogon_creds_cli_ServerPasswordSet_state);
1744 if (req == NULL) {
1745 return NULL;
1748 state->ev = ev;
1749 state->context = context;
1750 state->binding_handle = b;
1753 * netr_ServerPasswordSet
1755 E_md4hash(new_password, state->samr_password.hash);
1758 * netr_ServerPasswordSet2
1760 ok = encode_pw_buffer(state->samr_crypt_password.data,
1761 new_password, STR_UNICODE);
1762 if (!ok) {
1763 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1764 return tevent_req_post(req, ev);
1767 if (new_version != NULL) {
1768 struct NL_PASSWORD_VERSION version;
1769 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1770 uint32_t ofs = 512 - len;
1771 uint8_t *p;
1773 if (len > 500) {
1774 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1775 return tevent_req_post(req, ev);
1777 ofs -= 12;
1779 version.ReservedField = 0;
1780 version.PasswordVersionNumber = *new_version;
1781 version.PasswordVersionPresent =
1782 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1784 p = state->samr_crypt_password.data + ofs;
1785 SIVAL(p, 0, version.ReservedField);
1786 SIVAL(p, 4, version.PasswordVersionNumber);
1787 SIVAL(p, 8, version.PasswordVersionPresent);
1790 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1791 context->server.computer);
1792 if (tevent_req_nomem(state->srv_name_slash, req)) {
1793 return tevent_req_post(req, ev);
1796 dcerpc_binding_handle_auth_info(state->binding_handle,
1797 &state->auth_type,
1798 &state->auth_level);
1800 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1801 state->context);
1802 if (tevent_req_nomem(subreq, req)) {
1803 return tevent_req_post(req, ev);
1806 tevent_req_set_callback(subreq,
1807 netlogon_creds_cli_ServerPasswordSet_locked,
1808 req);
1810 return req;
1813 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1814 NTSTATUS status)
1816 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1817 tevent_req_data(req,
1818 struct netlogon_creds_cli_ServerPasswordSet_state);
1820 if (state->creds == NULL) {
1821 return;
1824 dcerpc_binding_handle_set_timeout(state->binding_handle,
1825 state->old_timeout);
1827 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1828 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1829 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1830 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1831 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1832 TALLOC_FREE(state->creds);
1833 return;
1836 netlogon_creds_cli_delete(state->context, &state->creds);
1839 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1841 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1843 struct tevent_req *req =
1844 tevent_req_callback_data(subreq,
1845 struct tevent_req);
1846 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1847 tevent_req_data(req,
1848 struct netlogon_creds_cli_ServerPasswordSet_state);
1849 NTSTATUS status;
1851 status = netlogon_creds_cli_lock_recv(subreq, state,
1852 &state->creds);
1853 TALLOC_FREE(subreq);
1854 if (tevent_req_nterror(req, status)) {
1855 return;
1858 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1859 switch (state->auth_level) {
1860 case DCERPC_AUTH_LEVEL_INTEGRITY:
1861 case DCERPC_AUTH_LEVEL_PRIVACY:
1862 break;
1863 default:
1864 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1865 return;
1867 } else {
1868 uint32_t tmp = state->creds->negotiate_flags;
1870 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1872 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1873 * it should be used, which means
1874 * we had a chance to verify no downgrade
1875 * happened.
1877 * This relies on netlogon_creds_cli_check*
1878 * being called before, as first request after
1879 * the DCERPC bind.
1881 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1882 return;
1886 state->old_timeout = dcerpc_binding_handle_set_timeout(
1887 state->binding_handle, 600000);
1890 * we defer all callbacks in order to cleanup
1891 * the database record.
1893 tevent_req_defer_callback(req, state->ev);
1895 state->tmp_creds = *state->creds;
1896 netlogon_creds_client_authenticator(&state->tmp_creds,
1897 &state->req_auth);
1898 ZERO_STRUCT(state->rep_auth);
1900 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1902 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1903 netlogon_creds_aes_encrypt(&state->tmp_creds,
1904 state->samr_crypt_password.data,
1905 516);
1906 } else {
1907 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1908 state->samr_crypt_password.data,
1909 516);
1912 memcpy(state->netr_crypt_password.data,
1913 state->samr_crypt_password.data, 512);
1914 state->netr_crypt_password.length =
1915 IVAL(state->samr_crypt_password.data, 512);
1917 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1918 state->binding_handle,
1919 state->srv_name_slash,
1920 state->tmp_creds.account_name,
1921 state->tmp_creds.secure_channel_type,
1922 state->tmp_creds.computer_name,
1923 &state->req_auth,
1924 &state->rep_auth,
1925 &state->netr_crypt_password);
1926 if (tevent_req_nomem(subreq, req)) {
1927 status = NT_STATUS_NO_MEMORY;
1928 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1929 return;
1931 } else {
1932 netlogon_creds_des_encrypt(&state->tmp_creds,
1933 &state->samr_password);
1935 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1936 state->binding_handle,
1937 state->srv_name_slash,
1938 state->tmp_creds.account_name,
1939 state->tmp_creds.secure_channel_type,
1940 state->tmp_creds.computer_name,
1941 &state->req_auth,
1942 &state->rep_auth,
1943 &state->samr_password);
1944 if (tevent_req_nomem(subreq, req)) {
1945 status = NT_STATUS_NO_MEMORY;
1946 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1947 return;
1951 tevent_req_set_callback(subreq,
1952 netlogon_creds_cli_ServerPasswordSet_done,
1953 req);
1956 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1958 struct tevent_req *req =
1959 tevent_req_callback_data(subreq,
1960 struct tevent_req);
1961 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1962 tevent_req_data(req,
1963 struct netlogon_creds_cli_ServerPasswordSet_state);
1964 NTSTATUS status;
1965 NTSTATUS result;
1966 bool ok;
1968 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1969 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1970 &result);
1971 TALLOC_FREE(subreq);
1972 if (tevent_req_nterror(req, status)) {
1973 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1974 return;
1976 } else {
1977 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1978 &result);
1979 TALLOC_FREE(subreq);
1980 if (tevent_req_nterror(req, status)) {
1981 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1982 return;
1986 ok = netlogon_creds_client_check(&state->tmp_creds,
1987 &state->rep_auth.cred);
1988 if (!ok) {
1989 status = NT_STATUS_ACCESS_DENIED;
1990 tevent_req_nterror(req, status);
1991 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1992 return;
1995 if (tevent_req_nterror(req, result)) {
1996 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
1997 return;
2000 dcerpc_binding_handle_set_timeout(state->binding_handle,
2001 state->old_timeout);
2003 *state->creds = state->tmp_creds;
2004 status = netlogon_creds_cli_store(state->context,
2005 &state->creds);
2006 if (tevent_req_nterror(req, status)) {
2007 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2008 return;
2011 tevent_req_done(req);
2014 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2016 NTSTATUS status;
2018 if (tevent_req_is_nterror(req, &status)) {
2019 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2020 tevent_req_received(req);
2021 return status;
2024 tevent_req_received(req);
2025 return NT_STATUS_OK;
2028 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2029 struct netlogon_creds_cli_context *context,
2030 struct dcerpc_binding_handle *b,
2031 const char *new_password,
2032 const uint32_t *new_version)
2034 TALLOC_CTX *frame = talloc_stackframe();
2035 struct tevent_context *ev;
2036 struct tevent_req *req;
2037 NTSTATUS status = NT_STATUS_NO_MEMORY;
2039 ev = samba_tevent_context_init(frame);
2040 if (ev == NULL) {
2041 goto fail;
2043 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2044 new_password,
2045 new_version);
2046 if (req == NULL) {
2047 goto fail;
2049 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2050 goto fail;
2052 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2053 fail:
2054 TALLOC_FREE(frame);
2055 return status;
2058 struct netlogon_creds_cli_LogonSamLogon_state {
2059 struct tevent_context *ev;
2060 struct netlogon_creds_cli_context *context;
2061 struct dcerpc_binding_handle *binding_handle;
2063 char *srv_name_slash;
2065 enum netr_LogonInfoClass logon_level;
2066 const union netr_LogonLevel *const_logon;
2067 union netr_LogonLevel *logon;
2068 uint32_t flags;
2070 uint16_t validation_level;
2071 union netr_Validation *validation;
2072 uint8_t authoritative;
2075 * do we need encryption at the application layer?
2077 bool user_encrypt;
2078 bool try_logon_ex;
2079 bool try_validation6;
2082 * the read only credentials before we started the operation
2084 struct netlogon_creds_CredentialState *ro_creds;
2086 struct netlogon_creds_CredentialState *lk_creds;
2088 struct netlogon_creds_CredentialState tmp_creds;
2089 struct netr_Authenticator req_auth;
2090 struct netr_Authenticator rep_auth;
2093 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2094 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2095 NTSTATUS status);
2097 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2098 struct tevent_context *ev,
2099 struct netlogon_creds_cli_context *context,
2100 struct dcerpc_binding_handle *b,
2101 enum netr_LogonInfoClass logon_level,
2102 const union netr_LogonLevel *logon,
2103 uint32_t flags)
2105 struct tevent_req *req;
2106 struct netlogon_creds_cli_LogonSamLogon_state *state;
2108 req = tevent_req_create(mem_ctx, &state,
2109 struct netlogon_creds_cli_LogonSamLogon_state);
2110 if (req == NULL) {
2111 return NULL;
2114 state->ev = ev;
2115 state->context = context;
2116 state->binding_handle = b;
2118 state->logon_level = logon_level;
2119 state->const_logon = logon;
2120 state->flags = flags;
2122 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2123 context->server.computer);
2124 if (tevent_req_nomem(state->srv_name_slash, req)) {
2125 return tevent_req_post(req, ev);
2128 switch (logon_level) {
2129 case NetlogonInteractiveInformation:
2130 case NetlogonInteractiveTransitiveInformation:
2131 case NetlogonServiceInformation:
2132 case NetlogonServiceTransitiveInformation:
2133 case NetlogonGenericInformation:
2134 state->user_encrypt = true;
2135 break;
2137 case NetlogonNetworkInformation:
2138 case NetlogonNetworkTransitiveInformation:
2139 break;
2142 state->validation = talloc_zero(state, union netr_Validation);
2143 if (tevent_req_nomem(state->validation, req)) {
2144 return tevent_req_post(req, ev);
2147 netlogon_creds_cli_LogonSamLogon_start(req);
2148 if (!tevent_req_is_in_progress(req)) {
2149 return tevent_req_post(req, ev);
2153 * we defer all callbacks in order to cleanup
2154 * the database record.
2156 tevent_req_defer_callback(req, state->ev);
2157 return req;
2160 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2161 NTSTATUS status)
2163 struct netlogon_creds_cli_LogonSamLogon_state *state =
2164 tevent_req_data(req,
2165 struct netlogon_creds_cli_LogonSamLogon_state);
2167 if (state->lk_creds == NULL) {
2168 return;
2171 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2173 * This is a hack to recover from a bug in old
2174 * Samba servers, when LogonSamLogonEx() fails:
2176 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2178 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2180 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2181 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2182 * If the sign/seal check fails.
2184 * In that case we need to cleanup the netlogon session.
2186 * It's the job of the caller to disconnect the current
2187 * connection, if netlogon_creds_cli_LogonSamLogon()
2188 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2190 if (!state->context->server.try_logon_with) {
2191 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2195 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2196 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2197 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2198 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2199 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2200 TALLOC_FREE(state->lk_creds);
2201 return;
2204 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2207 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2209 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2211 struct netlogon_creds_cli_LogonSamLogon_state *state =
2212 tevent_req_data(req,
2213 struct netlogon_creds_cli_LogonSamLogon_state);
2214 struct tevent_req *subreq;
2215 NTSTATUS status;
2216 enum dcerpc_AuthType auth_type;
2217 enum dcerpc_AuthLevel auth_level;
2219 TALLOC_FREE(state->ro_creds);
2220 TALLOC_FREE(state->logon);
2221 ZERO_STRUCTP(state->validation);
2223 dcerpc_binding_handle_auth_info(state->binding_handle,
2224 &auth_type, &auth_level);
2226 state->try_logon_ex = state->context->server.try_logon_ex;
2227 state->try_validation6 = state->context->server.try_validation6;
2229 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2230 state->try_logon_ex = false;
2233 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2234 state->try_validation6 = false;
2237 if (state->try_logon_ex) {
2238 if (state->try_validation6) {
2239 state->validation_level = 6;
2240 } else {
2241 state->validation_level = 3;
2242 state->user_encrypt = true;
2245 state->logon = netlogon_creds_shallow_copy_logon(state,
2246 state->logon_level,
2247 state->const_logon);
2248 if (tevent_req_nomem(state->logon, req)) {
2249 status = NT_STATUS_NO_MEMORY;
2250 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2251 return;
2254 if (state->user_encrypt) {
2255 status = netlogon_creds_cli_get(state->context,
2256 state,
2257 &state->ro_creds);
2258 if (!NT_STATUS_IS_OK(status)) {
2259 status = NT_STATUS_ACCESS_DENIED;
2260 tevent_req_nterror(req, status);
2261 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2262 return;
2265 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2266 state->logon_level,
2267 state->logon);
2270 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2271 state->binding_handle,
2272 state->srv_name_slash,
2273 state->context->client.computer,
2274 state->logon_level,
2275 state->logon,
2276 state->validation_level,
2277 state->validation,
2278 &state->authoritative,
2279 &state->flags);
2280 if (tevent_req_nomem(subreq, req)) {
2281 status = NT_STATUS_NO_MEMORY;
2282 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2283 return;
2285 tevent_req_set_callback(subreq,
2286 netlogon_creds_cli_LogonSamLogon_done,
2287 req);
2288 return;
2291 if (state->lk_creds == NULL) {
2292 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2293 state->context);
2294 if (tevent_req_nomem(subreq, req)) {
2295 status = NT_STATUS_NO_MEMORY;
2296 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2297 return;
2299 tevent_req_set_callback(subreq,
2300 netlogon_creds_cli_LogonSamLogon_done,
2301 req);
2302 return;
2305 state->tmp_creds = *state->lk_creds;
2306 netlogon_creds_client_authenticator(&state->tmp_creds,
2307 &state->req_auth);
2308 ZERO_STRUCT(state->rep_auth);
2310 state->logon = netlogon_creds_shallow_copy_logon(state,
2311 state->logon_level,
2312 state->const_logon);
2313 if (tevent_req_nomem(state->logon, req)) {
2314 status = NT_STATUS_NO_MEMORY;
2315 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2316 return;
2319 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2320 state->logon_level,
2321 state->logon);
2323 state->validation_level = 3;
2325 if (state->context->server.try_logon_with) {
2326 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2327 state->binding_handle,
2328 state->srv_name_slash,
2329 state->context->client.computer,
2330 &state->req_auth,
2331 &state->rep_auth,
2332 state->logon_level,
2333 state->logon,
2334 state->validation_level,
2335 state->validation,
2336 &state->authoritative,
2337 &state->flags);
2338 if (tevent_req_nomem(subreq, req)) {
2339 status = NT_STATUS_NO_MEMORY;
2340 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2341 return;
2343 } else {
2344 state->flags = 0;
2346 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2347 state->binding_handle,
2348 state->srv_name_slash,
2349 state->context->client.computer,
2350 &state->req_auth,
2351 &state->rep_auth,
2352 state->logon_level,
2353 state->logon,
2354 state->validation_level,
2355 state->validation,
2356 &state->authoritative);
2357 if (tevent_req_nomem(subreq, req)) {
2358 status = NT_STATUS_NO_MEMORY;
2359 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2360 return;
2364 tevent_req_set_callback(subreq,
2365 netlogon_creds_cli_LogonSamLogon_done,
2366 req);
2369 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2371 struct tevent_req *req =
2372 tevent_req_callback_data(subreq,
2373 struct tevent_req);
2374 struct netlogon_creds_cli_LogonSamLogon_state *state =
2375 tevent_req_data(req,
2376 struct netlogon_creds_cli_LogonSamLogon_state);
2377 NTSTATUS status;
2378 NTSTATUS result;
2379 bool ok;
2381 if (state->try_logon_ex) {
2382 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2383 state->validation,
2384 &result);
2385 TALLOC_FREE(subreq);
2386 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2387 state->context->server.try_validation6 = false;
2388 state->context->server.try_logon_ex = false;
2389 netlogon_creds_cli_LogonSamLogon_start(req);
2390 return;
2392 if (tevent_req_nterror(req, status)) {
2393 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2394 return;
2397 if ((state->validation_level == 6) &&
2398 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2399 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2400 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2402 state->context->server.try_validation6 = false;
2403 netlogon_creds_cli_LogonSamLogon_start(req);
2404 return;
2407 if (tevent_req_nterror(req, result)) {
2408 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2409 return;
2412 if (state->ro_creds == NULL) {
2413 tevent_req_done(req);
2414 return;
2417 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2418 if (!ok) {
2420 * We got a race, lets retry with on authenticator
2421 * protection.
2423 TALLOC_FREE(state->ro_creds);
2424 state->try_logon_ex = false;
2425 netlogon_creds_cli_LogonSamLogon_start(req);
2426 return;
2429 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2430 state->validation_level,
2431 state->validation);
2433 tevent_req_done(req);
2434 return;
2437 if (state->lk_creds == NULL) {
2438 status = netlogon_creds_cli_lock_recv(subreq, state,
2439 &state->lk_creds);
2440 TALLOC_FREE(subreq);
2441 if (tevent_req_nterror(req, status)) {
2442 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2443 return;
2446 netlogon_creds_cli_LogonSamLogon_start(req);
2447 return;
2450 if (state->context->server.try_logon_with) {
2451 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2452 state->validation,
2453 &result);
2454 TALLOC_FREE(subreq);
2455 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2456 state->context->server.try_logon_with = false;
2457 netlogon_creds_cli_LogonSamLogon_start(req);
2458 return;
2460 if (tevent_req_nterror(req, status)) {
2461 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2462 return;
2464 } else {
2465 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2466 state->validation,
2467 &result);
2468 TALLOC_FREE(subreq);
2469 if (tevent_req_nterror(req, status)) {
2470 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2471 return;
2475 ok = netlogon_creds_client_check(&state->tmp_creds,
2476 &state->rep_auth.cred);
2477 if (!ok) {
2478 status = NT_STATUS_ACCESS_DENIED;
2479 tevent_req_nterror(req, status);
2480 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2481 return;
2484 *state->lk_creds = state->tmp_creds;
2485 status = netlogon_creds_cli_store(state->context,
2486 &state->lk_creds);
2487 if (tevent_req_nterror(req, status)) {
2488 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2489 return;
2492 if (tevent_req_nterror(req, result)) {
2493 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2494 return;
2497 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2498 state->validation_level,
2499 state->validation);
2501 tevent_req_done(req);
2504 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2505 TALLOC_CTX *mem_ctx,
2506 uint16_t *validation_level,
2507 union netr_Validation **validation,
2508 uint8_t *authoritative,
2509 uint32_t *flags)
2511 struct netlogon_creds_cli_LogonSamLogon_state *state =
2512 tevent_req_data(req,
2513 struct netlogon_creds_cli_LogonSamLogon_state);
2514 NTSTATUS status;
2516 /* authoritative is also returned on error */
2517 *authoritative = state->authoritative;
2519 if (tevent_req_is_nterror(req, &status)) {
2520 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2521 tevent_req_received(req);
2522 return status;
2525 *validation_level = state->validation_level;
2526 *validation = talloc_move(mem_ctx, &state->validation);
2527 *flags = state->flags;
2529 tevent_req_received(req);
2530 return NT_STATUS_OK;
2533 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2534 struct netlogon_creds_cli_context *context,
2535 struct dcerpc_binding_handle *b,
2536 enum netr_LogonInfoClass logon_level,
2537 const union netr_LogonLevel *logon,
2538 TALLOC_CTX *mem_ctx,
2539 uint16_t *validation_level,
2540 union netr_Validation **validation,
2541 uint8_t *authoritative,
2542 uint32_t *flags)
2544 TALLOC_CTX *frame = talloc_stackframe();
2545 struct tevent_context *ev;
2546 struct tevent_req *req;
2547 NTSTATUS status = NT_STATUS_NO_MEMORY;
2549 ev = samba_tevent_context_init(frame);
2550 if (ev == NULL) {
2551 goto fail;
2553 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2554 logon_level, logon,
2555 *flags);
2556 if (req == NULL) {
2557 goto fail;
2559 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2560 goto fail;
2562 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2563 validation_level,
2564 validation,
2565 authoritative,
2566 flags);
2567 fail:
2568 TALLOC_FREE(frame);
2569 return status;
2572 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2573 struct tevent_context *ev;
2574 struct netlogon_creds_cli_context *context;
2575 struct dcerpc_binding_handle *binding_handle;
2577 char *srv_name_slash;
2578 enum dcerpc_AuthType auth_type;
2579 enum dcerpc_AuthLevel auth_level;
2581 const char *site_name;
2582 uint32_t dns_ttl;
2583 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2585 struct netlogon_creds_CredentialState *creds;
2586 struct netlogon_creds_CredentialState tmp_creds;
2587 struct netr_Authenticator req_auth;
2588 struct netr_Authenticator rep_auth;
2591 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2592 NTSTATUS status);
2593 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2595 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2596 struct tevent_context *ev,
2597 struct netlogon_creds_cli_context *context,
2598 struct dcerpc_binding_handle *b,
2599 const char *site_name,
2600 uint32_t dns_ttl,
2601 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2603 struct tevent_req *req;
2604 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2605 struct tevent_req *subreq;
2607 req = tevent_req_create(mem_ctx, &state,
2608 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2609 if (req == NULL) {
2610 return NULL;
2613 state->ev = ev;
2614 state->context = context;
2615 state->binding_handle = b;
2617 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2618 context->server.computer);
2619 if (tevent_req_nomem(state->srv_name_slash, req)) {
2620 return tevent_req_post(req, ev);
2623 state->site_name = site_name;
2624 state->dns_ttl = dns_ttl;
2625 state->dns_names = dns_names;
2627 dcerpc_binding_handle_auth_info(state->binding_handle,
2628 &state->auth_type,
2629 &state->auth_level);
2631 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2632 state->context);
2633 if (tevent_req_nomem(subreq, req)) {
2634 return tevent_req_post(req, ev);
2637 tevent_req_set_callback(subreq,
2638 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2639 req);
2641 return req;
2644 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2645 NTSTATUS status)
2647 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2648 tevent_req_data(req,
2649 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2651 if (state->creds == NULL) {
2652 return;
2655 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2656 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2657 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2658 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2659 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2660 TALLOC_FREE(state->creds);
2661 return;
2664 netlogon_creds_cli_delete(state->context, &state->creds);
2667 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2669 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2671 struct tevent_req *req =
2672 tevent_req_callback_data(subreq,
2673 struct tevent_req);
2674 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2675 tevent_req_data(req,
2676 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2677 NTSTATUS status;
2679 status = netlogon_creds_cli_lock_recv(subreq, state,
2680 &state->creds);
2681 TALLOC_FREE(subreq);
2682 if (tevent_req_nterror(req, status)) {
2683 return;
2686 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2687 switch (state->auth_level) {
2688 case DCERPC_AUTH_LEVEL_INTEGRITY:
2689 case DCERPC_AUTH_LEVEL_PRIVACY:
2690 break;
2691 default:
2692 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2693 return;
2695 } else {
2696 uint32_t tmp = state->creds->negotiate_flags;
2698 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2700 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2701 * it should be used, which means
2702 * we had a chance to verify no downgrade
2703 * happened.
2705 * This relies on netlogon_creds_cli_check*
2706 * being called before, as first request after
2707 * the DCERPC bind.
2709 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2710 return;
2715 * we defer all callbacks in order to cleanup
2716 * the database record.
2718 tevent_req_defer_callback(req, state->ev);
2720 state->tmp_creds = *state->creds;
2721 netlogon_creds_client_authenticator(&state->tmp_creds,
2722 &state->req_auth);
2723 ZERO_STRUCT(state->rep_auth);
2725 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2726 state->binding_handle,
2727 state->srv_name_slash,
2728 state->tmp_creds.computer_name,
2729 &state->req_auth,
2730 &state->rep_auth,
2731 state->site_name,
2732 state->dns_ttl,
2733 state->dns_names);
2734 if (tevent_req_nomem(subreq, req)) {
2735 status = NT_STATUS_NO_MEMORY;
2736 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2737 return;
2740 tevent_req_set_callback(subreq,
2741 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2742 req);
2745 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2747 struct tevent_req *req =
2748 tevent_req_callback_data(subreq,
2749 struct tevent_req);
2750 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2751 tevent_req_data(req,
2752 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2753 NTSTATUS status;
2754 NTSTATUS result;
2755 bool ok;
2758 * We use state->dns_names as the memory context, as this is
2759 * the only in/out variable and it has been overwritten by the
2760 * out parameter from the server.
2762 * We need to preserve the return value until the caller can use it.
2764 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2765 &result);
2766 TALLOC_FREE(subreq);
2767 if (tevent_req_nterror(req, status)) {
2768 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2769 return;
2772 ok = netlogon_creds_client_check(&state->tmp_creds,
2773 &state->rep_auth.cred);
2774 if (!ok) {
2775 status = NT_STATUS_ACCESS_DENIED;
2776 tevent_req_nterror(req, status);
2777 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2778 return;
2781 if (tevent_req_nterror(req, result)) {
2782 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2783 return;
2786 *state->creds = state->tmp_creds;
2787 status = netlogon_creds_cli_store(state->context,
2788 &state->creds);
2789 if (tevent_req_nterror(req, status)) {
2790 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2791 return;
2794 tevent_req_done(req);
2797 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2799 NTSTATUS status;
2801 if (tevent_req_is_nterror(req, &status)) {
2802 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2803 tevent_req_received(req);
2804 return status;
2807 tevent_req_received(req);
2808 return NT_STATUS_OK;
2811 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2812 struct netlogon_creds_cli_context *context,
2813 struct dcerpc_binding_handle *b,
2814 const char *site_name,
2815 uint32_t dns_ttl,
2816 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2818 TALLOC_CTX *frame = talloc_stackframe();
2819 struct tevent_context *ev;
2820 struct tevent_req *req;
2821 NTSTATUS status = NT_STATUS_NO_MEMORY;
2823 ev = samba_tevent_context_init(frame);
2824 if (ev == NULL) {
2825 goto fail;
2827 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2828 site_name,
2829 dns_ttl,
2830 dns_names);
2831 if (req == NULL) {
2832 goto fail;
2834 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2835 goto fail;
2837 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2838 fail:
2839 TALLOC_FREE(frame);
2840 return status;
2843 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2844 struct tevent_context *ev;
2845 struct netlogon_creds_cli_context *context;
2846 struct dcerpc_binding_handle *binding_handle;
2848 char *srv_name_slash;
2849 enum dcerpc_AuthType auth_type;
2850 enum dcerpc_AuthLevel auth_level;
2852 struct samr_Password new_owf_password;
2853 struct samr_Password old_owf_password;
2854 struct netr_TrustInfo *trust_info;
2856 struct netlogon_creds_CredentialState *creds;
2857 struct netlogon_creds_CredentialState tmp_creds;
2858 struct netr_Authenticator req_auth;
2859 struct netr_Authenticator rep_auth;
2862 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2863 NTSTATUS status);
2864 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2866 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2867 struct tevent_context *ev,
2868 struct netlogon_creds_cli_context *context,
2869 struct dcerpc_binding_handle *b)
2871 struct tevent_req *req;
2872 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2873 struct tevent_req *subreq;
2875 req = tevent_req_create(mem_ctx, &state,
2876 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2877 if (req == NULL) {
2878 return NULL;
2881 state->ev = ev;
2882 state->context = context;
2883 state->binding_handle = b;
2885 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2886 context->server.computer);
2887 if (tevent_req_nomem(state->srv_name_slash, req)) {
2888 return tevent_req_post(req, ev);
2891 dcerpc_binding_handle_auth_info(state->binding_handle,
2892 &state->auth_type,
2893 &state->auth_level);
2895 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2896 state->context);
2897 if (tevent_req_nomem(subreq, req)) {
2898 return tevent_req_post(req, ev);
2901 tevent_req_set_callback(subreq,
2902 netlogon_creds_cli_ServerGetTrustInfo_locked,
2903 req);
2905 return req;
2908 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2909 NTSTATUS status)
2911 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2912 tevent_req_data(req,
2913 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2915 if (state->creds == NULL) {
2916 return;
2919 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2920 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2921 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2922 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2923 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2924 TALLOC_FREE(state->creds);
2925 return;
2928 netlogon_creds_cli_delete(state->context, &state->creds);
2931 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2933 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2935 struct tevent_req *req =
2936 tevent_req_callback_data(subreq,
2937 struct tevent_req);
2938 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2939 tevent_req_data(req,
2940 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2941 NTSTATUS status;
2943 status = netlogon_creds_cli_lock_recv(subreq, state,
2944 &state->creds);
2945 TALLOC_FREE(subreq);
2946 if (tevent_req_nterror(req, status)) {
2947 return;
2950 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2951 switch (state->auth_level) {
2952 case DCERPC_AUTH_LEVEL_PRIVACY:
2953 break;
2954 default:
2955 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2956 return;
2958 } else {
2959 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2960 return;
2964 * we defer all callbacks in order to cleanup
2965 * the database record.
2967 tevent_req_defer_callback(req, state->ev);
2969 state->tmp_creds = *state->creds;
2970 netlogon_creds_client_authenticator(&state->tmp_creds,
2971 &state->req_auth);
2972 ZERO_STRUCT(state->rep_auth);
2974 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
2975 state->binding_handle,
2976 state->srv_name_slash,
2977 state->tmp_creds.account_name,
2978 state->tmp_creds.secure_channel_type,
2979 state->tmp_creds.computer_name,
2980 &state->req_auth,
2981 &state->rep_auth,
2982 &state->new_owf_password,
2983 &state->old_owf_password,
2984 &state->trust_info);
2985 if (tevent_req_nomem(subreq, req)) {
2986 status = NT_STATUS_NO_MEMORY;
2987 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
2988 return;
2991 tevent_req_set_callback(subreq,
2992 netlogon_creds_cli_ServerGetTrustInfo_done,
2993 req);
2996 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
2998 struct tevent_req *req =
2999 tevent_req_callback_data(subreq,
3000 struct tevent_req);
3001 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3002 tevent_req_data(req,
3003 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3004 NTSTATUS status;
3005 NTSTATUS result;
3006 const struct samr_Password zero = {};
3007 int cmp;
3008 bool ok;
3011 * We use state->dns_names as the memory context, as this is
3012 * the only in/out variable and it has been overwritten by the
3013 * out parameter from the server.
3015 * We need to preserve the return value until the caller can use it.
3017 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3018 TALLOC_FREE(subreq);
3019 if (tevent_req_nterror(req, status)) {
3020 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3021 return;
3024 ok = netlogon_creds_client_check(&state->tmp_creds,
3025 &state->rep_auth.cred);
3026 if (!ok) {
3027 status = NT_STATUS_ACCESS_DENIED;
3028 tevent_req_nterror(req, status);
3029 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3030 return;
3033 if (tevent_req_nterror(req, result)) {
3034 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3035 return;
3038 cmp = memcmp(state->new_owf_password.hash,
3039 zero.hash, sizeof(zero.hash));
3040 if (cmp != 0) {
3041 netlogon_creds_des_decrypt(&state->tmp_creds,
3042 &state->new_owf_password);
3044 cmp = memcmp(state->old_owf_password.hash,
3045 zero.hash, sizeof(zero.hash));
3046 if (cmp != 0) {
3047 netlogon_creds_des_decrypt(&state->tmp_creds,
3048 &state->old_owf_password);
3051 *state->creds = state->tmp_creds;
3052 status = netlogon_creds_cli_store(state->context,
3053 &state->creds);
3054 if (tevent_req_nterror(req, status)) {
3055 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3056 return;
3059 tevent_req_done(req);
3062 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3063 TALLOC_CTX *mem_ctx,
3064 struct samr_Password *new_owf_password,
3065 struct samr_Password *old_owf_password,
3066 struct netr_TrustInfo **trust_info)
3068 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3069 tevent_req_data(req,
3070 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3071 NTSTATUS status;
3073 if (tevent_req_is_nterror(req, &status)) {
3074 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3075 tevent_req_received(req);
3076 return status;
3079 if (new_owf_password != NULL) {
3080 *new_owf_password = state->new_owf_password;
3082 if (old_owf_password != NULL) {
3083 *old_owf_password = state->old_owf_password;
3085 if (trust_info != NULL) {
3086 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3089 tevent_req_received(req);
3090 return NT_STATUS_OK;
3093 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3094 struct netlogon_creds_cli_context *context,
3095 struct dcerpc_binding_handle *b,
3096 TALLOC_CTX *mem_ctx,
3097 struct samr_Password *new_owf_password,
3098 struct samr_Password *old_owf_password,
3099 struct netr_TrustInfo **trust_info)
3101 TALLOC_CTX *frame = talloc_stackframe();
3102 struct tevent_context *ev;
3103 struct tevent_req *req;
3104 NTSTATUS status = NT_STATUS_NO_MEMORY;
3106 ev = samba_tevent_context_init(frame);
3107 if (ev == NULL) {
3108 goto fail;
3110 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3111 if (req == NULL) {
3112 goto fail;
3114 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3115 goto fail;
3117 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3118 mem_ctx,
3119 new_owf_password,
3120 old_owf_password,
3121 trust_info);
3122 fail:
3123 TALLOC_FREE(frame);
3124 return status;
3127 struct netlogon_creds_cli_GetForestTrustInformation_state {
3128 struct tevent_context *ev;
3129 struct netlogon_creds_cli_context *context;
3130 struct dcerpc_binding_handle *binding_handle;
3132 char *srv_name_slash;
3133 enum dcerpc_AuthType auth_type;
3134 enum dcerpc_AuthLevel auth_level;
3136 uint32_t flags;
3137 struct lsa_ForestTrustInformation *forest_trust_info;
3139 struct netlogon_creds_CredentialState *creds;
3140 struct netlogon_creds_CredentialState tmp_creds;
3141 struct netr_Authenticator req_auth;
3142 struct netr_Authenticator rep_auth;
3145 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3146 NTSTATUS status);
3147 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3149 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3150 struct tevent_context *ev,
3151 struct netlogon_creds_cli_context *context,
3152 struct dcerpc_binding_handle *b)
3154 struct tevent_req *req;
3155 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3156 struct tevent_req *subreq;
3158 req = tevent_req_create(mem_ctx, &state,
3159 struct netlogon_creds_cli_GetForestTrustInformation_state);
3160 if (req == NULL) {
3161 return NULL;
3164 state->ev = ev;
3165 state->context = context;
3166 state->binding_handle = b;
3168 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3169 context->server.computer);
3170 if (tevent_req_nomem(state->srv_name_slash, req)) {
3171 return tevent_req_post(req, ev);
3174 state->flags = 0;
3176 dcerpc_binding_handle_auth_info(state->binding_handle,
3177 &state->auth_type,
3178 &state->auth_level);
3180 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3181 state->context);
3182 if (tevent_req_nomem(subreq, req)) {
3183 return tevent_req_post(req, ev);
3186 tevent_req_set_callback(subreq,
3187 netlogon_creds_cli_GetForestTrustInformation_locked,
3188 req);
3190 return req;
3193 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3194 NTSTATUS status)
3196 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3197 tevent_req_data(req,
3198 struct netlogon_creds_cli_GetForestTrustInformation_state);
3200 if (state->creds == NULL) {
3201 return;
3204 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3205 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3206 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3207 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3208 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3209 TALLOC_FREE(state->creds);
3210 return;
3213 netlogon_creds_cli_delete(state->context, &state->creds);
3216 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3218 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3220 struct tevent_req *req =
3221 tevent_req_callback_data(subreq,
3222 struct tevent_req);
3223 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3224 tevent_req_data(req,
3225 struct netlogon_creds_cli_GetForestTrustInformation_state);
3226 NTSTATUS status;
3228 status = netlogon_creds_cli_lock_recv(subreq, state,
3229 &state->creds);
3230 TALLOC_FREE(subreq);
3231 if (tevent_req_nterror(req, status)) {
3232 return;
3235 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3236 switch (state->auth_level) {
3237 case DCERPC_AUTH_LEVEL_INTEGRITY:
3238 case DCERPC_AUTH_LEVEL_PRIVACY:
3239 break;
3240 default:
3241 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3242 return;
3244 } else {
3245 uint32_t tmp = state->creds->negotiate_flags;
3247 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3249 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3250 * it should be used, which means
3251 * we had a chance to verify no downgrade
3252 * happened.
3254 * This relies on netlogon_creds_cli_check*
3255 * being called before, as first request after
3256 * the DCERPC bind.
3258 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3259 return;
3264 * we defer all callbacks in order to cleanup
3265 * the database record.
3267 tevent_req_defer_callback(req, state->ev);
3269 state->tmp_creds = *state->creds;
3270 netlogon_creds_client_authenticator(&state->tmp_creds,
3271 &state->req_auth);
3272 ZERO_STRUCT(state->rep_auth);
3274 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3275 state->binding_handle,
3276 state->srv_name_slash,
3277 state->tmp_creds.computer_name,
3278 &state->req_auth,
3279 &state->rep_auth,
3280 state->flags,
3281 &state->forest_trust_info);
3282 if (tevent_req_nomem(subreq, req)) {
3283 status = NT_STATUS_NO_MEMORY;
3284 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3285 return;
3288 tevent_req_set_callback(subreq,
3289 netlogon_creds_cli_GetForestTrustInformation_done,
3290 req);
3293 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3295 struct tevent_req *req =
3296 tevent_req_callback_data(subreq,
3297 struct tevent_req);
3298 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3299 tevent_req_data(req,
3300 struct netlogon_creds_cli_GetForestTrustInformation_state);
3301 NTSTATUS status;
3302 NTSTATUS result;
3303 bool ok;
3306 * We use state->dns_names as the memory context, as this is
3307 * the only in/out variable and it has been overwritten by the
3308 * out parameter from the server.
3310 * We need to preserve the return value until the caller can use it.
3312 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3313 TALLOC_FREE(subreq);
3314 if (tevent_req_nterror(req, status)) {
3315 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3316 return;
3319 ok = netlogon_creds_client_check(&state->tmp_creds,
3320 &state->rep_auth.cred);
3321 if (!ok) {
3322 status = NT_STATUS_ACCESS_DENIED;
3323 tevent_req_nterror(req, status);
3324 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3325 return;
3328 if (tevent_req_nterror(req, result)) {
3329 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3330 return;
3333 *state->creds = state->tmp_creds;
3334 status = netlogon_creds_cli_store(state->context,
3335 &state->creds);
3336 if (tevent_req_nterror(req, status)) {
3337 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3338 return;
3341 tevent_req_done(req);
3344 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3345 TALLOC_CTX *mem_ctx,
3346 struct lsa_ForestTrustInformation **forest_trust_info)
3348 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3349 tevent_req_data(req,
3350 struct netlogon_creds_cli_GetForestTrustInformation_state);
3351 NTSTATUS status;
3353 if (tevent_req_is_nterror(req, &status)) {
3354 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3355 tevent_req_received(req);
3356 return status;
3359 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3361 tevent_req_received(req);
3362 return NT_STATUS_OK;
3365 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3366 struct netlogon_creds_cli_context *context,
3367 struct dcerpc_binding_handle *b,
3368 TALLOC_CTX *mem_ctx,
3369 struct lsa_ForestTrustInformation **forest_trust_info)
3371 TALLOC_CTX *frame = talloc_stackframe();
3372 struct tevent_context *ev;
3373 struct tevent_req *req;
3374 NTSTATUS status = NT_STATUS_NO_MEMORY;
3376 ev = samba_tevent_context_init(frame);
3377 if (ev == NULL) {
3378 goto fail;
3380 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3381 if (req == NULL) {
3382 goto fail;
3384 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3385 goto fail;
3387 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3388 mem_ctx,
3389 forest_trust_info);
3390 fail:
3391 TALLOC_FREE(frame);
3392 return status;