Changes to make the Solaris C compiler happy.
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blobd55142e3ee2322e7de6e63d3229696c977131acd
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"
38 #include "libds/common/roles.h"
40 struct netlogon_creds_cli_locked_state;
42 struct netlogon_creds_cli_context {
43 struct {
44 const char *computer;
45 const char *account;
46 uint32_t proposed_flags;
47 uint32_t required_flags;
48 enum netr_SchannelType type;
49 enum dcerpc_AuthLevel auth_level;
50 } client;
52 struct {
53 const char *computer;
54 const char *netbios_domain;
55 uint32_t cached_flags;
56 bool try_validation6;
57 bool try_logon_ex;
58 bool try_logon_with;
59 } server;
61 struct {
62 const char *key_name;
63 TDB_DATA key_data;
64 struct db_context *ctx;
65 struct g_lock_ctx *g_ctx;
66 struct netlogon_creds_cli_locked_state *locked_state;
67 } db;
70 struct netlogon_creds_cli_locked_state {
71 struct netlogon_creds_cli_context *context;
72 bool is_glocked;
73 struct netlogon_creds_CredentialState *creds;
76 static int netlogon_creds_cli_locked_state_destructor(
77 struct netlogon_creds_cli_locked_state *state)
79 struct netlogon_creds_cli_context *context = state->context;
81 if (context == NULL) {
82 return 0;
85 if (context->db.locked_state == state) {
86 context->db.locked_state = NULL;
89 if (state->is_glocked) {
90 g_lock_unlock(context->db.g_ctx,
91 context->db.key_name);
94 return 0;
97 static NTSTATUS netlogon_creds_cli_context_common(
98 const char *client_computer,
99 const char *client_account,
100 enum netr_SchannelType type,
101 enum dcerpc_AuthLevel auth_level,
102 uint32_t proposed_flags,
103 uint32_t required_flags,
104 const char *server_computer,
105 const char *server_netbios_domain,
106 TALLOC_CTX *mem_ctx,
107 struct netlogon_creds_cli_context **_context)
109 struct netlogon_creds_cli_context *context = NULL;
110 TALLOC_CTX *frame = talloc_stackframe();
111 char *_key_name = NULL;
112 char *server_netbios_name = NULL;
113 char *p = NULL;
115 *_context = NULL;
117 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
118 if (context == NULL) {
119 TALLOC_FREE(frame);
120 return NT_STATUS_NO_MEMORY;
123 context->client.computer = talloc_strdup(context, client_computer);
124 if (context->client.computer == NULL) {
125 TALLOC_FREE(context);
126 TALLOC_FREE(frame);
127 return NT_STATUS_NO_MEMORY;
130 context->client.account = talloc_strdup(context, client_account);
131 if (context->client.account == NULL) {
132 TALLOC_FREE(context);
133 TALLOC_FREE(frame);
134 return NT_STATUS_NO_MEMORY;
137 context->client.proposed_flags = proposed_flags;
138 context->client.required_flags = required_flags;
139 context->client.type = type;
140 context->client.auth_level = auth_level;
142 context->server.computer = talloc_strdup(context, server_computer);
143 if (context->server.computer == NULL) {
144 TALLOC_FREE(context);
145 TALLOC_FREE(frame);
146 return NT_STATUS_NO_MEMORY;
149 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
150 if (context->server.netbios_domain == NULL) {
151 TALLOC_FREE(context);
152 TALLOC_FREE(frame);
153 return NT_STATUS_NO_MEMORY;
157 * TODO:
158 * Force the callers to provide a unique
159 * value for server_computer and use this directly.
161 * For now we have to deal with
162 * "HOSTNAME" vs. "hostname.example.com".
164 server_netbios_name = talloc_strdup(frame, server_computer);
165 if (server_netbios_name == NULL) {
166 TALLOC_FREE(context);
167 TALLOC_FREE(frame);
168 return NT_STATUS_NO_MEMORY;
171 p = strchr(server_netbios_name, '.');
172 if (p != NULL) {
173 p[0] = '\0';
176 _key_name = talloc_asprintf(frame, "CLI[%s/%s]/SRV[%s/%s]",
177 client_computer,
178 client_account,
179 server_netbios_name,
180 server_netbios_domain);
181 if (_key_name == NULL) {
182 TALLOC_FREE(context);
183 TALLOC_FREE(frame);
184 return NT_STATUS_NO_MEMORY;
187 context->db.key_name = talloc_strdup_upper(context, _key_name);
188 if (context->db.key_name == NULL) {
189 TALLOC_FREE(context);
190 TALLOC_FREE(frame);
191 return NT_STATUS_NO_MEMORY;
194 context->db.key_data = string_term_tdb_data(context->db.key_name);
196 *_context = context;
197 TALLOC_FREE(frame);
198 return NT_STATUS_OK;
201 static struct db_context *netlogon_creds_cli_global_db;
203 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
205 if (netlogon_creds_cli_global_db != NULL) {
206 return NT_STATUS_INVALID_PARAMETER_MIX;
209 netlogon_creds_cli_global_db = talloc_move(talloc_autofree_context(), db);
210 return NT_STATUS_OK;
213 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
215 char *fname;
216 struct db_context *global_db;
218 if (netlogon_creds_cli_global_db != NULL) {
219 return NT_STATUS_OK;
222 fname = lpcfg_private_db_path(talloc_autofree_context(), lp_ctx, "netlogon_creds_cli");
223 if (fname == NULL) {
224 return NT_STATUS_NO_MEMORY;
227 global_db = dbwrap_local_open(talloc_autofree_context(), lp_ctx,
228 fname, 0,
229 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
230 O_RDWR|O_CREAT,
231 0600, DBWRAP_LOCK_ORDER_2,
232 DBWRAP_FLAG_NONE);
233 if (global_db == NULL) {
234 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
235 fname, strerror(errno)));
236 talloc_free(fname);
237 return NT_STATUS_NO_MEMORY;
239 TALLOC_FREE(fname);
241 netlogon_creds_cli_global_db = global_db;
242 return NT_STATUS_OK;
245 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
246 struct messaging_context *msg_ctx,
247 const char *client_account,
248 enum netr_SchannelType type,
249 const char *server_computer,
250 const char *server_netbios_domain,
251 TALLOC_CTX *mem_ctx,
252 struct netlogon_creds_cli_context **_context)
254 TALLOC_CTX *frame = talloc_stackframe();
255 NTSTATUS status;
256 struct netlogon_creds_cli_context *context = NULL;
257 const char *client_computer;
258 uint32_t proposed_flags;
259 uint32_t required_flags = 0;
260 bool reject_md5_servers = false;
261 bool require_strong_key = false;
262 int require_sign_or_seal = true;
263 bool seal_secure_channel = true;
264 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
265 bool neutralize_nt4_emulation = false;
267 *_context = NULL;
269 client_computer = lpcfg_netbios_name(lp_ctx);
270 if (strlen(client_computer) > 15) {
271 return NT_STATUS_INVALID_PARAMETER_MIX;
275 * allow overwrite per domain
276 * reject md5 servers:<netbios_domain>
278 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
279 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
280 "reject md5 servers",
281 server_netbios_domain,
282 reject_md5_servers);
285 * allow overwrite per domain
286 * require strong key:<netbios_domain>
288 require_strong_key = lpcfg_require_strong_key(lp_ctx);
289 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
290 "require strong key",
291 server_netbios_domain,
292 require_strong_key);
295 * allow overwrite per domain
296 * client schannel:<netbios_domain>
298 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
299 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
300 "client schannel",
301 server_netbios_domain,
302 require_sign_or_seal);
305 * allow overwrite per domain
306 * winbind sealed pipes:<netbios_domain>
308 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
309 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
310 "winbind sealed pipes",
311 server_netbios_domain,
312 seal_secure_channel);
315 * allow overwrite per domain
316 * neutralize nt4 emulation:<netbios_domain>
318 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
319 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
320 "neutralize nt4 emulation",
321 server_netbios_domain,
322 neutralize_nt4_emulation);
324 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
325 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
327 switch (type) {
328 case SEC_CHAN_WKSTA:
329 if (lpcfg_security(lp_ctx) == SEC_ADS) {
331 * AD domains should be secure
333 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
334 require_sign_or_seal = true;
335 require_strong_key = true;
337 break;
339 case SEC_CHAN_DOMAIN:
340 break;
342 case SEC_CHAN_DNS_DOMAIN:
344 * AD domains should be secure
346 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
347 require_sign_or_seal = true;
348 require_strong_key = true;
349 neutralize_nt4_emulation = true;
350 break;
352 case SEC_CHAN_BDC:
353 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
354 require_sign_or_seal = true;
355 require_strong_key = true;
356 break;
358 case SEC_CHAN_RODC:
359 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
360 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
361 require_sign_or_seal = true;
362 require_strong_key = true;
363 neutralize_nt4_emulation = true;
364 break;
366 default:
367 TALLOC_FREE(frame);
368 return NT_STATUS_INVALID_PARAMETER;
371 if (neutralize_nt4_emulation) {
372 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
375 if (require_sign_or_seal == false) {
376 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
377 } else {
378 required_flags |= NETLOGON_NEG_ARCFOUR;
379 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
382 if (reject_md5_servers) {
383 required_flags |= NETLOGON_NEG_ARCFOUR;
384 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
385 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
386 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
389 if (require_strong_key) {
390 required_flags |= NETLOGON_NEG_ARCFOUR;
391 required_flags |= NETLOGON_NEG_STRONG_KEYS;
392 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
395 proposed_flags |= required_flags;
397 if (seal_secure_channel) {
398 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
399 } else {
400 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
403 status = netlogon_creds_cli_context_common(client_computer,
404 client_account,
405 type,
406 auth_level,
407 proposed_flags,
408 required_flags,
409 server_computer,
410 server_netbios_domain,
411 mem_ctx,
412 &context);
413 if (!NT_STATUS_IS_OK(status)) {
414 TALLOC_FREE(frame);
415 return status;
418 if (msg_ctx != NULL) {
419 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
420 if (context->db.g_ctx == NULL) {
421 TALLOC_FREE(context);
422 TALLOC_FREE(frame);
423 return NT_STATUS_NO_MEMORY;
427 if (netlogon_creds_cli_global_db != NULL) {
428 context->db.ctx = netlogon_creds_cli_global_db;
429 *_context = context;
430 TALLOC_FREE(frame);
431 return NT_STATUS_OK;
434 status = netlogon_creds_cli_open_global_db(lp_ctx);
435 if (!NT_STATUS_IS_OK(status)) {
436 TALLOC_FREE(context);
437 TALLOC_FREE(frame);
438 return NT_STATUS_NO_MEMORY;
441 context->db.ctx = netlogon_creds_cli_global_db;
442 *_context = context;
443 TALLOC_FREE(frame);
444 return NT_STATUS_OK;
447 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
448 const char *client_account,
449 enum netr_SchannelType type,
450 uint32_t proposed_flags,
451 uint32_t required_flags,
452 enum dcerpc_AuthLevel auth_level,
453 const char *server_computer,
454 const char *server_netbios_domain,
455 TALLOC_CTX *mem_ctx,
456 struct netlogon_creds_cli_context **_context)
458 NTSTATUS status;
459 struct netlogon_creds_cli_context *context = NULL;
461 *_context = NULL;
463 status = netlogon_creds_cli_context_common(client_computer,
464 client_account,
465 type,
466 auth_level,
467 proposed_flags,
468 required_flags,
469 server_computer,
470 server_netbios_domain,
471 mem_ctx,
472 &context);
473 if (!NT_STATUS_IS_OK(status)) {
474 return status;
477 context->db.ctx = db_open_rbt(context);
478 if (context->db.ctx == NULL) {
479 talloc_free(context);
480 return NT_STATUS_NO_MEMORY;
483 *_context = context;
484 return NT_STATUS_OK;
487 char *netlogon_creds_cli_debug_string(
488 const struct netlogon_creds_cli_context *context,
489 TALLOC_CTX *mem_ctx)
491 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
492 context->db.key_name);
495 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
496 struct netlogon_creds_cli_context *context)
498 return context->client.auth_level;
501 struct netlogon_creds_cli_fetch_state {
502 TALLOC_CTX *mem_ctx;
503 struct netlogon_creds_CredentialState *creds;
504 uint32_t required_flags;
505 NTSTATUS status;
508 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
509 void *private_data)
511 struct netlogon_creds_cli_fetch_state *state =
512 (struct netlogon_creds_cli_fetch_state *)private_data;
513 enum ndr_err_code ndr_err;
514 DATA_BLOB blob;
515 uint32_t tmp_flags;
517 state->creds = talloc_zero(state->mem_ctx,
518 struct netlogon_creds_CredentialState);
519 if (state->creds == NULL) {
520 state->status = NT_STATUS_NO_MEMORY;
521 return;
524 blob.data = data.dptr;
525 blob.length = data.dsize;
527 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
528 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
529 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
530 TALLOC_FREE(state->creds);
531 state->status = ndr_map_error2ntstatus(ndr_err);
532 return;
535 tmp_flags = state->creds->negotiate_flags;
536 tmp_flags &= state->required_flags;
537 if (tmp_flags != state->required_flags) {
538 TALLOC_FREE(state->creds);
539 state->status = NT_STATUS_DOWNGRADE_DETECTED;
540 return;
543 state->status = NT_STATUS_OK;
546 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
547 TALLOC_CTX *mem_ctx,
548 struct netlogon_creds_CredentialState **_creds)
550 NTSTATUS status;
551 struct netlogon_creds_cli_fetch_state fstate = {
552 .mem_ctx = mem_ctx,
553 .status = NT_STATUS_INTERNAL_ERROR,
554 .required_flags = context->client.required_flags,
556 static const struct netr_Credential zero_creds;
558 *_creds = NULL;
560 status = dbwrap_parse_record(context->db.ctx,
561 context->db.key_data,
562 netlogon_creds_cli_fetch_parser,
563 &fstate);
564 if (!NT_STATUS_IS_OK(status)) {
565 return status;
567 status = fstate.status;
568 if (!NT_STATUS_IS_OK(status)) {
569 return status;
573 * mark it as invalid for step operations.
575 fstate.creds->sequence = 0;
576 fstate.creds->seed = zero_creds;
577 fstate.creds->client = zero_creds;
578 fstate.creds->server = zero_creds;
580 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
581 *_creds = fstate.creds;
582 return NT_STATUS_OK;
586 * It is really important to try SamLogonEx here,
587 * because multiple processes can talk to the same
588 * domain controller, without using the credential
589 * chain.
591 * With a normal SamLogon call, we must keep the
592 * credentials chain updated and intact between all
593 * users of the machine account (which would imply
594 * cross-node communication for every NTLM logon).
596 * The credentials chain is not per NETLOGON pipe
597 * connection, but globally on the server/client pair
598 * by computer name, while the client is free to use
599 * any computer name. We include the cluster node number
600 * in our computer name in order to avoid cross node
601 * coordination of the credential chain.
603 * It's also important to use NetlogonValidationSamInfo4 (6),
604 * because it relies on the rpc transport encryption
605 * and avoids using the global netlogon schannel
606 * session key to en/decrypt secret information
607 * like the user_session_key for network logons.
609 * [MS-APDS] 3.1.5.2 NTLM Network Logon
610 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
611 * NETLOGON_NEG_AUTHENTICATED_RPC set together
612 * are the indication that the server supports
613 * NetlogonValidationSamInfo4 (6). And it must only
614 * be used if "SealSecureChannel" is used.
616 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
617 * check is done in netlogon_creds_cli_LogonSamLogon*().
619 context->server.cached_flags = fstate.creds->negotiate_flags;
620 context->server.try_validation6 = true;
621 context->server.try_logon_ex = true;
622 context->server.try_logon_with = true;
624 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
625 context->server.try_validation6 = false;
626 context->server.try_logon_ex = false;
628 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
629 context->server.try_validation6 = false;
632 *_creds = fstate.creds;
633 return NT_STATUS_OK;
636 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
637 const struct netlogon_creds_CredentialState *creds1)
639 TALLOC_CTX *frame = talloc_stackframe();
640 struct netlogon_creds_CredentialState *creds2;
641 DATA_BLOB blob1;
642 DATA_BLOB blob2;
643 NTSTATUS status;
644 enum ndr_err_code ndr_err;
645 int cmp;
647 status = netlogon_creds_cli_get(context, frame, &creds2);
648 if (!NT_STATUS_IS_OK(status)) {
649 TALLOC_FREE(frame);
650 return false;
653 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
654 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
655 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
656 TALLOC_FREE(frame);
657 return false;
660 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
661 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
662 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
663 TALLOC_FREE(frame);
664 return false;
667 if (blob1.length != blob2.length) {
668 TALLOC_FREE(frame);
669 return false;
672 cmp = memcmp(blob1.data, blob2.data, blob1.length);
673 if (cmp != 0) {
674 TALLOC_FREE(frame);
675 return false;
678 TALLOC_FREE(frame);
679 return true;
682 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
683 struct netlogon_creds_CredentialState **_creds)
685 struct netlogon_creds_CredentialState *creds = *_creds;
686 NTSTATUS status;
687 enum ndr_err_code ndr_err;
688 DATA_BLOB blob;
689 TDB_DATA data;
691 *_creds = NULL;
693 if (context->db.locked_state == NULL) {
695 * this was not the result of netlogon_creds_cli_lock*()
697 TALLOC_FREE(creds);
698 return NT_STATUS_INVALID_PAGE_PROTECTION;
701 if (context->db.locked_state->creds != creds) {
703 * this was not the result of netlogon_creds_cli_lock*()
705 TALLOC_FREE(creds);
706 return NT_STATUS_INVALID_PAGE_PROTECTION;
709 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
710 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
711 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
712 TALLOC_FREE(creds);
713 status = ndr_map_error2ntstatus(ndr_err);
714 return status;
717 data.dptr = blob.data;
718 data.dsize = blob.length;
720 status = dbwrap_store(context->db.ctx,
721 context->db.key_data,
722 data, TDB_REPLACE);
723 TALLOC_FREE(creds);
724 if (!NT_STATUS_IS_OK(status)) {
725 return status;
728 return NT_STATUS_OK;
731 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
732 struct netlogon_creds_CredentialState **_creds)
734 struct netlogon_creds_CredentialState *creds = *_creds;
735 NTSTATUS status;
737 *_creds = NULL;
739 if (context->db.locked_state == NULL) {
741 * this was not the result of netlogon_creds_cli_lock*()
743 TALLOC_FREE(creds);
744 return NT_STATUS_INVALID_PAGE_PROTECTION;
747 if (context->db.locked_state->creds != creds) {
749 * this was not the result of netlogon_creds_cli_lock*()
751 TALLOC_FREE(creds);
752 return NT_STATUS_INVALID_PAGE_PROTECTION;
755 status = dbwrap_delete(context->db.ctx,
756 context->db.key_data);
757 TALLOC_FREE(creds);
758 if (!NT_STATUS_IS_OK(status)) {
759 return status;
762 return NT_STATUS_OK;
765 struct netlogon_creds_cli_lock_state {
766 struct netlogon_creds_cli_locked_state *locked_state;
767 struct netlogon_creds_CredentialState *creds;
770 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
771 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
773 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
774 struct tevent_context *ev,
775 struct netlogon_creds_cli_context *context)
777 struct tevent_req *req;
778 struct netlogon_creds_cli_lock_state *state;
779 struct netlogon_creds_cli_locked_state *locked_state;
780 struct tevent_req *subreq;
782 req = tevent_req_create(mem_ctx, &state,
783 struct netlogon_creds_cli_lock_state);
784 if (req == NULL) {
785 return NULL;
788 if (context->db.locked_state != NULL) {
789 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
790 return tevent_req_post(req, ev);
793 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
794 if (tevent_req_nomem(locked_state, req)) {
795 return tevent_req_post(req, ev);
797 talloc_set_destructor(locked_state,
798 netlogon_creds_cli_locked_state_destructor);
799 locked_state->context = context;
801 context->db.locked_state = locked_state;
802 state->locked_state = locked_state;
804 if (context->db.g_ctx == NULL) {
805 netlogon_creds_cli_lock_fetch(req);
806 if (!tevent_req_is_in_progress(req)) {
807 return tevent_req_post(req, ev);
810 return req;
813 subreq = g_lock_lock_send(state, ev,
814 context->db.g_ctx,
815 context->db.key_name,
816 G_LOCK_WRITE);
817 if (tevent_req_nomem(subreq, req)) {
818 return tevent_req_post(req, ev);
820 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
822 return req;
825 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
827 struct tevent_req *req =
828 tevent_req_callback_data(subreq,
829 struct tevent_req);
830 struct netlogon_creds_cli_lock_state *state =
831 tevent_req_data(req,
832 struct netlogon_creds_cli_lock_state);
833 NTSTATUS status;
835 status = g_lock_lock_recv(subreq);
836 TALLOC_FREE(subreq);
837 if (tevent_req_nterror(req, status)) {
838 return;
840 state->locked_state->is_glocked = true;
842 netlogon_creds_cli_lock_fetch(req);
845 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
847 struct netlogon_creds_cli_lock_state *state =
848 tevent_req_data(req,
849 struct netlogon_creds_cli_lock_state);
850 struct netlogon_creds_cli_context *context = state->locked_state->context;
851 struct netlogon_creds_cli_fetch_state fstate = {
852 .status = NT_STATUS_INTERNAL_ERROR,
853 .required_flags = context->client.required_flags,
855 NTSTATUS status;
857 fstate.mem_ctx = state;
858 status = dbwrap_parse_record(context->db.ctx,
859 context->db.key_data,
860 netlogon_creds_cli_fetch_parser,
861 &fstate);
862 if (tevent_req_nterror(req, status)) {
863 return;
865 status = fstate.status;
866 if (tevent_req_nterror(req, status)) {
867 return;
870 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
871 state->creds = fstate.creds;
872 tevent_req_done(req);
873 return;
876 context->server.cached_flags = fstate.creds->negotiate_flags;
877 context->server.try_validation6 = true;
878 context->server.try_logon_ex = true;
879 context->server.try_logon_with = true;
881 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
882 context->server.try_validation6 = false;
883 context->server.try_logon_ex = false;
885 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
886 context->server.try_validation6 = false;
889 state->creds = fstate.creds;
890 tevent_req_done(req);
891 return;
894 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
895 TALLOC_CTX *mem_ctx,
896 struct netlogon_creds_CredentialState **creds)
898 struct netlogon_creds_cli_lock_state *state =
899 tevent_req_data(req,
900 struct netlogon_creds_cli_lock_state);
901 NTSTATUS status;
903 if (tevent_req_is_nterror(req, &status)) {
904 tevent_req_received(req);
905 return status;
908 talloc_steal(state->creds, state->locked_state);
909 state->locked_state->creds = state->creds;
910 *creds = talloc_move(mem_ctx, &state->creds);
911 tevent_req_received(req);
912 return NT_STATUS_OK;
915 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
916 TALLOC_CTX *mem_ctx,
917 struct netlogon_creds_CredentialState **creds)
919 TALLOC_CTX *frame = talloc_stackframe();
920 struct tevent_context *ev;
921 struct tevent_req *req;
922 NTSTATUS status = NT_STATUS_NO_MEMORY;
924 ev = samba_tevent_context_init(frame);
925 if (ev == NULL) {
926 goto fail;
928 req = netlogon_creds_cli_lock_send(frame, ev, context);
929 if (req == NULL) {
930 goto fail;
932 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
933 goto fail;
935 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
936 fail:
937 TALLOC_FREE(frame);
938 return status;
941 struct netlogon_creds_cli_auth_state {
942 struct tevent_context *ev;
943 struct netlogon_creds_cli_context *context;
944 struct dcerpc_binding_handle *binding_handle;
945 struct samr_Password current_nt_hash;
946 struct samr_Password previous_nt_hash;
947 struct samr_Password used_nt_hash;
948 char *srv_name_slash;
949 uint32_t current_flags;
950 struct netr_Credential client_challenge;
951 struct netr_Credential server_challenge;
952 struct netlogon_creds_CredentialState *creds;
953 struct netr_Credential client_credential;
954 struct netr_Credential server_credential;
955 uint32_t rid;
956 bool try_auth3;
957 bool try_auth2;
958 bool require_auth2;
959 bool try_previous_nt_hash;
960 struct netlogon_creds_cli_locked_state *locked_state;
963 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
964 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
966 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
967 struct tevent_context *ev,
968 struct netlogon_creds_cli_context *context,
969 struct dcerpc_binding_handle *b,
970 struct samr_Password current_nt_hash,
971 const struct samr_Password *previous_nt_hash)
973 struct tevent_req *req;
974 struct netlogon_creds_cli_auth_state *state;
975 struct netlogon_creds_cli_locked_state *locked_state;
976 NTSTATUS status;
978 req = tevent_req_create(mem_ctx, &state,
979 struct netlogon_creds_cli_auth_state);
980 if (req == NULL) {
981 return NULL;
984 state->ev = ev;
985 state->context = context;
986 state->binding_handle = b;
987 state->current_nt_hash = current_nt_hash;
988 if (previous_nt_hash != NULL) {
989 state->previous_nt_hash = *previous_nt_hash;
990 state->try_previous_nt_hash = true;
993 if (context->db.locked_state != NULL) {
994 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
995 return tevent_req_post(req, ev);
998 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
999 if (tevent_req_nomem(locked_state, req)) {
1000 return tevent_req_post(req, ev);
1002 talloc_set_destructor(locked_state,
1003 netlogon_creds_cli_locked_state_destructor);
1004 locked_state->context = context;
1006 context->db.locked_state = locked_state;
1007 state->locked_state = locked_state;
1009 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1010 context->server.computer);
1011 if (tevent_req_nomem(state->srv_name_slash, req)) {
1012 return tevent_req_post(req, ev);
1015 state->try_auth3 = true;
1016 state->try_auth2 = true;
1018 if (context->client.required_flags != 0) {
1019 state->require_auth2 = true;
1022 state->used_nt_hash = state->current_nt_hash;
1023 state->current_flags = context->client.proposed_flags;
1025 if (context->db.g_ctx != NULL) {
1026 struct tevent_req *subreq;
1028 subreq = g_lock_lock_send(state, ev,
1029 context->db.g_ctx,
1030 context->db.key_name,
1031 G_LOCK_WRITE);
1032 if (tevent_req_nomem(subreq, req)) {
1033 return tevent_req_post(req, ev);
1035 tevent_req_set_callback(subreq,
1036 netlogon_creds_cli_auth_locked,
1037 req);
1039 return req;
1042 status = dbwrap_purge(state->context->db.ctx,
1043 state->context->db.key_data);
1044 if (tevent_req_nterror(req, status)) {
1045 return tevent_req_post(req, ev);
1048 netlogon_creds_cli_auth_challenge_start(req);
1049 if (!tevent_req_is_in_progress(req)) {
1050 return tevent_req_post(req, ev);
1053 return req;
1056 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1058 struct tevent_req *req =
1059 tevent_req_callback_data(subreq,
1060 struct tevent_req);
1061 struct netlogon_creds_cli_auth_state *state =
1062 tevent_req_data(req,
1063 struct netlogon_creds_cli_auth_state);
1064 NTSTATUS status;
1066 status = g_lock_lock_recv(subreq);
1067 TALLOC_FREE(subreq);
1068 if (tevent_req_nterror(req, status)) {
1069 return;
1071 state->locked_state->is_glocked = true;
1073 status = dbwrap_purge(state->context->db.ctx,
1074 state->context->db.key_data);
1075 if (tevent_req_nterror(req, status)) {
1076 return;
1079 netlogon_creds_cli_auth_challenge_start(req);
1082 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1084 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1086 struct netlogon_creds_cli_auth_state *state =
1087 tevent_req_data(req,
1088 struct netlogon_creds_cli_auth_state);
1089 struct tevent_req *subreq;
1091 TALLOC_FREE(state->creds);
1093 generate_random_buffer(state->client_challenge.data,
1094 sizeof(state->client_challenge.data));
1096 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1097 state->binding_handle,
1098 state->srv_name_slash,
1099 state->context->client.computer,
1100 &state->client_challenge,
1101 &state->server_challenge);
1102 if (tevent_req_nomem(subreq, req)) {
1103 return;
1105 tevent_req_set_callback(subreq,
1106 netlogon_creds_cli_auth_challenge_done,
1107 req);
1110 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1112 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1114 struct tevent_req *req =
1115 tevent_req_callback_data(subreq,
1116 struct tevent_req);
1117 struct netlogon_creds_cli_auth_state *state =
1118 tevent_req_data(req,
1119 struct netlogon_creds_cli_auth_state);
1120 NTSTATUS status;
1121 NTSTATUS result;
1123 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1124 TALLOC_FREE(subreq);
1125 if (tevent_req_nterror(req, status)) {
1126 return;
1128 if (tevent_req_nterror(req, result)) {
1129 return;
1132 if (!state->try_auth3 && !state->try_auth2) {
1133 state->current_flags = 0;
1136 /* Calculate the session key and client credentials */
1138 state->creds = netlogon_creds_client_init(state,
1139 state->context->client.account,
1140 state->context->client.computer,
1141 state->context->client.type,
1142 &state->client_challenge,
1143 &state->server_challenge,
1144 &state->used_nt_hash,
1145 &state->client_credential,
1146 state->current_flags);
1147 if (tevent_req_nomem(state->creds, req)) {
1148 return;
1151 if (state->try_auth3) {
1152 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1153 state->binding_handle,
1154 state->srv_name_slash,
1155 state->context->client.account,
1156 state->context->client.type,
1157 state->context->client.computer,
1158 &state->client_credential,
1159 &state->server_credential,
1160 &state->creds->negotiate_flags,
1161 &state->rid);
1162 if (tevent_req_nomem(subreq, req)) {
1163 return;
1165 } else if (state->try_auth2) {
1166 state->rid = 0;
1168 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1169 state->binding_handle,
1170 state->srv_name_slash,
1171 state->context->client.account,
1172 state->context->client.type,
1173 state->context->client.computer,
1174 &state->client_credential,
1175 &state->server_credential,
1176 &state->creds->negotiate_flags);
1177 if (tevent_req_nomem(subreq, req)) {
1178 return;
1180 } else {
1181 state->rid = 0;
1183 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1184 state->binding_handle,
1185 state->srv_name_slash,
1186 state->context->client.account,
1187 state->context->client.type,
1188 state->context->client.computer,
1189 &state->client_credential,
1190 &state->server_credential);
1191 if (tevent_req_nomem(subreq, req)) {
1192 return;
1195 tevent_req_set_callback(subreq,
1196 netlogon_creds_cli_auth_srvauth_done,
1197 req);
1200 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1202 struct tevent_req *req =
1203 tevent_req_callback_data(subreq,
1204 struct tevent_req);
1205 struct netlogon_creds_cli_auth_state *state =
1206 tevent_req_data(req,
1207 struct netlogon_creds_cli_auth_state);
1208 NTSTATUS status;
1209 NTSTATUS result;
1210 bool ok;
1211 enum ndr_err_code ndr_err;
1212 DATA_BLOB blob;
1213 TDB_DATA data;
1214 uint32_t tmp_flags;
1216 if (state->try_auth3) {
1217 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1218 &result);
1219 TALLOC_FREE(subreq);
1220 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1221 state->try_auth3 = false;
1222 netlogon_creds_cli_auth_challenge_start(req);
1223 return;
1225 if (tevent_req_nterror(req, status)) {
1226 return;
1228 } else if (state->try_auth2) {
1229 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1230 &result);
1231 TALLOC_FREE(subreq);
1232 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1233 state->try_auth2 = false;
1234 if (state->require_auth2) {
1235 status = NT_STATUS_DOWNGRADE_DETECTED;
1236 tevent_req_nterror(req, status);
1237 return;
1239 netlogon_creds_cli_auth_challenge_start(req);
1240 return;
1242 if (tevent_req_nterror(req, status)) {
1243 return;
1245 } else {
1246 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1247 &result);
1248 TALLOC_FREE(subreq);
1249 if (tevent_req_nterror(req, status)) {
1250 return;
1254 if (!NT_STATUS_IS_OK(result) &&
1255 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1257 tevent_req_nterror(req, result);
1258 return;
1261 tmp_flags = state->creds->negotiate_flags;
1262 tmp_flags &= state->context->client.required_flags;
1263 if (tmp_flags != state->context->client.required_flags) {
1264 if (NT_STATUS_IS_OK(result)) {
1265 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1266 return;
1268 tevent_req_nterror(req, result);
1269 return;
1272 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1274 tmp_flags = state->context->client.proposed_flags;
1275 if ((state->current_flags == tmp_flags) &&
1276 (state->creds->negotiate_flags != tmp_flags))
1279 * lets retry with the negotiated flags
1281 state->current_flags = state->creds->negotiate_flags;
1282 netlogon_creds_cli_auth_challenge_start(req);
1283 return;
1286 if (!state->try_previous_nt_hash) {
1288 * we already retried, giving up...
1290 tevent_req_nterror(req, result);
1291 return;
1295 * lets retry with the old nt hash.
1297 state->try_previous_nt_hash = false;
1298 state->used_nt_hash = state->previous_nt_hash;
1299 state->current_flags = state->context->client.proposed_flags;
1300 netlogon_creds_cli_auth_challenge_start(req);
1301 return;
1304 ok = netlogon_creds_client_check(state->creds,
1305 &state->server_credential);
1306 if (!ok) {
1307 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1308 return;
1311 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1312 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1313 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1314 status = ndr_map_error2ntstatus(ndr_err);
1315 tevent_req_nterror(req, status);
1316 return;
1319 data.dptr = blob.data;
1320 data.dsize = blob.length;
1322 status = dbwrap_store(state->context->db.ctx,
1323 state->context->db.key_data,
1324 data, TDB_REPLACE);
1325 TALLOC_FREE(state->locked_state);
1326 if (tevent_req_nterror(req, status)) {
1327 return;
1330 tevent_req_done(req);
1333 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req)
1335 NTSTATUS status;
1337 if (tevent_req_is_nterror(req, &status)) {
1338 tevent_req_received(req);
1339 return status;
1342 tevent_req_received(req);
1343 return NT_STATUS_OK;
1346 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1347 struct dcerpc_binding_handle *b,
1348 struct samr_Password current_nt_hash,
1349 const struct samr_Password *previous_nt_hash)
1351 TALLOC_CTX *frame = talloc_stackframe();
1352 struct tevent_context *ev;
1353 struct tevent_req *req;
1354 NTSTATUS status = NT_STATUS_NO_MEMORY;
1356 ev = samba_tevent_context_init(frame);
1357 if (ev == NULL) {
1358 goto fail;
1360 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1361 current_nt_hash,
1362 previous_nt_hash);
1363 if (req == NULL) {
1364 goto fail;
1366 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1367 goto fail;
1369 status = netlogon_creds_cli_auth_recv(req);
1370 fail:
1371 TALLOC_FREE(frame);
1372 return status;
1375 struct netlogon_creds_cli_check_state {
1376 struct tevent_context *ev;
1377 struct netlogon_creds_cli_context *context;
1378 struct dcerpc_binding_handle *binding_handle;
1380 char *srv_name_slash;
1382 union netr_Capabilities caps;
1384 struct netlogon_creds_CredentialState *creds;
1385 struct netlogon_creds_CredentialState tmp_creds;
1386 struct netr_Authenticator req_auth;
1387 struct netr_Authenticator rep_auth;
1390 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1391 NTSTATUS status);
1392 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1394 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1395 struct tevent_context *ev,
1396 struct netlogon_creds_cli_context *context,
1397 struct dcerpc_binding_handle *b)
1399 struct tevent_req *req;
1400 struct netlogon_creds_cli_check_state *state;
1401 struct tevent_req *subreq;
1402 enum dcerpc_AuthType auth_type;
1403 enum dcerpc_AuthLevel auth_level;
1405 req = tevent_req_create(mem_ctx, &state,
1406 struct netlogon_creds_cli_check_state);
1407 if (req == NULL) {
1408 return NULL;
1411 state->ev = ev;
1412 state->context = context;
1413 state->binding_handle = b;
1415 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1416 context->server.computer);
1417 if (tevent_req_nomem(state->srv_name_slash, req)) {
1418 return tevent_req_post(req, ev);
1421 dcerpc_binding_handle_auth_info(state->binding_handle,
1422 &auth_type, &auth_level);
1424 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1425 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1426 return tevent_req_post(req, ev);
1429 switch (auth_level) {
1430 case DCERPC_AUTH_LEVEL_INTEGRITY:
1431 case DCERPC_AUTH_LEVEL_PRIVACY:
1432 break;
1433 default:
1434 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1435 return tevent_req_post(req, ev);
1438 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1439 state->context);
1440 if (tevent_req_nomem(subreq, req)) {
1441 return tevent_req_post(req, ev);
1444 tevent_req_set_callback(subreq,
1445 netlogon_creds_cli_check_locked,
1446 req);
1448 return req;
1451 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1452 NTSTATUS status)
1454 struct netlogon_creds_cli_check_state *state =
1455 tevent_req_data(req,
1456 struct netlogon_creds_cli_check_state);
1458 if (state->creds == NULL) {
1459 return;
1462 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1463 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1464 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1465 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1466 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1467 TALLOC_FREE(state->creds);
1468 return;
1471 netlogon_creds_cli_delete(state->context, &state->creds);
1474 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1476 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1478 struct tevent_req *req =
1479 tevent_req_callback_data(subreq,
1480 struct tevent_req);
1481 struct netlogon_creds_cli_check_state *state =
1482 tevent_req_data(req,
1483 struct netlogon_creds_cli_check_state);
1484 NTSTATUS status;
1486 status = netlogon_creds_cli_lock_recv(subreq, state,
1487 &state->creds);
1488 TALLOC_FREE(subreq);
1489 if (tevent_req_nterror(req, status)) {
1490 return;
1494 * we defer all callbacks in order to cleanup
1495 * the database record.
1497 tevent_req_defer_callback(req, state->ev);
1499 state->tmp_creds = *state->creds;
1500 netlogon_creds_client_authenticator(&state->tmp_creds,
1501 &state->req_auth);
1502 ZERO_STRUCT(state->rep_auth);
1504 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1505 state->binding_handle,
1506 state->srv_name_slash,
1507 state->context->client.computer,
1508 &state->req_auth,
1509 &state->rep_auth,
1511 &state->caps);
1512 if (tevent_req_nomem(subreq, req)) {
1513 status = NT_STATUS_NO_MEMORY;
1514 netlogon_creds_cli_check_cleanup(req, status);
1515 return;
1517 tevent_req_set_callback(subreq,
1518 netlogon_creds_cli_check_caps,
1519 req);
1522 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1524 struct tevent_req *req =
1525 tevent_req_callback_data(subreq,
1526 struct tevent_req);
1527 struct netlogon_creds_cli_check_state *state =
1528 tevent_req_data(req,
1529 struct netlogon_creds_cli_check_state);
1530 NTSTATUS status;
1531 NTSTATUS result;
1532 bool ok;
1534 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1535 &result);
1536 TALLOC_FREE(subreq);
1537 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1539 * Note that the negotiated flags are already checked
1540 * for our required flags after the ServerAuthenticate3/2 call.
1542 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1544 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1546 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1547 * already, we expect this to work!
1549 status = NT_STATUS_DOWNGRADE_DETECTED;
1550 tevent_req_nterror(req, status);
1551 netlogon_creds_cli_check_cleanup(req, status);
1552 return;
1555 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1557 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1558 * we expect this to work at least as far as the
1559 * NOT_SUPPORTED error handled below!
1561 * NT 4.0 and Old Samba servers are not
1562 * allowed without "require strong key = no"
1564 status = NT_STATUS_DOWNGRADE_DETECTED;
1565 tevent_req_nterror(req, status);
1566 netlogon_creds_cli_check_cleanup(req, status);
1567 return;
1571 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1572 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1573 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1575 * This is needed against NT 4.0 and old Samba servers.
1577 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1578 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1579 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1580 * with the next request as the sequence number processing
1581 * gets out of sync.
1583 netlogon_creds_cli_check_cleanup(req, status);
1584 tevent_req_done(req);
1585 return;
1587 if (tevent_req_nterror(req, status)) {
1588 netlogon_creds_cli_check_cleanup(req, status);
1589 return;
1592 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1594 * Note that the negotiated flags are already checked
1595 * for our required flags after the ServerAuthenticate3/2 call.
1597 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1599 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1601 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1602 * already, we expect this to work!
1604 status = NT_STATUS_DOWNGRADE_DETECTED;
1605 tevent_req_nterror(req, status);
1606 netlogon_creds_cli_check_cleanup(req, status);
1607 return;
1611 * This is ok, the server does not support
1612 * NETLOGON_NEG_SUPPORTS_AES.
1614 * netr_LogonGetCapabilities() was
1615 * netr_LogonDummyRoutine1() before
1616 * NETLOGON_NEG_SUPPORTS_AES was invented.
1618 netlogon_creds_cli_check_cleanup(req, result);
1619 tevent_req_done(req);
1620 return;
1623 ok = netlogon_creds_client_check(&state->tmp_creds,
1624 &state->rep_auth.cred);
1625 if (!ok) {
1626 status = NT_STATUS_ACCESS_DENIED;
1627 tevent_req_nterror(req, status);
1628 netlogon_creds_cli_check_cleanup(req, status);
1629 return;
1632 if (tevent_req_nterror(req, result)) {
1633 netlogon_creds_cli_check_cleanup(req, result);
1634 return;
1637 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1638 status = NT_STATUS_DOWNGRADE_DETECTED;
1639 tevent_req_nterror(req, status);
1640 netlogon_creds_cli_check_cleanup(req, status);
1641 return;
1645 * This is the key check that makes this check secure. If we
1646 * get OK here (rather than NOT_SUPPORTED), then the server
1647 * did support AES. If the server only proposed STRONG_KEYS
1648 * and not AES, then it should have failed with
1649 * NOT_IMPLEMENTED. We always send AES as a client, so the
1650 * server should always have returned it.
1652 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1653 status = NT_STATUS_DOWNGRADE_DETECTED;
1654 tevent_req_nterror(req, status);
1655 netlogon_creds_cli_check_cleanup(req, status);
1656 return;
1659 *state->creds = state->tmp_creds;
1660 status = netlogon_creds_cli_store(state->context,
1661 &state->creds);
1662 netlogon_creds_cli_check_cleanup(req, status);
1663 if (tevent_req_nterror(req, status)) {
1664 return;
1667 tevent_req_done(req);
1670 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1672 NTSTATUS status;
1674 if (tevent_req_is_nterror(req, &status)) {
1675 netlogon_creds_cli_check_cleanup(req, status);
1676 tevent_req_received(req);
1677 return status;
1680 tevent_req_received(req);
1681 return NT_STATUS_OK;
1684 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1685 struct dcerpc_binding_handle *b)
1687 TALLOC_CTX *frame = talloc_stackframe();
1688 struct tevent_context *ev;
1689 struct tevent_req *req;
1690 NTSTATUS status = NT_STATUS_NO_MEMORY;
1692 ev = samba_tevent_context_init(frame);
1693 if (ev == NULL) {
1694 goto fail;
1696 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1697 if (req == NULL) {
1698 goto fail;
1700 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1701 goto fail;
1703 status = netlogon_creds_cli_check_recv(req);
1704 fail:
1705 TALLOC_FREE(frame);
1706 return status;
1709 struct netlogon_creds_cli_ServerPasswordSet_state {
1710 struct tevent_context *ev;
1711 struct netlogon_creds_cli_context *context;
1712 struct dcerpc_binding_handle *binding_handle;
1713 uint32_t old_timeout;
1715 char *srv_name_slash;
1716 enum dcerpc_AuthType auth_type;
1717 enum dcerpc_AuthLevel auth_level;
1719 struct samr_CryptPassword samr_crypt_password;
1720 struct netr_CryptPassword netr_crypt_password;
1721 struct samr_Password samr_password;
1723 struct netlogon_creds_CredentialState *creds;
1724 struct netlogon_creds_CredentialState tmp_creds;
1725 struct netr_Authenticator req_auth;
1726 struct netr_Authenticator rep_auth;
1729 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1730 NTSTATUS status);
1731 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1733 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1734 struct tevent_context *ev,
1735 struct netlogon_creds_cli_context *context,
1736 struct dcerpc_binding_handle *b,
1737 const char *new_password,
1738 const uint32_t *new_version)
1740 struct tevent_req *req;
1741 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1742 struct tevent_req *subreq;
1743 bool ok;
1745 req = tevent_req_create(mem_ctx, &state,
1746 struct netlogon_creds_cli_ServerPasswordSet_state);
1747 if (req == NULL) {
1748 return NULL;
1751 state->ev = ev;
1752 state->context = context;
1753 state->binding_handle = b;
1756 * netr_ServerPasswordSet
1758 ok = E_md4hash(new_password, state->samr_password.hash);
1759 if (!ok) {
1760 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1761 return tevent_req_post(req, ev);
1765 * netr_ServerPasswordSet2
1767 ok = encode_pw_buffer(state->samr_crypt_password.data,
1768 new_password, STR_UNICODE);
1769 if (!ok) {
1770 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1771 return tevent_req_post(req, ev);
1774 if (new_version != NULL) {
1775 struct NL_PASSWORD_VERSION version;
1776 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1777 uint32_t ofs = 512 - len;
1778 uint8_t *p;
1780 if (len > 500) {
1781 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1782 return tevent_req_post(req, ev);
1784 ofs -= 12;
1786 version.ReservedField = 0;
1787 version.PasswordVersionNumber = *new_version;
1788 version.PasswordVersionPresent =
1789 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1791 p = state->samr_crypt_password.data + ofs;
1792 SIVAL(p, 0, version.ReservedField);
1793 SIVAL(p, 4, version.PasswordVersionNumber);
1794 SIVAL(p, 8, version.PasswordVersionPresent);
1797 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1798 context->server.computer);
1799 if (tevent_req_nomem(state->srv_name_slash, req)) {
1800 return tevent_req_post(req, ev);
1803 dcerpc_binding_handle_auth_info(state->binding_handle,
1804 &state->auth_type,
1805 &state->auth_level);
1807 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1808 state->context);
1809 if (tevent_req_nomem(subreq, req)) {
1810 return tevent_req_post(req, ev);
1813 tevent_req_set_callback(subreq,
1814 netlogon_creds_cli_ServerPasswordSet_locked,
1815 req);
1817 return req;
1820 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1821 NTSTATUS status)
1823 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1824 tevent_req_data(req,
1825 struct netlogon_creds_cli_ServerPasswordSet_state);
1827 if (state->creds == NULL) {
1828 return;
1831 dcerpc_binding_handle_set_timeout(state->binding_handle,
1832 state->old_timeout);
1834 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1835 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1836 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1837 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1838 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1839 TALLOC_FREE(state->creds);
1840 return;
1843 netlogon_creds_cli_delete(state->context, &state->creds);
1846 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1848 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1850 struct tevent_req *req =
1851 tevent_req_callback_data(subreq,
1852 struct tevent_req);
1853 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1854 tevent_req_data(req,
1855 struct netlogon_creds_cli_ServerPasswordSet_state);
1856 NTSTATUS status;
1858 status = netlogon_creds_cli_lock_recv(subreq, state,
1859 &state->creds);
1860 TALLOC_FREE(subreq);
1861 if (tevent_req_nterror(req, status)) {
1862 return;
1865 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1866 switch (state->auth_level) {
1867 case DCERPC_AUTH_LEVEL_INTEGRITY:
1868 case DCERPC_AUTH_LEVEL_PRIVACY:
1869 break;
1870 default:
1871 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1872 return;
1874 } else {
1875 uint32_t tmp = state->creds->negotiate_flags;
1877 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1879 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1880 * it should be used, which means
1881 * we had a chance to verify no downgrade
1882 * happened.
1884 * This relies on netlogon_creds_cli_check*
1885 * being called before, as first request after
1886 * the DCERPC bind.
1888 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1889 return;
1893 state->old_timeout = dcerpc_binding_handle_set_timeout(
1894 state->binding_handle, 600000);
1897 * we defer all callbacks in order to cleanup
1898 * the database record.
1900 tevent_req_defer_callback(req, state->ev);
1902 state->tmp_creds = *state->creds;
1903 netlogon_creds_client_authenticator(&state->tmp_creds,
1904 &state->req_auth);
1905 ZERO_STRUCT(state->rep_auth);
1907 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1909 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1910 netlogon_creds_aes_encrypt(&state->tmp_creds,
1911 state->samr_crypt_password.data,
1912 516);
1913 } else {
1914 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1915 state->samr_crypt_password.data,
1916 516);
1919 memcpy(state->netr_crypt_password.data,
1920 state->samr_crypt_password.data, 512);
1921 state->netr_crypt_password.length =
1922 IVAL(state->samr_crypt_password.data, 512);
1924 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1925 state->binding_handle,
1926 state->srv_name_slash,
1927 state->tmp_creds.account_name,
1928 state->tmp_creds.secure_channel_type,
1929 state->tmp_creds.computer_name,
1930 &state->req_auth,
1931 &state->rep_auth,
1932 &state->netr_crypt_password);
1933 if (tevent_req_nomem(subreq, req)) {
1934 status = NT_STATUS_NO_MEMORY;
1935 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1936 return;
1938 } else {
1939 netlogon_creds_des_encrypt(&state->tmp_creds,
1940 &state->samr_password);
1942 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1943 state->binding_handle,
1944 state->srv_name_slash,
1945 state->tmp_creds.account_name,
1946 state->tmp_creds.secure_channel_type,
1947 state->tmp_creds.computer_name,
1948 &state->req_auth,
1949 &state->rep_auth,
1950 &state->samr_password);
1951 if (tevent_req_nomem(subreq, req)) {
1952 status = NT_STATUS_NO_MEMORY;
1953 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1954 return;
1958 tevent_req_set_callback(subreq,
1959 netlogon_creds_cli_ServerPasswordSet_done,
1960 req);
1963 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1965 struct tevent_req *req =
1966 tevent_req_callback_data(subreq,
1967 struct tevent_req);
1968 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1969 tevent_req_data(req,
1970 struct netlogon_creds_cli_ServerPasswordSet_state);
1971 NTSTATUS status;
1972 NTSTATUS result;
1973 bool ok;
1975 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1976 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1977 &result);
1978 TALLOC_FREE(subreq);
1979 if (tevent_req_nterror(req, status)) {
1980 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1981 return;
1983 } else {
1984 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1985 &result);
1986 TALLOC_FREE(subreq);
1987 if (tevent_req_nterror(req, status)) {
1988 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1989 return;
1993 ok = netlogon_creds_client_check(&state->tmp_creds,
1994 &state->rep_auth.cred);
1995 if (!ok) {
1996 status = NT_STATUS_ACCESS_DENIED;
1997 tevent_req_nterror(req, status);
1998 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1999 return;
2002 if (tevent_req_nterror(req, result)) {
2003 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2004 return;
2007 dcerpc_binding_handle_set_timeout(state->binding_handle,
2008 state->old_timeout);
2010 *state->creds = state->tmp_creds;
2011 status = netlogon_creds_cli_store(state->context,
2012 &state->creds);
2013 if (tevent_req_nterror(req, status)) {
2014 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2015 return;
2018 tevent_req_done(req);
2021 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2023 NTSTATUS status;
2025 if (tevent_req_is_nterror(req, &status)) {
2026 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2027 tevent_req_received(req);
2028 return status;
2031 tevent_req_received(req);
2032 return NT_STATUS_OK;
2035 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2036 struct netlogon_creds_cli_context *context,
2037 struct dcerpc_binding_handle *b,
2038 const char *new_password,
2039 const uint32_t *new_version)
2041 TALLOC_CTX *frame = talloc_stackframe();
2042 struct tevent_context *ev;
2043 struct tevent_req *req;
2044 NTSTATUS status = NT_STATUS_NO_MEMORY;
2046 ev = samba_tevent_context_init(frame);
2047 if (ev == NULL) {
2048 goto fail;
2050 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2051 new_password,
2052 new_version);
2053 if (req == NULL) {
2054 goto fail;
2056 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2057 goto fail;
2059 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2060 fail:
2061 TALLOC_FREE(frame);
2062 return status;
2065 struct netlogon_creds_cli_LogonSamLogon_state {
2066 struct tevent_context *ev;
2067 struct netlogon_creds_cli_context *context;
2068 struct dcerpc_binding_handle *binding_handle;
2070 char *srv_name_slash;
2072 enum netr_LogonInfoClass logon_level;
2073 const union netr_LogonLevel *const_logon;
2074 union netr_LogonLevel *logon;
2075 uint32_t flags;
2077 uint16_t validation_level;
2078 union netr_Validation *validation;
2079 uint8_t authoritative;
2082 * do we need encryption at the application layer?
2084 bool user_encrypt;
2085 bool try_logon_ex;
2086 bool try_validation6;
2089 * the read only credentials before we started the operation
2090 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2092 struct netlogon_creds_CredentialState *ro_creds;
2095 * The (locked) credentials used for the credential chain
2096 * used for netr_LogonSamLogonWithFlags() or
2097 * netr_LogonSamLogonWith().
2099 struct netlogon_creds_CredentialState *lk_creds;
2102 * While we have locked the global credentials (lk_creds above)
2103 * we operate an a temporary copy, because a server
2104 * may not support netr_LogonSamLogonWithFlags() and
2105 * didn't process our netr_Authenticator, so we need to
2106 * restart from lk_creds.
2108 struct netlogon_creds_CredentialState tmp_creds;
2109 struct netr_Authenticator req_auth;
2110 struct netr_Authenticator rep_auth;
2113 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2114 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2115 NTSTATUS status);
2117 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2118 struct tevent_context *ev,
2119 struct netlogon_creds_cli_context *context,
2120 struct dcerpc_binding_handle *b,
2121 enum netr_LogonInfoClass logon_level,
2122 const union netr_LogonLevel *logon,
2123 uint32_t flags)
2125 struct tevent_req *req;
2126 struct netlogon_creds_cli_LogonSamLogon_state *state;
2128 req = tevent_req_create(mem_ctx, &state,
2129 struct netlogon_creds_cli_LogonSamLogon_state);
2130 if (req == NULL) {
2131 return NULL;
2134 state->ev = ev;
2135 state->context = context;
2136 state->binding_handle = b;
2138 state->logon_level = logon_level;
2139 state->const_logon = logon;
2140 state->flags = flags;
2142 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2143 context->server.computer);
2144 if (tevent_req_nomem(state->srv_name_slash, req)) {
2145 return tevent_req_post(req, ev);
2148 switch (logon_level) {
2149 case NetlogonInteractiveInformation:
2150 case NetlogonInteractiveTransitiveInformation:
2151 case NetlogonServiceInformation:
2152 case NetlogonServiceTransitiveInformation:
2153 case NetlogonGenericInformation:
2154 state->user_encrypt = true;
2155 break;
2157 case NetlogonNetworkInformation:
2158 case NetlogonNetworkTransitiveInformation:
2159 break;
2162 state->validation = talloc_zero(state, union netr_Validation);
2163 if (tevent_req_nomem(state->validation, req)) {
2164 return tevent_req_post(req, ev);
2167 netlogon_creds_cli_LogonSamLogon_start(req);
2168 if (!tevent_req_is_in_progress(req)) {
2169 return tevent_req_post(req, ev);
2173 * we defer all callbacks in order to cleanup
2174 * the database record.
2176 tevent_req_defer_callback(req, state->ev);
2177 return req;
2180 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2181 NTSTATUS status)
2183 struct netlogon_creds_cli_LogonSamLogon_state *state =
2184 tevent_req_data(req,
2185 struct netlogon_creds_cli_LogonSamLogon_state);
2187 if (state->lk_creds == NULL) {
2188 return;
2191 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2193 * This is a hack to recover from a bug in old
2194 * Samba servers, when LogonSamLogonEx() fails:
2196 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2198 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2200 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2201 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2202 * If the sign/seal check fails.
2204 * In that case we need to cleanup the netlogon session.
2206 * It's the job of the caller to disconnect the current
2207 * connection, if netlogon_creds_cli_LogonSamLogon()
2208 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2210 if (!state->context->server.try_logon_with) {
2211 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2215 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2216 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2217 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2218 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2219 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2220 TALLOC_FREE(state->lk_creds);
2221 return;
2224 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2227 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2229 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2231 struct netlogon_creds_cli_LogonSamLogon_state *state =
2232 tevent_req_data(req,
2233 struct netlogon_creds_cli_LogonSamLogon_state);
2234 struct tevent_req *subreq;
2235 NTSTATUS status;
2236 enum dcerpc_AuthType auth_type;
2237 enum dcerpc_AuthLevel auth_level;
2239 TALLOC_FREE(state->ro_creds);
2240 TALLOC_FREE(state->logon);
2241 ZERO_STRUCTP(state->validation);
2243 dcerpc_binding_handle_auth_info(state->binding_handle,
2244 &auth_type, &auth_level);
2246 state->try_logon_ex = state->context->server.try_logon_ex;
2247 state->try_validation6 = state->context->server.try_validation6;
2249 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2250 state->try_logon_ex = false;
2253 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2254 state->try_validation6 = false;
2257 if (state->try_logon_ex) {
2258 if (state->try_validation6) {
2259 state->validation_level = 6;
2260 } else {
2261 state->validation_level = 3;
2262 state->user_encrypt = true;
2265 state->logon = netlogon_creds_shallow_copy_logon(state,
2266 state->logon_level,
2267 state->const_logon);
2268 if (tevent_req_nomem(state->logon, req)) {
2269 status = NT_STATUS_NO_MEMORY;
2270 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2271 return;
2274 if (state->user_encrypt) {
2275 status = netlogon_creds_cli_get(state->context,
2276 state,
2277 &state->ro_creds);
2278 if (!NT_STATUS_IS_OK(status)) {
2279 status = NT_STATUS_ACCESS_DENIED;
2280 tevent_req_nterror(req, status);
2281 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2282 return;
2285 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2286 state->logon_level,
2287 state->logon);
2290 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2291 state->binding_handle,
2292 state->srv_name_slash,
2293 state->context->client.computer,
2294 state->logon_level,
2295 state->logon,
2296 state->validation_level,
2297 state->validation,
2298 &state->authoritative,
2299 &state->flags);
2300 if (tevent_req_nomem(subreq, req)) {
2301 status = NT_STATUS_NO_MEMORY;
2302 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2303 return;
2305 tevent_req_set_callback(subreq,
2306 netlogon_creds_cli_LogonSamLogon_done,
2307 req);
2308 return;
2311 if (state->lk_creds == NULL) {
2312 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2313 state->context);
2314 if (tevent_req_nomem(subreq, req)) {
2315 status = NT_STATUS_NO_MEMORY;
2316 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2317 return;
2319 tevent_req_set_callback(subreq,
2320 netlogon_creds_cli_LogonSamLogon_done,
2321 req);
2322 return;
2325 state->tmp_creds = *state->lk_creds;
2326 netlogon_creds_client_authenticator(&state->tmp_creds,
2327 &state->req_auth);
2328 ZERO_STRUCT(state->rep_auth);
2330 state->logon = netlogon_creds_shallow_copy_logon(state,
2331 state->logon_level,
2332 state->const_logon);
2333 if (tevent_req_nomem(state->logon, req)) {
2334 status = NT_STATUS_NO_MEMORY;
2335 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2336 return;
2339 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2340 state->logon_level,
2341 state->logon);
2343 state->validation_level = 3;
2345 if (state->context->server.try_logon_with) {
2346 subreq = dcerpc_netr_LogonSamLogonWithFlags_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 &state->flags);
2358 if (tevent_req_nomem(subreq, req)) {
2359 status = NT_STATUS_NO_MEMORY;
2360 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2361 return;
2363 } else {
2364 state->flags = 0;
2366 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2367 state->binding_handle,
2368 state->srv_name_slash,
2369 state->context->client.computer,
2370 &state->req_auth,
2371 &state->rep_auth,
2372 state->logon_level,
2373 state->logon,
2374 state->validation_level,
2375 state->validation,
2376 &state->authoritative);
2377 if (tevent_req_nomem(subreq, req)) {
2378 status = NT_STATUS_NO_MEMORY;
2379 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2380 return;
2384 tevent_req_set_callback(subreq,
2385 netlogon_creds_cli_LogonSamLogon_done,
2386 req);
2389 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2391 struct tevent_req *req =
2392 tevent_req_callback_data(subreq,
2393 struct tevent_req);
2394 struct netlogon_creds_cli_LogonSamLogon_state *state =
2395 tevent_req_data(req,
2396 struct netlogon_creds_cli_LogonSamLogon_state);
2397 NTSTATUS status;
2398 NTSTATUS result;
2399 bool ok;
2401 if (state->try_logon_ex) {
2402 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2403 state->validation,
2404 &result);
2405 TALLOC_FREE(subreq);
2406 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2407 state->context->server.try_validation6 = false;
2408 state->context->server.try_logon_ex = false;
2409 netlogon_creds_cli_LogonSamLogon_start(req);
2410 return;
2412 if (tevent_req_nterror(req, status)) {
2413 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2414 return;
2417 if ((state->validation_level == 6) &&
2418 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2419 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2420 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2422 state->context->server.try_validation6 = false;
2423 netlogon_creds_cli_LogonSamLogon_start(req);
2424 return;
2427 if (tevent_req_nterror(req, result)) {
2428 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2429 return;
2432 if (state->ro_creds == NULL) {
2433 tevent_req_done(req);
2434 return;
2437 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2438 if (!ok) {
2440 * We got a race, lets retry with on authenticator
2441 * protection.
2443 * netlogon_creds_cli_LogonSamLogon_start()
2444 * will TALLOC_FREE(state->ro_creds);
2446 state->try_logon_ex = false;
2447 netlogon_creds_cli_LogonSamLogon_start(req);
2448 return;
2451 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2452 state->validation_level,
2453 state->validation);
2455 tevent_req_done(req);
2456 return;
2459 if (state->lk_creds == NULL) {
2460 status = netlogon_creds_cli_lock_recv(subreq, state,
2461 &state->lk_creds);
2462 TALLOC_FREE(subreq);
2463 if (tevent_req_nterror(req, status)) {
2464 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2465 return;
2468 netlogon_creds_cli_LogonSamLogon_start(req);
2469 return;
2472 if (state->context->server.try_logon_with) {
2473 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2474 state->validation,
2475 &result);
2476 TALLOC_FREE(subreq);
2477 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2478 state->context->server.try_logon_with = false;
2479 netlogon_creds_cli_LogonSamLogon_start(req);
2480 return;
2482 if (tevent_req_nterror(req, status)) {
2483 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2484 return;
2486 } else {
2487 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2488 state->validation,
2489 &result);
2490 TALLOC_FREE(subreq);
2491 if (tevent_req_nterror(req, status)) {
2492 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2493 return;
2497 ok = netlogon_creds_client_check(&state->tmp_creds,
2498 &state->rep_auth.cred);
2499 if (!ok) {
2500 status = NT_STATUS_ACCESS_DENIED;
2501 tevent_req_nterror(req, status);
2502 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2503 return;
2506 *state->lk_creds = state->tmp_creds;
2507 status = netlogon_creds_cli_store(state->context,
2508 &state->lk_creds);
2509 if (tevent_req_nterror(req, status)) {
2510 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2511 return;
2514 if (tevent_req_nterror(req, result)) {
2515 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2516 return;
2519 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2520 state->validation_level,
2521 state->validation);
2523 tevent_req_done(req);
2526 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2527 TALLOC_CTX *mem_ctx,
2528 uint16_t *validation_level,
2529 union netr_Validation **validation,
2530 uint8_t *authoritative,
2531 uint32_t *flags)
2533 struct netlogon_creds_cli_LogonSamLogon_state *state =
2534 tevent_req_data(req,
2535 struct netlogon_creds_cli_LogonSamLogon_state);
2536 NTSTATUS status;
2538 /* authoritative is also returned on error */
2539 *authoritative = state->authoritative;
2541 if (tevent_req_is_nterror(req, &status)) {
2542 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2543 tevent_req_received(req);
2544 return status;
2547 *validation_level = state->validation_level;
2548 *validation = talloc_move(mem_ctx, &state->validation);
2549 *flags = state->flags;
2551 tevent_req_received(req);
2552 return NT_STATUS_OK;
2555 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2556 struct netlogon_creds_cli_context *context,
2557 struct dcerpc_binding_handle *b,
2558 enum netr_LogonInfoClass logon_level,
2559 const union netr_LogonLevel *logon,
2560 TALLOC_CTX *mem_ctx,
2561 uint16_t *validation_level,
2562 union netr_Validation **validation,
2563 uint8_t *authoritative,
2564 uint32_t *flags)
2566 TALLOC_CTX *frame = talloc_stackframe();
2567 struct tevent_context *ev;
2568 struct tevent_req *req;
2569 NTSTATUS status = NT_STATUS_NO_MEMORY;
2571 ev = samba_tevent_context_init(frame);
2572 if (ev == NULL) {
2573 goto fail;
2575 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2576 logon_level, logon,
2577 *flags);
2578 if (req == NULL) {
2579 goto fail;
2581 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2582 goto fail;
2584 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2585 validation_level,
2586 validation,
2587 authoritative,
2588 flags);
2589 fail:
2590 TALLOC_FREE(frame);
2591 return status;
2594 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2595 struct tevent_context *ev;
2596 struct netlogon_creds_cli_context *context;
2597 struct dcerpc_binding_handle *binding_handle;
2599 char *srv_name_slash;
2600 enum dcerpc_AuthType auth_type;
2601 enum dcerpc_AuthLevel auth_level;
2603 const char *site_name;
2604 uint32_t dns_ttl;
2605 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2607 struct netlogon_creds_CredentialState *creds;
2608 struct netlogon_creds_CredentialState tmp_creds;
2609 struct netr_Authenticator req_auth;
2610 struct netr_Authenticator rep_auth;
2613 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2614 NTSTATUS status);
2615 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2617 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2618 struct tevent_context *ev,
2619 struct netlogon_creds_cli_context *context,
2620 struct dcerpc_binding_handle *b,
2621 const char *site_name,
2622 uint32_t dns_ttl,
2623 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2625 struct tevent_req *req;
2626 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2627 struct tevent_req *subreq;
2629 req = tevent_req_create(mem_ctx, &state,
2630 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2631 if (req == NULL) {
2632 return NULL;
2635 state->ev = ev;
2636 state->context = context;
2637 state->binding_handle = b;
2639 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2640 context->server.computer);
2641 if (tevent_req_nomem(state->srv_name_slash, req)) {
2642 return tevent_req_post(req, ev);
2645 state->site_name = site_name;
2646 state->dns_ttl = dns_ttl;
2647 state->dns_names = dns_names;
2649 dcerpc_binding_handle_auth_info(state->binding_handle,
2650 &state->auth_type,
2651 &state->auth_level);
2653 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2654 state->context);
2655 if (tevent_req_nomem(subreq, req)) {
2656 return tevent_req_post(req, ev);
2659 tevent_req_set_callback(subreq,
2660 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2661 req);
2663 return req;
2666 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2667 NTSTATUS status)
2669 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2670 tevent_req_data(req,
2671 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2673 if (state->creds == NULL) {
2674 return;
2677 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2678 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2679 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2680 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2681 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2682 TALLOC_FREE(state->creds);
2683 return;
2686 netlogon_creds_cli_delete(state->context, &state->creds);
2689 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2691 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2693 struct tevent_req *req =
2694 tevent_req_callback_data(subreq,
2695 struct tevent_req);
2696 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2697 tevent_req_data(req,
2698 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2699 NTSTATUS status;
2701 status = netlogon_creds_cli_lock_recv(subreq, state,
2702 &state->creds);
2703 TALLOC_FREE(subreq);
2704 if (tevent_req_nterror(req, status)) {
2705 return;
2708 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2709 switch (state->auth_level) {
2710 case DCERPC_AUTH_LEVEL_INTEGRITY:
2711 case DCERPC_AUTH_LEVEL_PRIVACY:
2712 break;
2713 default:
2714 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2715 return;
2717 } else {
2718 uint32_t tmp = state->creds->negotiate_flags;
2720 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2722 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2723 * it should be used, which means
2724 * we had a chance to verify no downgrade
2725 * happened.
2727 * This relies on netlogon_creds_cli_check*
2728 * being called before, as first request after
2729 * the DCERPC bind.
2731 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2732 return;
2737 * we defer all callbacks in order to cleanup
2738 * the database record.
2740 tevent_req_defer_callback(req, state->ev);
2742 state->tmp_creds = *state->creds;
2743 netlogon_creds_client_authenticator(&state->tmp_creds,
2744 &state->req_auth);
2745 ZERO_STRUCT(state->rep_auth);
2747 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2748 state->binding_handle,
2749 state->srv_name_slash,
2750 state->tmp_creds.computer_name,
2751 &state->req_auth,
2752 &state->rep_auth,
2753 state->site_name,
2754 state->dns_ttl,
2755 state->dns_names);
2756 if (tevent_req_nomem(subreq, req)) {
2757 status = NT_STATUS_NO_MEMORY;
2758 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2759 return;
2762 tevent_req_set_callback(subreq,
2763 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2764 req);
2767 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2769 struct tevent_req *req =
2770 tevent_req_callback_data(subreq,
2771 struct tevent_req);
2772 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2773 tevent_req_data(req,
2774 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2775 NTSTATUS status;
2776 NTSTATUS result;
2777 bool ok;
2780 * We use state->dns_names as the memory context, as this is
2781 * the only in/out variable and it has been overwritten by the
2782 * out parameter from the server.
2784 * We need to preserve the return value until the caller can use it.
2786 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2787 &result);
2788 TALLOC_FREE(subreq);
2789 if (tevent_req_nterror(req, status)) {
2790 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2791 return;
2794 ok = netlogon_creds_client_check(&state->tmp_creds,
2795 &state->rep_auth.cred);
2796 if (!ok) {
2797 status = NT_STATUS_ACCESS_DENIED;
2798 tevent_req_nterror(req, status);
2799 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2800 return;
2803 if (tevent_req_nterror(req, result)) {
2804 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2805 return;
2808 *state->creds = state->tmp_creds;
2809 status = netlogon_creds_cli_store(state->context,
2810 &state->creds);
2811 if (tevent_req_nterror(req, status)) {
2812 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2813 return;
2816 tevent_req_done(req);
2819 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2821 NTSTATUS status;
2823 if (tevent_req_is_nterror(req, &status)) {
2824 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2825 tevent_req_received(req);
2826 return status;
2829 tevent_req_received(req);
2830 return NT_STATUS_OK;
2833 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2834 struct netlogon_creds_cli_context *context,
2835 struct dcerpc_binding_handle *b,
2836 const char *site_name,
2837 uint32_t dns_ttl,
2838 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2840 TALLOC_CTX *frame = talloc_stackframe();
2841 struct tevent_context *ev;
2842 struct tevent_req *req;
2843 NTSTATUS status = NT_STATUS_NO_MEMORY;
2845 ev = samba_tevent_context_init(frame);
2846 if (ev == NULL) {
2847 goto fail;
2849 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2850 site_name,
2851 dns_ttl,
2852 dns_names);
2853 if (req == NULL) {
2854 goto fail;
2856 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2857 goto fail;
2859 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2860 fail:
2861 TALLOC_FREE(frame);
2862 return status;
2865 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2866 struct tevent_context *ev;
2867 struct netlogon_creds_cli_context *context;
2868 struct dcerpc_binding_handle *binding_handle;
2870 char *srv_name_slash;
2871 enum dcerpc_AuthType auth_type;
2872 enum dcerpc_AuthLevel auth_level;
2874 struct samr_Password new_owf_password;
2875 struct samr_Password old_owf_password;
2876 struct netr_TrustInfo *trust_info;
2878 struct netlogon_creds_CredentialState *creds;
2879 struct netlogon_creds_CredentialState tmp_creds;
2880 struct netr_Authenticator req_auth;
2881 struct netr_Authenticator rep_auth;
2884 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2885 NTSTATUS status);
2886 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2888 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2889 struct tevent_context *ev,
2890 struct netlogon_creds_cli_context *context,
2891 struct dcerpc_binding_handle *b)
2893 struct tevent_req *req;
2894 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2895 struct tevent_req *subreq;
2897 req = tevent_req_create(mem_ctx, &state,
2898 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2899 if (req == NULL) {
2900 return NULL;
2903 state->ev = ev;
2904 state->context = context;
2905 state->binding_handle = b;
2907 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2908 context->server.computer);
2909 if (tevent_req_nomem(state->srv_name_slash, req)) {
2910 return tevent_req_post(req, ev);
2913 dcerpc_binding_handle_auth_info(state->binding_handle,
2914 &state->auth_type,
2915 &state->auth_level);
2917 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2918 state->context);
2919 if (tevent_req_nomem(subreq, req)) {
2920 return tevent_req_post(req, ev);
2923 tevent_req_set_callback(subreq,
2924 netlogon_creds_cli_ServerGetTrustInfo_locked,
2925 req);
2927 return req;
2930 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2931 NTSTATUS status)
2933 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2934 tevent_req_data(req,
2935 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2937 if (state->creds == NULL) {
2938 return;
2941 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2942 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2943 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2944 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2945 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2946 TALLOC_FREE(state->creds);
2947 return;
2950 netlogon_creds_cli_delete(state->context, &state->creds);
2953 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2955 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2957 struct tevent_req *req =
2958 tevent_req_callback_data(subreq,
2959 struct tevent_req);
2960 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2961 tevent_req_data(req,
2962 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2963 NTSTATUS status;
2965 status = netlogon_creds_cli_lock_recv(subreq, state,
2966 &state->creds);
2967 TALLOC_FREE(subreq);
2968 if (tevent_req_nterror(req, status)) {
2969 return;
2972 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2973 switch (state->auth_level) {
2974 case DCERPC_AUTH_LEVEL_PRIVACY:
2975 break;
2976 default:
2977 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2978 return;
2980 } else {
2981 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2982 return;
2986 * we defer all callbacks in order to cleanup
2987 * the database record.
2989 tevent_req_defer_callback(req, state->ev);
2991 state->tmp_creds = *state->creds;
2992 netlogon_creds_client_authenticator(&state->tmp_creds,
2993 &state->req_auth);
2994 ZERO_STRUCT(state->rep_auth);
2996 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
2997 state->binding_handle,
2998 state->srv_name_slash,
2999 state->tmp_creds.account_name,
3000 state->tmp_creds.secure_channel_type,
3001 state->tmp_creds.computer_name,
3002 &state->req_auth,
3003 &state->rep_auth,
3004 &state->new_owf_password,
3005 &state->old_owf_password,
3006 &state->trust_info);
3007 if (tevent_req_nomem(subreq, req)) {
3008 status = NT_STATUS_NO_MEMORY;
3009 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3010 return;
3013 tevent_req_set_callback(subreq,
3014 netlogon_creds_cli_ServerGetTrustInfo_done,
3015 req);
3018 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3020 struct tevent_req *req =
3021 tevent_req_callback_data(subreq,
3022 struct tevent_req);
3023 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3024 tevent_req_data(req,
3025 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3026 NTSTATUS status;
3027 NTSTATUS result;
3028 const struct samr_Password zero = {};
3029 int cmp;
3030 bool ok;
3033 * We use state->dns_names as the memory context, as this is
3034 * the only in/out variable and it has been overwritten by the
3035 * out parameter from the server.
3037 * We need to preserve the return value until the caller can use it.
3039 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3040 TALLOC_FREE(subreq);
3041 if (tevent_req_nterror(req, status)) {
3042 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3043 return;
3046 ok = netlogon_creds_client_check(&state->tmp_creds,
3047 &state->rep_auth.cred);
3048 if (!ok) {
3049 status = NT_STATUS_ACCESS_DENIED;
3050 tevent_req_nterror(req, status);
3051 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3052 return;
3055 if (tevent_req_nterror(req, result)) {
3056 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3057 return;
3060 cmp = memcmp(state->new_owf_password.hash,
3061 zero.hash, sizeof(zero.hash));
3062 if (cmp != 0) {
3063 netlogon_creds_des_decrypt(&state->tmp_creds,
3064 &state->new_owf_password);
3066 cmp = memcmp(state->old_owf_password.hash,
3067 zero.hash, sizeof(zero.hash));
3068 if (cmp != 0) {
3069 netlogon_creds_des_decrypt(&state->tmp_creds,
3070 &state->old_owf_password);
3073 *state->creds = state->tmp_creds;
3074 status = netlogon_creds_cli_store(state->context,
3075 &state->creds);
3076 if (tevent_req_nterror(req, status)) {
3077 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3078 return;
3081 tevent_req_done(req);
3084 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3085 TALLOC_CTX *mem_ctx,
3086 struct samr_Password *new_owf_password,
3087 struct samr_Password *old_owf_password,
3088 struct netr_TrustInfo **trust_info)
3090 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3091 tevent_req_data(req,
3092 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3093 NTSTATUS status;
3095 if (tevent_req_is_nterror(req, &status)) {
3096 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3097 tevent_req_received(req);
3098 return status;
3101 if (new_owf_password != NULL) {
3102 *new_owf_password = state->new_owf_password;
3104 if (old_owf_password != NULL) {
3105 *old_owf_password = state->old_owf_password;
3107 if (trust_info != NULL) {
3108 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3111 tevent_req_received(req);
3112 return NT_STATUS_OK;
3115 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3116 struct netlogon_creds_cli_context *context,
3117 struct dcerpc_binding_handle *b,
3118 TALLOC_CTX *mem_ctx,
3119 struct samr_Password *new_owf_password,
3120 struct samr_Password *old_owf_password,
3121 struct netr_TrustInfo **trust_info)
3123 TALLOC_CTX *frame = talloc_stackframe();
3124 struct tevent_context *ev;
3125 struct tevent_req *req;
3126 NTSTATUS status = NT_STATUS_NO_MEMORY;
3128 ev = samba_tevent_context_init(frame);
3129 if (ev == NULL) {
3130 goto fail;
3132 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3133 if (req == NULL) {
3134 goto fail;
3136 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3137 goto fail;
3139 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3140 mem_ctx,
3141 new_owf_password,
3142 old_owf_password,
3143 trust_info);
3144 fail:
3145 TALLOC_FREE(frame);
3146 return status;
3149 struct netlogon_creds_cli_GetForestTrustInformation_state {
3150 struct tevent_context *ev;
3151 struct netlogon_creds_cli_context *context;
3152 struct dcerpc_binding_handle *binding_handle;
3154 char *srv_name_slash;
3155 enum dcerpc_AuthType auth_type;
3156 enum dcerpc_AuthLevel auth_level;
3158 uint32_t flags;
3159 struct lsa_ForestTrustInformation *forest_trust_info;
3161 struct netlogon_creds_CredentialState *creds;
3162 struct netlogon_creds_CredentialState tmp_creds;
3163 struct netr_Authenticator req_auth;
3164 struct netr_Authenticator rep_auth;
3167 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3168 NTSTATUS status);
3169 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3171 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3172 struct tevent_context *ev,
3173 struct netlogon_creds_cli_context *context,
3174 struct dcerpc_binding_handle *b)
3176 struct tevent_req *req;
3177 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3178 struct tevent_req *subreq;
3180 req = tevent_req_create(mem_ctx, &state,
3181 struct netlogon_creds_cli_GetForestTrustInformation_state);
3182 if (req == NULL) {
3183 return NULL;
3186 state->ev = ev;
3187 state->context = context;
3188 state->binding_handle = b;
3190 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3191 context->server.computer);
3192 if (tevent_req_nomem(state->srv_name_slash, req)) {
3193 return tevent_req_post(req, ev);
3196 state->flags = 0;
3198 dcerpc_binding_handle_auth_info(state->binding_handle,
3199 &state->auth_type,
3200 &state->auth_level);
3202 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3203 state->context);
3204 if (tevent_req_nomem(subreq, req)) {
3205 return tevent_req_post(req, ev);
3208 tevent_req_set_callback(subreq,
3209 netlogon_creds_cli_GetForestTrustInformation_locked,
3210 req);
3212 return req;
3215 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3216 NTSTATUS status)
3218 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3219 tevent_req_data(req,
3220 struct netlogon_creds_cli_GetForestTrustInformation_state);
3222 if (state->creds == NULL) {
3223 return;
3226 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3227 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3228 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3229 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3230 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3231 TALLOC_FREE(state->creds);
3232 return;
3235 netlogon_creds_cli_delete(state->context, &state->creds);
3238 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3240 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3242 struct tevent_req *req =
3243 tevent_req_callback_data(subreq,
3244 struct tevent_req);
3245 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3246 tevent_req_data(req,
3247 struct netlogon_creds_cli_GetForestTrustInformation_state);
3248 NTSTATUS status;
3250 status = netlogon_creds_cli_lock_recv(subreq, state,
3251 &state->creds);
3252 TALLOC_FREE(subreq);
3253 if (tevent_req_nterror(req, status)) {
3254 return;
3257 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3258 switch (state->auth_level) {
3259 case DCERPC_AUTH_LEVEL_INTEGRITY:
3260 case DCERPC_AUTH_LEVEL_PRIVACY:
3261 break;
3262 default:
3263 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3264 return;
3266 } else {
3267 uint32_t tmp = state->creds->negotiate_flags;
3269 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3271 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3272 * it should be used, which means
3273 * we had a chance to verify no downgrade
3274 * happened.
3276 * This relies on netlogon_creds_cli_check*
3277 * being called before, as first request after
3278 * the DCERPC bind.
3280 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3281 return;
3286 * we defer all callbacks in order to cleanup
3287 * the database record.
3289 tevent_req_defer_callback(req, state->ev);
3291 state->tmp_creds = *state->creds;
3292 netlogon_creds_client_authenticator(&state->tmp_creds,
3293 &state->req_auth);
3294 ZERO_STRUCT(state->rep_auth);
3296 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3297 state->binding_handle,
3298 state->srv_name_slash,
3299 state->tmp_creds.computer_name,
3300 &state->req_auth,
3301 &state->rep_auth,
3302 state->flags,
3303 &state->forest_trust_info);
3304 if (tevent_req_nomem(subreq, req)) {
3305 status = NT_STATUS_NO_MEMORY;
3306 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3307 return;
3310 tevent_req_set_callback(subreq,
3311 netlogon_creds_cli_GetForestTrustInformation_done,
3312 req);
3315 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3317 struct tevent_req *req =
3318 tevent_req_callback_data(subreq,
3319 struct tevent_req);
3320 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3321 tevent_req_data(req,
3322 struct netlogon_creds_cli_GetForestTrustInformation_state);
3323 NTSTATUS status;
3324 NTSTATUS result;
3325 bool ok;
3328 * We use state->dns_names as the memory context, as this is
3329 * the only in/out variable and it has been overwritten by the
3330 * out parameter from the server.
3332 * We need to preserve the return value until the caller can use it.
3334 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3335 TALLOC_FREE(subreq);
3336 if (tevent_req_nterror(req, status)) {
3337 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3338 return;
3341 ok = netlogon_creds_client_check(&state->tmp_creds,
3342 &state->rep_auth.cred);
3343 if (!ok) {
3344 status = NT_STATUS_ACCESS_DENIED;
3345 tevent_req_nterror(req, status);
3346 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3347 return;
3350 if (tevent_req_nterror(req, result)) {
3351 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3352 return;
3355 *state->creds = state->tmp_creds;
3356 status = netlogon_creds_cli_store(state->context,
3357 &state->creds);
3358 if (tevent_req_nterror(req, status)) {
3359 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3360 return;
3363 tevent_req_done(req);
3366 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3367 TALLOC_CTX *mem_ctx,
3368 struct lsa_ForestTrustInformation **forest_trust_info)
3370 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3371 tevent_req_data(req,
3372 struct netlogon_creds_cli_GetForestTrustInformation_state);
3373 NTSTATUS status;
3375 if (tevent_req_is_nterror(req, &status)) {
3376 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3377 tevent_req_received(req);
3378 return status;
3381 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3383 tevent_req_received(req);
3384 return NT_STATUS_OK;
3387 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3388 struct netlogon_creds_cli_context *context,
3389 struct dcerpc_binding_handle *b,
3390 TALLOC_CTX *mem_ctx,
3391 struct lsa_ForestTrustInformation **forest_trust_info)
3393 TALLOC_CTX *frame = talloc_stackframe();
3394 struct tevent_context *ev;
3395 struct tevent_req *req;
3396 NTSTATUS status = NT_STATUS_NO_MEMORY;
3398 ev = samba_tevent_context_init(frame);
3399 if (ev == NULL) {
3400 goto fail;
3402 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3403 if (req == NULL) {
3404 goto fail;
3406 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3407 goto fail;
3409 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3410 mem_ctx,
3411 forest_trust_info);
3412 fail:
3413 TALLOC_FREE(frame);
3414 return status;