Revert "script/release.sh: use 8 byte gpg key ids"
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob38b1351f59178e7165f8a09613cea73d1f826da2
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 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
488 struct netlogon_creds_cli_context *context)
490 return context->client.auth_level;
493 struct netlogon_creds_cli_fetch_state {
494 TALLOC_CTX *mem_ctx;
495 struct netlogon_creds_CredentialState *creds;
496 uint32_t required_flags;
497 NTSTATUS status;
500 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
501 void *private_data)
503 struct netlogon_creds_cli_fetch_state *state =
504 (struct netlogon_creds_cli_fetch_state *)private_data;
505 enum ndr_err_code ndr_err;
506 DATA_BLOB blob;
507 uint32_t tmp_flags;
509 state->creds = talloc_zero(state->mem_ctx,
510 struct netlogon_creds_CredentialState);
511 if (state->creds == NULL) {
512 state->status = NT_STATUS_NO_MEMORY;
513 return;
516 blob.data = data.dptr;
517 blob.length = data.dsize;
519 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
520 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
521 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
522 TALLOC_FREE(state->creds);
523 state->status = ndr_map_error2ntstatus(ndr_err);
524 return;
527 tmp_flags = state->creds->negotiate_flags;
528 tmp_flags &= state->required_flags;
529 if (tmp_flags != state->required_flags) {
530 TALLOC_FREE(state->creds);
531 state->status = NT_STATUS_DOWNGRADE_DETECTED;
532 return;
535 state->status = NT_STATUS_OK;
538 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
539 TALLOC_CTX *mem_ctx,
540 struct netlogon_creds_CredentialState **_creds)
542 NTSTATUS status;
543 struct netlogon_creds_cli_fetch_state fstate = {
544 .mem_ctx = mem_ctx,
545 .status = NT_STATUS_INTERNAL_ERROR,
546 .required_flags = context->client.required_flags,
548 static const struct netr_Credential zero_creds;
550 *_creds = NULL;
552 status = dbwrap_parse_record(context->db.ctx,
553 context->db.key_data,
554 netlogon_creds_cli_fetch_parser,
555 &fstate);
556 if (!NT_STATUS_IS_OK(status)) {
557 return status;
559 status = fstate.status;
560 if (!NT_STATUS_IS_OK(status)) {
561 return status;
565 * mark it as invalid for step operations.
567 fstate.creds->sequence = 0;
568 fstate.creds->seed = zero_creds;
569 fstate.creds->client = zero_creds;
570 fstate.creds->server = zero_creds;
572 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
573 *_creds = fstate.creds;
574 return NT_STATUS_OK;
578 * It is really important to try SamLogonEx here,
579 * because multiple processes can talk to the same
580 * domain controller, without using the credential
581 * chain.
583 * With a normal SamLogon call, we must keep the
584 * credentials chain updated and intact between all
585 * users of the machine account (which would imply
586 * cross-node communication for every NTLM logon).
588 * The credentials chain is not per NETLOGON pipe
589 * connection, but globally on the server/client pair
590 * by computer name, while the client is free to use
591 * any computer name. We include the cluster node number
592 * in our computer name in order to avoid cross node
593 * coordination of the credential chain.
595 * It's also important to use NetlogonValidationSamInfo4 (6),
596 * because it relies on the rpc transport encryption
597 * and avoids using the global netlogon schannel
598 * session key to en/decrypt secret information
599 * like the user_session_key for network logons.
601 * [MS-APDS] 3.1.5.2 NTLM Network Logon
602 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
603 * NETLOGON_NEG_AUTHENTICATED_RPC set together
604 * are the indication that the server supports
605 * NetlogonValidationSamInfo4 (6). And it must only
606 * be used if "SealSecureChannel" is used.
608 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
609 * check is done in netlogon_creds_cli_LogonSamLogon*().
611 context->server.cached_flags = fstate.creds->negotiate_flags;
612 context->server.try_validation6 = true;
613 context->server.try_logon_ex = true;
614 context->server.try_logon_with = true;
616 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
617 context->server.try_validation6 = false;
618 context->server.try_logon_ex = false;
620 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
621 context->server.try_validation6 = false;
624 *_creds = fstate.creds;
625 return NT_STATUS_OK;
628 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
629 const struct netlogon_creds_CredentialState *creds1)
631 TALLOC_CTX *frame = talloc_stackframe();
632 struct netlogon_creds_CredentialState *creds2;
633 DATA_BLOB blob1;
634 DATA_BLOB blob2;
635 NTSTATUS status;
636 enum ndr_err_code ndr_err;
637 int cmp;
639 status = netlogon_creds_cli_get(context, frame, &creds2);
640 if (!NT_STATUS_IS_OK(status)) {
641 TALLOC_FREE(frame);
642 return false;
645 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
646 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
647 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
648 TALLOC_FREE(frame);
649 return false;
652 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
653 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
654 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
655 TALLOC_FREE(frame);
656 return false;
659 if (blob1.length != blob2.length) {
660 TALLOC_FREE(frame);
661 return false;
664 cmp = memcmp(blob1.data, blob2.data, blob1.length);
665 if (cmp != 0) {
666 TALLOC_FREE(frame);
667 return false;
670 TALLOC_FREE(frame);
671 return true;
674 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
675 struct netlogon_creds_CredentialState **_creds)
677 struct netlogon_creds_CredentialState *creds = *_creds;
678 NTSTATUS status;
679 enum ndr_err_code ndr_err;
680 DATA_BLOB blob;
681 TDB_DATA data;
683 *_creds = NULL;
685 if (context->db.locked_state == NULL) {
687 * this was not the result of netlogon_creds_cli_lock*()
689 TALLOC_FREE(creds);
690 return NT_STATUS_INVALID_PAGE_PROTECTION;
693 if (context->db.locked_state->creds != creds) {
695 * this was not the result of netlogon_creds_cli_lock*()
697 TALLOC_FREE(creds);
698 return NT_STATUS_INVALID_PAGE_PROTECTION;
701 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
702 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
703 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
704 TALLOC_FREE(creds);
705 status = ndr_map_error2ntstatus(ndr_err);
706 return status;
709 data.dptr = blob.data;
710 data.dsize = blob.length;
712 status = dbwrap_store(context->db.ctx,
713 context->db.key_data,
714 data, TDB_REPLACE);
715 TALLOC_FREE(creds);
716 if (!NT_STATUS_IS_OK(status)) {
717 return status;
720 return NT_STATUS_OK;
723 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
724 struct netlogon_creds_CredentialState **_creds)
726 struct netlogon_creds_CredentialState *creds = *_creds;
727 NTSTATUS status;
729 *_creds = NULL;
731 if (context->db.locked_state == NULL) {
733 * this was not the result of netlogon_creds_cli_lock*()
735 TALLOC_FREE(creds);
736 return NT_STATUS_INVALID_PAGE_PROTECTION;
739 if (context->db.locked_state->creds != creds) {
741 * this was not the result of netlogon_creds_cli_lock*()
743 TALLOC_FREE(creds);
744 return NT_STATUS_INVALID_PAGE_PROTECTION;
747 status = dbwrap_delete(context->db.ctx,
748 context->db.key_data);
749 TALLOC_FREE(creds);
750 if (!NT_STATUS_IS_OK(status)) {
751 return status;
754 return NT_STATUS_OK;
757 struct netlogon_creds_cli_lock_state {
758 struct netlogon_creds_cli_locked_state *locked_state;
759 struct netlogon_creds_CredentialState *creds;
762 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
763 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
765 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
766 struct tevent_context *ev,
767 struct netlogon_creds_cli_context *context)
769 struct tevent_req *req;
770 struct netlogon_creds_cli_lock_state *state;
771 struct netlogon_creds_cli_locked_state *locked_state;
772 struct tevent_req *subreq;
774 req = tevent_req_create(mem_ctx, &state,
775 struct netlogon_creds_cli_lock_state);
776 if (req == NULL) {
777 return NULL;
780 if (context->db.locked_state != NULL) {
781 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
782 return tevent_req_post(req, ev);
785 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
786 if (tevent_req_nomem(locked_state, req)) {
787 return tevent_req_post(req, ev);
789 talloc_set_destructor(locked_state,
790 netlogon_creds_cli_locked_state_destructor);
791 locked_state->context = context;
793 context->db.locked_state = locked_state;
794 state->locked_state = locked_state;
796 if (context->db.g_ctx == NULL) {
797 netlogon_creds_cli_lock_fetch(req);
798 if (!tevent_req_is_in_progress(req)) {
799 return tevent_req_post(req, ev);
802 return req;
805 subreq = g_lock_lock_send(state, ev,
806 context->db.g_ctx,
807 context->db.key_name,
808 G_LOCK_WRITE);
809 if (tevent_req_nomem(subreq, req)) {
810 return tevent_req_post(req, ev);
812 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
814 return req;
817 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
819 struct tevent_req *req =
820 tevent_req_callback_data(subreq,
821 struct tevent_req);
822 struct netlogon_creds_cli_lock_state *state =
823 tevent_req_data(req,
824 struct netlogon_creds_cli_lock_state);
825 NTSTATUS status;
827 status = g_lock_lock_recv(subreq);
828 TALLOC_FREE(subreq);
829 if (tevent_req_nterror(req, status)) {
830 return;
832 state->locked_state->is_glocked = true;
834 netlogon_creds_cli_lock_fetch(req);
837 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
839 struct netlogon_creds_cli_lock_state *state =
840 tevent_req_data(req,
841 struct netlogon_creds_cli_lock_state);
842 struct netlogon_creds_cli_context *context = state->locked_state->context;
843 struct netlogon_creds_cli_fetch_state fstate = {
844 .status = NT_STATUS_INTERNAL_ERROR,
845 .required_flags = context->client.required_flags,
847 NTSTATUS status;
849 fstate.mem_ctx = state;
850 status = dbwrap_parse_record(context->db.ctx,
851 context->db.key_data,
852 netlogon_creds_cli_fetch_parser,
853 &fstate);
854 if (tevent_req_nterror(req, status)) {
855 return;
857 status = fstate.status;
858 if (tevent_req_nterror(req, status)) {
859 return;
862 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
863 state->creds = fstate.creds;
864 tevent_req_done(req);
865 return;
868 context->server.cached_flags = fstate.creds->negotiate_flags;
869 context->server.try_validation6 = true;
870 context->server.try_logon_ex = true;
871 context->server.try_logon_with = true;
873 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
874 context->server.try_validation6 = false;
875 context->server.try_logon_ex = false;
877 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
878 context->server.try_validation6 = false;
881 state->creds = fstate.creds;
882 tevent_req_done(req);
883 return;
886 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
887 TALLOC_CTX *mem_ctx,
888 struct netlogon_creds_CredentialState **creds)
890 struct netlogon_creds_cli_lock_state *state =
891 tevent_req_data(req,
892 struct netlogon_creds_cli_lock_state);
893 NTSTATUS status;
895 if (tevent_req_is_nterror(req, &status)) {
896 tevent_req_received(req);
897 return status;
900 talloc_steal(state->creds, state->locked_state);
901 state->locked_state->creds = state->creds;
902 *creds = talloc_move(mem_ctx, &state->creds);
903 tevent_req_received(req);
904 return NT_STATUS_OK;
907 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
908 TALLOC_CTX *mem_ctx,
909 struct netlogon_creds_CredentialState **creds)
911 TALLOC_CTX *frame = talloc_stackframe();
912 struct tevent_context *ev;
913 struct tevent_req *req;
914 NTSTATUS status = NT_STATUS_NO_MEMORY;
916 ev = samba_tevent_context_init(frame);
917 if (ev == NULL) {
918 goto fail;
920 req = netlogon_creds_cli_lock_send(frame, ev, context);
921 if (req == NULL) {
922 goto fail;
924 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
925 goto fail;
927 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
928 fail:
929 TALLOC_FREE(frame);
930 return status;
933 struct netlogon_creds_cli_auth_state {
934 struct tevent_context *ev;
935 struct netlogon_creds_cli_context *context;
936 struct dcerpc_binding_handle *binding_handle;
937 struct samr_Password current_nt_hash;
938 struct samr_Password previous_nt_hash;
939 struct samr_Password used_nt_hash;
940 char *srv_name_slash;
941 uint32_t current_flags;
942 struct netr_Credential client_challenge;
943 struct netr_Credential server_challenge;
944 struct netlogon_creds_CredentialState *creds;
945 struct netr_Credential client_credential;
946 struct netr_Credential server_credential;
947 uint32_t rid;
948 bool try_auth3;
949 bool try_auth2;
950 bool require_auth2;
951 bool try_previous_nt_hash;
952 struct netlogon_creds_cli_locked_state *locked_state;
955 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
956 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
958 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
959 struct tevent_context *ev,
960 struct netlogon_creds_cli_context *context,
961 struct dcerpc_binding_handle *b,
962 struct samr_Password current_nt_hash,
963 const struct samr_Password *previous_nt_hash)
965 struct tevent_req *req;
966 struct netlogon_creds_cli_auth_state *state;
967 struct netlogon_creds_cli_locked_state *locked_state;
968 NTSTATUS status;
970 req = tevent_req_create(mem_ctx, &state,
971 struct netlogon_creds_cli_auth_state);
972 if (req == NULL) {
973 return NULL;
976 state->ev = ev;
977 state->context = context;
978 state->binding_handle = b;
979 state->current_nt_hash = current_nt_hash;
980 if (previous_nt_hash != NULL) {
981 state->previous_nt_hash = *previous_nt_hash;
982 state->try_previous_nt_hash = true;
985 if (context->db.locked_state != NULL) {
986 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
987 return tevent_req_post(req, ev);
990 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
991 if (tevent_req_nomem(locked_state, req)) {
992 return tevent_req_post(req, ev);
994 talloc_set_destructor(locked_state,
995 netlogon_creds_cli_locked_state_destructor);
996 locked_state->context = context;
998 context->db.locked_state = locked_state;
999 state->locked_state = locked_state;
1001 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1002 context->server.computer);
1003 if (tevent_req_nomem(state->srv_name_slash, req)) {
1004 return tevent_req_post(req, ev);
1007 state->try_auth3 = true;
1008 state->try_auth2 = true;
1010 if (context->client.required_flags != 0) {
1011 state->require_auth2 = true;
1014 state->used_nt_hash = state->current_nt_hash;
1015 state->current_flags = context->client.proposed_flags;
1017 if (context->db.g_ctx != NULL) {
1018 struct tevent_req *subreq;
1020 subreq = g_lock_lock_send(state, ev,
1021 context->db.g_ctx,
1022 context->db.key_name,
1023 G_LOCK_WRITE);
1024 if (tevent_req_nomem(subreq, req)) {
1025 return tevent_req_post(req, ev);
1027 tevent_req_set_callback(subreq,
1028 netlogon_creds_cli_auth_locked,
1029 req);
1031 return req;
1034 status = dbwrap_purge(state->context->db.ctx,
1035 state->context->db.key_data);
1036 if (tevent_req_nterror(req, status)) {
1037 return tevent_req_post(req, ev);
1040 netlogon_creds_cli_auth_challenge_start(req);
1041 if (!tevent_req_is_in_progress(req)) {
1042 return tevent_req_post(req, ev);
1045 return req;
1048 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1050 struct tevent_req *req =
1051 tevent_req_callback_data(subreq,
1052 struct tevent_req);
1053 struct netlogon_creds_cli_auth_state *state =
1054 tevent_req_data(req,
1055 struct netlogon_creds_cli_auth_state);
1056 NTSTATUS status;
1058 status = g_lock_lock_recv(subreq);
1059 TALLOC_FREE(subreq);
1060 if (tevent_req_nterror(req, status)) {
1061 return;
1063 state->locked_state->is_glocked = true;
1065 status = dbwrap_purge(state->context->db.ctx,
1066 state->context->db.key_data);
1067 if (tevent_req_nterror(req, status)) {
1068 return;
1071 netlogon_creds_cli_auth_challenge_start(req);
1074 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1076 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1078 struct netlogon_creds_cli_auth_state *state =
1079 tevent_req_data(req,
1080 struct netlogon_creds_cli_auth_state);
1081 struct tevent_req *subreq;
1083 TALLOC_FREE(state->creds);
1085 generate_random_buffer(state->client_challenge.data,
1086 sizeof(state->client_challenge.data));
1088 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1089 state->binding_handle,
1090 state->srv_name_slash,
1091 state->context->client.computer,
1092 &state->client_challenge,
1093 &state->server_challenge);
1094 if (tevent_req_nomem(subreq, req)) {
1095 return;
1097 tevent_req_set_callback(subreq,
1098 netlogon_creds_cli_auth_challenge_done,
1099 req);
1102 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1104 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1106 struct tevent_req *req =
1107 tevent_req_callback_data(subreq,
1108 struct tevent_req);
1109 struct netlogon_creds_cli_auth_state *state =
1110 tevent_req_data(req,
1111 struct netlogon_creds_cli_auth_state);
1112 NTSTATUS status;
1113 NTSTATUS result;
1115 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1116 TALLOC_FREE(subreq);
1117 if (tevent_req_nterror(req, status)) {
1118 return;
1120 if (tevent_req_nterror(req, result)) {
1121 return;
1124 if (!state->try_auth3 && !state->try_auth2) {
1125 state->current_flags = 0;
1128 /* Calculate the session key and client credentials */
1130 state->creds = netlogon_creds_client_init(state,
1131 state->context->client.account,
1132 state->context->client.computer,
1133 state->context->client.type,
1134 &state->client_challenge,
1135 &state->server_challenge,
1136 &state->used_nt_hash,
1137 &state->client_credential,
1138 state->current_flags);
1139 if (tevent_req_nomem(state->creds, req)) {
1140 return;
1143 if (state->try_auth3) {
1144 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1145 state->binding_handle,
1146 state->srv_name_slash,
1147 state->context->client.account,
1148 state->context->client.type,
1149 state->context->client.computer,
1150 &state->client_credential,
1151 &state->server_credential,
1152 &state->creds->negotiate_flags,
1153 &state->rid);
1154 if (tevent_req_nomem(subreq, req)) {
1155 return;
1157 } else if (state->try_auth2) {
1158 state->rid = 0;
1160 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1161 state->binding_handle,
1162 state->srv_name_slash,
1163 state->context->client.account,
1164 state->context->client.type,
1165 state->context->client.computer,
1166 &state->client_credential,
1167 &state->server_credential,
1168 &state->creds->negotiate_flags);
1169 if (tevent_req_nomem(subreq, req)) {
1170 return;
1172 } else {
1173 state->rid = 0;
1175 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1176 state->binding_handle,
1177 state->srv_name_slash,
1178 state->context->client.account,
1179 state->context->client.type,
1180 state->context->client.computer,
1181 &state->client_credential,
1182 &state->server_credential);
1183 if (tevent_req_nomem(subreq, req)) {
1184 return;
1187 tevent_req_set_callback(subreq,
1188 netlogon_creds_cli_auth_srvauth_done,
1189 req);
1192 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1194 struct tevent_req *req =
1195 tevent_req_callback_data(subreq,
1196 struct tevent_req);
1197 struct netlogon_creds_cli_auth_state *state =
1198 tevent_req_data(req,
1199 struct netlogon_creds_cli_auth_state);
1200 NTSTATUS status;
1201 NTSTATUS result;
1202 bool ok;
1203 enum ndr_err_code ndr_err;
1204 DATA_BLOB blob;
1205 TDB_DATA data;
1206 uint32_t tmp_flags;
1208 if (state->try_auth3) {
1209 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1210 &result);
1211 TALLOC_FREE(subreq);
1212 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1213 state->try_auth3 = false;
1214 netlogon_creds_cli_auth_challenge_start(req);
1215 return;
1217 if (tevent_req_nterror(req, status)) {
1218 return;
1220 } else if (state->try_auth2) {
1221 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1222 &result);
1223 TALLOC_FREE(subreq);
1224 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1225 state->try_auth2 = false;
1226 if (state->require_auth2) {
1227 status = NT_STATUS_DOWNGRADE_DETECTED;
1228 tevent_req_nterror(req, status);
1229 return;
1231 netlogon_creds_cli_auth_challenge_start(req);
1232 return;
1234 if (tevent_req_nterror(req, status)) {
1235 return;
1237 } else {
1238 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1239 &result);
1240 TALLOC_FREE(subreq);
1241 if (tevent_req_nterror(req, status)) {
1242 return;
1246 if (!NT_STATUS_IS_OK(result) &&
1247 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1249 tevent_req_nterror(req, result);
1250 return;
1253 tmp_flags = state->creds->negotiate_flags;
1254 tmp_flags &= state->context->client.required_flags;
1255 if (tmp_flags != state->context->client.required_flags) {
1256 if (NT_STATUS_IS_OK(result)) {
1257 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1258 return;
1260 tevent_req_nterror(req, result);
1261 return;
1264 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1266 tmp_flags = state->context->client.proposed_flags;
1267 if ((state->current_flags == tmp_flags) &&
1268 (state->creds->negotiate_flags != tmp_flags))
1271 * lets retry with the negotiated flags
1273 state->current_flags = state->creds->negotiate_flags;
1274 netlogon_creds_cli_auth_challenge_start(req);
1275 return;
1278 if (!state->try_previous_nt_hash) {
1280 * we already retried, giving up...
1282 tevent_req_nterror(req, result);
1283 return;
1287 * lets retry with the old nt hash.
1289 state->try_previous_nt_hash = false;
1290 state->used_nt_hash = state->previous_nt_hash;
1291 state->current_flags = state->context->client.proposed_flags;
1292 netlogon_creds_cli_auth_challenge_start(req);
1293 return;
1296 ok = netlogon_creds_client_check(state->creds,
1297 &state->server_credential);
1298 if (!ok) {
1299 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1300 return;
1303 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1304 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1305 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1306 status = ndr_map_error2ntstatus(ndr_err);
1307 tevent_req_nterror(req, status);
1308 return;
1311 data.dptr = blob.data;
1312 data.dsize = blob.length;
1314 status = dbwrap_store(state->context->db.ctx,
1315 state->context->db.key_data,
1316 data, TDB_REPLACE);
1317 TALLOC_FREE(state->locked_state);
1318 if (tevent_req_nterror(req, status)) {
1319 return;
1322 tevent_req_done(req);
1325 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req)
1327 NTSTATUS status;
1329 if (tevent_req_is_nterror(req, &status)) {
1330 tevent_req_received(req);
1331 return status;
1334 tevent_req_received(req);
1335 return NT_STATUS_OK;
1338 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1339 struct dcerpc_binding_handle *b,
1340 struct samr_Password current_nt_hash,
1341 const struct samr_Password *previous_nt_hash)
1343 TALLOC_CTX *frame = talloc_stackframe();
1344 struct tevent_context *ev;
1345 struct tevent_req *req;
1346 NTSTATUS status = NT_STATUS_NO_MEMORY;
1348 ev = samba_tevent_context_init(frame);
1349 if (ev == NULL) {
1350 goto fail;
1352 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1353 current_nt_hash,
1354 previous_nt_hash);
1355 if (req == NULL) {
1356 goto fail;
1358 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1359 goto fail;
1361 status = netlogon_creds_cli_auth_recv(req);
1362 fail:
1363 TALLOC_FREE(frame);
1364 return status;
1367 struct netlogon_creds_cli_check_state {
1368 struct tevent_context *ev;
1369 struct netlogon_creds_cli_context *context;
1370 struct dcerpc_binding_handle *binding_handle;
1372 char *srv_name_slash;
1374 union netr_Capabilities caps;
1376 struct netlogon_creds_CredentialState *creds;
1377 struct netlogon_creds_CredentialState tmp_creds;
1378 struct netr_Authenticator req_auth;
1379 struct netr_Authenticator rep_auth;
1382 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1383 NTSTATUS status);
1384 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1386 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1387 struct tevent_context *ev,
1388 struct netlogon_creds_cli_context *context,
1389 struct dcerpc_binding_handle *b)
1391 struct tevent_req *req;
1392 struct netlogon_creds_cli_check_state *state;
1393 struct tevent_req *subreq;
1394 enum dcerpc_AuthType auth_type;
1395 enum dcerpc_AuthLevel auth_level;
1397 req = tevent_req_create(mem_ctx, &state,
1398 struct netlogon_creds_cli_check_state);
1399 if (req == NULL) {
1400 return NULL;
1403 state->ev = ev;
1404 state->context = context;
1405 state->binding_handle = b;
1407 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1408 context->server.computer);
1409 if (tevent_req_nomem(state->srv_name_slash, req)) {
1410 return tevent_req_post(req, ev);
1413 dcerpc_binding_handle_auth_info(state->binding_handle,
1414 &auth_type, &auth_level);
1416 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1417 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1418 return tevent_req_post(req, ev);
1421 switch (auth_level) {
1422 case DCERPC_AUTH_LEVEL_INTEGRITY:
1423 case DCERPC_AUTH_LEVEL_PRIVACY:
1424 break;
1425 default:
1426 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1427 return tevent_req_post(req, ev);
1430 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1431 state->context);
1432 if (tevent_req_nomem(subreq, req)) {
1433 return tevent_req_post(req, ev);
1436 tevent_req_set_callback(subreq,
1437 netlogon_creds_cli_check_locked,
1438 req);
1440 return req;
1443 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1444 NTSTATUS status)
1446 struct netlogon_creds_cli_check_state *state =
1447 tevent_req_data(req,
1448 struct netlogon_creds_cli_check_state);
1450 if (state->creds == NULL) {
1451 return;
1454 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1455 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1456 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1457 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1458 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1459 TALLOC_FREE(state->creds);
1460 return;
1463 netlogon_creds_cli_delete(state->context, &state->creds);
1466 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1468 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1470 struct tevent_req *req =
1471 tevent_req_callback_data(subreq,
1472 struct tevent_req);
1473 struct netlogon_creds_cli_check_state *state =
1474 tevent_req_data(req,
1475 struct netlogon_creds_cli_check_state);
1476 NTSTATUS status;
1478 status = netlogon_creds_cli_lock_recv(subreq, state,
1479 &state->creds);
1480 TALLOC_FREE(subreq);
1481 if (tevent_req_nterror(req, status)) {
1482 return;
1486 * we defer all callbacks in order to cleanup
1487 * the database record.
1489 tevent_req_defer_callback(req, state->ev);
1491 state->tmp_creds = *state->creds;
1492 netlogon_creds_client_authenticator(&state->tmp_creds,
1493 &state->req_auth);
1494 ZERO_STRUCT(state->rep_auth);
1496 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1497 state->binding_handle,
1498 state->srv_name_slash,
1499 state->context->client.computer,
1500 &state->req_auth,
1501 &state->rep_auth,
1503 &state->caps);
1504 if (tevent_req_nomem(subreq, req)) {
1505 status = NT_STATUS_NO_MEMORY;
1506 netlogon_creds_cli_check_cleanup(req, status);
1507 return;
1509 tevent_req_set_callback(subreq,
1510 netlogon_creds_cli_check_caps,
1511 req);
1514 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1516 struct tevent_req *req =
1517 tevent_req_callback_data(subreq,
1518 struct tevent_req);
1519 struct netlogon_creds_cli_check_state *state =
1520 tevent_req_data(req,
1521 struct netlogon_creds_cli_check_state);
1522 NTSTATUS status;
1523 NTSTATUS result;
1524 bool ok;
1526 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1527 &result);
1528 TALLOC_FREE(subreq);
1529 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1531 * Note that the negotiated flags are already checked
1532 * for our required flags after the ServerAuthenticate3/2 call.
1534 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1536 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1538 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1539 * already, we expect this to work!
1541 status = NT_STATUS_DOWNGRADE_DETECTED;
1542 tevent_req_nterror(req, status);
1543 netlogon_creds_cli_check_cleanup(req, status);
1544 return;
1547 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1549 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1550 * we expect this to work at least as far as the
1551 * NOT_SUPPORTED error handled below!
1553 * NT 4.0 and Old Samba servers are not
1554 * allowed without "require strong key = no"
1556 status = NT_STATUS_DOWNGRADE_DETECTED;
1557 tevent_req_nterror(req, status);
1558 netlogon_creds_cli_check_cleanup(req, status);
1559 return;
1563 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1564 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1565 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1567 * This is needed against NT 4.0 and old Samba servers.
1569 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1570 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1571 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1572 * with the next request as the sequence number processing
1573 * gets out of sync.
1575 netlogon_creds_cli_check_cleanup(req, status);
1576 tevent_req_done(req);
1577 return;
1579 if (tevent_req_nterror(req, status)) {
1580 netlogon_creds_cli_check_cleanup(req, status);
1581 return;
1584 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1586 * Note that the negotiated flags are already checked
1587 * for our required flags after the ServerAuthenticate3/2 call.
1589 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1591 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1593 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1594 * already, we expect this to work!
1596 status = NT_STATUS_DOWNGRADE_DETECTED;
1597 tevent_req_nterror(req, status);
1598 netlogon_creds_cli_check_cleanup(req, status);
1599 return;
1603 * This is ok, the server does not support
1604 * NETLOGON_NEG_SUPPORTS_AES.
1606 * netr_LogonGetCapabilities() was
1607 * netr_LogonDummyRoutine1() before
1608 * NETLOGON_NEG_SUPPORTS_AES was invented.
1610 netlogon_creds_cli_check_cleanup(req, result);
1611 tevent_req_done(req);
1612 return;
1615 ok = netlogon_creds_client_check(&state->tmp_creds,
1616 &state->rep_auth.cred);
1617 if (!ok) {
1618 status = NT_STATUS_ACCESS_DENIED;
1619 tevent_req_nterror(req, status);
1620 netlogon_creds_cli_check_cleanup(req, status);
1621 return;
1624 if (tevent_req_nterror(req, result)) {
1625 netlogon_creds_cli_check_cleanup(req, result);
1626 return;
1629 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1630 status = NT_STATUS_DOWNGRADE_DETECTED;
1631 tevent_req_nterror(req, status);
1632 netlogon_creds_cli_check_cleanup(req, status);
1633 return;
1637 * This is the key check that makes this check secure. If we
1638 * get OK here (rather than NOT_SUPPORTED), then the server
1639 * did support AES. If the server only proposed STRONG_KEYS
1640 * and not AES, then it should have failed with
1641 * NOT_IMPLEMENTED. We always send AES as a client, so the
1642 * server should always have returned it.
1644 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1645 status = NT_STATUS_DOWNGRADE_DETECTED;
1646 tevent_req_nterror(req, status);
1647 netlogon_creds_cli_check_cleanup(req, status);
1648 return;
1651 *state->creds = state->tmp_creds;
1652 status = netlogon_creds_cli_store(state->context,
1653 &state->creds);
1654 netlogon_creds_cli_check_cleanup(req, status);
1655 if (tevent_req_nterror(req, status)) {
1656 return;
1659 tevent_req_done(req);
1662 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1664 NTSTATUS status;
1666 if (tevent_req_is_nterror(req, &status)) {
1667 netlogon_creds_cli_check_cleanup(req, status);
1668 tevent_req_received(req);
1669 return status;
1672 tevent_req_received(req);
1673 return NT_STATUS_OK;
1676 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1677 struct dcerpc_binding_handle *b)
1679 TALLOC_CTX *frame = talloc_stackframe();
1680 struct tevent_context *ev;
1681 struct tevent_req *req;
1682 NTSTATUS status = NT_STATUS_NO_MEMORY;
1684 ev = samba_tevent_context_init(frame);
1685 if (ev == NULL) {
1686 goto fail;
1688 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1689 if (req == NULL) {
1690 goto fail;
1692 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1693 goto fail;
1695 status = netlogon_creds_cli_check_recv(req);
1696 fail:
1697 TALLOC_FREE(frame);
1698 return status;
1701 struct netlogon_creds_cli_ServerPasswordSet_state {
1702 struct tevent_context *ev;
1703 struct netlogon_creds_cli_context *context;
1704 struct dcerpc_binding_handle *binding_handle;
1705 uint32_t old_timeout;
1707 char *srv_name_slash;
1708 enum dcerpc_AuthType auth_type;
1709 enum dcerpc_AuthLevel auth_level;
1711 struct samr_CryptPassword samr_crypt_password;
1712 struct netr_CryptPassword netr_crypt_password;
1713 struct samr_Password samr_password;
1715 struct netlogon_creds_CredentialState *creds;
1716 struct netlogon_creds_CredentialState tmp_creds;
1717 struct netr_Authenticator req_auth;
1718 struct netr_Authenticator rep_auth;
1721 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1722 NTSTATUS status);
1723 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1725 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1726 struct tevent_context *ev,
1727 struct netlogon_creds_cli_context *context,
1728 struct dcerpc_binding_handle *b,
1729 const char *new_password,
1730 const uint32_t *new_version)
1732 struct tevent_req *req;
1733 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1734 struct tevent_req *subreq;
1735 bool ok;
1737 req = tevent_req_create(mem_ctx, &state,
1738 struct netlogon_creds_cli_ServerPasswordSet_state);
1739 if (req == NULL) {
1740 return NULL;
1743 state->ev = ev;
1744 state->context = context;
1745 state->binding_handle = b;
1748 * netr_ServerPasswordSet
1750 E_md4hash(new_password, state->samr_password.hash);
1753 * netr_ServerPasswordSet2
1755 ok = encode_pw_buffer(state->samr_crypt_password.data,
1756 new_password, STR_UNICODE);
1757 if (!ok) {
1758 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1759 return tevent_req_post(req, ev);
1762 if (new_version != NULL) {
1763 struct NL_PASSWORD_VERSION version;
1764 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1765 uint32_t ofs = 512 - len;
1766 uint8_t *p;
1768 if (len > 500) {
1769 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1770 return tevent_req_post(req, ev);
1772 ofs -= 12;
1774 version.ReservedField = 0;
1775 version.PasswordVersionNumber = *new_version;
1776 version.PasswordVersionPresent =
1777 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1779 p = state->samr_crypt_password.data + ofs;
1780 SIVAL(p, 0, version.ReservedField);
1781 SIVAL(p, 4, version.PasswordVersionNumber);
1782 SIVAL(p, 8, version.PasswordVersionPresent);
1785 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1786 context->server.computer);
1787 if (tevent_req_nomem(state->srv_name_slash, req)) {
1788 return tevent_req_post(req, ev);
1791 dcerpc_binding_handle_auth_info(state->binding_handle,
1792 &state->auth_type,
1793 &state->auth_level);
1795 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1796 state->context);
1797 if (tevent_req_nomem(subreq, req)) {
1798 return tevent_req_post(req, ev);
1801 tevent_req_set_callback(subreq,
1802 netlogon_creds_cli_ServerPasswordSet_locked,
1803 req);
1805 return req;
1808 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1809 NTSTATUS status)
1811 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1812 tevent_req_data(req,
1813 struct netlogon_creds_cli_ServerPasswordSet_state);
1815 if (state->creds == NULL) {
1816 return;
1819 dcerpc_binding_handle_set_timeout(state->binding_handle,
1820 state->old_timeout);
1822 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1823 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1824 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1825 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1826 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1827 TALLOC_FREE(state->creds);
1828 return;
1831 netlogon_creds_cli_delete(state->context, &state->creds);
1834 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1836 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1838 struct tevent_req *req =
1839 tevent_req_callback_data(subreq,
1840 struct tevent_req);
1841 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1842 tevent_req_data(req,
1843 struct netlogon_creds_cli_ServerPasswordSet_state);
1844 NTSTATUS status;
1846 status = netlogon_creds_cli_lock_recv(subreq, state,
1847 &state->creds);
1848 TALLOC_FREE(subreq);
1849 if (tevent_req_nterror(req, status)) {
1850 return;
1853 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1854 switch (state->auth_level) {
1855 case DCERPC_AUTH_LEVEL_INTEGRITY:
1856 case DCERPC_AUTH_LEVEL_PRIVACY:
1857 break;
1858 default:
1859 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1860 return;
1862 } else {
1863 uint32_t tmp = state->creds->negotiate_flags;
1865 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1867 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1868 * it should be used, which means
1869 * we had a chance to verify no downgrade
1870 * happened.
1872 * This relies on netlogon_creds_cli_check*
1873 * being called before, as first request after
1874 * the DCERPC bind.
1876 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1877 return;
1881 state->old_timeout = dcerpc_binding_handle_set_timeout(
1882 state->binding_handle, 600000);
1885 * we defer all callbacks in order to cleanup
1886 * the database record.
1888 tevent_req_defer_callback(req, state->ev);
1890 state->tmp_creds = *state->creds;
1891 netlogon_creds_client_authenticator(&state->tmp_creds,
1892 &state->req_auth);
1893 ZERO_STRUCT(state->rep_auth);
1895 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1897 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1898 netlogon_creds_aes_encrypt(&state->tmp_creds,
1899 state->samr_crypt_password.data,
1900 516);
1901 } else {
1902 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1903 state->samr_crypt_password.data,
1904 516);
1907 memcpy(state->netr_crypt_password.data,
1908 state->samr_crypt_password.data, 512);
1909 state->netr_crypt_password.length =
1910 IVAL(state->samr_crypt_password.data, 512);
1912 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1913 state->binding_handle,
1914 state->srv_name_slash,
1915 state->tmp_creds.account_name,
1916 state->tmp_creds.secure_channel_type,
1917 state->tmp_creds.computer_name,
1918 &state->req_auth,
1919 &state->rep_auth,
1920 &state->netr_crypt_password);
1921 if (tevent_req_nomem(subreq, req)) {
1922 status = NT_STATUS_NO_MEMORY;
1923 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1924 return;
1926 } else {
1927 netlogon_creds_des_encrypt(&state->tmp_creds,
1928 &state->samr_password);
1930 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1931 state->binding_handle,
1932 state->srv_name_slash,
1933 state->tmp_creds.account_name,
1934 state->tmp_creds.secure_channel_type,
1935 state->tmp_creds.computer_name,
1936 &state->req_auth,
1937 &state->rep_auth,
1938 &state->samr_password);
1939 if (tevent_req_nomem(subreq, req)) {
1940 status = NT_STATUS_NO_MEMORY;
1941 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1942 return;
1946 tevent_req_set_callback(subreq,
1947 netlogon_creds_cli_ServerPasswordSet_done,
1948 req);
1951 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1953 struct tevent_req *req =
1954 tevent_req_callback_data(subreq,
1955 struct tevent_req);
1956 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1957 tevent_req_data(req,
1958 struct netlogon_creds_cli_ServerPasswordSet_state);
1959 NTSTATUS status;
1960 NTSTATUS result;
1961 bool ok;
1963 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1964 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1965 &result);
1966 TALLOC_FREE(subreq);
1967 if (tevent_req_nterror(req, status)) {
1968 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1969 return;
1971 } else {
1972 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1973 &result);
1974 TALLOC_FREE(subreq);
1975 if (tevent_req_nterror(req, status)) {
1976 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1977 return;
1981 ok = netlogon_creds_client_check(&state->tmp_creds,
1982 &state->rep_auth.cred);
1983 if (!ok) {
1984 status = NT_STATUS_ACCESS_DENIED;
1985 tevent_req_nterror(req, status);
1986 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1987 return;
1990 if (tevent_req_nterror(req, result)) {
1991 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
1992 return;
1995 dcerpc_binding_handle_set_timeout(state->binding_handle,
1996 state->old_timeout);
1998 *state->creds = state->tmp_creds;
1999 status = netlogon_creds_cli_store(state->context,
2000 &state->creds);
2001 if (tevent_req_nterror(req, status)) {
2002 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2003 return;
2006 tevent_req_done(req);
2009 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2011 NTSTATUS status;
2013 if (tevent_req_is_nterror(req, &status)) {
2014 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2015 tevent_req_received(req);
2016 return status;
2019 tevent_req_received(req);
2020 return NT_STATUS_OK;
2023 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2024 struct netlogon_creds_cli_context *context,
2025 struct dcerpc_binding_handle *b,
2026 const char *new_password,
2027 const uint32_t *new_version)
2029 TALLOC_CTX *frame = talloc_stackframe();
2030 struct tevent_context *ev;
2031 struct tevent_req *req;
2032 NTSTATUS status = NT_STATUS_NO_MEMORY;
2034 ev = samba_tevent_context_init(frame);
2035 if (ev == NULL) {
2036 goto fail;
2038 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2039 new_password,
2040 new_version);
2041 if (req == NULL) {
2042 goto fail;
2044 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2045 goto fail;
2047 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2048 fail:
2049 TALLOC_FREE(frame);
2050 return status;
2053 struct netlogon_creds_cli_LogonSamLogon_state {
2054 struct tevent_context *ev;
2055 struct netlogon_creds_cli_context *context;
2056 struct dcerpc_binding_handle *binding_handle;
2058 char *srv_name_slash;
2060 enum netr_LogonInfoClass logon_level;
2061 const union netr_LogonLevel *const_logon;
2062 union netr_LogonLevel *logon;
2063 uint32_t flags;
2065 uint16_t validation_level;
2066 union netr_Validation *validation;
2067 uint8_t authoritative;
2070 * do we need encryption at the application layer?
2072 bool user_encrypt;
2073 bool try_logon_ex;
2074 bool try_validation6;
2077 * the read only credentials before we started the operation
2079 struct netlogon_creds_CredentialState *ro_creds;
2081 struct netlogon_creds_CredentialState *lk_creds;
2083 struct netlogon_creds_CredentialState tmp_creds;
2084 struct netr_Authenticator req_auth;
2085 struct netr_Authenticator rep_auth;
2088 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2089 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2090 NTSTATUS status);
2092 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2093 struct tevent_context *ev,
2094 struct netlogon_creds_cli_context *context,
2095 struct dcerpc_binding_handle *b,
2096 enum netr_LogonInfoClass logon_level,
2097 const union netr_LogonLevel *logon,
2098 uint32_t flags)
2100 struct tevent_req *req;
2101 struct netlogon_creds_cli_LogonSamLogon_state *state;
2103 req = tevent_req_create(mem_ctx, &state,
2104 struct netlogon_creds_cli_LogonSamLogon_state);
2105 if (req == NULL) {
2106 return NULL;
2109 state->ev = ev;
2110 state->context = context;
2111 state->binding_handle = b;
2113 state->logon_level = logon_level;
2114 state->const_logon = logon;
2115 state->flags = flags;
2117 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2118 context->server.computer);
2119 if (tevent_req_nomem(state->srv_name_slash, req)) {
2120 return tevent_req_post(req, ev);
2123 switch (logon_level) {
2124 case NetlogonInteractiveInformation:
2125 case NetlogonInteractiveTransitiveInformation:
2126 case NetlogonServiceInformation:
2127 case NetlogonServiceTransitiveInformation:
2128 case NetlogonGenericInformation:
2129 state->user_encrypt = true;
2130 break;
2132 case NetlogonNetworkInformation:
2133 case NetlogonNetworkTransitiveInformation:
2134 break;
2137 state->validation = talloc_zero(state, union netr_Validation);
2138 if (tevent_req_nomem(state->validation, req)) {
2139 return tevent_req_post(req, ev);
2142 netlogon_creds_cli_LogonSamLogon_start(req);
2143 if (!tevent_req_is_in_progress(req)) {
2144 return tevent_req_post(req, ev);
2148 * we defer all callbacks in order to cleanup
2149 * the database record.
2151 tevent_req_defer_callback(req, state->ev);
2152 return req;
2155 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2156 NTSTATUS status)
2158 struct netlogon_creds_cli_LogonSamLogon_state *state =
2159 tevent_req_data(req,
2160 struct netlogon_creds_cli_LogonSamLogon_state);
2162 if (state->lk_creds == NULL) {
2163 return;
2166 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2168 * This is a hack to recover from a bug in old
2169 * Samba servers, when LogonSamLogonEx() fails:
2171 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2173 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2175 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2176 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2177 * If the sign/seal check fails.
2179 * In that case we need to cleanup the netlogon session.
2181 * It's the job of the caller to disconnect the current
2182 * connection, if netlogon_creds_cli_LogonSamLogon()
2183 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2185 if (!state->context->server.try_logon_with) {
2186 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2190 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2191 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2192 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2193 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2194 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2195 TALLOC_FREE(state->lk_creds);
2196 return;
2199 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2202 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2204 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2206 struct netlogon_creds_cli_LogonSamLogon_state *state =
2207 tevent_req_data(req,
2208 struct netlogon_creds_cli_LogonSamLogon_state);
2209 struct tevent_req *subreq;
2210 NTSTATUS status;
2211 enum dcerpc_AuthType auth_type;
2212 enum dcerpc_AuthLevel auth_level;
2214 TALLOC_FREE(state->ro_creds);
2215 TALLOC_FREE(state->logon);
2216 ZERO_STRUCTP(state->validation);
2218 dcerpc_binding_handle_auth_info(state->binding_handle,
2219 &auth_type, &auth_level);
2221 state->try_logon_ex = state->context->server.try_logon_ex;
2222 state->try_validation6 = state->context->server.try_validation6;
2224 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2225 state->try_logon_ex = false;
2228 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2229 state->try_validation6 = false;
2232 if (state->try_logon_ex) {
2233 if (state->try_validation6) {
2234 state->validation_level = 6;
2235 } else {
2236 state->validation_level = 3;
2237 state->user_encrypt = true;
2240 state->logon = netlogon_creds_shallow_copy_logon(state,
2241 state->logon_level,
2242 state->const_logon);
2243 if (tevent_req_nomem(state->logon, req)) {
2244 status = NT_STATUS_NO_MEMORY;
2245 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2246 return;
2249 if (state->user_encrypt) {
2250 status = netlogon_creds_cli_get(state->context,
2251 state,
2252 &state->ro_creds);
2253 if (!NT_STATUS_IS_OK(status)) {
2254 status = NT_STATUS_ACCESS_DENIED;
2255 tevent_req_nterror(req, status);
2256 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2257 return;
2260 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2261 state->logon_level,
2262 state->logon);
2265 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2266 state->binding_handle,
2267 state->srv_name_slash,
2268 state->context->client.computer,
2269 state->logon_level,
2270 state->logon,
2271 state->validation_level,
2272 state->validation,
2273 &state->authoritative,
2274 &state->flags);
2275 if (tevent_req_nomem(subreq, req)) {
2276 status = NT_STATUS_NO_MEMORY;
2277 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2278 return;
2280 tevent_req_set_callback(subreq,
2281 netlogon_creds_cli_LogonSamLogon_done,
2282 req);
2283 return;
2286 if (state->lk_creds == NULL) {
2287 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2288 state->context);
2289 if (tevent_req_nomem(subreq, req)) {
2290 status = NT_STATUS_NO_MEMORY;
2291 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2292 return;
2294 tevent_req_set_callback(subreq,
2295 netlogon_creds_cli_LogonSamLogon_done,
2296 req);
2297 return;
2300 state->tmp_creds = *state->lk_creds;
2301 netlogon_creds_client_authenticator(&state->tmp_creds,
2302 &state->req_auth);
2303 ZERO_STRUCT(state->rep_auth);
2305 state->logon = netlogon_creds_shallow_copy_logon(state,
2306 state->logon_level,
2307 state->const_logon);
2308 if (tevent_req_nomem(state->logon, req)) {
2309 status = NT_STATUS_NO_MEMORY;
2310 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2311 return;
2314 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2315 state->logon_level,
2316 state->logon);
2318 state->validation_level = 3;
2320 if (state->context->server.try_logon_with) {
2321 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2322 state->binding_handle,
2323 state->srv_name_slash,
2324 state->context->client.computer,
2325 &state->req_auth,
2326 &state->rep_auth,
2327 state->logon_level,
2328 state->logon,
2329 state->validation_level,
2330 state->validation,
2331 &state->authoritative,
2332 &state->flags);
2333 if (tevent_req_nomem(subreq, req)) {
2334 status = NT_STATUS_NO_MEMORY;
2335 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2336 return;
2338 } else {
2339 state->flags = 0;
2341 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2342 state->binding_handle,
2343 state->srv_name_slash,
2344 state->context->client.computer,
2345 &state->req_auth,
2346 &state->rep_auth,
2347 state->logon_level,
2348 state->logon,
2349 state->validation_level,
2350 state->validation,
2351 &state->authoritative);
2352 if (tevent_req_nomem(subreq, req)) {
2353 status = NT_STATUS_NO_MEMORY;
2354 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2355 return;
2359 tevent_req_set_callback(subreq,
2360 netlogon_creds_cli_LogonSamLogon_done,
2361 req);
2364 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2366 struct tevent_req *req =
2367 tevent_req_callback_data(subreq,
2368 struct tevent_req);
2369 struct netlogon_creds_cli_LogonSamLogon_state *state =
2370 tevent_req_data(req,
2371 struct netlogon_creds_cli_LogonSamLogon_state);
2372 NTSTATUS status;
2373 NTSTATUS result;
2374 bool ok;
2376 if (state->try_logon_ex) {
2377 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2378 state->validation,
2379 &result);
2380 TALLOC_FREE(subreq);
2381 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2382 state->context->server.try_validation6 = false;
2383 state->context->server.try_logon_ex = false;
2384 netlogon_creds_cli_LogonSamLogon_start(req);
2385 return;
2387 if (tevent_req_nterror(req, status)) {
2388 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2389 return;
2392 if ((state->validation_level == 6) &&
2393 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2394 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2395 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2397 state->context->server.try_validation6 = false;
2398 netlogon_creds_cli_LogonSamLogon_start(req);
2399 return;
2402 if (tevent_req_nterror(req, result)) {
2403 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2404 return;
2407 if (state->ro_creds == NULL) {
2408 tevent_req_done(req);
2409 return;
2412 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2413 if (!ok) {
2415 * We got a race, lets retry with on authenticator
2416 * protection.
2418 TALLOC_FREE(state->ro_creds);
2419 state->try_logon_ex = false;
2420 netlogon_creds_cli_LogonSamLogon_start(req);
2421 return;
2424 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2425 state->validation_level,
2426 state->validation);
2428 tevent_req_done(req);
2429 return;
2432 if (state->lk_creds == NULL) {
2433 status = netlogon_creds_cli_lock_recv(subreq, state,
2434 &state->lk_creds);
2435 TALLOC_FREE(subreq);
2436 if (tevent_req_nterror(req, status)) {
2437 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2438 return;
2441 netlogon_creds_cli_LogonSamLogon_start(req);
2442 return;
2445 if (state->context->server.try_logon_with) {
2446 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2447 state->validation,
2448 &result);
2449 TALLOC_FREE(subreq);
2450 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2451 state->context->server.try_logon_with = false;
2452 netlogon_creds_cli_LogonSamLogon_start(req);
2453 return;
2455 if (tevent_req_nterror(req, status)) {
2456 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2457 return;
2459 } else {
2460 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2461 state->validation,
2462 &result);
2463 TALLOC_FREE(subreq);
2464 if (tevent_req_nterror(req, status)) {
2465 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2466 return;
2470 ok = netlogon_creds_client_check(&state->tmp_creds,
2471 &state->rep_auth.cred);
2472 if (!ok) {
2473 status = NT_STATUS_ACCESS_DENIED;
2474 tevent_req_nterror(req, status);
2475 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2476 return;
2479 *state->lk_creds = state->tmp_creds;
2480 status = netlogon_creds_cli_store(state->context,
2481 &state->lk_creds);
2482 if (tevent_req_nterror(req, status)) {
2483 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2484 return;
2487 if (tevent_req_nterror(req, result)) {
2488 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2489 return;
2492 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2493 state->validation_level,
2494 state->validation);
2496 tevent_req_done(req);
2499 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2500 TALLOC_CTX *mem_ctx,
2501 uint16_t *validation_level,
2502 union netr_Validation **validation,
2503 uint8_t *authoritative,
2504 uint32_t *flags)
2506 struct netlogon_creds_cli_LogonSamLogon_state *state =
2507 tevent_req_data(req,
2508 struct netlogon_creds_cli_LogonSamLogon_state);
2509 NTSTATUS status;
2511 /* authoritative is also returned on error */
2512 *authoritative = state->authoritative;
2514 if (tevent_req_is_nterror(req, &status)) {
2515 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2516 tevent_req_received(req);
2517 return status;
2520 *validation_level = state->validation_level;
2521 *validation = talloc_move(mem_ctx, &state->validation);
2522 *flags = state->flags;
2524 tevent_req_received(req);
2525 return NT_STATUS_OK;
2528 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2529 struct netlogon_creds_cli_context *context,
2530 struct dcerpc_binding_handle *b,
2531 enum netr_LogonInfoClass logon_level,
2532 const union netr_LogonLevel *logon,
2533 TALLOC_CTX *mem_ctx,
2534 uint16_t *validation_level,
2535 union netr_Validation **validation,
2536 uint8_t *authoritative,
2537 uint32_t *flags)
2539 TALLOC_CTX *frame = talloc_stackframe();
2540 struct tevent_context *ev;
2541 struct tevent_req *req;
2542 NTSTATUS status = NT_STATUS_NO_MEMORY;
2544 ev = samba_tevent_context_init(frame);
2545 if (ev == NULL) {
2546 goto fail;
2548 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2549 logon_level, logon,
2550 *flags);
2551 if (req == NULL) {
2552 goto fail;
2554 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2555 goto fail;
2557 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2558 validation_level,
2559 validation,
2560 authoritative,
2561 flags);
2562 fail:
2563 TALLOC_FREE(frame);
2564 return status;
2567 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2568 struct tevent_context *ev;
2569 struct netlogon_creds_cli_context *context;
2570 struct dcerpc_binding_handle *binding_handle;
2572 char *srv_name_slash;
2573 enum dcerpc_AuthType auth_type;
2574 enum dcerpc_AuthLevel auth_level;
2576 const char *site_name;
2577 uint32_t dns_ttl;
2578 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2580 struct netlogon_creds_CredentialState *creds;
2581 struct netlogon_creds_CredentialState tmp_creds;
2582 struct netr_Authenticator req_auth;
2583 struct netr_Authenticator rep_auth;
2586 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2587 NTSTATUS status);
2588 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2590 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2591 struct tevent_context *ev,
2592 struct netlogon_creds_cli_context *context,
2593 struct dcerpc_binding_handle *b,
2594 const char *site_name,
2595 uint32_t dns_ttl,
2596 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2598 struct tevent_req *req;
2599 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2600 struct tevent_req *subreq;
2602 req = tevent_req_create(mem_ctx, &state,
2603 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2604 if (req == NULL) {
2605 return NULL;
2608 state->ev = ev;
2609 state->context = context;
2610 state->binding_handle = b;
2612 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2613 context->server.computer);
2614 if (tevent_req_nomem(state->srv_name_slash, req)) {
2615 return tevent_req_post(req, ev);
2618 state->site_name = site_name;
2619 state->dns_ttl = dns_ttl;
2620 state->dns_names = dns_names;
2622 dcerpc_binding_handle_auth_info(state->binding_handle,
2623 &state->auth_type,
2624 &state->auth_level);
2626 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2627 state->context);
2628 if (tevent_req_nomem(subreq, req)) {
2629 return tevent_req_post(req, ev);
2632 tevent_req_set_callback(subreq,
2633 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2634 req);
2636 return req;
2639 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2640 NTSTATUS status)
2642 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2643 tevent_req_data(req,
2644 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2646 if (state->creds == NULL) {
2647 return;
2650 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2651 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2652 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2653 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2654 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2655 TALLOC_FREE(state->creds);
2656 return;
2659 netlogon_creds_cli_delete(state->context, &state->creds);
2662 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2664 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2666 struct tevent_req *req =
2667 tevent_req_callback_data(subreq,
2668 struct tevent_req);
2669 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2670 tevent_req_data(req,
2671 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2672 NTSTATUS status;
2674 status = netlogon_creds_cli_lock_recv(subreq, state,
2675 &state->creds);
2676 TALLOC_FREE(subreq);
2677 if (tevent_req_nterror(req, status)) {
2678 return;
2681 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2682 switch (state->auth_level) {
2683 case DCERPC_AUTH_LEVEL_INTEGRITY:
2684 case DCERPC_AUTH_LEVEL_PRIVACY:
2685 break;
2686 default:
2687 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2688 return;
2690 } else {
2691 uint32_t tmp = state->creds->negotiate_flags;
2693 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2695 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2696 * it should be used, which means
2697 * we had a chance to verify no downgrade
2698 * happened.
2700 * This relies on netlogon_creds_cli_check*
2701 * being called before, as first request after
2702 * the DCERPC bind.
2704 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2705 return;
2710 * we defer all callbacks in order to cleanup
2711 * the database record.
2713 tevent_req_defer_callback(req, state->ev);
2715 state->tmp_creds = *state->creds;
2716 netlogon_creds_client_authenticator(&state->tmp_creds,
2717 &state->req_auth);
2718 ZERO_STRUCT(state->rep_auth);
2720 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2721 state->binding_handle,
2722 state->srv_name_slash,
2723 state->tmp_creds.computer_name,
2724 &state->req_auth,
2725 &state->rep_auth,
2726 state->site_name,
2727 state->dns_ttl,
2728 state->dns_names);
2729 if (tevent_req_nomem(subreq, req)) {
2730 status = NT_STATUS_NO_MEMORY;
2731 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2732 return;
2735 tevent_req_set_callback(subreq,
2736 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2737 req);
2740 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2742 struct tevent_req *req =
2743 tevent_req_callback_data(subreq,
2744 struct tevent_req);
2745 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2746 tevent_req_data(req,
2747 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2748 NTSTATUS status;
2749 NTSTATUS result;
2750 bool ok;
2753 * We use state->dns_names as the memory context, as this is
2754 * the only in/out variable and it has been overwritten by the
2755 * out parameter from the server.
2757 * We need to preserve the return value until the caller can use it.
2759 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2760 &result);
2761 TALLOC_FREE(subreq);
2762 if (tevent_req_nterror(req, status)) {
2763 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2764 return;
2767 ok = netlogon_creds_client_check(&state->tmp_creds,
2768 &state->rep_auth.cred);
2769 if (!ok) {
2770 status = NT_STATUS_ACCESS_DENIED;
2771 tevent_req_nterror(req, status);
2772 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2773 return;
2776 if (tevent_req_nterror(req, result)) {
2777 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2778 return;
2781 *state->creds = state->tmp_creds;
2782 status = netlogon_creds_cli_store(state->context,
2783 &state->creds);
2784 if (tevent_req_nterror(req, status)) {
2785 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2786 return;
2789 tevent_req_done(req);
2792 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2794 NTSTATUS status;
2796 if (tevent_req_is_nterror(req, &status)) {
2797 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2798 tevent_req_received(req);
2799 return status;
2802 tevent_req_received(req);
2803 return NT_STATUS_OK;
2806 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2807 struct netlogon_creds_cli_context *context,
2808 struct dcerpc_binding_handle *b,
2809 const char *site_name,
2810 uint32_t dns_ttl,
2811 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2813 TALLOC_CTX *frame = talloc_stackframe();
2814 struct tevent_context *ev;
2815 struct tevent_req *req;
2816 NTSTATUS status = NT_STATUS_NO_MEMORY;
2818 ev = samba_tevent_context_init(frame);
2819 if (ev == NULL) {
2820 goto fail;
2822 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2823 site_name,
2824 dns_ttl,
2825 dns_names);
2826 if (req == NULL) {
2827 goto fail;
2829 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2830 goto fail;
2832 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2833 fail:
2834 TALLOC_FREE(frame);
2835 return status;
2838 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2839 struct tevent_context *ev;
2840 struct netlogon_creds_cli_context *context;
2841 struct dcerpc_binding_handle *binding_handle;
2843 char *srv_name_slash;
2844 enum dcerpc_AuthType auth_type;
2845 enum dcerpc_AuthLevel auth_level;
2847 struct samr_Password new_owf_password;
2848 struct samr_Password old_owf_password;
2849 struct netr_TrustInfo *trust_info;
2851 struct netlogon_creds_CredentialState *creds;
2852 struct netlogon_creds_CredentialState tmp_creds;
2853 struct netr_Authenticator req_auth;
2854 struct netr_Authenticator rep_auth;
2857 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2858 NTSTATUS status);
2859 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2861 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2862 struct tevent_context *ev,
2863 struct netlogon_creds_cli_context *context,
2864 struct dcerpc_binding_handle *b)
2866 struct tevent_req *req;
2867 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2868 struct tevent_req *subreq;
2870 req = tevent_req_create(mem_ctx, &state,
2871 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2872 if (req == NULL) {
2873 return NULL;
2876 state->ev = ev;
2877 state->context = context;
2878 state->binding_handle = b;
2880 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2881 context->server.computer);
2882 if (tevent_req_nomem(state->srv_name_slash, req)) {
2883 return tevent_req_post(req, ev);
2886 dcerpc_binding_handle_auth_info(state->binding_handle,
2887 &state->auth_type,
2888 &state->auth_level);
2890 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2891 state->context);
2892 if (tevent_req_nomem(subreq, req)) {
2893 return tevent_req_post(req, ev);
2896 tevent_req_set_callback(subreq,
2897 netlogon_creds_cli_ServerGetTrustInfo_locked,
2898 req);
2900 return req;
2903 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2904 NTSTATUS status)
2906 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2907 tevent_req_data(req,
2908 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2910 if (state->creds == NULL) {
2911 return;
2914 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2915 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2916 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2917 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2918 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2919 TALLOC_FREE(state->creds);
2920 return;
2923 netlogon_creds_cli_delete(state->context, &state->creds);
2926 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2928 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2930 struct tevent_req *req =
2931 tevent_req_callback_data(subreq,
2932 struct tevent_req);
2933 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2934 tevent_req_data(req,
2935 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2936 NTSTATUS status;
2938 status = netlogon_creds_cli_lock_recv(subreq, state,
2939 &state->creds);
2940 TALLOC_FREE(subreq);
2941 if (tevent_req_nterror(req, status)) {
2942 return;
2945 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2946 switch (state->auth_level) {
2947 case DCERPC_AUTH_LEVEL_PRIVACY:
2948 break;
2949 default:
2950 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2951 return;
2953 } else {
2954 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2955 return;
2959 * we defer all callbacks in order to cleanup
2960 * the database record.
2962 tevent_req_defer_callback(req, state->ev);
2964 state->tmp_creds = *state->creds;
2965 netlogon_creds_client_authenticator(&state->tmp_creds,
2966 &state->req_auth);
2967 ZERO_STRUCT(state->rep_auth);
2969 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
2970 state->binding_handle,
2971 state->srv_name_slash,
2972 state->tmp_creds.account_name,
2973 state->tmp_creds.secure_channel_type,
2974 state->tmp_creds.computer_name,
2975 &state->req_auth,
2976 &state->rep_auth,
2977 &state->new_owf_password,
2978 &state->old_owf_password,
2979 &state->trust_info);
2980 if (tevent_req_nomem(subreq, req)) {
2981 status = NT_STATUS_NO_MEMORY;
2982 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
2983 return;
2986 tevent_req_set_callback(subreq,
2987 netlogon_creds_cli_ServerGetTrustInfo_done,
2988 req);
2991 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
2993 struct tevent_req *req =
2994 tevent_req_callback_data(subreq,
2995 struct tevent_req);
2996 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2997 tevent_req_data(req,
2998 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2999 NTSTATUS status;
3000 NTSTATUS result;
3001 const struct samr_Password zero = {};
3002 int cmp;
3003 bool ok;
3006 * We use state->dns_names as the memory context, as this is
3007 * the only in/out variable and it has been overwritten by the
3008 * out parameter from the server.
3010 * We need to preserve the return value until the caller can use it.
3012 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3013 TALLOC_FREE(subreq);
3014 if (tevent_req_nterror(req, status)) {
3015 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3016 return;
3019 ok = netlogon_creds_client_check(&state->tmp_creds,
3020 &state->rep_auth.cred);
3021 if (!ok) {
3022 status = NT_STATUS_ACCESS_DENIED;
3023 tevent_req_nterror(req, status);
3024 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3025 return;
3028 if (tevent_req_nterror(req, result)) {
3029 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3030 return;
3033 cmp = memcmp(state->new_owf_password.hash,
3034 zero.hash, sizeof(zero.hash));
3035 if (cmp != 0) {
3036 netlogon_creds_des_decrypt(&state->tmp_creds,
3037 &state->new_owf_password);
3039 cmp = memcmp(state->old_owf_password.hash,
3040 zero.hash, sizeof(zero.hash));
3041 if (cmp != 0) {
3042 netlogon_creds_des_decrypt(&state->tmp_creds,
3043 &state->old_owf_password);
3046 *state->creds = state->tmp_creds;
3047 status = netlogon_creds_cli_store(state->context,
3048 &state->creds);
3049 if (tevent_req_nterror(req, status)) {
3050 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3051 return;
3054 tevent_req_done(req);
3057 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3058 TALLOC_CTX *mem_ctx,
3059 struct samr_Password *new_owf_password,
3060 struct samr_Password *old_owf_password,
3061 struct netr_TrustInfo **trust_info)
3063 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3064 tevent_req_data(req,
3065 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3066 NTSTATUS status;
3068 if (tevent_req_is_nterror(req, &status)) {
3069 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3070 tevent_req_received(req);
3071 return status;
3074 if (new_owf_password != NULL) {
3075 *new_owf_password = state->new_owf_password;
3077 if (old_owf_password != NULL) {
3078 *old_owf_password = state->old_owf_password;
3080 if (trust_info != NULL) {
3081 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3084 tevent_req_received(req);
3085 return NT_STATUS_OK;
3088 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3089 struct netlogon_creds_cli_context *context,
3090 struct dcerpc_binding_handle *b,
3091 TALLOC_CTX *mem_ctx,
3092 struct samr_Password *new_owf_password,
3093 struct samr_Password *old_owf_password,
3094 struct netr_TrustInfo **trust_info)
3096 TALLOC_CTX *frame = talloc_stackframe();
3097 struct tevent_context *ev;
3098 struct tevent_req *req;
3099 NTSTATUS status = NT_STATUS_NO_MEMORY;
3101 ev = samba_tevent_context_init(frame);
3102 if (ev == NULL) {
3103 goto fail;
3105 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3106 if (req == NULL) {
3107 goto fail;
3109 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3110 goto fail;
3112 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3113 mem_ctx,
3114 new_owf_password,
3115 old_owf_password,
3116 trust_info);
3117 fail:
3118 TALLOC_FREE(frame);
3119 return status;
3122 struct netlogon_creds_cli_GetForestTrustInformation_state {
3123 struct tevent_context *ev;
3124 struct netlogon_creds_cli_context *context;
3125 struct dcerpc_binding_handle *binding_handle;
3127 char *srv_name_slash;
3128 enum dcerpc_AuthType auth_type;
3129 enum dcerpc_AuthLevel auth_level;
3131 uint32_t flags;
3132 struct lsa_ForestTrustInformation *forest_trust_info;
3134 struct netlogon_creds_CredentialState *creds;
3135 struct netlogon_creds_CredentialState tmp_creds;
3136 struct netr_Authenticator req_auth;
3137 struct netr_Authenticator rep_auth;
3140 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3141 NTSTATUS status);
3142 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3144 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3145 struct tevent_context *ev,
3146 struct netlogon_creds_cli_context *context,
3147 struct dcerpc_binding_handle *b)
3149 struct tevent_req *req;
3150 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3151 struct tevent_req *subreq;
3153 req = tevent_req_create(mem_ctx, &state,
3154 struct netlogon_creds_cli_GetForestTrustInformation_state);
3155 if (req == NULL) {
3156 return NULL;
3159 state->ev = ev;
3160 state->context = context;
3161 state->binding_handle = b;
3163 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3164 context->server.computer);
3165 if (tevent_req_nomem(state->srv_name_slash, req)) {
3166 return tevent_req_post(req, ev);
3169 state->flags = 0;
3171 dcerpc_binding_handle_auth_info(state->binding_handle,
3172 &state->auth_type,
3173 &state->auth_level);
3175 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3176 state->context);
3177 if (tevent_req_nomem(subreq, req)) {
3178 return tevent_req_post(req, ev);
3181 tevent_req_set_callback(subreq,
3182 netlogon_creds_cli_GetForestTrustInformation_locked,
3183 req);
3185 return req;
3188 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3189 NTSTATUS status)
3191 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3192 tevent_req_data(req,
3193 struct netlogon_creds_cli_GetForestTrustInformation_state);
3195 if (state->creds == NULL) {
3196 return;
3199 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3200 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3201 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3202 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3203 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3204 TALLOC_FREE(state->creds);
3205 return;
3208 netlogon_creds_cli_delete(state->context, &state->creds);
3211 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3213 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3215 struct tevent_req *req =
3216 tevent_req_callback_data(subreq,
3217 struct tevent_req);
3218 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3219 tevent_req_data(req,
3220 struct netlogon_creds_cli_GetForestTrustInformation_state);
3221 NTSTATUS status;
3223 status = netlogon_creds_cli_lock_recv(subreq, state,
3224 &state->creds);
3225 TALLOC_FREE(subreq);
3226 if (tevent_req_nterror(req, status)) {
3227 return;
3230 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3231 switch (state->auth_level) {
3232 case DCERPC_AUTH_LEVEL_INTEGRITY:
3233 case DCERPC_AUTH_LEVEL_PRIVACY:
3234 break;
3235 default:
3236 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3237 return;
3239 } else {
3240 uint32_t tmp = state->creds->negotiate_flags;
3242 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3244 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3245 * it should be used, which means
3246 * we had a chance to verify no downgrade
3247 * happened.
3249 * This relies on netlogon_creds_cli_check*
3250 * being called before, as first request after
3251 * the DCERPC bind.
3253 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3254 return;
3259 * we defer all callbacks in order to cleanup
3260 * the database record.
3262 tevent_req_defer_callback(req, state->ev);
3264 state->tmp_creds = *state->creds;
3265 netlogon_creds_client_authenticator(&state->tmp_creds,
3266 &state->req_auth);
3267 ZERO_STRUCT(state->rep_auth);
3269 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3270 state->binding_handle,
3271 state->srv_name_slash,
3272 state->tmp_creds.computer_name,
3273 &state->req_auth,
3274 &state->rep_auth,
3275 state->flags,
3276 &state->forest_trust_info);
3277 if (tevent_req_nomem(subreq, req)) {
3278 status = NT_STATUS_NO_MEMORY;
3279 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3280 return;
3283 tevent_req_set_callback(subreq,
3284 netlogon_creds_cli_GetForestTrustInformation_done,
3285 req);
3288 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3290 struct tevent_req *req =
3291 tevent_req_callback_data(subreq,
3292 struct tevent_req);
3293 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3294 tevent_req_data(req,
3295 struct netlogon_creds_cli_GetForestTrustInformation_state);
3296 NTSTATUS status;
3297 NTSTATUS result;
3298 bool ok;
3301 * We use state->dns_names as the memory context, as this is
3302 * the only in/out variable and it has been overwritten by the
3303 * out parameter from the server.
3305 * We need to preserve the return value until the caller can use it.
3307 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3308 TALLOC_FREE(subreq);
3309 if (tevent_req_nterror(req, status)) {
3310 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3311 return;
3314 ok = netlogon_creds_client_check(&state->tmp_creds,
3315 &state->rep_auth.cred);
3316 if (!ok) {
3317 status = NT_STATUS_ACCESS_DENIED;
3318 tevent_req_nterror(req, status);
3319 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3320 return;
3323 if (tevent_req_nterror(req, result)) {
3324 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3325 return;
3328 *state->creds = state->tmp_creds;
3329 status = netlogon_creds_cli_store(state->context,
3330 &state->creds);
3331 if (tevent_req_nterror(req, status)) {
3332 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3333 return;
3336 tevent_req_done(req);
3339 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3340 TALLOC_CTX *mem_ctx,
3341 struct lsa_ForestTrustInformation **forest_trust_info)
3343 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3344 tevent_req_data(req,
3345 struct netlogon_creds_cli_GetForestTrustInformation_state);
3346 NTSTATUS status;
3348 if (tevent_req_is_nterror(req, &status)) {
3349 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3350 tevent_req_received(req);
3351 return status;
3354 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3356 tevent_req_received(req);
3357 return NT_STATUS_OK;
3360 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3361 struct netlogon_creds_cli_context *context,
3362 struct dcerpc_binding_handle *b,
3363 TALLOC_CTX *mem_ctx,
3364 struct lsa_ForestTrustInformation **forest_trust_info)
3366 TALLOC_CTX *frame = talloc_stackframe();
3367 struct tevent_context *ev;
3368 struct tevent_req *req;
3369 NTSTATUS status = NT_STATUS_NO_MEMORY;
3371 ev = samba_tevent_context_init(frame);
3372 if (ev == NULL) {
3373 goto fail;
3375 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3376 if (req == NULL) {
3377 goto fail;
3379 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3380 goto fail;
3382 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3383 mem_ctx,
3384 forest_trust_info);
3385 fail:
3386 TALLOC_FREE(frame);
3387 return status;