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/>.
23 #include "system/filesys.h"
25 #include "lib/util/tevent_ntstatus.h"
26 #include "lib/dbwrap/dbwrap.h"
27 #include "lib/dbwrap/dbwrap_rbt.h"
28 #include "lib/util/util_tdb.h"
29 #include "libcli/security/security.h"
30 #include "../lib/param/param.h"
31 #include "../libcli/auth/schannel.h"
32 #include "../librpc/gen_ndr/ndr_schannel.h"
33 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
34 #include "../librpc/gen_ndr/ndr_netlogon.h"
35 #include "../librpc/gen_ndr/server_id.h"
36 #include "netlogon_creds_cli.h"
37 #include "source3/include/messages.h"
38 #include "source3/include/g_lock.h"
39 #include "libds/common/roles.h"
40 #include "lib/crypto/md4.h"
41 #include "auth/credentials/credentials.h"
42 #include "lib/param/loadparm.h"
44 struct netlogon_creds_cli_locked_state;
46 struct netlogon_creds_cli_context {
50 uint32_t proposed_flags;
51 uint32_t required_flags;
52 enum netr_SchannelType type;
53 enum dcerpc_AuthLevel auth_level;
58 const char *netbios_domain;
59 const char *dns_domain;
60 uint32_t cached_flags;
69 struct db_context *ctx;
70 struct g_lock_ctx *g_ctx;
71 struct netlogon_creds_cli_locked_state *locked_state;
72 enum netlogon_creds_cli_lck_type lock;
76 struct netlogon_creds_cli_locked_state {
77 struct netlogon_creds_cli_context *context;
79 struct netlogon_creds_CredentialState *creds;
82 static int netlogon_creds_cli_locked_state_destructor(
83 struct netlogon_creds_cli_locked_state *state)
85 struct netlogon_creds_cli_context *context = state->context;
87 if (context == NULL) {
91 if (context->db.locked_state == state) {
92 context->db.locked_state = NULL;
95 if (state->is_glocked) {
96 g_lock_unlock(context->db.g_ctx,
97 string_term_tdb_data(context->db.key_name));
103 static NTSTATUS netlogon_creds_cli_context_common(
104 const char *client_computer,
105 const char *client_account,
106 enum netr_SchannelType type,
107 enum dcerpc_AuthLevel auth_level,
108 uint32_t proposed_flags,
109 uint32_t required_flags,
110 const char *server_computer,
111 const char *server_netbios_domain,
112 const char *server_dns_domain,
114 struct netlogon_creds_cli_context **_context)
116 struct netlogon_creds_cli_context *context = NULL;
117 char *_key_name = NULL;
118 size_t server_netbios_name_len;
123 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
124 if (context == NULL) {
125 return NT_STATUS_NO_MEMORY;
128 context->client.computer = talloc_strdup(context, client_computer);
129 if (context->client.computer == NULL) {
130 TALLOC_FREE(context);
131 return NT_STATUS_NO_MEMORY;
134 context->client.account = talloc_strdup(context, client_account);
135 if (context->client.account == NULL) {
136 TALLOC_FREE(context);
137 return NT_STATUS_NO_MEMORY;
140 context->client.proposed_flags = proposed_flags;
141 context->client.required_flags = required_flags;
142 context->client.type = type;
143 context->client.auth_level = auth_level;
145 context->server.computer = talloc_strdup(context, server_computer);
146 if (context->server.computer == NULL) {
147 TALLOC_FREE(context);
148 return NT_STATUS_NO_MEMORY;
151 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
152 if (context->server.netbios_domain == NULL) {
153 TALLOC_FREE(context);
154 return NT_STATUS_NO_MEMORY;
157 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
158 if (context->server.dns_domain == NULL) {
159 TALLOC_FREE(context);
160 return NT_STATUS_NO_MEMORY;
165 * Force the callers to provide a unique
166 * value for server_computer and use this directly.
168 * For now we have to deal with
169 * "HOSTNAME" vs. "hostname.example.com".
172 p = strchr(server_computer, '.');
174 server_netbios_name_len = p-server_computer;
176 server_netbios_name_len = strlen(server_computer);
179 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
182 (int)server_netbios_name_len,
184 server_netbios_domain);
185 if (_key_name == NULL) {
186 TALLOC_FREE(context);
187 return NT_STATUS_NO_MEMORY;
190 context->db.key_name = talloc_strdup_upper(context, _key_name);
191 TALLOC_FREE(_key_name);
192 if (context->db.key_name == NULL) {
193 TALLOC_FREE(context);
194 return NT_STATUS_NO_MEMORY;
197 context->db.key_data = string_term_tdb_data(context->db.key_name);
203 static struct db_context *netlogon_creds_cli_global_db;
205 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
207 if (netlogon_creds_cli_global_db != NULL) {
208 return NT_STATUS_INVALID_PARAMETER_MIX;
211 netlogon_creds_cli_global_db = talloc_move(NULL, db);
215 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
218 struct db_context *global_db;
219 int hash_size, tdb_flags;
221 if (netlogon_creds_cli_global_db != NULL) {
225 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
227 return NT_STATUS_NO_MEMORY;
230 hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
231 tdb_flags = lpcfg_tdb_flags(
233 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
235 global_db = dbwrap_local_open(
244 if (global_db == NULL) {
245 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
246 fname, strerror(errno)));
248 return NT_STATUS_NO_MEMORY;
252 netlogon_creds_cli_global_db = global_db;
256 void netlogon_creds_cli_close_global_db(void)
258 TALLOC_FREE(netlogon_creds_cli_global_db);
261 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
262 struct messaging_context *msg_ctx,
263 const char *client_account,
264 enum netr_SchannelType type,
265 const char *server_computer,
266 const char *server_netbios_domain,
267 const char *server_dns_domain,
269 struct netlogon_creds_cli_context **_context)
271 TALLOC_CTX *frame = talloc_stackframe();
273 struct netlogon_creds_cli_context *context = NULL;
274 const char *client_computer;
275 uint32_t proposed_flags;
276 uint32_t required_flags = 0;
277 bool reject_md5_servers = false;
278 bool require_strong_key = false;
279 int require_sign_or_seal = true;
280 bool seal_secure_channel = true;
281 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
282 bool neutralize_nt4_emulation = false;
286 if (msg_ctx == NULL) {
288 return NT_STATUS_INVALID_PARAMETER_MIX;
291 client_computer = lpcfg_netbios_name(lp_ctx);
292 if (strlen(client_computer) > 15) {
294 return NT_STATUS_INVALID_PARAMETER_MIX;
298 * allow overwrite per domain
299 * reject md5 servers:<netbios_domain>
301 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
302 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
303 "reject md5 servers",
304 server_netbios_domain,
308 * allow overwrite per domain
309 * require strong key:<netbios_domain>
311 require_strong_key = lpcfg_require_strong_key(lp_ctx);
312 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
313 "require strong key",
314 server_netbios_domain,
318 * allow overwrite per domain
319 * client schannel:<netbios_domain>
321 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
322 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
324 server_netbios_domain,
325 require_sign_or_seal);
328 * allow overwrite per domain
329 * winbind sealed pipes:<netbios_domain>
331 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
332 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
333 "winbind sealed pipes",
334 server_netbios_domain,
335 seal_secure_channel);
338 * allow overwrite per domain
339 * neutralize nt4 emulation:<netbios_domain>
341 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
342 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
343 "neutralize nt4 emulation",
344 server_netbios_domain,
345 neutralize_nt4_emulation);
347 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
348 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
352 if (lpcfg_security(lp_ctx) == SEC_ADS) {
354 * AD domains should be secure
356 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
357 require_sign_or_seal = true;
358 require_strong_key = true;
362 case SEC_CHAN_DOMAIN:
365 case SEC_CHAN_DNS_DOMAIN:
367 * AD domains should be secure
369 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
370 require_sign_or_seal = true;
371 require_strong_key = true;
372 neutralize_nt4_emulation = true;
376 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
377 require_sign_or_seal = true;
378 require_strong_key = true;
382 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
383 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
384 require_sign_or_seal = true;
385 require_strong_key = true;
386 neutralize_nt4_emulation = true;
391 return NT_STATUS_INVALID_PARAMETER;
394 if (neutralize_nt4_emulation) {
395 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
398 if (require_sign_or_seal) {
399 required_flags |= NETLOGON_NEG_ARCFOUR;
400 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
402 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
405 if (reject_md5_servers) {
406 required_flags |= NETLOGON_NEG_ARCFOUR;
407 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
408 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
409 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
412 if (require_strong_key) {
413 required_flags |= NETLOGON_NEG_ARCFOUR;
414 required_flags |= NETLOGON_NEG_STRONG_KEYS;
415 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
419 * If weak crypto is disabled, do not announce that we support RC4 and
422 if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
423 required_flags &= ~NETLOGON_NEG_ARCFOUR;
424 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
425 proposed_flags &= ~NETLOGON_NEG_ARCFOUR;
426 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
429 proposed_flags |= required_flags;
431 if (seal_secure_channel) {
432 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
434 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
437 status = netlogon_creds_cli_context_common(client_computer,
444 server_netbios_domain,
448 if (!NT_STATUS_IS_OK(status)) {
453 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
454 if (context->db.g_ctx == NULL) {
455 TALLOC_FREE(context);
457 return NT_STATUS_NO_MEMORY;
460 status = netlogon_creds_cli_open_global_db(lp_ctx);
461 if (!NT_STATUS_IS_OK(status)) {
462 TALLOC_FREE(context);
464 return NT_STATUS_NO_MEMORY;
467 context->db.ctx = netlogon_creds_cli_global_db;
473 NTSTATUS netlogon_creds_bind_cli_credentials(
474 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
475 struct cli_credentials **pcli_creds)
477 struct cli_credentials *cli_creds;
478 struct netlogon_creds_CredentialState *ncreds;
481 cli_creds = cli_credentials_init(mem_ctx);
482 if (cli_creds == NULL) {
483 return NT_STATUS_NO_MEMORY;
485 cli_credentials_set_secure_channel_type(cli_creds,
486 context->client.type);
487 cli_credentials_set_username(cli_creds, context->client.account,
489 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
491 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
494 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
495 if (!NT_STATUS_IS_OK(status)) {
496 TALLOC_FREE(cli_creds);
499 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
501 *pcli_creds = cli_creds;
505 char *netlogon_creds_cli_debug_string(
506 const struct netlogon_creds_cli_context *context,
509 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
510 context->db.key_name);
513 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
514 struct netlogon_creds_cli_context *context)
516 return context->client.auth_level;
519 static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags,
520 uint32_t proposed_flags,
521 uint32_t required_flags)
523 uint32_t req_flags = required_flags;
526 req_flags = required_flags;
527 if ((negotiated_flags & NETLOGON_NEG_SUPPORTS_AES) &&
528 (proposed_flags & NETLOGON_NEG_SUPPORTS_AES))
530 req_flags &= ~NETLOGON_NEG_ARCFOUR|NETLOGON_NEG_STRONG_KEYS;
533 tmp_flags = negotiated_flags;
534 tmp_flags &= req_flags;
535 if (tmp_flags != req_flags) {
542 struct netlogon_creds_cli_fetch_state {
544 struct netlogon_creds_CredentialState *creds;
545 uint32_t proposed_flags;
546 uint32_t required_flags;
550 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
553 struct netlogon_creds_cli_fetch_state *state =
554 (struct netlogon_creds_cli_fetch_state *)private_data;
555 enum ndr_err_code ndr_err;
559 state->creds = talloc_zero(state->mem_ctx,
560 struct netlogon_creds_CredentialState);
561 if (state->creds == NULL) {
562 state->status = NT_STATUS_NO_MEMORY;
566 blob.data = data.dptr;
567 blob.length = data.dsize;
569 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
570 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
571 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
572 TALLOC_FREE(state->creds);
573 state->status = ndr_map_error2ntstatus(ndr_err);
577 if (DEBUGLEVEL >= 10) {
578 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
581 downgraded = netlogon_creds_cli_downgraded(
582 state->creds->negotiate_flags,
583 state->proposed_flags,
584 state->required_flags);
586 TALLOC_FREE(state->creds);
587 state->status = NT_STATUS_DOWNGRADE_DETECTED;
591 state->status = NT_STATUS_OK;
594 static NTSTATUS netlogon_creds_cli_get_internal(
595 struct netlogon_creds_cli_context *context,
596 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
598 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
600 struct netlogon_creds_CredentialState **_creds)
603 struct netlogon_creds_CredentialState *creds;
607 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
608 if (!NT_STATUS_IS_OK(status)) {
613 * mark it as invalid for step operations.
616 creds->seed = (struct netr_Credential) {{0}};
617 creds->client = (struct netr_Credential) {{0}};
618 creds->server = (struct netr_Credential) {{0}};
624 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
625 const struct netlogon_creds_CredentialState *creds1)
627 TALLOC_CTX *frame = talloc_stackframe();
628 struct netlogon_creds_CredentialState *creds2;
632 enum ndr_err_code ndr_err;
635 status = netlogon_creds_cli_get(context, frame, &creds2);
636 if (!NT_STATUS_IS_OK(status)) {
641 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
642 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
643 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
648 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
649 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
650 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
655 equal = data_blob_equal_const_time(&blob1, &blob2);
662 static NTSTATUS netlogon_creds_cli_store_internal(
663 struct netlogon_creds_cli_context *context,
664 struct netlogon_creds_CredentialState *creds)
667 enum ndr_err_code ndr_err;
671 if (DEBUGLEVEL >= 10) {
672 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
675 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
676 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
677 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
678 status = ndr_map_error2ntstatus(ndr_err);
682 data.dptr = blob.data;
683 data.dsize = blob.length;
685 status = dbwrap_store(context->db.ctx,
686 context->db.key_data,
688 TALLOC_FREE(data.dptr);
689 if (!NT_STATUS_IS_OK(status)) {
696 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
697 struct netlogon_creds_CredentialState *creds)
701 if (context->db.locked_state == NULL) {
703 * this was not the result of netlogon_creds_cli_lock*()
705 return NT_STATUS_INVALID_PAGE_PROTECTION;
708 if (context->db.locked_state->creds != creds) {
710 * this was not the result of netlogon_creds_cli_lock*()
712 return NT_STATUS_INVALID_PAGE_PROTECTION;
715 status = netlogon_creds_cli_store_internal(context, creds);
719 static NTSTATUS netlogon_creds_cli_delete_internal(
720 struct netlogon_creds_cli_context *context)
723 status = dbwrap_delete(context->db.ctx, context->db.key_data);
727 NTSTATUS netlogon_creds_cli_delete_lck(
728 struct netlogon_creds_cli_context *context)
732 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
733 return NT_STATUS_NOT_LOCKED;
736 status = netlogon_creds_cli_delete_internal(context);
740 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
741 struct netlogon_creds_CredentialState *creds)
745 if (context->db.locked_state == NULL) {
747 * this was not the result of netlogon_creds_cli_lock*()
749 return NT_STATUS_INVALID_PAGE_PROTECTION;
752 if (context->db.locked_state->creds != creds) {
754 * this was not the result of netlogon_creds_cli_lock*()
756 return NT_STATUS_INVALID_PAGE_PROTECTION;
759 status = netlogon_creds_cli_delete_internal(context);
763 struct netlogon_creds_cli_lock_state {
764 struct netlogon_creds_cli_locked_state *locked_state;
765 struct netlogon_creds_CredentialState *creds;
768 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
770 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
771 struct tevent_context *ev,
772 struct netlogon_creds_cli_context *context)
774 struct tevent_req *req;
775 struct netlogon_creds_cli_lock_state *state;
776 struct netlogon_creds_cli_locked_state *locked_state;
777 struct tevent_req *subreq;
779 req = tevent_req_create(mem_ctx, &state,
780 struct netlogon_creds_cli_lock_state);
785 if (context->db.locked_state != NULL) {
786 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
787 return tevent_req_post(req, ev);
790 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
791 if (tevent_req_nomem(locked_state, req)) {
792 return tevent_req_post(req, ev);
794 talloc_set_destructor(locked_state,
795 netlogon_creds_cli_locked_state_destructor);
796 locked_state->context = context;
798 context->db.locked_state = locked_state;
799 state->locked_state = locked_state;
801 if (context->db.g_ctx == NULL) {
804 status = netlogon_creds_cli_get_internal(
805 context, state, &state->creds);
806 if (tevent_req_nterror(req, status)) {
807 return tevent_req_post(req, ev);
813 subreq = g_lock_lock_send(state, ev,
815 string_term_tdb_data(context->db.key_name),
818 if (tevent_req_nomem(subreq, req)) {
819 return tevent_req_post(req, ev);
821 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
826 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
828 struct tevent_req *req =
829 tevent_req_callback_data(subreq,
831 struct netlogon_creds_cli_lock_state *state =
833 struct netlogon_creds_cli_lock_state);
836 status = g_lock_lock_recv(subreq);
838 if (tevent_req_nterror(req, status)) {
841 state->locked_state->is_glocked = true;
843 status = netlogon_creds_cli_get_internal(state->locked_state->context,
844 state, &state->creds);
845 if (tevent_req_nterror(req, status)) {
848 tevent_req_done(req);
851 static NTSTATUS netlogon_creds_cli_get_internal(
852 struct netlogon_creds_cli_context *context,
853 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
855 struct netlogon_creds_cli_fetch_state fstate = {
856 .status = NT_STATUS_INTERNAL_ERROR,
857 .proposed_flags = context->client.proposed_flags,
858 .required_flags = context->client.required_flags,
862 fstate.mem_ctx = mem_ctx;
863 status = dbwrap_parse_record(context->db.ctx,
864 context->db.key_data,
865 netlogon_creds_cli_fetch_parser,
867 if (!NT_STATUS_IS_OK(status)) {
870 if (!NT_STATUS_IS_OK(fstate.status)) {
871 return fstate.status;
874 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
875 *pcreds = fstate.creds;
880 * It is really important to try SamLogonEx here,
881 * because multiple processes can talk to the same
882 * domain controller, without using the credential
885 * With a normal SamLogon call, we must keep the
886 * credentials chain updated and intact between all
887 * users of the machine account (which would imply
888 * cross-node communication for every NTLM logon).
890 * The credentials chain is not per NETLOGON pipe
891 * connection, but globally on the server/client pair
894 * It's also important to use NetlogonValidationSamInfo4 (6),
895 * because it relies on the rpc transport encryption
896 * and avoids using the global netlogon schannel
897 * session key to en/decrypt secret information
898 * like the user_session_key for network logons.
900 * [MS-APDS] 3.1.5.2 NTLM Network Logon
901 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
902 * NETLOGON_NEG_AUTHENTICATED_RPC set together
903 * are the indication that the server supports
904 * NetlogonValidationSamInfo4 (6). And it must only
905 * be used if "SealSecureChannel" is used.
907 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
908 * check is done in netlogon_creds_cli_LogonSamLogon*().
911 context->server.cached_flags = fstate.creds->negotiate_flags;
912 context->server.try_validation6 = true;
913 context->server.try_logon_ex = true;
914 context->server.try_logon_with = true;
916 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
917 context->server.try_validation6 = false;
918 context->server.try_logon_ex = false;
920 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
921 context->server.try_validation6 = false;
924 *pcreds = fstate.creds;
928 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
930 struct netlogon_creds_CredentialState **creds)
932 struct netlogon_creds_cli_lock_state *state =
934 struct netlogon_creds_cli_lock_state);
937 if (tevent_req_is_nterror(req, &status)) {
938 tevent_req_received(req);
942 talloc_steal(state->creds, state->locked_state);
943 state->locked_state->creds = state->creds;
944 *creds = talloc_move(mem_ctx, &state->creds);
945 tevent_req_received(req);
949 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
951 struct netlogon_creds_CredentialState **creds)
953 TALLOC_CTX *frame = talloc_stackframe();
954 struct tevent_context *ev;
955 struct tevent_req *req;
956 NTSTATUS status = NT_STATUS_NO_MEMORY;
958 ev = samba_tevent_context_init(frame);
962 req = netlogon_creds_cli_lock_send(frame, ev, context);
966 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
969 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
975 struct netlogon_creds_cli_lck {
976 struct netlogon_creds_cli_context *context;
979 struct netlogon_creds_cli_lck_state {
980 struct netlogon_creds_cli_lck *lck;
981 enum netlogon_creds_cli_lck_type type;
984 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
985 static int netlogon_creds_cli_lck_destructor(
986 struct netlogon_creds_cli_lck *lck);
988 struct tevent_req *netlogon_creds_cli_lck_send(
989 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
990 struct netlogon_creds_cli_context *context,
991 enum netlogon_creds_cli_lck_type type)
993 struct tevent_req *req, *subreq;
994 struct netlogon_creds_cli_lck_state *state;
995 enum g_lock_type gtype;
997 req = tevent_req_create(mem_ctx, &state,
998 struct netlogon_creds_cli_lck_state);
1003 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
1004 DBG_DEBUG("context already locked\n");
1005 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
1006 return tevent_req_post(req, ev);
1010 case NETLOGON_CREDS_CLI_LCK_SHARED:
1011 gtype = G_LOCK_READ;
1013 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
1014 gtype = G_LOCK_WRITE;
1017 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1018 return tevent_req_post(req, ev);
1021 state->lck = talloc(state, struct netlogon_creds_cli_lck);
1022 if (tevent_req_nomem(state->lck, req)) {
1023 return tevent_req_post(req, ev);
1025 state->lck->context = context;
1028 subreq = g_lock_lock_send(state, ev,
1030 string_term_tdb_data(context->db.key_name),
1033 if (tevent_req_nomem(subreq, req)) {
1034 return tevent_req_post(req, ev);
1036 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
1041 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
1043 struct tevent_req *req = tevent_req_callback_data(
1044 subreq, struct tevent_req);
1045 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1046 req, struct netlogon_creds_cli_lck_state);
1049 status = g_lock_lock_recv(subreq);
1050 TALLOC_FREE(subreq);
1051 if (tevent_req_nterror(req, status)) {
1055 state->lck->context->db.lock = state->type;
1056 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1058 tevent_req_done(req);
1061 static int netlogon_creds_cli_lck_destructor(
1062 struct netlogon_creds_cli_lck *lck)
1064 struct netlogon_creds_cli_context *ctx = lck->context;
1067 status = g_lock_unlock(ctx->db.g_ctx,
1068 string_term_tdb_data(ctx->db.key_name));
1069 if (!NT_STATUS_IS_OK(status)) {
1070 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1071 smb_panic("g_lock_unlock failed");
1073 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1077 NTSTATUS netlogon_creds_cli_lck_recv(
1078 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1079 struct netlogon_creds_cli_lck **lck)
1081 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1082 req, struct netlogon_creds_cli_lck_state);
1085 if (tevent_req_is_nterror(req, &status)) {
1088 *lck = talloc_move(mem_ctx, &state->lck);
1089 return NT_STATUS_OK;
1092 NTSTATUS netlogon_creds_cli_lck(
1093 struct netlogon_creds_cli_context *context,
1094 enum netlogon_creds_cli_lck_type type,
1095 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1097 TALLOC_CTX *frame = talloc_stackframe();
1098 struct tevent_context *ev;
1099 struct tevent_req *req;
1100 NTSTATUS status = NT_STATUS_NO_MEMORY;
1102 ev = samba_tevent_context_init(frame);
1106 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1110 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1113 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1119 struct netlogon_creds_cli_auth_state {
1120 struct tevent_context *ev;
1121 struct netlogon_creds_cli_context *context;
1122 struct dcerpc_binding_handle *binding_handle;
1123 uint8_t num_nt_hashes;
1124 uint8_t idx_nt_hashes;
1125 const struct samr_Password * const *nt_hashes;
1126 const struct samr_Password *used_nt_hash;
1127 char *srv_name_slash;
1128 uint32_t current_flags;
1129 struct netr_Credential client_challenge;
1130 struct netr_Credential server_challenge;
1131 struct netlogon_creds_CredentialState *creds;
1132 struct netr_Credential client_credential;
1133 struct netr_Credential server_credential;
1140 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1142 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1143 struct tevent_context *ev,
1144 struct netlogon_creds_cli_context *context,
1145 struct dcerpc_binding_handle *b,
1146 uint8_t num_nt_hashes,
1147 const struct samr_Password * const *nt_hashes)
1149 struct tevent_req *req;
1150 struct netlogon_creds_cli_auth_state *state;
1153 req = tevent_req_create(mem_ctx, &state,
1154 struct netlogon_creds_cli_auth_state);
1160 state->context = context;
1161 state->binding_handle = b;
1162 if (num_nt_hashes < 1) {
1163 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1164 return tevent_req_post(req, ev);
1166 if (num_nt_hashes > 4) {
1167 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1168 return tevent_req_post(req, ev);
1171 state->num_nt_hashes = num_nt_hashes;
1172 state->idx_nt_hashes = 0;
1173 state->nt_hashes = nt_hashes;
1175 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1176 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1177 return tevent_req_post(req, ev);
1180 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1181 context->server.computer);
1182 if (tevent_req_nomem(state->srv_name_slash, req)) {
1183 return tevent_req_post(req, ev);
1186 state->try_auth3 = true;
1187 state->try_auth2 = true;
1189 if (context->client.required_flags != 0) {
1190 state->require_auth2 = true;
1193 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1194 state->current_flags = context->client.proposed_flags;
1196 status = dbwrap_purge(state->context->db.ctx,
1197 state->context->db.key_data);
1198 if (tevent_req_nterror(req, status)) {
1199 return tevent_req_post(req, ev);
1202 netlogon_creds_cli_auth_challenge_start(req);
1203 if (!tevent_req_is_in_progress(req)) {
1204 return tevent_req_post(req, ev);
1210 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1212 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1214 struct netlogon_creds_cli_auth_state *state =
1215 tevent_req_data(req,
1216 struct netlogon_creds_cli_auth_state);
1217 struct tevent_req *subreq;
1219 TALLOC_FREE(state->creds);
1221 netlogon_creds_random_challenge(&state->client_challenge);
1223 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1224 state->binding_handle,
1225 state->srv_name_slash,
1226 state->context->client.computer,
1227 &state->client_challenge,
1228 &state->server_challenge);
1229 if (tevent_req_nomem(subreq, req)) {
1232 tevent_req_set_callback(subreq,
1233 netlogon_creds_cli_auth_challenge_done,
1237 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1239 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1241 struct tevent_req *req =
1242 tevent_req_callback_data(subreq,
1244 struct netlogon_creds_cli_auth_state *state =
1245 tevent_req_data(req,
1246 struct netlogon_creds_cli_auth_state);
1250 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1251 TALLOC_FREE(subreq);
1252 if (tevent_req_nterror(req, status)) {
1255 if (tevent_req_nterror(req, result)) {
1259 if (!state->try_auth3 && !state->try_auth2) {
1260 state->current_flags = 0;
1263 /* Calculate the session key and client credentials */
1265 state->creds = netlogon_creds_client_init(state,
1266 state->context->client.account,
1267 state->context->client.computer,
1268 state->context->client.type,
1269 &state->client_challenge,
1270 &state->server_challenge,
1271 state->used_nt_hash,
1272 &state->client_credential,
1273 state->current_flags);
1274 if (tevent_req_nomem(state->creds, req)) {
1278 if (state->try_auth3) {
1279 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1280 state->binding_handle,
1281 state->srv_name_slash,
1282 state->context->client.account,
1283 state->context->client.type,
1284 state->context->client.computer,
1285 &state->client_credential,
1286 &state->server_credential,
1287 &state->creds->negotiate_flags,
1289 if (tevent_req_nomem(subreq, req)) {
1292 } else if (state->try_auth2) {
1295 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1296 state->binding_handle,
1297 state->srv_name_slash,
1298 state->context->client.account,
1299 state->context->client.type,
1300 state->context->client.computer,
1301 &state->client_credential,
1302 &state->server_credential,
1303 &state->creds->negotiate_flags);
1304 if (tevent_req_nomem(subreq, req)) {
1310 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1311 state->binding_handle,
1312 state->srv_name_slash,
1313 state->context->client.account,
1314 state->context->client.type,
1315 state->context->client.computer,
1316 &state->client_credential,
1317 &state->server_credential);
1318 if (tevent_req_nomem(subreq, req)) {
1322 tevent_req_set_callback(subreq,
1323 netlogon_creds_cli_auth_srvauth_done,
1327 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1329 struct tevent_req *req =
1330 tevent_req_callback_data(subreq,
1332 struct netlogon_creds_cli_auth_state *state =
1333 tevent_req_data(req,
1334 struct netlogon_creds_cli_auth_state);
1338 enum ndr_err_code ndr_err;
1343 if (state->try_auth3) {
1344 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1346 TALLOC_FREE(subreq);
1347 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1348 state->try_auth3 = false;
1349 netlogon_creds_cli_auth_challenge_start(req);
1352 if (tevent_req_nterror(req, status)) {
1355 } else if (state->try_auth2) {
1356 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1358 TALLOC_FREE(subreq);
1359 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1360 state->try_auth2 = false;
1361 if (state->require_auth2) {
1362 status = NT_STATUS_DOWNGRADE_DETECTED;
1363 tevent_req_nterror(req, status);
1366 netlogon_creds_cli_auth_challenge_start(req);
1369 if (tevent_req_nterror(req, status)) {
1373 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1375 TALLOC_FREE(subreq);
1376 if (tevent_req_nterror(req, status)) {
1381 if (!NT_STATUS_IS_OK(result) &&
1382 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1384 tevent_req_nterror(req, result);
1388 downgraded = netlogon_creds_cli_downgraded(
1389 state->creds->negotiate_flags,
1390 state->context->client.proposed_flags,
1391 state->context->client.required_flags);
1393 if (NT_STATUS_IS_OK(result)) {
1394 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1397 tevent_req_nterror(req, result);
1401 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1402 uint32_t tmp_flags = state->context->client.proposed_flags;
1403 if ((state->current_flags == tmp_flags) &&
1404 (state->creds->negotiate_flags != tmp_flags))
1407 * lets retry with the negotiated flags
1409 state->current_flags = state->creds->negotiate_flags;
1410 netlogon_creds_cli_auth_challenge_start(req);
1414 state->idx_nt_hashes += 1;
1415 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1417 * we already retried, giving up...
1419 tevent_req_nterror(req, result);
1424 * lets retry with the old nt hash.
1426 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1427 state->current_flags = state->context->client.proposed_flags;
1428 netlogon_creds_cli_auth_challenge_start(req);
1432 ok = netlogon_creds_client_check(state->creds,
1433 &state->server_credential);
1435 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1439 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1440 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1441 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1442 status = ndr_map_error2ntstatus(ndr_err);
1443 tevent_req_nterror(req, status);
1447 data.dptr = blob.data;
1448 data.dsize = blob.length;
1450 status = dbwrap_store(state->context->db.ctx,
1451 state->context->db.key_data,
1453 if (tevent_req_nterror(req, status)) {
1457 tevent_req_done(req);
1460 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1461 uint8_t *idx_nt_hashes)
1463 struct netlogon_creds_cli_auth_state *state =
1464 tevent_req_data(req,
1465 struct netlogon_creds_cli_auth_state);
1470 if (tevent_req_is_nterror(req, &status)) {
1471 tevent_req_received(req);
1475 *idx_nt_hashes = state->idx_nt_hashes;
1476 tevent_req_received(req);
1477 return NT_STATUS_OK;
1480 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1481 struct dcerpc_binding_handle *b,
1482 uint8_t num_nt_hashes,
1483 const struct samr_Password * const *nt_hashes,
1484 uint8_t *idx_nt_hashes)
1486 TALLOC_CTX *frame = talloc_stackframe();
1487 struct tevent_context *ev;
1488 struct tevent_req *req;
1489 NTSTATUS status = NT_STATUS_NO_MEMORY;
1493 ev = samba_tevent_context_init(frame);
1497 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1498 num_nt_hashes, nt_hashes);
1502 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1505 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1511 struct netlogon_creds_cli_check_state {
1512 struct tevent_context *ev;
1513 struct netlogon_creds_cli_context *context;
1514 struct dcerpc_binding_handle *binding_handle;
1516 char *srv_name_slash;
1518 union netr_Capabilities caps;
1520 struct netlogon_creds_CredentialState *creds;
1521 struct netr_Authenticator req_auth;
1522 struct netr_Authenticator rep_auth;
1525 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1527 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1529 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1530 struct tevent_context *ev,
1531 struct netlogon_creds_cli_context *context,
1532 struct dcerpc_binding_handle *b)
1534 struct tevent_req *req;
1535 struct netlogon_creds_cli_check_state *state;
1536 struct tevent_req *subreq;
1537 enum dcerpc_AuthType auth_type;
1538 enum dcerpc_AuthLevel auth_level;
1541 req = tevent_req_create(mem_ctx, &state,
1542 struct netlogon_creds_cli_check_state);
1548 state->context = context;
1549 state->binding_handle = b;
1551 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1552 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1553 return tevent_req_post(req, ev);
1556 status = netlogon_creds_cli_get_internal(context, state,
1558 if (tevent_req_nterror(req, status)) {
1559 return tevent_req_post(req, ev);
1562 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1563 context->server.computer);
1564 if (tevent_req_nomem(state->srv_name_slash, req)) {
1565 return tevent_req_post(req, ev);
1568 dcerpc_binding_handle_auth_info(state->binding_handle,
1569 &auth_type, &auth_level);
1571 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1572 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1573 return tevent_req_post(req, ev);
1576 switch (auth_level) {
1577 case DCERPC_AUTH_LEVEL_INTEGRITY:
1578 case DCERPC_AUTH_LEVEL_PRIVACY:
1581 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1582 return tevent_req_post(req, ev);
1586 * we defer all callbacks in order to cleanup
1587 * the database record.
1589 tevent_req_defer_callback(req, state->ev);
1591 status = netlogon_creds_client_authenticator(state->creds,
1593 if (tevent_req_nterror(req, status)) {
1594 return tevent_req_post(req, ev);
1596 ZERO_STRUCT(state->rep_auth);
1598 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1599 state->binding_handle,
1600 state->srv_name_slash,
1601 state->context->client.computer,
1606 if (tevent_req_nomem(subreq, req)) {
1607 return tevent_req_post(req, ev);
1610 tevent_req_set_callback(subreq,
1611 netlogon_creds_cli_check_caps,
1617 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1620 struct netlogon_creds_cli_check_state *state =
1621 tevent_req_data(req,
1622 struct netlogon_creds_cli_check_state);
1624 if (state->creds == NULL) {
1628 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1629 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1630 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1631 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1632 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1633 TALLOC_FREE(state->creds);
1637 netlogon_creds_cli_delete_lck(state->context);
1638 TALLOC_FREE(state->creds);
1641 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1643 struct tevent_req *req =
1644 tevent_req_callback_data(subreq,
1646 struct netlogon_creds_cli_check_state *state =
1647 tevent_req_data(req,
1648 struct netlogon_creds_cli_check_state);
1653 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1655 TALLOC_FREE(subreq);
1656 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1658 * Note that the negotiated flags are already checked
1659 * for our required flags after the ServerAuthenticate3/2 call.
1661 uint32_t negotiated = state->creds->negotiate_flags;
1663 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1665 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1666 * already, we expect this to work!
1668 status = NT_STATUS_DOWNGRADE_DETECTED;
1669 tevent_req_nterror(req, status);
1670 netlogon_creds_cli_check_cleanup(req, status);
1674 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1676 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1677 * we expect this to work at least as far as the
1678 * NOT_SUPPORTED error handled below!
1680 * NT 4.0 and Old Samba servers are not
1681 * allowed without "require strong key = no"
1683 status = NT_STATUS_DOWNGRADE_DETECTED;
1684 tevent_req_nterror(req, status);
1685 netlogon_creds_cli_check_cleanup(req, status);
1690 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1691 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1692 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1694 * This is needed against NT 4.0 and old Samba servers.
1696 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1697 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1698 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1699 * with the next request as the sequence number processing
1702 netlogon_creds_cli_check_cleanup(req, status);
1703 tevent_req_done(req);
1706 if (tevent_req_nterror(req, status)) {
1707 netlogon_creds_cli_check_cleanup(req, status);
1711 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1713 * Note that the negotiated flags are already checked
1714 * for our required flags after the ServerAuthenticate3/2 call.
1716 uint32_t negotiated = state->creds->negotiate_flags;
1718 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1720 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1721 * already, we expect this to work!
1723 status = NT_STATUS_DOWNGRADE_DETECTED;
1724 tevent_req_nterror(req, status);
1725 netlogon_creds_cli_check_cleanup(req, status);
1730 * This is ok, the server does not support
1731 * NETLOGON_NEG_SUPPORTS_AES.
1733 * netr_LogonGetCapabilities() was
1734 * netr_LogonDummyRoutine1() before
1735 * NETLOGON_NEG_SUPPORTS_AES was invented.
1737 netlogon_creds_cli_check_cleanup(req, result);
1738 tevent_req_done(req);
1742 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1744 status = NT_STATUS_ACCESS_DENIED;
1745 tevent_req_nterror(req, status);
1746 netlogon_creds_cli_check_cleanup(req, status);
1750 if (tevent_req_nterror(req, result)) {
1751 netlogon_creds_cli_check_cleanup(req, result);
1755 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1756 status = NT_STATUS_DOWNGRADE_DETECTED;
1757 tevent_req_nterror(req, status);
1758 netlogon_creds_cli_check_cleanup(req, status);
1763 * This is the key check that makes this check secure. If we
1764 * get OK here (rather than NOT_SUPPORTED), then the server
1765 * did support AES. If the server only proposed STRONG_KEYS
1766 * and not AES, then it should have failed with
1767 * NOT_IMPLEMENTED. We always send AES as a client, so the
1768 * server should always have returned it.
1770 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1771 status = NT_STATUS_DOWNGRADE_DETECTED;
1772 tevent_req_nterror(req, status);
1773 netlogon_creds_cli_check_cleanup(req, status);
1777 status = netlogon_creds_cli_store_internal(state->context,
1779 if (tevent_req_nterror(req, status)) {
1783 tevent_req_done(req);
1786 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1787 union netr_Capabilities *capabilities)
1789 struct netlogon_creds_cli_check_state *state = tevent_req_data(
1790 req, struct netlogon_creds_cli_check_state);
1793 if (tevent_req_is_nterror(req, &status)) {
1794 netlogon_creds_cli_check_cleanup(req, status);
1795 tevent_req_received(req);
1799 if (capabilities != NULL) {
1800 *capabilities = state->caps;
1803 tevent_req_received(req);
1804 return NT_STATUS_OK;
1807 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1808 struct dcerpc_binding_handle *b,
1809 union netr_Capabilities *capabilities)
1811 TALLOC_CTX *frame = talloc_stackframe();
1812 struct tevent_context *ev;
1813 struct tevent_req *req;
1814 NTSTATUS status = NT_STATUS_NO_MEMORY;
1816 ev = samba_tevent_context_init(frame);
1820 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1824 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1827 status = netlogon_creds_cli_check_recv(req, capabilities);
1833 struct netlogon_creds_cli_ServerPasswordSet_state {
1834 struct tevent_context *ev;
1835 struct netlogon_creds_cli_context *context;
1836 struct dcerpc_binding_handle *binding_handle;
1837 uint32_t old_timeout;
1839 char *srv_name_slash;
1840 enum dcerpc_AuthType auth_type;
1841 enum dcerpc_AuthLevel auth_level;
1843 struct samr_CryptPassword samr_crypt_password;
1844 struct netr_CryptPassword netr_crypt_password;
1845 struct samr_Password samr_password;
1847 struct netlogon_creds_CredentialState *creds;
1848 struct netlogon_creds_CredentialState tmp_creds;
1849 struct netr_Authenticator req_auth;
1850 struct netr_Authenticator rep_auth;
1853 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1855 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1857 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1858 struct tevent_context *ev,
1859 struct netlogon_creds_cli_context *context,
1860 struct dcerpc_binding_handle *b,
1861 const DATA_BLOB *new_password,
1862 const uint32_t *new_version)
1864 struct tevent_req *req;
1865 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1866 struct tevent_req *subreq;
1869 req = tevent_req_create(mem_ctx, &state,
1870 struct netlogon_creds_cli_ServerPasswordSet_state);
1876 state->context = context;
1877 state->binding_handle = b;
1879 if (new_password->length < 14) {
1880 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1881 return tevent_req_post(req, ev);
1885 * netr_ServerPasswordSet
1887 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1890 * netr_ServerPasswordSet2
1892 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1895 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1896 return tevent_req_post(req, ev);
1899 if (new_version != NULL) {
1900 struct NL_PASSWORD_VERSION version;
1901 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1902 uint32_t ofs = 512 - len;
1906 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1907 return tevent_req_post(req, ev);
1911 version.ReservedField = 0;
1912 version.PasswordVersionNumber = *new_version;
1913 version.PasswordVersionPresent =
1914 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1916 p = state->samr_crypt_password.data + ofs;
1917 SIVAL(p, 0, version.ReservedField);
1918 SIVAL(p, 4, version.PasswordVersionNumber);
1919 SIVAL(p, 8, version.PasswordVersionPresent);
1922 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1923 context->server.computer);
1924 if (tevent_req_nomem(state->srv_name_slash, req)) {
1925 return tevent_req_post(req, ev);
1928 dcerpc_binding_handle_auth_info(state->binding_handle,
1930 &state->auth_level);
1932 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1934 if (tevent_req_nomem(subreq, req)) {
1935 return tevent_req_post(req, ev);
1938 tevent_req_set_callback(subreq,
1939 netlogon_creds_cli_ServerPasswordSet_locked,
1945 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1948 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1949 tevent_req_data(req,
1950 struct netlogon_creds_cli_ServerPasswordSet_state);
1952 if (state->creds == NULL) {
1956 dcerpc_binding_handle_set_timeout(state->binding_handle,
1957 state->old_timeout);
1959 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1960 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1961 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1962 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1963 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1964 TALLOC_FREE(state->creds);
1968 netlogon_creds_cli_delete(state->context, state->creds);
1969 TALLOC_FREE(state->creds);
1972 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1974 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1976 struct tevent_req *req =
1977 tevent_req_callback_data(subreq,
1979 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1980 tevent_req_data(req,
1981 struct netlogon_creds_cli_ServerPasswordSet_state);
1984 status = netlogon_creds_cli_lock_recv(subreq, state,
1986 TALLOC_FREE(subreq);
1987 if (tevent_req_nterror(req, status)) {
1991 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1992 switch (state->auth_level) {
1993 case DCERPC_AUTH_LEVEL_INTEGRITY:
1994 case DCERPC_AUTH_LEVEL_PRIVACY:
1997 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2001 uint32_t tmp = state->creds->negotiate_flags;
2003 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2005 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2006 * it should be used, which means
2007 * we had a chance to verify no downgrade
2010 * This relies on netlogon_creds_cli_check*
2011 * being called before, as first request after
2014 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2019 state->old_timeout = dcerpc_binding_handle_set_timeout(
2020 state->binding_handle, 600000);
2023 * we defer all callbacks in order to cleanup
2024 * the database record.
2026 tevent_req_defer_callback(req, state->ev);
2028 state->tmp_creds = *state->creds;
2029 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2031 if (tevent_req_nterror(req, status)) {
2034 ZERO_STRUCT(state->rep_auth);
2036 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2038 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
2039 status = netlogon_creds_aes_encrypt(&state->tmp_creds,
2040 state->samr_crypt_password.data,
2042 if (tevent_req_nterror(req, status)) {
2043 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2047 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
2048 state->samr_crypt_password.data,
2050 if (tevent_req_nterror(req, status)) {
2051 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2056 memcpy(state->netr_crypt_password.data,
2057 state->samr_crypt_password.data, 512);
2058 state->netr_crypt_password.length =
2059 IVAL(state->samr_crypt_password.data, 512);
2061 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2062 state->binding_handle,
2063 state->srv_name_slash,
2064 state->tmp_creds.account_name,
2065 state->tmp_creds.secure_channel_type,
2066 state->tmp_creds.computer_name,
2069 &state->netr_crypt_password);
2070 if (tevent_req_nomem(subreq, req)) {
2071 status = NT_STATUS_NO_MEMORY;
2072 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2076 status = netlogon_creds_des_encrypt(&state->tmp_creds,
2077 &state->samr_password);
2078 if (tevent_req_nterror(req, status)) {
2079 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2083 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2084 state->binding_handle,
2085 state->srv_name_slash,
2086 state->tmp_creds.account_name,
2087 state->tmp_creds.secure_channel_type,
2088 state->tmp_creds.computer_name,
2091 &state->samr_password);
2092 if (tevent_req_nomem(subreq, req)) {
2093 status = NT_STATUS_NO_MEMORY;
2094 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2099 tevent_req_set_callback(subreq,
2100 netlogon_creds_cli_ServerPasswordSet_done,
2104 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2106 struct tevent_req *req =
2107 tevent_req_callback_data(subreq,
2109 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2110 tevent_req_data(req,
2111 struct netlogon_creds_cli_ServerPasswordSet_state);
2116 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2117 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2119 TALLOC_FREE(subreq);
2120 if (tevent_req_nterror(req, status)) {
2121 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2125 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2127 TALLOC_FREE(subreq);
2128 if (tevent_req_nterror(req, status)) {
2129 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2134 ok = netlogon_creds_client_check(&state->tmp_creds,
2135 &state->rep_auth.cred);
2137 status = NT_STATUS_ACCESS_DENIED;
2138 tevent_req_nterror(req, status);
2139 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2143 if (tevent_req_nterror(req, result)) {
2144 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2148 dcerpc_binding_handle_set_timeout(state->binding_handle,
2149 state->old_timeout);
2151 *state->creds = state->tmp_creds;
2152 status = netlogon_creds_cli_store(state->context,
2154 TALLOC_FREE(state->creds);
2155 if (tevent_req_nterror(req, status)) {
2156 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2160 tevent_req_done(req);
2163 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2167 if (tevent_req_is_nterror(req, &status)) {
2168 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2169 tevent_req_received(req);
2173 tevent_req_received(req);
2174 return NT_STATUS_OK;
2177 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2178 struct netlogon_creds_cli_context *context,
2179 struct dcerpc_binding_handle *b,
2180 const DATA_BLOB *new_password,
2181 const uint32_t *new_version)
2183 TALLOC_CTX *frame = talloc_stackframe();
2184 struct tevent_context *ev;
2185 struct tevent_req *req;
2186 NTSTATUS status = NT_STATUS_NO_MEMORY;
2188 ev = samba_tevent_context_init(frame);
2192 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2198 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2201 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2207 struct netlogon_creds_cli_LogonSamLogon_state {
2208 struct tevent_context *ev;
2209 struct netlogon_creds_cli_context *context;
2210 struct dcerpc_binding_handle *binding_handle;
2212 char *srv_name_slash;
2214 enum netr_LogonInfoClass logon_level;
2215 const union netr_LogonLevel *const_logon;
2216 union netr_LogonLevel *logon;
2219 uint16_t validation_level;
2220 union netr_Validation *validation;
2221 uint8_t authoritative;
2224 * do we need encryption at the application layer?
2228 bool try_validation6;
2231 * the read only credentials before we started the operation
2232 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2234 struct netlogon_creds_CredentialState *ro_creds;
2237 * The (locked) credentials used for the credential chain
2238 * used for netr_LogonSamLogonWithFlags() or
2239 * netr_LogonSamLogonWith().
2241 struct netlogon_creds_CredentialState *lk_creds;
2244 * While we have locked the global credentials (lk_creds above)
2245 * we operate an a temporary copy, because a server
2246 * may not support netr_LogonSamLogonWithFlags() and
2247 * didn't process our netr_Authenticator, so we need to
2248 * restart from lk_creds.
2250 struct netlogon_creds_CredentialState tmp_creds;
2251 struct netr_Authenticator req_auth;
2252 struct netr_Authenticator rep_auth;
2255 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2256 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2259 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2260 struct tevent_context *ev,
2261 struct netlogon_creds_cli_context *context,
2262 struct dcerpc_binding_handle *b,
2263 enum netr_LogonInfoClass logon_level,
2264 const union netr_LogonLevel *logon,
2267 struct tevent_req *req;
2268 struct netlogon_creds_cli_LogonSamLogon_state *state;
2270 req = tevent_req_create(mem_ctx, &state,
2271 struct netlogon_creds_cli_LogonSamLogon_state);
2277 state->context = context;
2278 state->binding_handle = b;
2280 state->logon_level = logon_level;
2281 state->const_logon = logon;
2282 state->flags = flags;
2284 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2285 context->server.computer);
2286 if (tevent_req_nomem(state->srv_name_slash, req)) {
2287 return tevent_req_post(req, ev);
2290 switch (logon_level) {
2291 case NetlogonInteractiveInformation:
2292 case NetlogonInteractiveTransitiveInformation:
2293 case NetlogonServiceInformation:
2294 case NetlogonServiceTransitiveInformation:
2295 case NetlogonGenericInformation:
2296 state->user_encrypt = true;
2299 case NetlogonNetworkInformation:
2300 case NetlogonNetworkTransitiveInformation:
2304 state->validation = talloc_zero(state, union netr_Validation);
2305 if (tevent_req_nomem(state->validation, req)) {
2306 return tevent_req_post(req, ev);
2309 netlogon_creds_cli_LogonSamLogon_start(req);
2310 if (!tevent_req_is_in_progress(req)) {
2311 return tevent_req_post(req, ev);
2315 * we defer all callbacks in order to cleanup
2316 * the database record.
2318 tevent_req_defer_callback(req, state->ev);
2322 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2325 struct netlogon_creds_cli_LogonSamLogon_state *state =
2326 tevent_req_data(req,
2327 struct netlogon_creds_cli_LogonSamLogon_state);
2329 if (state->lk_creds == NULL) {
2333 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2335 * This is a hack to recover from a bug in old
2336 * Samba servers, when LogonSamLogonEx() fails:
2338 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2340 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2342 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2343 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2344 * If the sign/seal check fails.
2346 * In that case we need to cleanup the netlogon session.
2348 * It's the job of the caller to disconnect the current
2349 * connection, if netlogon_creds_cli_LogonSamLogon()
2350 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2352 if (!state->context->server.try_logon_with) {
2353 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2357 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2358 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2359 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2360 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2361 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2362 TALLOC_FREE(state->lk_creds);
2366 netlogon_creds_cli_delete(state->context, state->lk_creds);
2367 TALLOC_FREE(state->lk_creds);
2370 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2372 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2374 struct netlogon_creds_cli_LogonSamLogon_state *state =
2375 tevent_req_data(req,
2376 struct netlogon_creds_cli_LogonSamLogon_state);
2377 struct tevent_req *subreq;
2379 enum dcerpc_AuthType auth_type;
2380 enum dcerpc_AuthLevel auth_level;
2382 TALLOC_FREE(state->ro_creds);
2383 TALLOC_FREE(state->logon);
2384 ZERO_STRUCTP(state->validation);
2386 dcerpc_binding_handle_auth_info(state->binding_handle,
2387 &auth_type, &auth_level);
2389 state->try_logon_ex = state->context->server.try_logon_ex;
2390 state->try_validation6 = state->context->server.try_validation6;
2392 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2393 state->try_logon_ex = false;
2396 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2397 state->try_validation6 = false;
2400 if (state->try_logon_ex) {
2401 if (state->try_validation6) {
2402 state->validation_level = 6;
2404 state->validation_level = 3;
2405 state->user_encrypt = true;
2408 state->logon = netlogon_creds_shallow_copy_logon(state,
2410 state->const_logon);
2411 if (tevent_req_nomem(state->logon, req)) {
2412 status = NT_STATUS_NO_MEMORY;
2413 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2417 if (state->user_encrypt) {
2418 status = netlogon_creds_cli_get(state->context,
2421 if (!NT_STATUS_IS_OK(status)) {
2422 status = NT_STATUS_ACCESS_DENIED;
2423 tevent_req_nterror(req, status);
2424 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2428 status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2431 if (!NT_STATUS_IS_OK(status)) {
2432 status = NT_STATUS_ACCESS_DENIED;
2433 tevent_req_nterror(req, status);
2434 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2439 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2440 state->binding_handle,
2441 state->srv_name_slash,
2442 state->context->client.computer,
2445 state->validation_level,
2447 &state->authoritative,
2449 if (tevent_req_nomem(subreq, req)) {
2450 status = NT_STATUS_NO_MEMORY;
2451 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2454 tevent_req_set_callback(subreq,
2455 netlogon_creds_cli_LogonSamLogon_done,
2460 if (state->lk_creds == NULL) {
2461 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2463 if (tevent_req_nomem(subreq, req)) {
2464 status = NT_STATUS_NO_MEMORY;
2465 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2468 tevent_req_set_callback(subreq,
2469 netlogon_creds_cli_LogonSamLogon_done,
2474 state->tmp_creds = *state->lk_creds;
2475 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2477 if (tevent_req_nterror(req, status)) {
2478 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2481 ZERO_STRUCT(state->rep_auth);
2483 state->logon = netlogon_creds_shallow_copy_logon(state,
2485 state->const_logon);
2486 if (tevent_req_nomem(state->logon, req)) {
2487 status = NT_STATUS_NO_MEMORY;
2488 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2492 status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2495 if (tevent_req_nterror(req, status)) {
2496 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2500 state->validation_level = 3;
2502 if (state->context->server.try_logon_with) {
2503 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2504 state->binding_handle,
2505 state->srv_name_slash,
2506 state->context->client.computer,
2511 state->validation_level,
2513 &state->authoritative,
2515 if (tevent_req_nomem(subreq, req)) {
2516 status = NT_STATUS_NO_MEMORY;
2517 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2523 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2524 state->binding_handle,
2525 state->srv_name_slash,
2526 state->context->client.computer,
2531 state->validation_level,
2533 &state->authoritative);
2534 if (tevent_req_nomem(subreq, req)) {
2535 status = NT_STATUS_NO_MEMORY;
2536 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2541 tevent_req_set_callback(subreq,
2542 netlogon_creds_cli_LogonSamLogon_done,
2546 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2548 struct tevent_req *req =
2549 tevent_req_callback_data(subreq,
2551 struct netlogon_creds_cli_LogonSamLogon_state *state =
2552 tevent_req_data(req,
2553 struct netlogon_creds_cli_LogonSamLogon_state);
2558 if (state->try_logon_ex) {
2559 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2562 TALLOC_FREE(subreq);
2563 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2564 state->context->server.try_validation6 = false;
2565 state->context->server.try_logon_ex = false;
2566 netlogon_creds_cli_LogonSamLogon_start(req);
2569 if (tevent_req_nterror(req, status)) {
2570 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2574 if ((state->validation_level == 6) &&
2575 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2576 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2577 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2579 state->context->server.try_validation6 = false;
2580 netlogon_creds_cli_LogonSamLogon_start(req);
2584 if (tevent_req_nterror(req, result)) {
2585 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2589 if (state->ro_creds == NULL) {
2590 tevent_req_done(req);
2594 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2597 * We got a race, lets retry with on authenticator
2600 * netlogon_creds_cli_LogonSamLogon_start()
2601 * will TALLOC_FREE(state->ro_creds);
2603 state->try_logon_ex = false;
2604 netlogon_creds_cli_LogonSamLogon_start(req);
2608 status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2609 state->validation_level,
2611 if (tevent_req_nterror(req, status)) {
2612 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2616 tevent_req_done(req);
2620 if (state->lk_creds == NULL) {
2621 status = netlogon_creds_cli_lock_recv(subreq, state,
2623 TALLOC_FREE(subreq);
2624 if (tevent_req_nterror(req, status)) {
2625 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2629 netlogon_creds_cli_LogonSamLogon_start(req);
2633 if (state->context->server.try_logon_with) {
2634 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2637 TALLOC_FREE(subreq);
2638 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2639 state->context->server.try_logon_with = false;
2640 netlogon_creds_cli_LogonSamLogon_start(req);
2643 if (tevent_req_nterror(req, status)) {
2644 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2648 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2651 TALLOC_FREE(subreq);
2652 if (tevent_req_nterror(req, status)) {
2653 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2658 ok = netlogon_creds_client_check(&state->tmp_creds,
2659 &state->rep_auth.cred);
2661 status = NT_STATUS_ACCESS_DENIED;
2662 tevent_req_nterror(req, status);
2663 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2667 *state->lk_creds = state->tmp_creds;
2668 status = netlogon_creds_cli_store(state->context,
2670 TALLOC_FREE(state->lk_creds);
2672 if (tevent_req_nterror(req, status)) {
2673 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2677 if (tevent_req_nterror(req, result)) {
2678 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2682 status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2683 state->validation_level,
2685 if (tevent_req_nterror(req, status)) {
2686 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2690 tevent_req_done(req);
2693 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2694 TALLOC_CTX *mem_ctx,
2695 uint16_t *validation_level,
2696 union netr_Validation **validation,
2697 uint8_t *authoritative,
2700 struct netlogon_creds_cli_LogonSamLogon_state *state =
2701 tevent_req_data(req,
2702 struct netlogon_creds_cli_LogonSamLogon_state);
2705 /* authoritative is also returned on error */
2706 *authoritative = state->authoritative;
2708 if (tevent_req_is_nterror(req, &status)) {
2709 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2710 tevent_req_received(req);
2714 *validation_level = state->validation_level;
2715 *validation = talloc_move(mem_ctx, &state->validation);
2716 *flags = state->flags;
2718 tevent_req_received(req);
2719 return NT_STATUS_OK;
2722 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2723 struct netlogon_creds_cli_context *context,
2724 struct dcerpc_binding_handle *b,
2725 enum netr_LogonInfoClass logon_level,
2726 const union netr_LogonLevel *logon,
2727 TALLOC_CTX *mem_ctx,
2728 uint16_t *validation_level,
2729 union netr_Validation **validation,
2730 uint8_t *authoritative,
2733 TALLOC_CTX *frame = talloc_stackframe();
2734 struct tevent_context *ev;
2735 struct tevent_req *req;
2736 NTSTATUS status = NT_STATUS_NO_MEMORY;
2738 ev = samba_tevent_context_init(frame);
2742 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2748 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2751 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2761 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2762 struct tevent_context *ev;
2763 struct netlogon_creds_cli_context *context;
2764 struct dcerpc_binding_handle *binding_handle;
2766 char *srv_name_slash;
2767 enum dcerpc_AuthType auth_type;
2768 enum dcerpc_AuthLevel auth_level;
2770 const char *site_name;
2772 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2774 struct netlogon_creds_CredentialState *creds;
2775 struct netlogon_creds_CredentialState tmp_creds;
2776 struct netr_Authenticator req_auth;
2777 struct netr_Authenticator rep_auth;
2780 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2782 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2784 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2785 struct tevent_context *ev,
2786 struct netlogon_creds_cli_context *context,
2787 struct dcerpc_binding_handle *b,
2788 const char *site_name,
2790 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2792 struct tevent_req *req;
2793 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2794 struct tevent_req *subreq;
2796 req = tevent_req_create(mem_ctx, &state,
2797 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2803 state->context = context;
2804 state->binding_handle = b;
2806 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2807 context->server.computer);
2808 if (tevent_req_nomem(state->srv_name_slash, req)) {
2809 return tevent_req_post(req, ev);
2812 state->site_name = site_name;
2813 state->dns_ttl = dns_ttl;
2814 state->dns_names = dns_names;
2816 dcerpc_binding_handle_auth_info(state->binding_handle,
2818 &state->auth_level);
2820 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2822 if (tevent_req_nomem(subreq, req)) {
2823 return tevent_req_post(req, ev);
2826 tevent_req_set_callback(subreq,
2827 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2833 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2836 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2837 tevent_req_data(req,
2838 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2840 if (state->creds == NULL) {
2844 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2845 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2846 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2847 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2848 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2849 TALLOC_FREE(state->creds);
2853 netlogon_creds_cli_delete(state->context, state->creds);
2854 TALLOC_FREE(state->creds);
2857 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2859 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2861 struct tevent_req *req =
2862 tevent_req_callback_data(subreq,
2864 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2865 tevent_req_data(req,
2866 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2869 status = netlogon_creds_cli_lock_recv(subreq, state,
2871 TALLOC_FREE(subreq);
2872 if (tevent_req_nterror(req, status)) {
2876 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2877 switch (state->auth_level) {
2878 case DCERPC_AUTH_LEVEL_INTEGRITY:
2879 case DCERPC_AUTH_LEVEL_PRIVACY:
2882 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2886 uint32_t tmp = state->creds->negotiate_flags;
2888 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2890 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2891 * it should be used, which means
2892 * we had a chance to verify no downgrade
2895 * This relies on netlogon_creds_cli_check*
2896 * being called before, as first request after
2899 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2905 * we defer all callbacks in order to cleanup
2906 * the database record.
2908 tevent_req_defer_callback(req, state->ev);
2910 state->tmp_creds = *state->creds;
2911 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2913 if (tevent_req_nterror(req, status)) {
2916 ZERO_STRUCT(state->rep_auth);
2918 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2919 state->binding_handle,
2920 state->srv_name_slash,
2921 state->tmp_creds.computer_name,
2927 if (tevent_req_nomem(subreq, req)) {
2928 status = NT_STATUS_NO_MEMORY;
2929 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2933 tevent_req_set_callback(subreq,
2934 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2938 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2940 struct tevent_req *req =
2941 tevent_req_callback_data(subreq,
2943 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2944 tevent_req_data(req,
2945 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2951 * We use state->dns_names as the memory context, as this is
2952 * the only in/out variable and it has been overwritten by the
2953 * out parameter from the server.
2955 * We need to preserve the return value until the caller can use it.
2957 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2959 TALLOC_FREE(subreq);
2960 if (tevent_req_nterror(req, status)) {
2961 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2965 ok = netlogon_creds_client_check(&state->tmp_creds,
2966 &state->rep_auth.cred);
2968 status = NT_STATUS_ACCESS_DENIED;
2969 tevent_req_nterror(req, status);
2970 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2974 *state->creds = state->tmp_creds;
2975 status = netlogon_creds_cli_store(state->context,
2977 TALLOC_FREE(state->creds);
2979 if (tevent_req_nterror(req, status)) {
2980 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2984 if (tevent_req_nterror(req, result)) {
2985 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2989 tevent_req_done(req);
2992 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2996 if (tevent_req_is_nterror(req, &status)) {
2997 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2998 tevent_req_received(req);
3002 tevent_req_received(req);
3003 return NT_STATUS_OK;
3006 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
3007 struct netlogon_creds_cli_context *context,
3008 struct dcerpc_binding_handle *b,
3009 const char *site_name,
3011 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
3013 TALLOC_CTX *frame = talloc_stackframe();
3014 struct tevent_context *ev;
3015 struct tevent_req *req;
3016 NTSTATUS status = NT_STATUS_NO_MEMORY;
3018 ev = samba_tevent_context_init(frame);
3022 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
3029 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3032 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
3038 struct netlogon_creds_cli_ServerGetTrustInfo_state {
3039 struct tevent_context *ev;
3040 struct netlogon_creds_cli_context *context;
3041 struct dcerpc_binding_handle *binding_handle;
3043 char *srv_name_slash;
3044 enum dcerpc_AuthType auth_type;
3045 enum dcerpc_AuthLevel auth_level;
3047 struct samr_Password new_owf_password;
3048 struct samr_Password old_owf_password;
3049 struct netr_TrustInfo *trust_info;
3051 struct netlogon_creds_CredentialState *creds;
3052 struct netlogon_creds_CredentialState tmp_creds;
3053 struct netr_Authenticator req_auth;
3054 struct netr_Authenticator rep_auth;
3057 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3059 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
3061 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
3062 struct tevent_context *ev,
3063 struct netlogon_creds_cli_context *context,
3064 struct dcerpc_binding_handle *b)
3066 struct tevent_req *req;
3067 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
3068 struct tevent_req *subreq;
3070 req = tevent_req_create(mem_ctx, &state,
3071 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3077 state->context = context;
3078 state->binding_handle = b;
3080 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3081 context->server.computer);
3082 if (tevent_req_nomem(state->srv_name_slash, req)) {
3083 return tevent_req_post(req, ev);
3086 dcerpc_binding_handle_auth_info(state->binding_handle,
3088 &state->auth_level);
3090 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3092 if (tevent_req_nomem(subreq, req)) {
3093 return tevent_req_post(req, ev);
3096 tevent_req_set_callback(subreq,
3097 netlogon_creds_cli_ServerGetTrustInfo_locked,
3103 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3106 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3107 tevent_req_data(req,
3108 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3110 if (state->creds == NULL) {
3114 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3115 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3116 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3117 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3118 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3119 TALLOC_FREE(state->creds);
3123 netlogon_creds_cli_delete(state->context, state->creds);
3124 TALLOC_FREE(state->creds);
3127 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3129 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3131 struct tevent_req *req =
3132 tevent_req_callback_data(subreq,
3134 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3135 tevent_req_data(req,
3136 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3139 status = netlogon_creds_cli_lock_recv(subreq, state,
3141 TALLOC_FREE(subreq);
3142 if (tevent_req_nterror(req, status)) {
3146 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3147 switch (state->auth_level) {
3148 case DCERPC_AUTH_LEVEL_PRIVACY:
3151 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3155 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3160 * we defer all callbacks in order to cleanup
3161 * the database record.
3163 tevent_req_defer_callback(req, state->ev);
3165 state->tmp_creds = *state->creds;
3166 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3168 if (tevent_req_nterror(req, status)) {
3171 ZERO_STRUCT(state->rep_auth);
3173 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3174 state->binding_handle,
3175 state->srv_name_slash,
3176 state->tmp_creds.account_name,
3177 state->tmp_creds.secure_channel_type,
3178 state->tmp_creds.computer_name,
3181 &state->new_owf_password,
3182 &state->old_owf_password,
3183 &state->trust_info);
3184 if (tevent_req_nomem(subreq, req)) {
3185 status = NT_STATUS_NO_MEMORY;
3186 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3190 tevent_req_set_callback(subreq,
3191 netlogon_creds_cli_ServerGetTrustInfo_done,
3195 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3197 struct tevent_req *req =
3198 tevent_req_callback_data(subreq,
3200 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3201 tevent_req_data(req,
3202 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3205 const struct samr_Password zero = {};
3210 * We use state->dns_names as the memory context, as this is
3211 * the only in/out variable and it has been overwritten by the
3212 * out parameter from the server.
3214 * We need to preserve the return value until the caller can use it.
3216 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3217 TALLOC_FREE(subreq);
3218 if (tevent_req_nterror(req, status)) {
3219 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3223 ok = netlogon_creds_client_check(&state->tmp_creds,
3224 &state->rep_auth.cred);
3226 status = NT_STATUS_ACCESS_DENIED;
3227 tevent_req_nterror(req, status);
3228 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3232 cmp = mem_equal_const_time(state->new_owf_password.hash,
3233 zero.hash, sizeof(zero.hash));
3235 status = netlogon_creds_des_decrypt(&state->tmp_creds,
3236 &state->new_owf_password);
3237 if (tevent_req_nterror(req, status)) {
3238 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3242 cmp = mem_equal_const_time(state->old_owf_password.hash,
3243 zero.hash, sizeof(zero.hash));
3245 status = netlogon_creds_des_decrypt(&state->tmp_creds,
3246 &state->old_owf_password);
3247 if (tevent_req_nterror(req, status)) {
3248 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3253 *state->creds = state->tmp_creds;
3254 status = netlogon_creds_cli_store(state->context,
3256 TALLOC_FREE(state->creds);
3257 if (tevent_req_nterror(req, status)) {
3258 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3262 if (tevent_req_nterror(req, result)) {
3263 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3267 tevent_req_done(req);
3270 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3271 TALLOC_CTX *mem_ctx,
3272 struct samr_Password *new_owf_password,
3273 struct samr_Password *old_owf_password,
3274 struct netr_TrustInfo **trust_info)
3276 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3277 tevent_req_data(req,
3278 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3281 if (tevent_req_is_nterror(req, &status)) {
3282 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3283 tevent_req_received(req);
3287 if (new_owf_password != NULL) {
3288 *new_owf_password = state->new_owf_password;
3290 if (old_owf_password != NULL) {
3291 *old_owf_password = state->old_owf_password;
3293 if (trust_info != NULL) {
3294 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3297 tevent_req_received(req);
3298 return NT_STATUS_OK;
3301 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3302 struct netlogon_creds_cli_context *context,
3303 struct dcerpc_binding_handle *b,
3304 TALLOC_CTX *mem_ctx,
3305 struct samr_Password *new_owf_password,
3306 struct samr_Password *old_owf_password,
3307 struct netr_TrustInfo **trust_info)
3309 TALLOC_CTX *frame = talloc_stackframe();
3310 struct tevent_context *ev;
3311 struct tevent_req *req;
3312 NTSTATUS status = NT_STATUS_NO_MEMORY;
3314 ev = samba_tevent_context_init(frame);
3318 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3322 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3325 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3335 struct netlogon_creds_cli_GetForestTrustInformation_state {
3336 struct tevent_context *ev;
3337 struct netlogon_creds_cli_context *context;
3338 struct dcerpc_binding_handle *binding_handle;
3340 char *srv_name_slash;
3341 enum dcerpc_AuthType auth_type;
3342 enum dcerpc_AuthLevel auth_level;
3345 struct lsa_ForestTrustInformation *forest_trust_info;
3347 struct netlogon_creds_CredentialState *creds;
3348 struct netlogon_creds_CredentialState tmp_creds;
3349 struct netr_Authenticator req_auth;
3350 struct netr_Authenticator rep_auth;
3353 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3355 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3357 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3358 struct tevent_context *ev,
3359 struct netlogon_creds_cli_context *context,
3360 struct dcerpc_binding_handle *b)
3362 struct tevent_req *req;
3363 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3364 struct tevent_req *subreq;
3366 req = tevent_req_create(mem_ctx, &state,
3367 struct netlogon_creds_cli_GetForestTrustInformation_state);
3373 state->context = context;
3374 state->binding_handle = b;
3376 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3377 context->server.computer);
3378 if (tevent_req_nomem(state->srv_name_slash, req)) {
3379 return tevent_req_post(req, ev);
3384 dcerpc_binding_handle_auth_info(state->binding_handle,
3386 &state->auth_level);
3388 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3390 if (tevent_req_nomem(subreq, req)) {
3391 return tevent_req_post(req, ev);
3394 tevent_req_set_callback(subreq,
3395 netlogon_creds_cli_GetForestTrustInformation_locked,
3401 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3404 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3405 tevent_req_data(req,
3406 struct netlogon_creds_cli_GetForestTrustInformation_state);
3408 if (state->creds == NULL) {
3412 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3413 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3414 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3415 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3416 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3417 TALLOC_FREE(state->creds);
3421 netlogon_creds_cli_delete(state->context, state->creds);
3422 TALLOC_FREE(state->creds);
3425 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3427 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3429 struct tevent_req *req =
3430 tevent_req_callback_data(subreq,
3432 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3433 tevent_req_data(req,
3434 struct netlogon_creds_cli_GetForestTrustInformation_state);
3437 status = netlogon_creds_cli_lock_recv(subreq, state,
3439 TALLOC_FREE(subreq);
3440 if (tevent_req_nterror(req, status)) {
3444 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3445 switch (state->auth_level) {
3446 case DCERPC_AUTH_LEVEL_INTEGRITY:
3447 case DCERPC_AUTH_LEVEL_PRIVACY:
3450 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3454 uint32_t tmp = state->creds->negotiate_flags;
3456 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3458 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3459 * it should be used, which means
3460 * we had a chance to verify no downgrade
3463 * This relies on netlogon_creds_cli_check*
3464 * being called before, as first request after
3467 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3473 * we defer all callbacks in order to cleanup
3474 * the database record.
3476 tevent_req_defer_callback(req, state->ev);
3478 state->tmp_creds = *state->creds;
3479 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3481 if (tevent_req_nterror(req, status)) {
3484 ZERO_STRUCT(state->rep_auth);
3486 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3487 state->binding_handle,
3488 state->srv_name_slash,
3489 state->tmp_creds.computer_name,
3493 &state->forest_trust_info);
3494 if (tevent_req_nomem(subreq, req)) {
3495 status = NT_STATUS_NO_MEMORY;
3496 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3500 tevent_req_set_callback(subreq,
3501 netlogon_creds_cli_GetForestTrustInformation_done,
3505 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3507 struct tevent_req *req =
3508 tevent_req_callback_data(subreq,
3510 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3511 tevent_req_data(req,
3512 struct netlogon_creds_cli_GetForestTrustInformation_state);
3518 * We use state->dns_names as the memory context, as this is
3519 * the only in/out variable and it has been overwritten by the
3520 * out parameter from the server.
3522 * We need to preserve the return value until the caller can use it.
3524 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3525 TALLOC_FREE(subreq);
3526 if (tevent_req_nterror(req, status)) {
3527 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3531 ok = netlogon_creds_client_check(&state->tmp_creds,
3532 &state->rep_auth.cred);
3534 status = NT_STATUS_ACCESS_DENIED;
3535 tevent_req_nterror(req, status);
3536 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3540 *state->creds = state->tmp_creds;
3541 status = netlogon_creds_cli_store(state->context,
3543 TALLOC_FREE(state->creds);
3545 if (tevent_req_nterror(req, status)) {
3546 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3550 if (tevent_req_nterror(req, result)) {
3551 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3555 tevent_req_done(req);
3558 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3559 TALLOC_CTX *mem_ctx,
3560 struct lsa_ForestTrustInformation **forest_trust_info)
3562 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3563 tevent_req_data(req,
3564 struct netlogon_creds_cli_GetForestTrustInformation_state);
3567 if (tevent_req_is_nterror(req, &status)) {
3568 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3569 tevent_req_received(req);
3573 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3575 tevent_req_received(req);
3576 return NT_STATUS_OK;
3579 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3580 struct netlogon_creds_cli_context *context,
3581 struct dcerpc_binding_handle *b,
3582 TALLOC_CTX *mem_ctx,
3583 struct lsa_ForestTrustInformation **forest_trust_info)
3585 TALLOC_CTX *frame = talloc_stackframe();
3586 struct tevent_context *ev;
3587 struct tevent_req *req;
3588 NTSTATUS status = NT_STATUS_NO_MEMORY;
3590 ev = samba_tevent_context_init(frame);
3594 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3598 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3601 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3608 struct netlogon_creds_cli_SendToSam_state {
3609 struct tevent_context *ev;
3610 struct netlogon_creds_cli_context *context;
3611 struct dcerpc_binding_handle *binding_handle;
3613 char *srv_name_slash;
3614 enum dcerpc_AuthType auth_type;
3615 enum dcerpc_AuthLevel auth_level;
3619 struct netlogon_creds_CredentialState *creds;
3620 struct netlogon_creds_CredentialState tmp_creds;
3621 struct netr_Authenticator req_auth;
3622 struct netr_Authenticator rep_auth;
3625 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3627 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3629 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3630 struct tevent_context *ev,
3631 struct netlogon_creds_cli_context *context,
3632 struct dcerpc_binding_handle *b,
3633 struct netr_SendToSamBase *message)
3635 struct tevent_req *req;
3636 struct netlogon_creds_cli_SendToSam_state *state;
3637 struct tevent_req *subreq;
3638 enum ndr_err_code ndr_err;
3640 req = tevent_req_create(mem_ctx, &state,
3641 struct netlogon_creds_cli_SendToSam_state);
3647 state->context = context;
3648 state->binding_handle = b;
3650 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3651 context->server.computer);
3652 if (tevent_req_nomem(state->srv_name_slash, req)) {
3653 return tevent_req_post(req, ev);
3656 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3657 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3658 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3659 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3660 tevent_req_nterror(req, status);
3661 return tevent_req_post(req, ev);
3664 dcerpc_binding_handle_auth_info(state->binding_handle,
3666 &state->auth_level);
3668 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3670 if (tevent_req_nomem(subreq, req)) {
3671 return tevent_req_post(req, ev);
3674 tevent_req_set_callback(subreq,
3675 netlogon_creds_cli_SendToSam_locked,
3681 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3684 struct netlogon_creds_cli_SendToSam_state *state =
3685 tevent_req_data(req,
3686 struct netlogon_creds_cli_SendToSam_state);
3688 if (state->creds == NULL) {
3692 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3693 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3694 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3695 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3696 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3697 TALLOC_FREE(state->creds);
3701 netlogon_creds_cli_delete(state->context, state->creds);
3702 TALLOC_FREE(state->creds);
3705 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3707 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3709 struct tevent_req *req =
3710 tevent_req_callback_data(subreq,
3712 struct netlogon_creds_cli_SendToSam_state *state =
3713 tevent_req_data(req,
3714 struct netlogon_creds_cli_SendToSam_state);
3717 status = netlogon_creds_cli_lock_recv(subreq, state,
3719 TALLOC_FREE(subreq);
3720 if (tevent_req_nterror(req, status)) {
3724 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3725 switch (state->auth_level) {
3726 case DCERPC_AUTH_LEVEL_INTEGRITY:
3727 case DCERPC_AUTH_LEVEL_PRIVACY:
3730 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3734 uint32_t tmp = state->creds->negotiate_flags;
3736 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3738 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3739 * it should be used, which means
3740 * we had a chance to verify no downgrade
3743 * This relies on netlogon_creds_cli_check*
3744 * being called before, as first request after
3747 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3753 * we defer all callbacks in order to cleanup
3754 * the database record.
3756 tevent_req_defer_callback(req, state->ev);
3758 state->tmp_creds = *state->creds;
3759 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3761 if (tevent_req_nterror(req, status)) {
3764 ZERO_STRUCT(state->rep_auth);
3766 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3767 status = netlogon_creds_aes_encrypt(&state->tmp_creds,
3769 state->opaque.length);
3770 if (tevent_req_nterror(req, status)) {
3771 netlogon_creds_cli_SendToSam_cleanup(req, status);
3775 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
3777 state->opaque.length);
3778 if (tevent_req_nterror(req, status)) {
3779 netlogon_creds_cli_SendToSam_cleanup(req, status);
3784 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3785 state->binding_handle,
3786 state->srv_name_slash,
3787 state->tmp_creds.computer_name,
3791 state->opaque.length);
3792 if (tevent_req_nomem(subreq, req)) {
3793 status = NT_STATUS_NO_MEMORY;
3794 netlogon_creds_cli_SendToSam_cleanup(req, status);
3798 tevent_req_set_callback(subreq,
3799 netlogon_creds_cli_SendToSam_done,
3803 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3805 struct tevent_req *req =
3806 tevent_req_callback_data(subreq,
3808 struct netlogon_creds_cli_SendToSam_state *state =
3809 tevent_req_data(req,
3810 struct netlogon_creds_cli_SendToSam_state);
3815 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3816 TALLOC_FREE(subreq);
3817 if (tevent_req_nterror(req, status)) {
3818 netlogon_creds_cli_SendToSam_cleanup(req, status);
3822 ok = netlogon_creds_client_check(&state->tmp_creds,
3823 &state->rep_auth.cred);
3825 status = NT_STATUS_ACCESS_DENIED;
3826 tevent_req_nterror(req, status);
3827 netlogon_creds_cli_SendToSam_cleanup(req, status);
3831 *state->creds = state->tmp_creds;
3832 status = netlogon_creds_cli_store(state->context,
3834 TALLOC_FREE(state->creds);
3836 if (tevent_req_nterror(req, status)) {
3837 netlogon_creds_cli_SendToSam_cleanup(req, status);
3842 * Creds must be stored before we send back application errors
3843 * e.g. NT_STATUS_NOT_IMPLEMENTED
3845 if (tevent_req_nterror(req, result)) {
3846 netlogon_creds_cli_SendToSam_cleanup(req, result);
3850 tevent_req_done(req);
3853 NTSTATUS netlogon_creds_cli_SendToSam_recv(struct tevent_req *req)
3857 if (tevent_req_is_nterror(req, &status)) {
3858 netlogon_creds_cli_SendToSam_cleanup(req, status);
3859 tevent_req_received(req);
3863 tevent_req_received(req);
3864 return NT_STATUS_OK;
3867 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3868 struct dcerpc_binding_handle *b,
3869 struct netr_SendToSamBase *message)
3871 TALLOC_CTX *frame = talloc_stackframe();
3872 struct tevent_context *ev;
3873 struct tevent_req *req;
3874 NTSTATUS status = NT_STATUS_NO_MEMORY;
3876 ev = samba_tevent_context_init(frame);
3880 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3884 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3887 status = netlogon_creds_cli_SendToSam_recv(req);
3893 struct netlogon_creds_cli_LogonGetDomainInfo_state {
3894 struct tevent_context *ev;
3895 struct netlogon_creds_cli_context *context;
3896 struct dcerpc_binding_handle *binding_handle;
3898 char *srv_name_slash;
3899 enum dcerpc_AuthType auth_type;
3900 enum dcerpc_AuthLevel auth_level;
3903 union netr_WorkstationInfo *query;
3904 union netr_DomainInfo *info;
3906 struct netlogon_creds_CredentialState *creds;
3907 struct netlogon_creds_CredentialState tmp_creds;
3908 struct netr_Authenticator req_auth;
3909 struct netr_Authenticator rep_auth;
3912 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
3914 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq);
3916 struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
3917 struct tevent_context *ev,
3918 struct netlogon_creds_cli_context *context,
3919 struct dcerpc_binding_handle *b,
3921 union netr_WorkstationInfo *query)
3923 struct tevent_req *req;
3924 struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
3925 struct tevent_req *subreq;
3927 req = tevent_req_create(mem_ctx, &state,
3928 struct netlogon_creds_cli_LogonGetDomainInfo_state);
3934 state->context = context;
3935 state->binding_handle = b;
3937 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3938 context->server.computer);
3939 if (tevent_req_nomem(state->srv_name_slash, req)) {
3940 return tevent_req_post(req, ev);
3943 state->level = level;
3944 state->query = query;
3945 state->info = talloc_zero(state, union netr_DomainInfo);
3946 if (tevent_req_nomem(state->info, req)) {
3947 return tevent_req_post(req, ev);
3950 dcerpc_binding_handle_auth_info(state->binding_handle,
3952 &state->auth_level);
3954 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3956 if (tevent_req_nomem(subreq, req)) {
3957 return tevent_req_post(req, ev);
3960 tevent_req_set_callback(subreq,
3961 netlogon_creds_cli_LogonGetDomainInfo_locked,
3967 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
3970 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
3971 tevent_req_data(req,
3972 struct netlogon_creds_cli_LogonGetDomainInfo_state);
3974 if (state->creds == NULL) {
3978 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3979 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3980 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3981 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3982 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3983 TALLOC_FREE(state->creds);
3987 netlogon_creds_cli_delete(state->context, state->creds);
3990 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq);
3992 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq)
3994 struct tevent_req *req =
3995 tevent_req_callback_data(subreq,
3997 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
3998 tevent_req_data(req,
3999 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4002 status = netlogon_creds_cli_lock_recv(subreq, state,
4004 TALLOC_FREE(subreq);
4005 if (tevent_req_nterror(req, status)) {
4009 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
4010 switch (state->auth_level) {
4011 case DCERPC_AUTH_LEVEL_INTEGRITY:
4012 case DCERPC_AUTH_LEVEL_PRIVACY:
4015 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
4019 uint32_t tmp = state->creds->negotiate_flags;
4021 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
4023 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
4024 * it should be used, which means
4025 * we had a chance to verify no downgrade
4028 * This relies on netlogon_creds_cli_check*
4029 * being called before, as first request after
4032 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
4038 * we defer all callbacks in order to cleanup
4039 * the database record.
4041 tevent_req_defer_callback(req, state->ev);
4043 state->tmp_creds = *state->creds;
4044 status = netlogon_creds_client_authenticator(&state->tmp_creds,
4046 if (tevent_req_nterror(req, status)) {
4049 ZERO_STRUCT(state->rep_auth);
4051 subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev,
4052 state->binding_handle,
4053 state->srv_name_slash,
4054 state->tmp_creds.computer_name,
4060 if (tevent_req_nomem(subreq, req)) {
4061 status = NT_STATUS_NO_MEMORY;
4062 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4066 tevent_req_set_callback(subreq,
4067 netlogon_creds_cli_LogonGetDomainInfo_done,
4071 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
4073 struct tevent_req *req =
4074 tevent_req_callback_data(subreq,
4076 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4077 tevent_req_data(req,
4078 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4084 * We use state->dns_names as the memory context, as this is
4085 * the only in/out variable and it has been overwritten by the
4086 * out parameter from the server.
4088 * We need to preserve the return value until the caller can use it.
4090 status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result);
4091 TALLOC_FREE(subreq);
4092 if (tevent_req_nterror(req, status)) {
4093 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4097 ok = netlogon_creds_client_check(&state->tmp_creds,
4098 &state->rep_auth.cred);
4100 status = NT_STATUS_ACCESS_DENIED;
4101 tevent_req_nterror(req, status);
4102 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4106 if (tevent_req_nterror(req, result)) {
4107 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
4111 *state->creds = state->tmp_creds;
4112 status = netlogon_creds_cli_store(state->context,
4114 if (tevent_req_nterror(req, status)) {
4115 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4119 tevent_req_done(req);
4122 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
4123 TALLOC_CTX *mem_ctx,
4124 union netr_DomainInfo **info)
4126 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4127 tevent_req_data(req,
4128 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4131 if (tevent_req_is_nterror(req, &status)) {
4132 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4133 tevent_req_received(req);
4137 *info = talloc_move(mem_ctx, &state->info);
4139 tevent_req_received(req);
4140 return NT_STATUS_OK;
4143 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
4144 struct netlogon_creds_cli_context *context,
4145 struct dcerpc_binding_handle *b,
4146 TALLOC_CTX *mem_ctx,
4148 union netr_WorkstationInfo *query,
4149 union netr_DomainInfo **info)
4151 TALLOC_CTX *frame = talloc_stackframe();
4152 struct tevent_context *ev;
4153 struct tevent_req *req;
4154 NTSTATUS status = NT_STATUS_OK;
4156 ev = samba_tevent_context_init(frame);
4160 req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
4165 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4168 status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,