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/crypto.h"
41 #include "auth/credentials/credentials.h"
43 struct netlogon_creds_cli_locked_state;
45 struct netlogon_creds_cli_context {
49 uint32_t proposed_flags;
50 uint32_t required_flags;
51 enum netr_SchannelType type;
52 enum dcerpc_AuthLevel auth_level;
57 const char *netbios_domain;
58 const char *dns_domain;
59 uint32_t cached_flags;
68 struct db_context *ctx;
69 struct g_lock_ctx *g_ctx;
70 struct netlogon_creds_cli_locked_state *locked_state;
71 enum netlogon_creds_cli_lck_type lock;
75 struct netlogon_creds_cli_locked_state {
76 struct netlogon_creds_cli_context *context;
78 struct netlogon_creds_CredentialState *creds;
81 static int netlogon_creds_cli_locked_state_destructor(
82 struct netlogon_creds_cli_locked_state *state)
84 struct netlogon_creds_cli_context *context = state->context;
86 if (context == NULL) {
90 if (context->db.locked_state == state) {
91 context->db.locked_state = NULL;
94 if (state->is_glocked) {
95 g_lock_unlock(context->db.g_ctx,
96 string_term_tdb_data(context->db.key_name));
102 static NTSTATUS netlogon_creds_cli_context_common(
103 const char *client_computer,
104 const char *client_account,
105 enum netr_SchannelType type,
106 enum dcerpc_AuthLevel auth_level,
107 uint32_t proposed_flags,
108 uint32_t required_flags,
109 const char *server_computer,
110 const char *server_netbios_domain,
111 const char *server_dns_domain,
113 struct netlogon_creds_cli_context **_context)
115 struct netlogon_creds_cli_context *context = NULL;
116 char *_key_name = NULL;
117 size_t server_netbios_name_len;
122 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
123 if (context == NULL) {
124 return NT_STATUS_NO_MEMORY;
127 context->client.computer = talloc_strdup(context, client_computer);
128 if (context->client.computer == NULL) {
129 TALLOC_FREE(context);
130 return NT_STATUS_NO_MEMORY;
133 context->client.account = talloc_strdup(context, client_account);
134 if (context->client.account == NULL) {
135 TALLOC_FREE(context);
136 return NT_STATUS_NO_MEMORY;
139 context->client.proposed_flags = proposed_flags;
140 context->client.required_flags = required_flags;
141 context->client.type = type;
142 context->client.auth_level = auth_level;
144 context->server.computer = talloc_strdup(context, server_computer);
145 if (context->server.computer == NULL) {
146 TALLOC_FREE(context);
147 return NT_STATUS_NO_MEMORY;
150 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
151 if (context->server.netbios_domain == NULL) {
152 TALLOC_FREE(context);
153 return NT_STATUS_NO_MEMORY;
156 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
157 if (context->server.dns_domain == NULL) {
158 TALLOC_FREE(context);
159 return NT_STATUS_NO_MEMORY;
164 * Force the callers to provide a unique
165 * value for server_computer and use this directly.
167 * For now we have to deal with
168 * "HOSTNAME" vs. "hostname.example.com".
171 p = strchr(server_computer, '.');
173 server_netbios_name_len = p-server_computer;
175 server_netbios_name_len = strlen(server_computer);
178 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
181 (int)server_netbios_name_len,
183 server_netbios_domain);
184 if (_key_name == NULL) {
185 TALLOC_FREE(context);
186 return NT_STATUS_NO_MEMORY;
189 context->db.key_name = talloc_strdup_upper(context, _key_name);
190 TALLOC_FREE(_key_name);
191 if (context->db.key_name == NULL) {
192 TALLOC_FREE(context);
193 return NT_STATUS_NO_MEMORY;
196 context->db.key_data = string_term_tdb_data(context->db.key_name);
202 static struct db_context *netlogon_creds_cli_global_db;
204 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
206 if (netlogon_creds_cli_global_db != NULL) {
207 return NT_STATUS_INVALID_PARAMETER_MIX;
210 netlogon_creds_cli_global_db = talloc_move(NULL, db);
214 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
217 struct db_context *global_db;
218 int hash_size, tdb_flags;
220 if (netlogon_creds_cli_global_db != NULL) {
224 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
226 return NT_STATUS_NO_MEMORY;
229 hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
230 tdb_flags = lpcfg_tdb_flags(
232 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
234 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;
418 proposed_flags |= required_flags;
420 if (seal_secure_channel) {
421 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
423 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
426 status = netlogon_creds_cli_context_common(client_computer,
433 server_netbios_domain,
437 if (!NT_STATUS_IS_OK(status)) {
442 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
443 if (context->db.g_ctx == NULL) {
444 TALLOC_FREE(context);
446 return NT_STATUS_NO_MEMORY;
449 status = netlogon_creds_cli_open_global_db(lp_ctx);
450 if (!NT_STATUS_IS_OK(status)) {
451 TALLOC_FREE(context);
453 return NT_STATUS_NO_MEMORY;
456 context->db.ctx = netlogon_creds_cli_global_db;
462 NTSTATUS netlogon_creds_bind_cli_credentials(
463 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
464 struct cli_credentials **pcli_creds)
466 struct cli_credentials *cli_creds;
467 struct netlogon_creds_CredentialState *ncreds;
470 cli_creds = cli_credentials_init(mem_ctx);
471 if (cli_creds == NULL) {
472 return NT_STATUS_NO_MEMORY;
474 cli_credentials_set_secure_channel_type(cli_creds,
475 context->client.type);
476 cli_credentials_set_username(cli_creds, context->client.account,
478 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
480 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
483 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
484 if (!NT_STATUS_IS_OK(status)) {
485 TALLOC_FREE(cli_creds);
488 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
490 *pcli_creds = cli_creds;
494 char *netlogon_creds_cli_debug_string(
495 const struct netlogon_creds_cli_context *context,
498 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
499 context->db.key_name);
502 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
503 struct netlogon_creds_cli_context *context)
505 return context->client.auth_level;
508 struct netlogon_creds_cli_fetch_state {
510 struct netlogon_creds_CredentialState *creds;
511 uint32_t required_flags;
515 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
518 struct netlogon_creds_cli_fetch_state *state =
519 (struct netlogon_creds_cli_fetch_state *)private_data;
520 enum ndr_err_code ndr_err;
524 state->creds = talloc_zero(state->mem_ctx,
525 struct netlogon_creds_CredentialState);
526 if (state->creds == NULL) {
527 state->status = NT_STATUS_NO_MEMORY;
531 blob.data = data.dptr;
532 blob.length = data.dsize;
534 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
535 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
536 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
537 TALLOC_FREE(state->creds);
538 state->status = ndr_map_error2ntstatus(ndr_err);
542 if (DEBUGLEVEL >= 10) {
543 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
546 tmp_flags = state->creds->negotiate_flags;
547 tmp_flags &= state->required_flags;
548 if (tmp_flags != state->required_flags) {
549 TALLOC_FREE(state->creds);
550 state->status = NT_STATUS_DOWNGRADE_DETECTED;
554 state->status = NT_STATUS_OK;
557 static NTSTATUS netlogon_creds_cli_get_internal(
558 struct netlogon_creds_cli_context *context,
559 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
561 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
563 struct netlogon_creds_CredentialState **_creds)
566 struct netlogon_creds_CredentialState *creds;
570 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
571 if (!NT_STATUS_IS_OK(status)) {
576 * mark it as invalid for step operations.
579 creds->seed = (struct netr_Credential) {{0}};
580 creds->client = (struct netr_Credential) {{0}};
581 creds->server = (struct netr_Credential) {{0}};
587 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
588 const struct netlogon_creds_CredentialState *creds1)
590 TALLOC_CTX *frame = talloc_stackframe();
591 struct netlogon_creds_CredentialState *creds2;
595 enum ndr_err_code ndr_err;
598 status = netlogon_creds_cli_get(context, frame, &creds2);
599 if (!NT_STATUS_IS_OK(status)) {
604 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
605 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
606 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
611 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
612 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
613 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
618 cmp = data_blob_cmp(&blob1, &blob2);
625 static NTSTATUS netlogon_creds_cli_store_internal(
626 struct netlogon_creds_cli_context *context,
627 struct netlogon_creds_CredentialState *creds)
630 enum ndr_err_code ndr_err;
634 if (DEBUGLEVEL >= 10) {
635 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
638 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
639 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
640 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
641 status = ndr_map_error2ntstatus(ndr_err);
645 data.dptr = blob.data;
646 data.dsize = blob.length;
648 status = dbwrap_store(context->db.ctx,
649 context->db.key_data,
651 TALLOC_FREE(data.dptr);
652 if (!NT_STATUS_IS_OK(status)) {
659 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
660 struct netlogon_creds_CredentialState *creds)
664 if (context->db.locked_state == NULL) {
666 * this was not the result of netlogon_creds_cli_lock*()
668 return NT_STATUS_INVALID_PAGE_PROTECTION;
671 if (context->db.locked_state->creds != creds) {
673 * this was not the result of netlogon_creds_cli_lock*()
675 return NT_STATUS_INVALID_PAGE_PROTECTION;
678 status = netlogon_creds_cli_store_internal(context, creds);
682 static NTSTATUS netlogon_creds_cli_delete_internal(
683 struct netlogon_creds_cli_context *context)
686 status = dbwrap_delete(context->db.ctx, context->db.key_data);
690 NTSTATUS netlogon_creds_cli_delete_lck(
691 struct netlogon_creds_cli_context *context)
695 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
696 return NT_STATUS_NOT_LOCKED;
699 status = netlogon_creds_cli_delete_internal(context);
703 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
704 struct netlogon_creds_CredentialState *creds)
708 if (context->db.locked_state == NULL) {
710 * this was not the result of netlogon_creds_cli_lock*()
712 return NT_STATUS_INVALID_PAGE_PROTECTION;
715 if (context->db.locked_state->creds != creds) {
717 * this was not the result of netlogon_creds_cli_lock*()
719 return NT_STATUS_INVALID_PAGE_PROTECTION;
722 status = netlogon_creds_cli_delete_internal(context);
726 struct netlogon_creds_cli_lock_state {
727 struct netlogon_creds_cli_locked_state *locked_state;
728 struct netlogon_creds_CredentialState *creds;
731 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
733 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
734 struct tevent_context *ev,
735 struct netlogon_creds_cli_context *context)
737 struct tevent_req *req;
738 struct netlogon_creds_cli_lock_state *state;
739 struct netlogon_creds_cli_locked_state *locked_state;
740 struct tevent_req *subreq;
742 req = tevent_req_create(mem_ctx, &state,
743 struct netlogon_creds_cli_lock_state);
748 if (context->db.locked_state != NULL) {
749 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
750 return tevent_req_post(req, ev);
753 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
754 if (tevent_req_nomem(locked_state, req)) {
755 return tevent_req_post(req, ev);
757 talloc_set_destructor(locked_state,
758 netlogon_creds_cli_locked_state_destructor);
759 locked_state->context = context;
761 context->db.locked_state = locked_state;
762 state->locked_state = locked_state;
764 if (context->db.g_ctx == NULL) {
767 status = netlogon_creds_cli_get_internal(
768 context, state, &state->creds);
769 if (tevent_req_nterror(req, status)) {
770 return tevent_req_post(req, ev);
776 subreq = g_lock_lock_send(state, ev,
778 string_term_tdb_data(context->db.key_name),
780 if (tevent_req_nomem(subreq, req)) {
781 return tevent_req_post(req, ev);
783 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
788 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
790 struct tevent_req *req =
791 tevent_req_callback_data(subreq,
793 struct netlogon_creds_cli_lock_state *state =
795 struct netlogon_creds_cli_lock_state);
798 status = g_lock_lock_recv(subreq);
800 if (tevent_req_nterror(req, status)) {
803 state->locked_state->is_glocked = true;
805 status = netlogon_creds_cli_get_internal(state->locked_state->context,
806 state, &state->creds);
807 if (tevent_req_nterror(req, status)) {
810 tevent_req_done(req);
813 static NTSTATUS netlogon_creds_cli_get_internal(
814 struct netlogon_creds_cli_context *context,
815 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
817 struct netlogon_creds_cli_fetch_state fstate = {
818 .status = NT_STATUS_INTERNAL_ERROR,
819 .required_flags = context->client.required_flags,
823 fstate.mem_ctx = mem_ctx;
824 status = dbwrap_parse_record(context->db.ctx,
825 context->db.key_data,
826 netlogon_creds_cli_fetch_parser,
828 if (!NT_STATUS_IS_OK(status)) {
831 if (!NT_STATUS_IS_OK(fstate.status)) {
832 return fstate.status;
835 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
836 *pcreds = fstate.creds;
841 * It is really important to try SamLogonEx here,
842 * because multiple processes can talk to the same
843 * domain controller, without using the credential
846 * With a normal SamLogon call, we must keep the
847 * credentials chain updated and intact between all
848 * users of the machine account (which would imply
849 * cross-node communication for every NTLM logon).
851 * The credentials chain is not per NETLOGON pipe
852 * connection, but globally on the server/client pair
855 * It's also important to use NetlogonValidationSamInfo4 (6),
856 * because it relies on the rpc transport encryption
857 * and avoids using the global netlogon schannel
858 * session key to en/decrypt secret information
859 * like the user_session_key for network logons.
861 * [MS-APDS] 3.1.5.2 NTLM Network Logon
862 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
863 * NETLOGON_NEG_AUTHENTICATED_RPC set together
864 * are the indication that the server supports
865 * NetlogonValidationSamInfo4 (6). And it must only
866 * be used if "SealSecureChannel" is used.
868 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
869 * check is done in netlogon_creds_cli_LogonSamLogon*().
872 context->server.cached_flags = fstate.creds->negotiate_flags;
873 context->server.try_validation6 = true;
874 context->server.try_logon_ex = true;
875 context->server.try_logon_with = true;
877 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
878 context->server.try_validation6 = false;
879 context->server.try_logon_ex = false;
881 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
882 context->server.try_validation6 = false;
885 *pcreds = fstate.creds;
889 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
891 struct netlogon_creds_CredentialState **creds)
893 struct netlogon_creds_cli_lock_state *state =
895 struct netlogon_creds_cli_lock_state);
898 if (tevent_req_is_nterror(req, &status)) {
899 tevent_req_received(req);
903 talloc_steal(state->creds, state->locked_state);
904 state->locked_state->creds = state->creds;
905 *creds = talloc_move(mem_ctx, &state->creds);
906 tevent_req_received(req);
910 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
912 struct netlogon_creds_CredentialState **creds)
914 TALLOC_CTX *frame = talloc_stackframe();
915 struct tevent_context *ev;
916 struct tevent_req *req;
917 NTSTATUS status = NT_STATUS_NO_MEMORY;
919 ev = samba_tevent_context_init(frame);
923 req = netlogon_creds_cli_lock_send(frame, ev, context);
927 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
930 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
936 struct netlogon_creds_cli_lck {
937 struct netlogon_creds_cli_context *context;
940 struct netlogon_creds_cli_lck_state {
941 struct netlogon_creds_cli_lck *lck;
942 enum netlogon_creds_cli_lck_type type;
945 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
946 static int netlogon_creds_cli_lck_destructor(
947 struct netlogon_creds_cli_lck *lck);
949 struct tevent_req *netlogon_creds_cli_lck_send(
950 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
951 struct netlogon_creds_cli_context *context,
952 enum netlogon_creds_cli_lck_type type)
954 struct tevent_req *req, *subreq;
955 struct netlogon_creds_cli_lck_state *state;
956 enum g_lock_type gtype;
958 req = tevent_req_create(mem_ctx, &state,
959 struct netlogon_creds_cli_lck_state);
964 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
965 DBG_DEBUG("context already locked\n");
966 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
967 return tevent_req_post(req, ev);
971 case NETLOGON_CREDS_CLI_LCK_SHARED:
974 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
975 gtype = G_LOCK_WRITE;
978 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
979 return tevent_req_post(req, ev);
982 state->lck = talloc(state, struct netlogon_creds_cli_lck);
983 if (tevent_req_nomem(state->lck, req)) {
984 return tevent_req_post(req, ev);
986 state->lck->context = context;
989 subreq = g_lock_lock_send(state, ev,
991 string_term_tdb_data(context->db.key_name),
993 if (tevent_req_nomem(subreq, req)) {
994 return tevent_req_post(req, ev);
996 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
1001 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
1003 struct tevent_req *req = tevent_req_callback_data(
1004 subreq, struct tevent_req);
1005 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1006 req, struct netlogon_creds_cli_lck_state);
1009 status = g_lock_lock_recv(subreq);
1010 TALLOC_FREE(subreq);
1011 if (tevent_req_nterror(req, status)) {
1015 state->lck->context->db.lock = state->type;
1016 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1018 tevent_req_done(req);
1021 static int netlogon_creds_cli_lck_destructor(
1022 struct netlogon_creds_cli_lck *lck)
1024 struct netlogon_creds_cli_context *ctx = lck->context;
1027 status = g_lock_unlock(ctx->db.g_ctx,
1028 string_term_tdb_data(ctx->db.key_name));
1029 if (!NT_STATUS_IS_OK(status)) {
1030 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1031 smb_panic("g_lock_unlock failed");
1033 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1037 NTSTATUS netlogon_creds_cli_lck_recv(
1038 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1039 struct netlogon_creds_cli_lck **lck)
1041 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1042 req, struct netlogon_creds_cli_lck_state);
1045 if (tevent_req_is_nterror(req, &status)) {
1048 *lck = talloc_move(mem_ctx, &state->lck);
1049 return NT_STATUS_OK;
1052 NTSTATUS netlogon_creds_cli_lck(
1053 struct netlogon_creds_cli_context *context,
1054 enum netlogon_creds_cli_lck_type type,
1055 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1057 TALLOC_CTX *frame = talloc_stackframe();
1058 struct tevent_context *ev;
1059 struct tevent_req *req;
1060 NTSTATUS status = NT_STATUS_NO_MEMORY;
1062 ev = samba_tevent_context_init(frame);
1066 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1070 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1073 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1079 struct netlogon_creds_cli_auth_state {
1080 struct tevent_context *ev;
1081 struct netlogon_creds_cli_context *context;
1082 struct dcerpc_binding_handle *binding_handle;
1083 uint8_t num_nt_hashes;
1084 uint8_t idx_nt_hashes;
1085 const struct samr_Password * const *nt_hashes;
1086 const struct samr_Password *used_nt_hash;
1087 char *srv_name_slash;
1088 uint32_t current_flags;
1089 struct netr_Credential client_challenge;
1090 struct netr_Credential server_challenge;
1091 struct netlogon_creds_CredentialState *creds;
1092 struct netr_Credential client_credential;
1093 struct netr_Credential server_credential;
1100 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1102 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1103 struct tevent_context *ev,
1104 struct netlogon_creds_cli_context *context,
1105 struct dcerpc_binding_handle *b,
1106 uint8_t num_nt_hashes,
1107 const struct samr_Password * const *nt_hashes)
1109 struct tevent_req *req;
1110 struct netlogon_creds_cli_auth_state *state;
1113 req = tevent_req_create(mem_ctx, &state,
1114 struct netlogon_creds_cli_auth_state);
1120 state->context = context;
1121 state->binding_handle = b;
1122 if (num_nt_hashes < 1) {
1123 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1124 return tevent_req_post(req, ev);
1126 if (num_nt_hashes > 4) {
1127 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1128 return tevent_req_post(req, ev);
1131 state->num_nt_hashes = num_nt_hashes;
1132 state->idx_nt_hashes = 0;
1133 state->nt_hashes = nt_hashes;
1135 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1136 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1137 return tevent_req_post(req, ev);
1140 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1141 context->server.computer);
1142 if (tevent_req_nomem(state->srv_name_slash, req)) {
1143 return tevent_req_post(req, ev);
1146 state->try_auth3 = true;
1147 state->try_auth2 = true;
1149 if (context->client.required_flags != 0) {
1150 state->require_auth2 = true;
1153 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1154 state->current_flags = context->client.proposed_flags;
1156 status = dbwrap_purge(state->context->db.ctx,
1157 state->context->db.key_data);
1158 if (tevent_req_nterror(req, status)) {
1159 return tevent_req_post(req, ev);
1162 netlogon_creds_cli_auth_challenge_start(req);
1163 if (!tevent_req_is_in_progress(req)) {
1164 return tevent_req_post(req, ev);
1170 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1172 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1174 struct netlogon_creds_cli_auth_state *state =
1175 tevent_req_data(req,
1176 struct netlogon_creds_cli_auth_state);
1177 struct tevent_req *subreq;
1179 TALLOC_FREE(state->creds);
1181 generate_random_buffer(state->client_challenge.data,
1182 sizeof(state->client_challenge.data));
1184 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1185 state->binding_handle,
1186 state->srv_name_slash,
1187 state->context->client.computer,
1188 &state->client_challenge,
1189 &state->server_challenge);
1190 if (tevent_req_nomem(subreq, req)) {
1193 tevent_req_set_callback(subreq,
1194 netlogon_creds_cli_auth_challenge_done,
1198 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1200 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1202 struct tevent_req *req =
1203 tevent_req_callback_data(subreq,
1205 struct netlogon_creds_cli_auth_state *state =
1206 tevent_req_data(req,
1207 struct netlogon_creds_cli_auth_state);
1211 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1212 TALLOC_FREE(subreq);
1213 if (tevent_req_nterror(req, status)) {
1216 if (tevent_req_nterror(req, result)) {
1220 if (!state->try_auth3 && !state->try_auth2) {
1221 state->current_flags = 0;
1224 /* Calculate the session key and client credentials */
1226 state->creds = netlogon_creds_client_init(state,
1227 state->context->client.account,
1228 state->context->client.computer,
1229 state->context->client.type,
1230 &state->client_challenge,
1231 &state->server_challenge,
1232 state->used_nt_hash,
1233 &state->client_credential,
1234 state->current_flags);
1235 if (tevent_req_nomem(state->creds, req)) {
1239 if (state->try_auth3) {
1240 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1241 state->binding_handle,
1242 state->srv_name_slash,
1243 state->context->client.account,
1244 state->context->client.type,
1245 state->context->client.computer,
1246 &state->client_credential,
1247 &state->server_credential,
1248 &state->creds->negotiate_flags,
1250 if (tevent_req_nomem(subreq, req)) {
1253 } else if (state->try_auth2) {
1256 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1257 state->binding_handle,
1258 state->srv_name_slash,
1259 state->context->client.account,
1260 state->context->client.type,
1261 state->context->client.computer,
1262 &state->client_credential,
1263 &state->server_credential,
1264 &state->creds->negotiate_flags);
1265 if (tevent_req_nomem(subreq, req)) {
1271 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1272 state->binding_handle,
1273 state->srv_name_slash,
1274 state->context->client.account,
1275 state->context->client.type,
1276 state->context->client.computer,
1277 &state->client_credential,
1278 &state->server_credential);
1279 if (tevent_req_nomem(subreq, req)) {
1283 tevent_req_set_callback(subreq,
1284 netlogon_creds_cli_auth_srvauth_done,
1288 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1290 struct tevent_req *req =
1291 tevent_req_callback_data(subreq,
1293 struct netlogon_creds_cli_auth_state *state =
1294 tevent_req_data(req,
1295 struct netlogon_creds_cli_auth_state);
1299 enum ndr_err_code ndr_err;
1304 if (state->try_auth3) {
1305 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1307 TALLOC_FREE(subreq);
1308 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1309 state->try_auth3 = false;
1310 netlogon_creds_cli_auth_challenge_start(req);
1313 if (tevent_req_nterror(req, status)) {
1316 } else if (state->try_auth2) {
1317 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1319 TALLOC_FREE(subreq);
1320 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1321 state->try_auth2 = false;
1322 if (state->require_auth2) {
1323 status = NT_STATUS_DOWNGRADE_DETECTED;
1324 tevent_req_nterror(req, status);
1327 netlogon_creds_cli_auth_challenge_start(req);
1330 if (tevent_req_nterror(req, status)) {
1334 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1336 TALLOC_FREE(subreq);
1337 if (tevent_req_nterror(req, status)) {
1342 if (!NT_STATUS_IS_OK(result) &&
1343 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1345 tevent_req_nterror(req, result);
1349 tmp_flags = state->creds->negotiate_flags;
1350 tmp_flags &= state->context->client.required_flags;
1351 if (tmp_flags != state->context->client.required_flags) {
1352 if (NT_STATUS_IS_OK(result)) {
1353 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1356 tevent_req_nterror(req, result);
1360 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1362 tmp_flags = state->context->client.proposed_flags;
1363 if ((state->current_flags == tmp_flags) &&
1364 (state->creds->negotiate_flags != tmp_flags))
1367 * lets retry with the negotiated flags
1369 state->current_flags = state->creds->negotiate_flags;
1370 netlogon_creds_cli_auth_challenge_start(req);
1374 state->idx_nt_hashes += 1;
1375 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1377 * we already retried, giving up...
1379 tevent_req_nterror(req, result);
1384 * lets retry with the old nt hash.
1386 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1387 state->current_flags = state->context->client.proposed_flags;
1388 netlogon_creds_cli_auth_challenge_start(req);
1392 ok = netlogon_creds_client_check(state->creds,
1393 &state->server_credential);
1395 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1399 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1400 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1401 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1402 status = ndr_map_error2ntstatus(ndr_err);
1403 tevent_req_nterror(req, status);
1407 data.dptr = blob.data;
1408 data.dsize = blob.length;
1410 status = dbwrap_store(state->context->db.ctx,
1411 state->context->db.key_data,
1413 if (tevent_req_nterror(req, status)) {
1417 tevent_req_done(req);
1420 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1421 uint8_t *idx_nt_hashes)
1423 struct netlogon_creds_cli_auth_state *state =
1424 tevent_req_data(req,
1425 struct netlogon_creds_cli_auth_state);
1430 if (tevent_req_is_nterror(req, &status)) {
1431 tevent_req_received(req);
1435 *idx_nt_hashes = state->idx_nt_hashes;
1436 tevent_req_received(req);
1437 return NT_STATUS_OK;
1440 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1441 struct dcerpc_binding_handle *b,
1442 uint8_t num_nt_hashes,
1443 const struct samr_Password * const *nt_hashes,
1444 uint8_t *idx_nt_hashes)
1446 TALLOC_CTX *frame = talloc_stackframe();
1447 struct tevent_context *ev;
1448 struct tevent_req *req;
1449 NTSTATUS status = NT_STATUS_NO_MEMORY;
1453 ev = samba_tevent_context_init(frame);
1457 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1458 num_nt_hashes, nt_hashes);
1462 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1465 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1471 struct netlogon_creds_cli_check_state {
1472 struct tevent_context *ev;
1473 struct netlogon_creds_cli_context *context;
1474 struct dcerpc_binding_handle *binding_handle;
1476 char *srv_name_slash;
1478 union netr_Capabilities caps;
1480 struct netlogon_creds_CredentialState *creds;
1481 struct netr_Authenticator req_auth;
1482 struct netr_Authenticator rep_auth;
1485 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1487 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1489 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1490 struct tevent_context *ev,
1491 struct netlogon_creds_cli_context *context,
1492 struct dcerpc_binding_handle *b)
1494 struct tevent_req *req;
1495 struct netlogon_creds_cli_check_state *state;
1496 struct tevent_req *subreq;
1497 enum dcerpc_AuthType auth_type;
1498 enum dcerpc_AuthLevel auth_level;
1501 req = tevent_req_create(mem_ctx, &state,
1502 struct netlogon_creds_cli_check_state);
1508 state->context = context;
1509 state->binding_handle = b;
1511 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1512 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1513 return tevent_req_post(req, ev);
1516 status = netlogon_creds_cli_get_internal(context, state,
1518 if (tevent_req_nterror(req, status)) {
1519 return tevent_req_post(req, ev);
1522 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1523 context->server.computer);
1524 if (tevent_req_nomem(state->srv_name_slash, req)) {
1525 return tevent_req_post(req, ev);
1528 dcerpc_binding_handle_auth_info(state->binding_handle,
1529 &auth_type, &auth_level);
1531 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1532 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1533 return tevent_req_post(req, ev);
1536 switch (auth_level) {
1537 case DCERPC_AUTH_LEVEL_INTEGRITY:
1538 case DCERPC_AUTH_LEVEL_PRIVACY:
1541 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1542 return tevent_req_post(req, ev);
1546 * we defer all callbacks in order to cleanup
1547 * the database record.
1549 tevent_req_defer_callback(req, state->ev);
1551 netlogon_creds_client_authenticator(state->creds, &state->req_auth);
1552 ZERO_STRUCT(state->rep_auth);
1554 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1555 state->binding_handle,
1556 state->srv_name_slash,
1557 state->context->client.computer,
1562 if (tevent_req_nomem(subreq, req)) {
1563 return tevent_req_post(req, ev);
1566 tevent_req_set_callback(subreq,
1567 netlogon_creds_cli_check_caps,
1573 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1576 struct netlogon_creds_cli_check_state *state =
1577 tevent_req_data(req,
1578 struct netlogon_creds_cli_check_state);
1580 if (state->creds == NULL) {
1584 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1585 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1586 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1587 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1588 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1589 TALLOC_FREE(state->creds);
1593 netlogon_creds_cli_delete_lck(state->context);
1594 TALLOC_FREE(state->creds);
1597 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1599 struct tevent_req *req =
1600 tevent_req_callback_data(subreq,
1602 struct netlogon_creds_cli_check_state *state =
1603 tevent_req_data(req,
1604 struct netlogon_creds_cli_check_state);
1609 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1611 TALLOC_FREE(subreq);
1612 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1614 * Note that the negotiated flags are already checked
1615 * for our required flags after the ServerAuthenticate3/2 call.
1617 uint32_t negotiated = state->creds->negotiate_flags;
1619 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1621 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1622 * already, we expect this to work!
1624 status = NT_STATUS_DOWNGRADE_DETECTED;
1625 tevent_req_nterror(req, status);
1626 netlogon_creds_cli_check_cleanup(req, status);
1630 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1632 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1633 * we expect this to work at least as far as the
1634 * NOT_SUPPORTED error handled below!
1636 * NT 4.0 and Old Samba servers are not
1637 * allowed without "require strong key = no"
1639 status = NT_STATUS_DOWNGRADE_DETECTED;
1640 tevent_req_nterror(req, status);
1641 netlogon_creds_cli_check_cleanup(req, status);
1646 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1647 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1648 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1650 * This is needed against NT 4.0 and old Samba servers.
1652 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1653 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1654 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1655 * with the next request as the sequence number processing
1658 netlogon_creds_cli_check_cleanup(req, status);
1659 tevent_req_done(req);
1662 if (tevent_req_nterror(req, status)) {
1663 netlogon_creds_cli_check_cleanup(req, status);
1667 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1669 * Note that the negotiated flags are already checked
1670 * for our required flags after the ServerAuthenticate3/2 call.
1672 uint32_t negotiated = state->creds->negotiate_flags;
1674 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1676 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1677 * already, we expect this to work!
1679 status = NT_STATUS_DOWNGRADE_DETECTED;
1680 tevent_req_nterror(req, status);
1681 netlogon_creds_cli_check_cleanup(req, status);
1686 * This is ok, the server does not support
1687 * NETLOGON_NEG_SUPPORTS_AES.
1689 * netr_LogonGetCapabilities() was
1690 * netr_LogonDummyRoutine1() before
1691 * NETLOGON_NEG_SUPPORTS_AES was invented.
1693 netlogon_creds_cli_check_cleanup(req, result);
1694 tevent_req_done(req);
1698 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1700 status = NT_STATUS_ACCESS_DENIED;
1701 tevent_req_nterror(req, status);
1702 netlogon_creds_cli_check_cleanup(req, status);
1706 if (tevent_req_nterror(req, result)) {
1707 netlogon_creds_cli_check_cleanup(req, result);
1711 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1712 status = NT_STATUS_DOWNGRADE_DETECTED;
1713 tevent_req_nterror(req, status);
1714 netlogon_creds_cli_check_cleanup(req, status);
1719 * This is the key check that makes this check secure. If we
1720 * get OK here (rather than NOT_SUPPORTED), then the server
1721 * did support AES. If the server only proposed STRONG_KEYS
1722 * and not AES, then it should have failed with
1723 * NOT_IMPLEMENTED. We always send AES as a client, so the
1724 * server should always have returned it.
1726 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1727 status = NT_STATUS_DOWNGRADE_DETECTED;
1728 tevent_req_nterror(req, status);
1729 netlogon_creds_cli_check_cleanup(req, status);
1733 status = netlogon_creds_cli_store_internal(state->context,
1735 if (tevent_req_nterror(req, status)) {
1739 tevent_req_done(req);
1742 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1743 union netr_Capabilities *capabilities)
1745 struct netlogon_creds_cli_check_state *state = tevent_req_data(
1746 req, struct netlogon_creds_cli_check_state);
1749 if (tevent_req_is_nterror(req, &status)) {
1750 netlogon_creds_cli_check_cleanup(req, status);
1751 tevent_req_received(req);
1755 if (capabilities != NULL) {
1756 *capabilities = state->caps;
1759 tevent_req_received(req);
1760 return NT_STATUS_OK;
1763 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1764 struct dcerpc_binding_handle *b,
1765 union netr_Capabilities *capabilities)
1767 TALLOC_CTX *frame = talloc_stackframe();
1768 struct tevent_context *ev;
1769 struct tevent_req *req;
1770 NTSTATUS status = NT_STATUS_NO_MEMORY;
1772 ev = samba_tevent_context_init(frame);
1776 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1780 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1783 status = netlogon_creds_cli_check_recv(req, capabilities);
1789 struct netlogon_creds_cli_ServerPasswordSet_state {
1790 struct tevent_context *ev;
1791 struct netlogon_creds_cli_context *context;
1792 struct dcerpc_binding_handle *binding_handle;
1793 uint32_t old_timeout;
1795 char *srv_name_slash;
1796 enum dcerpc_AuthType auth_type;
1797 enum dcerpc_AuthLevel auth_level;
1799 struct samr_CryptPassword samr_crypt_password;
1800 struct netr_CryptPassword netr_crypt_password;
1801 struct samr_Password samr_password;
1803 struct netlogon_creds_CredentialState *creds;
1804 struct netlogon_creds_CredentialState tmp_creds;
1805 struct netr_Authenticator req_auth;
1806 struct netr_Authenticator rep_auth;
1809 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1811 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1813 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1814 struct tevent_context *ev,
1815 struct netlogon_creds_cli_context *context,
1816 struct dcerpc_binding_handle *b,
1817 const DATA_BLOB *new_password,
1818 const uint32_t *new_version)
1820 struct tevent_req *req;
1821 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1822 struct tevent_req *subreq;
1825 req = tevent_req_create(mem_ctx, &state,
1826 struct netlogon_creds_cli_ServerPasswordSet_state);
1832 state->context = context;
1833 state->binding_handle = b;
1835 if (new_password->length < 14) {
1836 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1837 return tevent_req_post(req, ev);
1841 * netr_ServerPasswordSet
1843 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1846 * netr_ServerPasswordSet2
1848 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1851 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1852 return tevent_req_post(req, ev);
1855 if (new_version != NULL) {
1856 struct NL_PASSWORD_VERSION version;
1857 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1858 uint32_t ofs = 512 - len;
1862 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1863 return tevent_req_post(req, ev);
1867 version.ReservedField = 0;
1868 version.PasswordVersionNumber = *new_version;
1869 version.PasswordVersionPresent =
1870 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1872 p = state->samr_crypt_password.data + ofs;
1873 SIVAL(p, 0, version.ReservedField);
1874 SIVAL(p, 4, version.PasswordVersionNumber);
1875 SIVAL(p, 8, version.PasswordVersionPresent);
1878 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1879 context->server.computer);
1880 if (tevent_req_nomem(state->srv_name_slash, req)) {
1881 return tevent_req_post(req, ev);
1884 dcerpc_binding_handle_auth_info(state->binding_handle,
1886 &state->auth_level);
1888 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1890 if (tevent_req_nomem(subreq, req)) {
1891 return tevent_req_post(req, ev);
1894 tevent_req_set_callback(subreq,
1895 netlogon_creds_cli_ServerPasswordSet_locked,
1901 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1904 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1905 tevent_req_data(req,
1906 struct netlogon_creds_cli_ServerPasswordSet_state);
1908 if (state->creds == NULL) {
1912 dcerpc_binding_handle_set_timeout(state->binding_handle,
1913 state->old_timeout);
1915 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1916 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1917 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1918 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1919 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1920 TALLOC_FREE(state->creds);
1924 netlogon_creds_cli_delete(state->context, state->creds);
1925 TALLOC_FREE(state->creds);
1928 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1930 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1932 struct tevent_req *req =
1933 tevent_req_callback_data(subreq,
1935 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1936 tevent_req_data(req,
1937 struct netlogon_creds_cli_ServerPasswordSet_state);
1940 status = netlogon_creds_cli_lock_recv(subreq, state,
1942 TALLOC_FREE(subreq);
1943 if (tevent_req_nterror(req, status)) {
1947 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1948 switch (state->auth_level) {
1949 case DCERPC_AUTH_LEVEL_INTEGRITY:
1950 case DCERPC_AUTH_LEVEL_PRIVACY:
1953 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1957 uint32_t tmp = state->creds->negotiate_flags;
1959 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1961 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1962 * it should be used, which means
1963 * we had a chance to verify no downgrade
1966 * This relies on netlogon_creds_cli_check*
1967 * being called before, as first request after
1970 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1975 state->old_timeout = dcerpc_binding_handle_set_timeout(
1976 state->binding_handle, 600000);
1979 * we defer all callbacks in order to cleanup
1980 * the database record.
1982 tevent_req_defer_callback(req, state->ev);
1984 state->tmp_creds = *state->creds;
1985 netlogon_creds_client_authenticator(&state->tmp_creds,
1987 ZERO_STRUCT(state->rep_auth);
1989 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1991 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1992 netlogon_creds_aes_encrypt(&state->tmp_creds,
1993 state->samr_crypt_password.data,
1996 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1997 state->samr_crypt_password.data,
2001 memcpy(state->netr_crypt_password.data,
2002 state->samr_crypt_password.data, 512);
2003 state->netr_crypt_password.length =
2004 IVAL(state->samr_crypt_password.data, 512);
2006 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2007 state->binding_handle,
2008 state->srv_name_slash,
2009 state->tmp_creds.account_name,
2010 state->tmp_creds.secure_channel_type,
2011 state->tmp_creds.computer_name,
2014 &state->netr_crypt_password);
2015 if (tevent_req_nomem(subreq, req)) {
2016 status = NT_STATUS_NO_MEMORY;
2017 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2021 netlogon_creds_des_encrypt(&state->tmp_creds,
2022 &state->samr_password);
2024 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2025 state->binding_handle,
2026 state->srv_name_slash,
2027 state->tmp_creds.account_name,
2028 state->tmp_creds.secure_channel_type,
2029 state->tmp_creds.computer_name,
2032 &state->samr_password);
2033 if (tevent_req_nomem(subreq, req)) {
2034 status = NT_STATUS_NO_MEMORY;
2035 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2040 tevent_req_set_callback(subreq,
2041 netlogon_creds_cli_ServerPasswordSet_done,
2045 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2047 struct tevent_req *req =
2048 tevent_req_callback_data(subreq,
2050 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2051 tevent_req_data(req,
2052 struct netlogon_creds_cli_ServerPasswordSet_state);
2057 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2058 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2060 TALLOC_FREE(subreq);
2061 if (tevent_req_nterror(req, status)) {
2062 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2066 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2068 TALLOC_FREE(subreq);
2069 if (tevent_req_nterror(req, status)) {
2070 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2075 ok = netlogon_creds_client_check(&state->tmp_creds,
2076 &state->rep_auth.cred);
2078 status = NT_STATUS_ACCESS_DENIED;
2079 tevent_req_nterror(req, status);
2080 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2084 if (tevent_req_nterror(req, result)) {
2085 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2089 dcerpc_binding_handle_set_timeout(state->binding_handle,
2090 state->old_timeout);
2092 *state->creds = state->tmp_creds;
2093 status = netlogon_creds_cli_store(state->context,
2095 TALLOC_FREE(state->creds);
2096 if (tevent_req_nterror(req, status)) {
2097 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2101 tevent_req_done(req);
2104 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2108 if (tevent_req_is_nterror(req, &status)) {
2109 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2110 tevent_req_received(req);
2114 tevent_req_received(req);
2115 return NT_STATUS_OK;
2118 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2119 struct netlogon_creds_cli_context *context,
2120 struct dcerpc_binding_handle *b,
2121 const DATA_BLOB *new_password,
2122 const uint32_t *new_version)
2124 TALLOC_CTX *frame = talloc_stackframe();
2125 struct tevent_context *ev;
2126 struct tevent_req *req;
2127 NTSTATUS status = NT_STATUS_NO_MEMORY;
2129 ev = samba_tevent_context_init(frame);
2133 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2139 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2142 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2148 struct netlogon_creds_cli_LogonSamLogon_state {
2149 struct tevent_context *ev;
2150 struct netlogon_creds_cli_context *context;
2151 struct dcerpc_binding_handle *binding_handle;
2153 char *srv_name_slash;
2155 enum netr_LogonInfoClass logon_level;
2156 const union netr_LogonLevel *const_logon;
2157 union netr_LogonLevel *logon;
2160 uint16_t validation_level;
2161 union netr_Validation *validation;
2162 uint8_t authoritative;
2165 * do we need encryption at the application layer?
2169 bool try_validation6;
2172 * the read only credentials before we started the operation
2173 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2175 struct netlogon_creds_CredentialState *ro_creds;
2178 * The (locked) credentials used for the credential chain
2179 * used for netr_LogonSamLogonWithFlags() or
2180 * netr_LogonSamLogonWith().
2182 struct netlogon_creds_CredentialState *lk_creds;
2185 * While we have locked the global credentials (lk_creds above)
2186 * we operate an a temporary copy, because a server
2187 * may not support netr_LogonSamLogonWithFlags() and
2188 * didn't process our netr_Authenticator, so we need to
2189 * restart from lk_creds.
2191 struct netlogon_creds_CredentialState tmp_creds;
2192 struct netr_Authenticator req_auth;
2193 struct netr_Authenticator rep_auth;
2196 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2197 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2200 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2201 struct tevent_context *ev,
2202 struct netlogon_creds_cli_context *context,
2203 struct dcerpc_binding_handle *b,
2204 enum netr_LogonInfoClass logon_level,
2205 const union netr_LogonLevel *logon,
2208 struct tevent_req *req;
2209 struct netlogon_creds_cli_LogonSamLogon_state *state;
2211 req = tevent_req_create(mem_ctx, &state,
2212 struct netlogon_creds_cli_LogonSamLogon_state);
2218 state->context = context;
2219 state->binding_handle = b;
2221 state->logon_level = logon_level;
2222 state->const_logon = logon;
2223 state->flags = flags;
2225 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2226 context->server.computer);
2227 if (tevent_req_nomem(state->srv_name_slash, req)) {
2228 return tevent_req_post(req, ev);
2231 switch (logon_level) {
2232 case NetlogonInteractiveInformation:
2233 case NetlogonInteractiveTransitiveInformation:
2234 case NetlogonServiceInformation:
2235 case NetlogonServiceTransitiveInformation:
2236 case NetlogonGenericInformation:
2237 state->user_encrypt = true;
2240 case NetlogonNetworkInformation:
2241 case NetlogonNetworkTransitiveInformation:
2245 state->validation = talloc_zero(state, union netr_Validation);
2246 if (tevent_req_nomem(state->validation, req)) {
2247 return tevent_req_post(req, ev);
2250 netlogon_creds_cli_LogonSamLogon_start(req);
2251 if (!tevent_req_is_in_progress(req)) {
2252 return tevent_req_post(req, ev);
2256 * we defer all callbacks in order to cleanup
2257 * the database record.
2259 tevent_req_defer_callback(req, state->ev);
2263 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2266 struct netlogon_creds_cli_LogonSamLogon_state *state =
2267 tevent_req_data(req,
2268 struct netlogon_creds_cli_LogonSamLogon_state);
2270 if (state->lk_creds == NULL) {
2274 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2276 * This is a hack to recover from a bug in old
2277 * Samba servers, when LogonSamLogonEx() fails:
2279 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2281 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2283 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2284 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2285 * If the sign/seal check fails.
2287 * In that case we need to cleanup the netlogon session.
2289 * It's the job of the caller to disconnect the current
2290 * connection, if netlogon_creds_cli_LogonSamLogon()
2291 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2293 if (!state->context->server.try_logon_with) {
2294 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2298 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2299 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2300 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2301 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2302 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2303 TALLOC_FREE(state->lk_creds);
2307 netlogon_creds_cli_delete(state->context, state->lk_creds);
2308 TALLOC_FREE(state->lk_creds);
2311 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2313 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2315 struct netlogon_creds_cli_LogonSamLogon_state *state =
2316 tevent_req_data(req,
2317 struct netlogon_creds_cli_LogonSamLogon_state);
2318 struct tevent_req *subreq;
2320 enum dcerpc_AuthType auth_type;
2321 enum dcerpc_AuthLevel auth_level;
2323 TALLOC_FREE(state->ro_creds);
2324 TALLOC_FREE(state->logon);
2325 ZERO_STRUCTP(state->validation);
2327 dcerpc_binding_handle_auth_info(state->binding_handle,
2328 &auth_type, &auth_level);
2330 state->try_logon_ex = state->context->server.try_logon_ex;
2331 state->try_validation6 = state->context->server.try_validation6;
2333 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2334 state->try_logon_ex = false;
2337 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2338 state->try_validation6 = false;
2341 if (state->try_logon_ex) {
2342 if (state->try_validation6) {
2343 state->validation_level = 6;
2345 state->validation_level = 3;
2346 state->user_encrypt = true;
2349 state->logon = netlogon_creds_shallow_copy_logon(state,
2351 state->const_logon);
2352 if (tevent_req_nomem(state->logon, req)) {
2353 status = NT_STATUS_NO_MEMORY;
2354 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2358 if (state->user_encrypt) {
2359 status = netlogon_creds_cli_get(state->context,
2362 if (!NT_STATUS_IS_OK(status)) {
2363 status = NT_STATUS_ACCESS_DENIED;
2364 tevent_req_nterror(req, status);
2365 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2369 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2374 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2375 state->binding_handle,
2376 state->srv_name_slash,
2377 state->context->client.computer,
2380 state->validation_level,
2382 &state->authoritative,
2384 if (tevent_req_nomem(subreq, req)) {
2385 status = NT_STATUS_NO_MEMORY;
2386 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2389 tevent_req_set_callback(subreq,
2390 netlogon_creds_cli_LogonSamLogon_done,
2395 if (state->lk_creds == NULL) {
2396 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2398 if (tevent_req_nomem(subreq, req)) {
2399 status = NT_STATUS_NO_MEMORY;
2400 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2403 tevent_req_set_callback(subreq,
2404 netlogon_creds_cli_LogonSamLogon_done,
2409 state->tmp_creds = *state->lk_creds;
2410 netlogon_creds_client_authenticator(&state->tmp_creds,
2412 ZERO_STRUCT(state->rep_auth);
2414 state->logon = netlogon_creds_shallow_copy_logon(state,
2416 state->const_logon);
2417 if (tevent_req_nomem(state->logon, req)) {
2418 status = NT_STATUS_NO_MEMORY;
2419 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2423 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2427 state->validation_level = 3;
2429 if (state->context->server.try_logon_with) {
2430 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2431 state->binding_handle,
2432 state->srv_name_slash,
2433 state->context->client.computer,
2438 state->validation_level,
2440 &state->authoritative,
2442 if (tevent_req_nomem(subreq, req)) {
2443 status = NT_STATUS_NO_MEMORY;
2444 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2450 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2451 state->binding_handle,
2452 state->srv_name_slash,
2453 state->context->client.computer,
2458 state->validation_level,
2460 &state->authoritative);
2461 if (tevent_req_nomem(subreq, req)) {
2462 status = NT_STATUS_NO_MEMORY;
2463 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2468 tevent_req_set_callback(subreq,
2469 netlogon_creds_cli_LogonSamLogon_done,
2473 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2475 struct tevent_req *req =
2476 tevent_req_callback_data(subreq,
2478 struct netlogon_creds_cli_LogonSamLogon_state *state =
2479 tevent_req_data(req,
2480 struct netlogon_creds_cli_LogonSamLogon_state);
2485 if (state->try_logon_ex) {
2486 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2489 TALLOC_FREE(subreq);
2490 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2491 state->context->server.try_validation6 = false;
2492 state->context->server.try_logon_ex = false;
2493 netlogon_creds_cli_LogonSamLogon_start(req);
2496 if (tevent_req_nterror(req, status)) {
2497 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2501 if ((state->validation_level == 6) &&
2502 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2503 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2504 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2506 state->context->server.try_validation6 = false;
2507 netlogon_creds_cli_LogonSamLogon_start(req);
2511 if (tevent_req_nterror(req, result)) {
2512 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2516 if (state->ro_creds == NULL) {
2517 tevent_req_done(req);
2521 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2524 * We got a race, lets retry with on authenticator
2527 * netlogon_creds_cli_LogonSamLogon_start()
2528 * will TALLOC_FREE(state->ro_creds);
2530 state->try_logon_ex = false;
2531 netlogon_creds_cli_LogonSamLogon_start(req);
2535 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2536 state->validation_level,
2539 tevent_req_done(req);
2543 if (state->lk_creds == NULL) {
2544 status = netlogon_creds_cli_lock_recv(subreq, state,
2546 TALLOC_FREE(subreq);
2547 if (tevent_req_nterror(req, status)) {
2548 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2552 netlogon_creds_cli_LogonSamLogon_start(req);
2556 if (state->context->server.try_logon_with) {
2557 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2560 TALLOC_FREE(subreq);
2561 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2562 state->context->server.try_logon_with = false;
2563 netlogon_creds_cli_LogonSamLogon_start(req);
2566 if (tevent_req_nterror(req, status)) {
2567 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2571 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2574 TALLOC_FREE(subreq);
2575 if (tevent_req_nterror(req, status)) {
2576 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2581 ok = netlogon_creds_client_check(&state->tmp_creds,
2582 &state->rep_auth.cred);
2584 status = NT_STATUS_ACCESS_DENIED;
2585 tevent_req_nterror(req, status);
2586 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2590 *state->lk_creds = state->tmp_creds;
2591 status = netlogon_creds_cli_store(state->context,
2593 TALLOC_FREE(state->lk_creds);
2595 if (tevent_req_nterror(req, status)) {
2596 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2600 if (tevent_req_nterror(req, result)) {
2601 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2605 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2606 state->validation_level,
2609 tevent_req_done(req);
2612 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2613 TALLOC_CTX *mem_ctx,
2614 uint16_t *validation_level,
2615 union netr_Validation **validation,
2616 uint8_t *authoritative,
2619 struct netlogon_creds_cli_LogonSamLogon_state *state =
2620 tevent_req_data(req,
2621 struct netlogon_creds_cli_LogonSamLogon_state);
2624 /* authoritative is also returned on error */
2625 *authoritative = state->authoritative;
2627 if (tevent_req_is_nterror(req, &status)) {
2628 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2629 tevent_req_received(req);
2633 *validation_level = state->validation_level;
2634 *validation = talloc_move(mem_ctx, &state->validation);
2635 *flags = state->flags;
2637 tevent_req_received(req);
2638 return NT_STATUS_OK;
2641 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2642 struct netlogon_creds_cli_context *context,
2643 struct dcerpc_binding_handle *b,
2644 enum netr_LogonInfoClass logon_level,
2645 const union netr_LogonLevel *logon,
2646 TALLOC_CTX *mem_ctx,
2647 uint16_t *validation_level,
2648 union netr_Validation **validation,
2649 uint8_t *authoritative,
2652 TALLOC_CTX *frame = talloc_stackframe();
2653 struct tevent_context *ev;
2654 struct tevent_req *req;
2655 NTSTATUS status = NT_STATUS_NO_MEMORY;
2657 ev = samba_tevent_context_init(frame);
2661 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2667 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2670 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2680 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2681 struct tevent_context *ev;
2682 struct netlogon_creds_cli_context *context;
2683 struct dcerpc_binding_handle *binding_handle;
2685 char *srv_name_slash;
2686 enum dcerpc_AuthType auth_type;
2687 enum dcerpc_AuthLevel auth_level;
2689 const char *site_name;
2691 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2693 struct netlogon_creds_CredentialState *creds;
2694 struct netlogon_creds_CredentialState tmp_creds;
2695 struct netr_Authenticator req_auth;
2696 struct netr_Authenticator rep_auth;
2699 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2701 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2703 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2704 struct tevent_context *ev,
2705 struct netlogon_creds_cli_context *context,
2706 struct dcerpc_binding_handle *b,
2707 const char *site_name,
2709 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2711 struct tevent_req *req;
2712 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2713 struct tevent_req *subreq;
2715 req = tevent_req_create(mem_ctx, &state,
2716 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2722 state->context = context;
2723 state->binding_handle = b;
2725 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2726 context->server.computer);
2727 if (tevent_req_nomem(state->srv_name_slash, req)) {
2728 return tevent_req_post(req, ev);
2731 state->site_name = site_name;
2732 state->dns_ttl = dns_ttl;
2733 state->dns_names = dns_names;
2735 dcerpc_binding_handle_auth_info(state->binding_handle,
2737 &state->auth_level);
2739 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2741 if (tevent_req_nomem(subreq, req)) {
2742 return tevent_req_post(req, ev);
2745 tevent_req_set_callback(subreq,
2746 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2752 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2755 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2756 tevent_req_data(req,
2757 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2759 if (state->creds == NULL) {
2763 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2764 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2765 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2766 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2767 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2768 TALLOC_FREE(state->creds);
2772 netlogon_creds_cli_delete(state->context, state->creds);
2773 TALLOC_FREE(state->creds);
2776 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2778 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2780 struct tevent_req *req =
2781 tevent_req_callback_data(subreq,
2783 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2784 tevent_req_data(req,
2785 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2788 status = netlogon_creds_cli_lock_recv(subreq, state,
2790 TALLOC_FREE(subreq);
2791 if (tevent_req_nterror(req, status)) {
2795 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2796 switch (state->auth_level) {
2797 case DCERPC_AUTH_LEVEL_INTEGRITY:
2798 case DCERPC_AUTH_LEVEL_PRIVACY:
2801 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2805 uint32_t tmp = state->creds->negotiate_flags;
2807 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2809 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2810 * it should be used, which means
2811 * we had a chance to verify no downgrade
2814 * This relies on netlogon_creds_cli_check*
2815 * being called before, as first request after
2818 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2824 * we defer all callbacks in order to cleanup
2825 * the database record.
2827 tevent_req_defer_callback(req, state->ev);
2829 state->tmp_creds = *state->creds;
2830 netlogon_creds_client_authenticator(&state->tmp_creds,
2832 ZERO_STRUCT(state->rep_auth);
2834 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2835 state->binding_handle,
2836 state->srv_name_slash,
2837 state->tmp_creds.computer_name,
2843 if (tevent_req_nomem(subreq, req)) {
2844 status = NT_STATUS_NO_MEMORY;
2845 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2849 tevent_req_set_callback(subreq,
2850 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2854 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2856 struct tevent_req *req =
2857 tevent_req_callback_data(subreq,
2859 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2860 tevent_req_data(req,
2861 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2867 * We use state->dns_names as the memory context, as this is
2868 * the only in/out variable and it has been overwritten by the
2869 * out parameter from the server.
2871 * We need to preserve the return value until the caller can use it.
2873 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2875 TALLOC_FREE(subreq);
2876 if (tevent_req_nterror(req, status)) {
2877 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2881 ok = netlogon_creds_client_check(&state->tmp_creds,
2882 &state->rep_auth.cred);
2884 status = NT_STATUS_ACCESS_DENIED;
2885 tevent_req_nterror(req, status);
2886 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2890 *state->creds = state->tmp_creds;
2891 status = netlogon_creds_cli_store(state->context,
2893 TALLOC_FREE(state->creds);
2895 if (tevent_req_nterror(req, status)) {
2896 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2900 if (tevent_req_nterror(req, result)) {
2901 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2905 tevent_req_done(req);
2908 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2912 if (tevent_req_is_nterror(req, &status)) {
2913 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2914 tevent_req_received(req);
2918 tevent_req_received(req);
2919 return NT_STATUS_OK;
2922 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2923 struct netlogon_creds_cli_context *context,
2924 struct dcerpc_binding_handle *b,
2925 const char *site_name,
2927 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2929 TALLOC_CTX *frame = talloc_stackframe();
2930 struct tevent_context *ev;
2931 struct tevent_req *req;
2932 NTSTATUS status = NT_STATUS_NO_MEMORY;
2934 ev = samba_tevent_context_init(frame);
2938 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2945 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2948 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2954 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2955 struct tevent_context *ev;
2956 struct netlogon_creds_cli_context *context;
2957 struct dcerpc_binding_handle *binding_handle;
2959 char *srv_name_slash;
2960 enum dcerpc_AuthType auth_type;
2961 enum dcerpc_AuthLevel auth_level;
2963 struct samr_Password new_owf_password;
2964 struct samr_Password old_owf_password;
2965 struct netr_TrustInfo *trust_info;
2967 struct netlogon_creds_CredentialState *creds;
2968 struct netlogon_creds_CredentialState tmp_creds;
2969 struct netr_Authenticator req_auth;
2970 struct netr_Authenticator rep_auth;
2973 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2975 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2977 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2978 struct tevent_context *ev,
2979 struct netlogon_creds_cli_context *context,
2980 struct dcerpc_binding_handle *b)
2982 struct tevent_req *req;
2983 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2984 struct tevent_req *subreq;
2986 req = tevent_req_create(mem_ctx, &state,
2987 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2993 state->context = context;
2994 state->binding_handle = b;
2996 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2997 context->server.computer);
2998 if (tevent_req_nomem(state->srv_name_slash, req)) {
2999 return tevent_req_post(req, ev);
3002 dcerpc_binding_handle_auth_info(state->binding_handle,
3004 &state->auth_level);
3006 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3008 if (tevent_req_nomem(subreq, req)) {
3009 return tevent_req_post(req, ev);
3012 tevent_req_set_callback(subreq,
3013 netlogon_creds_cli_ServerGetTrustInfo_locked,
3019 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3022 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3023 tevent_req_data(req,
3024 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3026 if (state->creds == NULL) {
3030 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3031 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3032 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3033 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3034 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3035 TALLOC_FREE(state->creds);
3039 netlogon_creds_cli_delete(state->context, state->creds);
3040 TALLOC_FREE(state->creds);
3043 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3045 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3047 struct tevent_req *req =
3048 tevent_req_callback_data(subreq,
3050 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3051 tevent_req_data(req,
3052 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3055 status = netlogon_creds_cli_lock_recv(subreq, state,
3057 TALLOC_FREE(subreq);
3058 if (tevent_req_nterror(req, status)) {
3062 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3063 switch (state->auth_level) {
3064 case DCERPC_AUTH_LEVEL_PRIVACY:
3067 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3071 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3076 * we defer all callbacks in order to cleanup
3077 * the database record.
3079 tevent_req_defer_callback(req, state->ev);
3081 state->tmp_creds = *state->creds;
3082 netlogon_creds_client_authenticator(&state->tmp_creds,
3084 ZERO_STRUCT(state->rep_auth);
3086 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3087 state->binding_handle,
3088 state->srv_name_slash,
3089 state->tmp_creds.account_name,
3090 state->tmp_creds.secure_channel_type,
3091 state->tmp_creds.computer_name,
3094 &state->new_owf_password,
3095 &state->old_owf_password,
3096 &state->trust_info);
3097 if (tevent_req_nomem(subreq, req)) {
3098 status = NT_STATUS_NO_MEMORY;
3099 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3103 tevent_req_set_callback(subreq,
3104 netlogon_creds_cli_ServerGetTrustInfo_done,
3108 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3110 struct tevent_req *req =
3111 tevent_req_callback_data(subreq,
3113 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3114 tevent_req_data(req,
3115 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3118 const struct samr_Password zero = {};
3123 * We use state->dns_names as the memory context, as this is
3124 * the only in/out variable and it has been overwritten by the
3125 * out parameter from the server.
3127 * We need to preserve the return value until the caller can use it.
3129 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3130 TALLOC_FREE(subreq);
3131 if (tevent_req_nterror(req, status)) {
3132 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3136 ok = netlogon_creds_client_check(&state->tmp_creds,
3137 &state->rep_auth.cred);
3139 status = NT_STATUS_ACCESS_DENIED;
3140 tevent_req_nterror(req, status);
3141 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3145 cmp = memcmp(state->new_owf_password.hash,
3146 zero.hash, sizeof(zero.hash));
3148 netlogon_creds_des_decrypt(&state->tmp_creds,
3149 &state->new_owf_password);
3151 cmp = memcmp(state->old_owf_password.hash,
3152 zero.hash, sizeof(zero.hash));
3154 netlogon_creds_des_decrypt(&state->tmp_creds,
3155 &state->old_owf_password);
3158 *state->creds = state->tmp_creds;
3159 status = netlogon_creds_cli_store(state->context,
3161 TALLOC_FREE(state->creds);
3162 if (tevent_req_nterror(req, status)) {
3163 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3167 if (tevent_req_nterror(req, result)) {
3168 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3172 tevent_req_done(req);
3175 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3176 TALLOC_CTX *mem_ctx,
3177 struct samr_Password *new_owf_password,
3178 struct samr_Password *old_owf_password,
3179 struct netr_TrustInfo **trust_info)
3181 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3182 tevent_req_data(req,
3183 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3186 if (tevent_req_is_nterror(req, &status)) {
3187 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3188 tevent_req_received(req);
3192 if (new_owf_password != NULL) {
3193 *new_owf_password = state->new_owf_password;
3195 if (old_owf_password != NULL) {
3196 *old_owf_password = state->old_owf_password;
3198 if (trust_info != NULL) {
3199 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3202 tevent_req_received(req);
3203 return NT_STATUS_OK;
3206 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3207 struct netlogon_creds_cli_context *context,
3208 struct dcerpc_binding_handle *b,
3209 TALLOC_CTX *mem_ctx,
3210 struct samr_Password *new_owf_password,
3211 struct samr_Password *old_owf_password,
3212 struct netr_TrustInfo **trust_info)
3214 TALLOC_CTX *frame = talloc_stackframe();
3215 struct tevent_context *ev;
3216 struct tevent_req *req;
3217 NTSTATUS status = NT_STATUS_NO_MEMORY;
3219 ev = samba_tevent_context_init(frame);
3223 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3227 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3230 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3240 struct netlogon_creds_cli_GetForestTrustInformation_state {
3241 struct tevent_context *ev;
3242 struct netlogon_creds_cli_context *context;
3243 struct dcerpc_binding_handle *binding_handle;
3245 char *srv_name_slash;
3246 enum dcerpc_AuthType auth_type;
3247 enum dcerpc_AuthLevel auth_level;
3250 struct lsa_ForestTrustInformation *forest_trust_info;
3252 struct netlogon_creds_CredentialState *creds;
3253 struct netlogon_creds_CredentialState tmp_creds;
3254 struct netr_Authenticator req_auth;
3255 struct netr_Authenticator rep_auth;
3258 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3260 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3262 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3263 struct tevent_context *ev,
3264 struct netlogon_creds_cli_context *context,
3265 struct dcerpc_binding_handle *b)
3267 struct tevent_req *req;
3268 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3269 struct tevent_req *subreq;
3271 req = tevent_req_create(mem_ctx, &state,
3272 struct netlogon_creds_cli_GetForestTrustInformation_state);
3278 state->context = context;
3279 state->binding_handle = b;
3281 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3282 context->server.computer);
3283 if (tevent_req_nomem(state->srv_name_slash, req)) {
3284 return tevent_req_post(req, ev);
3289 dcerpc_binding_handle_auth_info(state->binding_handle,
3291 &state->auth_level);
3293 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3295 if (tevent_req_nomem(subreq, req)) {
3296 return tevent_req_post(req, ev);
3299 tevent_req_set_callback(subreq,
3300 netlogon_creds_cli_GetForestTrustInformation_locked,
3306 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3309 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3310 tevent_req_data(req,
3311 struct netlogon_creds_cli_GetForestTrustInformation_state);
3313 if (state->creds == NULL) {
3317 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3318 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3319 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3320 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3321 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3322 TALLOC_FREE(state->creds);
3326 netlogon_creds_cli_delete(state->context, state->creds);
3327 TALLOC_FREE(state->creds);
3330 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3332 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3334 struct tevent_req *req =
3335 tevent_req_callback_data(subreq,
3337 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3338 tevent_req_data(req,
3339 struct netlogon_creds_cli_GetForestTrustInformation_state);
3342 status = netlogon_creds_cli_lock_recv(subreq, state,
3344 TALLOC_FREE(subreq);
3345 if (tevent_req_nterror(req, status)) {
3349 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3350 switch (state->auth_level) {
3351 case DCERPC_AUTH_LEVEL_INTEGRITY:
3352 case DCERPC_AUTH_LEVEL_PRIVACY:
3355 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3359 uint32_t tmp = state->creds->negotiate_flags;
3361 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3363 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3364 * it should be used, which means
3365 * we had a chance to verify no downgrade
3368 * This relies on netlogon_creds_cli_check*
3369 * being called before, as first request after
3372 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3378 * we defer all callbacks in order to cleanup
3379 * the database record.
3381 tevent_req_defer_callback(req, state->ev);
3383 state->tmp_creds = *state->creds;
3384 netlogon_creds_client_authenticator(&state->tmp_creds,
3386 ZERO_STRUCT(state->rep_auth);
3388 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3389 state->binding_handle,
3390 state->srv_name_slash,
3391 state->tmp_creds.computer_name,
3395 &state->forest_trust_info);
3396 if (tevent_req_nomem(subreq, req)) {
3397 status = NT_STATUS_NO_MEMORY;
3398 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3402 tevent_req_set_callback(subreq,
3403 netlogon_creds_cli_GetForestTrustInformation_done,
3407 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3409 struct tevent_req *req =
3410 tevent_req_callback_data(subreq,
3412 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3413 tevent_req_data(req,
3414 struct netlogon_creds_cli_GetForestTrustInformation_state);
3420 * We use state->dns_names as the memory context, as this is
3421 * the only in/out variable and it has been overwritten by the
3422 * out parameter from the server.
3424 * We need to preserve the return value until the caller can use it.
3426 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3427 TALLOC_FREE(subreq);
3428 if (tevent_req_nterror(req, status)) {
3429 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3433 ok = netlogon_creds_client_check(&state->tmp_creds,
3434 &state->rep_auth.cred);
3436 status = NT_STATUS_ACCESS_DENIED;
3437 tevent_req_nterror(req, status);
3438 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3442 *state->creds = state->tmp_creds;
3443 status = netlogon_creds_cli_store(state->context,
3445 TALLOC_FREE(state->creds);
3447 if (tevent_req_nterror(req, status)) {
3448 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3452 if (tevent_req_nterror(req, result)) {
3453 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3457 tevent_req_done(req);
3460 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3461 TALLOC_CTX *mem_ctx,
3462 struct lsa_ForestTrustInformation **forest_trust_info)
3464 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3465 tevent_req_data(req,
3466 struct netlogon_creds_cli_GetForestTrustInformation_state);
3469 if (tevent_req_is_nterror(req, &status)) {
3470 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3471 tevent_req_received(req);
3475 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3477 tevent_req_received(req);
3478 return NT_STATUS_OK;
3481 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3482 struct netlogon_creds_cli_context *context,
3483 struct dcerpc_binding_handle *b,
3484 TALLOC_CTX *mem_ctx,
3485 struct lsa_ForestTrustInformation **forest_trust_info)
3487 TALLOC_CTX *frame = talloc_stackframe();
3488 struct tevent_context *ev;
3489 struct tevent_req *req;
3490 NTSTATUS status = NT_STATUS_NO_MEMORY;
3492 ev = samba_tevent_context_init(frame);
3496 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3500 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3503 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3511 struct netlogon_creds_cli_SendToSam_state {
3512 struct tevent_context *ev;
3513 struct netlogon_creds_cli_context *context;
3514 struct dcerpc_binding_handle *binding_handle;
3516 char *srv_name_slash;
3517 enum dcerpc_AuthType auth_type;
3518 enum dcerpc_AuthLevel auth_level;
3522 struct netlogon_creds_CredentialState *creds;
3523 struct netlogon_creds_CredentialState tmp_creds;
3524 struct netr_Authenticator req_auth;
3525 struct netr_Authenticator rep_auth;
3528 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3530 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3532 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3533 struct tevent_context *ev,
3534 struct netlogon_creds_cli_context *context,
3535 struct dcerpc_binding_handle *b,
3536 struct netr_SendToSamBase *message)
3538 struct tevent_req *req;
3539 struct netlogon_creds_cli_SendToSam_state *state;
3540 struct tevent_req *subreq;
3541 enum ndr_err_code ndr_err;
3543 req = tevent_req_create(mem_ctx, &state,
3544 struct netlogon_creds_cli_SendToSam_state);
3550 state->context = context;
3551 state->binding_handle = b;
3553 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3554 context->server.computer);
3555 if (tevent_req_nomem(state->srv_name_slash, req)) {
3556 return tevent_req_post(req, ev);
3559 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3560 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3561 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3562 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3563 tevent_req_nterror(req, status);
3564 return tevent_req_post(req, ev);
3567 dcerpc_binding_handle_auth_info(state->binding_handle,
3569 &state->auth_level);
3571 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3573 if (tevent_req_nomem(subreq, req)) {
3574 return tevent_req_post(req, ev);
3577 tevent_req_set_callback(subreq,
3578 netlogon_creds_cli_SendToSam_locked,
3584 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3587 struct netlogon_creds_cli_SendToSam_state *state =
3588 tevent_req_data(req,
3589 struct netlogon_creds_cli_SendToSam_state);
3591 if (state->creds == NULL) {
3595 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3596 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3597 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3598 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3599 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3600 TALLOC_FREE(state->creds);
3604 netlogon_creds_cli_delete(state->context, state->creds);
3605 TALLOC_FREE(state->creds);
3608 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3610 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3612 struct tevent_req *req =
3613 tevent_req_callback_data(subreq,
3615 struct netlogon_creds_cli_SendToSam_state *state =
3616 tevent_req_data(req,
3617 struct netlogon_creds_cli_SendToSam_state);
3620 status = netlogon_creds_cli_lock_recv(subreq, state,
3622 TALLOC_FREE(subreq);
3623 if (tevent_req_nterror(req, status)) {
3627 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3628 switch (state->auth_level) {
3629 case DCERPC_AUTH_LEVEL_INTEGRITY:
3630 case DCERPC_AUTH_LEVEL_PRIVACY:
3633 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3637 uint32_t tmp = state->creds->negotiate_flags;
3639 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3641 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3642 * it should be used, which means
3643 * we had a chance to verify no downgrade
3646 * This relies on netlogon_creds_cli_check*
3647 * being called before, as first request after
3650 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3656 * we defer all callbacks in order to cleanup
3657 * the database record.
3659 tevent_req_defer_callback(req, state->ev);
3661 state->tmp_creds = *state->creds;
3662 netlogon_creds_client_authenticator(&state->tmp_creds,
3664 ZERO_STRUCT(state->rep_auth);
3666 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3667 netlogon_creds_aes_encrypt(&state->tmp_creds,
3669 state->opaque.length);
3671 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3673 state->opaque.length);
3676 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3677 state->binding_handle,
3678 state->srv_name_slash,
3679 state->tmp_creds.computer_name,
3683 state->opaque.length);
3684 if (tevent_req_nomem(subreq, req)) {
3685 status = NT_STATUS_NO_MEMORY;
3686 netlogon_creds_cli_SendToSam_cleanup(req, status);
3690 tevent_req_set_callback(subreq,
3691 netlogon_creds_cli_SendToSam_done,
3695 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3697 struct tevent_req *req =
3698 tevent_req_callback_data(subreq,
3700 struct netlogon_creds_cli_SendToSam_state *state =
3701 tevent_req_data(req,
3702 struct netlogon_creds_cli_SendToSam_state);
3707 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3708 TALLOC_FREE(subreq);
3709 if (tevent_req_nterror(req, status)) {
3710 netlogon_creds_cli_SendToSam_cleanup(req, status);
3714 ok = netlogon_creds_client_check(&state->tmp_creds,
3715 &state->rep_auth.cred);
3717 status = NT_STATUS_ACCESS_DENIED;
3718 tevent_req_nterror(req, status);
3719 netlogon_creds_cli_SendToSam_cleanup(req, status);
3723 *state->creds = state->tmp_creds;
3724 status = netlogon_creds_cli_store(state->context,
3726 TALLOC_FREE(state->creds);
3728 if (tevent_req_nterror(req, status)) {
3729 netlogon_creds_cli_SendToSam_cleanup(req, status);
3734 * Creds must be stored before we send back application errors
3735 * e.g. NT_STATUS_NOT_IMPLEMENTED
3737 if (tevent_req_nterror(req, result)) {
3738 netlogon_creds_cli_SendToSam_cleanup(req, result);
3742 tevent_req_done(req);
3745 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3746 struct dcerpc_binding_handle *b,
3747 struct netr_SendToSamBase *message)
3749 TALLOC_CTX *frame = talloc_stackframe();
3750 struct tevent_context *ev;
3751 struct tevent_req *req;
3752 NTSTATUS status = NT_STATUS_OK;
3754 ev = samba_tevent_context_init(frame);
3758 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3762 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3766 /* Ignore the result */