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 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;
219 if (netlogon_creds_cli_global_db != NULL) {
223 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
225 return NT_STATUS_NO_MEMORY;
228 global_db = dbwrap_local_open(NULL, lp_ctx,
230 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
232 0600, DBWRAP_LOCK_ORDER_2,
234 if (global_db == NULL) {
235 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
236 fname, strerror(errno)));
238 return NT_STATUS_NO_MEMORY;
242 netlogon_creds_cli_global_db = global_db;
246 void netlogon_creds_cli_close_global_db(void)
248 TALLOC_FREE(netlogon_creds_cli_global_db);
251 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
252 struct messaging_context *msg_ctx,
253 const char *client_account,
254 enum netr_SchannelType type,
255 const char *server_computer,
256 const char *server_netbios_domain,
257 const char *server_dns_domain,
259 struct netlogon_creds_cli_context **_context)
261 TALLOC_CTX *frame = talloc_stackframe();
263 struct netlogon_creds_cli_context *context = NULL;
264 const char *client_computer;
265 uint32_t proposed_flags;
266 uint32_t required_flags = 0;
267 bool reject_md5_servers = false;
268 bool require_strong_key = false;
269 int require_sign_or_seal = true;
270 bool seal_secure_channel = true;
271 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
272 bool neutralize_nt4_emulation = false;
276 if (msg_ctx == NULL) {
278 return NT_STATUS_INVALID_PARAMETER_MIX;
281 client_computer = lpcfg_netbios_name(lp_ctx);
282 if (strlen(client_computer) > 15) {
284 return NT_STATUS_INVALID_PARAMETER_MIX;
288 * allow overwrite per domain
289 * reject md5 servers:<netbios_domain>
291 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
292 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
293 "reject md5 servers",
294 server_netbios_domain,
298 * allow overwrite per domain
299 * require strong key:<netbios_domain>
301 require_strong_key = lpcfg_require_strong_key(lp_ctx);
302 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
303 "require strong key",
304 server_netbios_domain,
308 * allow overwrite per domain
309 * client schannel:<netbios_domain>
311 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
312 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
314 server_netbios_domain,
315 require_sign_or_seal);
318 * allow overwrite per domain
319 * winbind sealed pipes:<netbios_domain>
321 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
322 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
323 "winbind sealed pipes",
324 server_netbios_domain,
325 seal_secure_channel);
328 * allow overwrite per domain
329 * neutralize nt4 emulation:<netbios_domain>
331 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
332 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
333 "neutralize nt4 emulation",
334 server_netbios_domain,
335 neutralize_nt4_emulation);
337 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
338 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
342 if (lpcfg_security(lp_ctx) == SEC_ADS) {
344 * AD domains should be secure
346 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
347 require_sign_or_seal = true;
348 require_strong_key = true;
352 case SEC_CHAN_DOMAIN:
355 case SEC_CHAN_DNS_DOMAIN:
357 * AD domains should be secure
359 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
360 require_sign_or_seal = true;
361 require_strong_key = true;
362 neutralize_nt4_emulation = true;
366 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
367 require_sign_or_seal = true;
368 require_strong_key = true;
372 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
373 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
374 require_sign_or_seal = true;
375 require_strong_key = true;
376 neutralize_nt4_emulation = true;
381 return NT_STATUS_INVALID_PARAMETER;
384 if (neutralize_nt4_emulation) {
385 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
388 if (require_sign_or_seal) {
389 required_flags |= NETLOGON_NEG_ARCFOUR;
390 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
392 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
395 if (reject_md5_servers) {
396 required_flags |= NETLOGON_NEG_ARCFOUR;
397 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
398 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
399 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
402 if (require_strong_key) {
403 required_flags |= NETLOGON_NEG_ARCFOUR;
404 required_flags |= NETLOGON_NEG_STRONG_KEYS;
405 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
408 proposed_flags |= required_flags;
410 if (seal_secure_channel) {
411 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
413 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
416 status = netlogon_creds_cli_context_common(client_computer,
423 server_netbios_domain,
427 if (!NT_STATUS_IS_OK(status)) {
432 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
433 if (context->db.g_ctx == NULL) {
434 TALLOC_FREE(context);
436 return NT_STATUS_NO_MEMORY;
439 status = netlogon_creds_cli_open_global_db(lp_ctx);
440 if (!NT_STATUS_IS_OK(status)) {
441 TALLOC_FREE(context);
443 return NT_STATUS_NO_MEMORY;
446 context->db.ctx = netlogon_creds_cli_global_db;
452 NTSTATUS netlogon_creds_bind_cli_credentials(
453 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
454 struct cli_credentials **pcli_creds)
456 struct cli_credentials *cli_creds;
457 struct netlogon_creds_CredentialState *ncreds;
460 cli_creds = cli_credentials_init(mem_ctx);
461 if (cli_creds == NULL) {
462 return NT_STATUS_NO_MEMORY;
464 cli_credentials_set_secure_channel_type(cli_creds,
465 context->client.type);
466 cli_credentials_set_username(cli_creds, context->client.account,
468 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
470 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
473 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
474 if (!NT_STATUS_IS_OK(status)) {
475 TALLOC_FREE(cli_creds);
478 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
480 *pcli_creds = cli_creds;
484 char *netlogon_creds_cli_debug_string(
485 const struct netlogon_creds_cli_context *context,
488 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
489 context->db.key_name);
492 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
493 struct netlogon_creds_cli_context *context)
495 return context->client.auth_level;
498 struct netlogon_creds_cli_fetch_state {
500 struct netlogon_creds_CredentialState *creds;
501 uint32_t required_flags;
505 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
508 struct netlogon_creds_cli_fetch_state *state =
509 (struct netlogon_creds_cli_fetch_state *)private_data;
510 enum ndr_err_code ndr_err;
514 state->creds = talloc_zero(state->mem_ctx,
515 struct netlogon_creds_CredentialState);
516 if (state->creds == NULL) {
517 state->status = NT_STATUS_NO_MEMORY;
521 blob.data = data.dptr;
522 blob.length = data.dsize;
524 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
525 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
526 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
527 TALLOC_FREE(state->creds);
528 state->status = ndr_map_error2ntstatus(ndr_err);
532 if (DEBUGLEVEL >= 10) {
533 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
536 tmp_flags = state->creds->negotiate_flags;
537 tmp_flags &= state->required_flags;
538 if (tmp_flags != state->required_flags) {
539 TALLOC_FREE(state->creds);
540 state->status = NT_STATUS_DOWNGRADE_DETECTED;
544 state->status = NT_STATUS_OK;
547 static NTSTATUS netlogon_creds_cli_get_internal(
548 struct netlogon_creds_cli_context *context,
549 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
551 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
553 struct netlogon_creds_CredentialState **_creds)
556 struct netlogon_creds_CredentialState *creds;
560 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
561 if (!NT_STATUS_IS_OK(status)) {
566 * mark it as invalid for step operations.
569 creds->seed = (struct netr_Credential) {{0}};
570 creds->client = (struct netr_Credential) {{0}};
571 creds->server = (struct netr_Credential) {{0}};
577 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
578 const struct netlogon_creds_CredentialState *creds1)
580 TALLOC_CTX *frame = talloc_stackframe();
581 struct netlogon_creds_CredentialState *creds2;
585 enum ndr_err_code ndr_err;
588 status = netlogon_creds_cli_get(context, frame, &creds2);
589 if (!NT_STATUS_IS_OK(status)) {
594 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
595 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
596 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
601 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
602 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
603 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
608 cmp = data_blob_cmp(&blob1, &blob2);
615 static NTSTATUS netlogon_creds_cli_store_internal(
616 struct netlogon_creds_cli_context *context,
617 struct netlogon_creds_CredentialState *creds)
620 enum ndr_err_code ndr_err;
624 if (DEBUGLEVEL >= 10) {
625 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
628 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
629 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
630 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
631 status = ndr_map_error2ntstatus(ndr_err);
635 data.dptr = blob.data;
636 data.dsize = blob.length;
638 status = dbwrap_store(context->db.ctx,
639 context->db.key_data,
641 TALLOC_FREE(data.dptr);
642 if (!NT_STATUS_IS_OK(status)) {
649 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
650 struct netlogon_creds_CredentialState *creds)
654 if (context->db.locked_state == NULL) {
656 * this was not the result of netlogon_creds_cli_lock*()
658 return NT_STATUS_INVALID_PAGE_PROTECTION;
661 if (context->db.locked_state->creds != creds) {
663 * this was not the result of netlogon_creds_cli_lock*()
665 return NT_STATUS_INVALID_PAGE_PROTECTION;
668 status = netlogon_creds_cli_store_internal(context, creds);
672 static NTSTATUS netlogon_creds_cli_delete_internal(
673 struct netlogon_creds_cli_context *context)
676 status = dbwrap_delete(context->db.ctx, context->db.key_data);
680 NTSTATUS netlogon_creds_cli_delete_lck(
681 struct netlogon_creds_cli_context *context)
685 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
686 return NT_STATUS_NOT_LOCKED;
689 status = netlogon_creds_cli_delete_internal(context);
693 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
694 struct netlogon_creds_CredentialState *creds)
698 if (context->db.locked_state == NULL) {
700 * this was not the result of netlogon_creds_cli_lock*()
702 return NT_STATUS_INVALID_PAGE_PROTECTION;
705 if (context->db.locked_state->creds != creds) {
707 * this was not the result of netlogon_creds_cli_lock*()
709 return NT_STATUS_INVALID_PAGE_PROTECTION;
712 status = netlogon_creds_cli_delete_internal(context);
716 struct netlogon_creds_cli_lock_state {
717 struct netlogon_creds_cli_locked_state *locked_state;
718 struct netlogon_creds_CredentialState *creds;
721 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
723 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
724 struct tevent_context *ev,
725 struct netlogon_creds_cli_context *context)
727 struct tevent_req *req;
728 struct netlogon_creds_cli_lock_state *state;
729 struct netlogon_creds_cli_locked_state *locked_state;
730 struct tevent_req *subreq;
732 req = tevent_req_create(mem_ctx, &state,
733 struct netlogon_creds_cli_lock_state);
738 if (context->db.locked_state != NULL) {
739 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
740 return tevent_req_post(req, ev);
743 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
744 if (tevent_req_nomem(locked_state, req)) {
745 return tevent_req_post(req, ev);
747 talloc_set_destructor(locked_state,
748 netlogon_creds_cli_locked_state_destructor);
749 locked_state->context = context;
751 context->db.locked_state = locked_state;
752 state->locked_state = locked_state;
754 if (context->db.g_ctx == NULL) {
757 status = netlogon_creds_cli_get_internal(
758 context, state, &state->creds);
759 if (tevent_req_nterror(req, status)) {
760 return tevent_req_post(req, ev);
766 subreq = g_lock_lock_send(state, ev,
768 context->db.key_name,
770 if (tevent_req_nomem(subreq, req)) {
771 return tevent_req_post(req, ev);
773 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
778 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
780 struct tevent_req *req =
781 tevent_req_callback_data(subreq,
783 struct netlogon_creds_cli_lock_state *state =
785 struct netlogon_creds_cli_lock_state);
788 status = g_lock_lock_recv(subreq);
790 if (tevent_req_nterror(req, status)) {
793 state->locked_state->is_glocked = true;
795 status = netlogon_creds_cli_get_internal(state->locked_state->context,
796 state, &state->creds);
797 if (tevent_req_nterror(req, status)) {
800 tevent_req_done(req);
803 static NTSTATUS netlogon_creds_cli_get_internal(
804 struct netlogon_creds_cli_context *context,
805 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
807 struct netlogon_creds_cli_fetch_state fstate = {
808 .status = NT_STATUS_INTERNAL_ERROR,
809 .required_flags = context->client.required_flags,
813 fstate.mem_ctx = mem_ctx;
814 status = dbwrap_parse_record(context->db.ctx,
815 context->db.key_data,
816 netlogon_creds_cli_fetch_parser,
818 if (!NT_STATUS_IS_OK(status)) {
821 if (!NT_STATUS_IS_OK(fstate.status)) {
822 return fstate.status;
825 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
826 *pcreds = fstate.creds;
831 * It is really important to try SamLogonEx here,
832 * because multiple processes can talk to the same
833 * domain controller, without using the credential
836 * With a normal SamLogon call, we must keep the
837 * credentials chain updated and intact between all
838 * users of the machine account (which would imply
839 * cross-node communication for every NTLM logon).
841 * The credentials chain is not per NETLOGON pipe
842 * connection, but globally on the server/client pair
845 * It's also important to use NetlogonValidationSamInfo4 (6),
846 * because it relies on the rpc transport encryption
847 * and avoids using the global netlogon schannel
848 * session key to en/decrypt secret information
849 * like the user_session_key for network logons.
851 * [MS-APDS] 3.1.5.2 NTLM Network Logon
852 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
853 * NETLOGON_NEG_AUTHENTICATED_RPC set together
854 * are the indication that the server supports
855 * NetlogonValidationSamInfo4 (6). And it must only
856 * be used if "SealSecureChannel" is used.
858 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
859 * check is done in netlogon_creds_cli_LogonSamLogon*().
862 context->server.cached_flags = fstate.creds->negotiate_flags;
863 context->server.try_validation6 = true;
864 context->server.try_logon_ex = true;
865 context->server.try_logon_with = true;
867 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
868 context->server.try_validation6 = false;
869 context->server.try_logon_ex = false;
871 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
872 context->server.try_validation6 = false;
875 *pcreds = fstate.creds;
879 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
881 struct netlogon_creds_CredentialState **creds)
883 struct netlogon_creds_cli_lock_state *state =
885 struct netlogon_creds_cli_lock_state);
888 if (tevent_req_is_nterror(req, &status)) {
889 tevent_req_received(req);
893 talloc_steal(state->creds, state->locked_state);
894 state->locked_state->creds = state->creds;
895 *creds = talloc_move(mem_ctx, &state->creds);
896 tevent_req_received(req);
900 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
902 struct netlogon_creds_CredentialState **creds)
904 TALLOC_CTX *frame = talloc_stackframe();
905 struct tevent_context *ev;
906 struct tevent_req *req;
907 NTSTATUS status = NT_STATUS_NO_MEMORY;
909 ev = samba_tevent_context_init(frame);
913 req = netlogon_creds_cli_lock_send(frame, ev, context);
917 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
920 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
926 struct netlogon_creds_cli_lck {
927 struct netlogon_creds_cli_context *context;
930 struct netlogon_creds_cli_lck_state {
931 struct netlogon_creds_cli_lck *lck;
932 enum netlogon_creds_cli_lck_type type;
935 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
936 static int netlogon_creds_cli_lck_destructor(
937 struct netlogon_creds_cli_lck *lck);
939 struct tevent_req *netlogon_creds_cli_lck_send(
940 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
941 struct netlogon_creds_cli_context *context,
942 enum netlogon_creds_cli_lck_type type)
944 struct tevent_req *req, *subreq;
945 struct netlogon_creds_cli_lck_state *state;
946 enum g_lock_type gtype;
948 req = tevent_req_create(mem_ctx, &state,
949 struct netlogon_creds_cli_lck_state);
954 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
955 DBG_DEBUG("context already locked\n");
956 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
957 return tevent_req_post(req, ev);
961 case NETLOGON_CREDS_CLI_LCK_SHARED:
964 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
965 gtype = G_LOCK_WRITE;
968 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
969 return tevent_req_post(req, ev);
972 state->lck = talloc(state, struct netlogon_creds_cli_lck);
973 if (tevent_req_nomem(state->lck, req)) {
974 return tevent_req_post(req, ev);
976 state->lck->context = context;
979 subreq = g_lock_lock_send(state, ev,
981 context->db.key_name,
983 if (tevent_req_nomem(subreq, req)) {
984 return tevent_req_post(req, ev);
986 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
991 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
993 struct tevent_req *req = tevent_req_callback_data(
994 subreq, struct tevent_req);
995 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
996 req, struct netlogon_creds_cli_lck_state);
999 status = g_lock_lock_recv(subreq);
1000 TALLOC_FREE(subreq);
1001 if (tevent_req_nterror(req, status)) {
1005 state->lck->context->db.lock = state->type;
1006 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1008 tevent_req_done(req);
1011 static int netlogon_creds_cli_lck_destructor(
1012 struct netlogon_creds_cli_lck *lck)
1014 struct netlogon_creds_cli_context *ctx = lck->context;
1017 status = g_lock_unlock(ctx->db.g_ctx, ctx->db.key_name);
1018 if (!NT_STATUS_IS_OK(status)) {
1019 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1020 smb_panic("g_lock_unlock failed");
1022 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1026 NTSTATUS netlogon_creds_cli_lck_recv(
1027 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1028 struct netlogon_creds_cli_lck **lck)
1030 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1031 req, struct netlogon_creds_cli_lck_state);
1034 if (tevent_req_is_nterror(req, &status)) {
1037 *lck = talloc_move(mem_ctx, &state->lck);
1038 return NT_STATUS_OK;
1041 NTSTATUS netlogon_creds_cli_lck(
1042 struct netlogon_creds_cli_context *context,
1043 enum netlogon_creds_cli_lck_type type,
1044 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1046 TALLOC_CTX *frame = talloc_stackframe();
1047 struct tevent_context *ev;
1048 struct tevent_req *req;
1049 NTSTATUS status = NT_STATUS_NO_MEMORY;
1051 ev = samba_tevent_context_init(frame);
1055 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1059 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1062 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1068 struct netlogon_creds_cli_auth_state {
1069 struct tevent_context *ev;
1070 struct netlogon_creds_cli_context *context;
1071 struct dcerpc_binding_handle *binding_handle;
1072 uint8_t num_nt_hashes;
1073 uint8_t idx_nt_hashes;
1074 const struct samr_Password * const *nt_hashes;
1075 const struct samr_Password *used_nt_hash;
1076 char *srv_name_slash;
1077 uint32_t current_flags;
1078 struct netr_Credential client_challenge;
1079 struct netr_Credential server_challenge;
1080 struct netlogon_creds_CredentialState *creds;
1081 struct netr_Credential client_credential;
1082 struct netr_Credential server_credential;
1089 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1091 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1092 struct tevent_context *ev,
1093 struct netlogon_creds_cli_context *context,
1094 struct dcerpc_binding_handle *b,
1095 uint8_t num_nt_hashes,
1096 const struct samr_Password * const *nt_hashes)
1098 struct tevent_req *req;
1099 struct netlogon_creds_cli_auth_state *state;
1102 req = tevent_req_create(mem_ctx, &state,
1103 struct netlogon_creds_cli_auth_state);
1109 state->context = context;
1110 state->binding_handle = b;
1111 if (num_nt_hashes < 1) {
1112 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1113 return tevent_req_post(req, ev);
1115 if (num_nt_hashes > 4) {
1116 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1117 return tevent_req_post(req, ev);
1120 state->num_nt_hashes = num_nt_hashes;
1121 state->idx_nt_hashes = 0;
1122 state->nt_hashes = nt_hashes;
1124 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1125 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1126 return tevent_req_post(req, ev);
1129 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1130 context->server.computer);
1131 if (tevent_req_nomem(state->srv_name_slash, req)) {
1132 return tevent_req_post(req, ev);
1135 state->try_auth3 = true;
1136 state->try_auth2 = true;
1138 if (context->client.required_flags != 0) {
1139 state->require_auth2 = true;
1142 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1143 state->current_flags = context->client.proposed_flags;
1145 status = dbwrap_purge(state->context->db.ctx,
1146 state->context->db.key_data);
1147 if (tevent_req_nterror(req, status)) {
1148 return tevent_req_post(req, ev);
1151 netlogon_creds_cli_auth_challenge_start(req);
1152 if (!tevent_req_is_in_progress(req)) {
1153 return tevent_req_post(req, ev);
1159 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1161 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1163 struct netlogon_creds_cli_auth_state *state =
1164 tevent_req_data(req,
1165 struct netlogon_creds_cli_auth_state);
1166 struct tevent_req *subreq;
1168 TALLOC_FREE(state->creds);
1170 generate_random_buffer(state->client_challenge.data,
1171 sizeof(state->client_challenge.data));
1173 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1174 state->binding_handle,
1175 state->srv_name_slash,
1176 state->context->client.computer,
1177 &state->client_challenge,
1178 &state->server_challenge);
1179 if (tevent_req_nomem(subreq, req)) {
1182 tevent_req_set_callback(subreq,
1183 netlogon_creds_cli_auth_challenge_done,
1187 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1189 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1191 struct tevent_req *req =
1192 tevent_req_callback_data(subreq,
1194 struct netlogon_creds_cli_auth_state *state =
1195 tevent_req_data(req,
1196 struct netlogon_creds_cli_auth_state);
1200 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1201 TALLOC_FREE(subreq);
1202 if (tevent_req_nterror(req, status)) {
1205 if (tevent_req_nterror(req, result)) {
1209 if (!state->try_auth3 && !state->try_auth2) {
1210 state->current_flags = 0;
1213 /* Calculate the session key and client credentials */
1215 state->creds = netlogon_creds_client_init(state,
1216 state->context->client.account,
1217 state->context->client.computer,
1218 state->context->client.type,
1219 &state->client_challenge,
1220 &state->server_challenge,
1221 state->used_nt_hash,
1222 &state->client_credential,
1223 state->current_flags);
1224 if (tevent_req_nomem(state->creds, req)) {
1228 if (state->try_auth3) {
1229 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1230 state->binding_handle,
1231 state->srv_name_slash,
1232 state->context->client.account,
1233 state->context->client.type,
1234 state->context->client.computer,
1235 &state->client_credential,
1236 &state->server_credential,
1237 &state->creds->negotiate_flags,
1239 if (tevent_req_nomem(subreq, req)) {
1242 } else if (state->try_auth2) {
1245 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1246 state->binding_handle,
1247 state->srv_name_slash,
1248 state->context->client.account,
1249 state->context->client.type,
1250 state->context->client.computer,
1251 &state->client_credential,
1252 &state->server_credential,
1253 &state->creds->negotiate_flags);
1254 if (tevent_req_nomem(subreq, req)) {
1260 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1261 state->binding_handle,
1262 state->srv_name_slash,
1263 state->context->client.account,
1264 state->context->client.type,
1265 state->context->client.computer,
1266 &state->client_credential,
1267 &state->server_credential);
1268 if (tevent_req_nomem(subreq, req)) {
1272 tevent_req_set_callback(subreq,
1273 netlogon_creds_cli_auth_srvauth_done,
1277 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1279 struct tevent_req *req =
1280 tevent_req_callback_data(subreq,
1282 struct netlogon_creds_cli_auth_state *state =
1283 tevent_req_data(req,
1284 struct netlogon_creds_cli_auth_state);
1288 enum ndr_err_code ndr_err;
1293 if (state->try_auth3) {
1294 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1296 TALLOC_FREE(subreq);
1297 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1298 state->try_auth3 = false;
1299 netlogon_creds_cli_auth_challenge_start(req);
1302 if (tevent_req_nterror(req, status)) {
1305 } else if (state->try_auth2) {
1306 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1308 TALLOC_FREE(subreq);
1309 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1310 state->try_auth2 = false;
1311 if (state->require_auth2) {
1312 status = NT_STATUS_DOWNGRADE_DETECTED;
1313 tevent_req_nterror(req, status);
1316 netlogon_creds_cli_auth_challenge_start(req);
1319 if (tevent_req_nterror(req, status)) {
1323 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1325 TALLOC_FREE(subreq);
1326 if (tevent_req_nterror(req, status)) {
1331 if (!NT_STATUS_IS_OK(result) &&
1332 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1334 tevent_req_nterror(req, result);
1338 tmp_flags = state->creds->negotiate_flags;
1339 tmp_flags &= state->context->client.required_flags;
1340 if (tmp_flags != state->context->client.required_flags) {
1341 if (NT_STATUS_IS_OK(result)) {
1342 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1345 tevent_req_nterror(req, result);
1349 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1351 tmp_flags = state->context->client.proposed_flags;
1352 if ((state->current_flags == tmp_flags) &&
1353 (state->creds->negotiate_flags != tmp_flags))
1356 * lets retry with the negotiated flags
1358 state->current_flags = state->creds->negotiate_flags;
1359 netlogon_creds_cli_auth_challenge_start(req);
1363 state->idx_nt_hashes += 1;
1364 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1366 * we already retried, giving up...
1368 tevent_req_nterror(req, result);
1373 * lets retry with the old nt hash.
1375 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1376 state->current_flags = state->context->client.proposed_flags;
1377 netlogon_creds_cli_auth_challenge_start(req);
1381 ok = netlogon_creds_client_check(state->creds,
1382 &state->server_credential);
1384 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1388 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1389 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1390 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1391 status = ndr_map_error2ntstatus(ndr_err);
1392 tevent_req_nterror(req, status);
1396 data.dptr = blob.data;
1397 data.dsize = blob.length;
1399 status = dbwrap_store(state->context->db.ctx,
1400 state->context->db.key_data,
1402 if (tevent_req_nterror(req, status)) {
1406 tevent_req_done(req);
1409 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1410 uint8_t *idx_nt_hashes)
1412 struct netlogon_creds_cli_auth_state *state =
1413 tevent_req_data(req,
1414 struct netlogon_creds_cli_auth_state);
1419 if (tevent_req_is_nterror(req, &status)) {
1420 tevent_req_received(req);
1424 *idx_nt_hashes = state->idx_nt_hashes;
1425 tevent_req_received(req);
1426 return NT_STATUS_OK;
1429 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1430 struct dcerpc_binding_handle *b,
1431 uint8_t num_nt_hashes,
1432 const struct samr_Password * const *nt_hashes,
1433 uint8_t *idx_nt_hashes)
1435 TALLOC_CTX *frame = talloc_stackframe();
1436 struct tevent_context *ev;
1437 struct tevent_req *req;
1438 NTSTATUS status = NT_STATUS_NO_MEMORY;
1442 ev = samba_tevent_context_init(frame);
1446 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1447 num_nt_hashes, nt_hashes);
1451 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1454 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1460 struct netlogon_creds_cli_check_state {
1461 struct tevent_context *ev;
1462 struct netlogon_creds_cli_context *context;
1463 struct dcerpc_binding_handle *binding_handle;
1465 char *srv_name_slash;
1467 union netr_Capabilities caps;
1469 struct netlogon_creds_CredentialState *creds;
1470 struct netr_Authenticator req_auth;
1471 struct netr_Authenticator rep_auth;
1474 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1476 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1478 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1479 struct tevent_context *ev,
1480 struct netlogon_creds_cli_context *context,
1481 struct dcerpc_binding_handle *b)
1483 struct tevent_req *req;
1484 struct netlogon_creds_cli_check_state *state;
1485 struct tevent_req *subreq;
1486 enum dcerpc_AuthType auth_type;
1487 enum dcerpc_AuthLevel auth_level;
1490 req = tevent_req_create(mem_ctx, &state,
1491 struct netlogon_creds_cli_check_state);
1497 state->context = context;
1498 state->binding_handle = b;
1500 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1501 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1502 return tevent_req_post(req, ev);
1505 status = netlogon_creds_cli_get_internal(context, state,
1507 if (tevent_req_nterror(req, status)) {
1508 return tevent_req_post(req, ev);
1511 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1512 context->server.computer);
1513 if (tevent_req_nomem(state->srv_name_slash, req)) {
1514 return tevent_req_post(req, ev);
1517 dcerpc_binding_handle_auth_info(state->binding_handle,
1518 &auth_type, &auth_level);
1520 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1521 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1522 return tevent_req_post(req, ev);
1525 switch (auth_level) {
1526 case DCERPC_AUTH_LEVEL_INTEGRITY:
1527 case DCERPC_AUTH_LEVEL_PRIVACY:
1530 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1531 return tevent_req_post(req, ev);
1535 * we defer all callbacks in order to cleanup
1536 * the database record.
1538 tevent_req_defer_callback(req, state->ev);
1540 netlogon_creds_client_authenticator(state->creds, &state->req_auth);
1541 ZERO_STRUCT(state->rep_auth);
1543 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1544 state->binding_handle,
1545 state->srv_name_slash,
1546 state->context->client.computer,
1551 if (tevent_req_nomem(subreq, req)) {
1552 return tevent_req_post(req, ev);
1555 tevent_req_set_callback(subreq,
1556 netlogon_creds_cli_check_caps,
1562 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1565 struct netlogon_creds_cli_check_state *state =
1566 tevent_req_data(req,
1567 struct netlogon_creds_cli_check_state);
1569 if (state->creds == NULL) {
1573 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1574 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1575 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1576 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1577 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1578 TALLOC_FREE(state->creds);
1582 netlogon_creds_cli_delete_lck(state->context);
1583 TALLOC_FREE(state->creds);
1586 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1588 struct tevent_req *req =
1589 tevent_req_callback_data(subreq,
1591 struct netlogon_creds_cli_check_state *state =
1592 tevent_req_data(req,
1593 struct netlogon_creds_cli_check_state);
1598 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1600 TALLOC_FREE(subreq);
1601 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1603 * Note that the negotiated flags are already checked
1604 * for our required flags after the ServerAuthenticate3/2 call.
1606 uint32_t negotiated = state->creds->negotiate_flags;
1608 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1610 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1611 * already, we expect this to work!
1613 status = NT_STATUS_DOWNGRADE_DETECTED;
1614 tevent_req_nterror(req, status);
1615 netlogon_creds_cli_check_cleanup(req, status);
1619 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1621 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1622 * we expect this to work at least as far as the
1623 * NOT_SUPPORTED error handled below!
1625 * NT 4.0 and Old Samba servers are not
1626 * allowed without "require strong key = no"
1628 status = NT_STATUS_DOWNGRADE_DETECTED;
1629 tevent_req_nterror(req, status);
1630 netlogon_creds_cli_check_cleanup(req, status);
1635 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1636 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1637 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1639 * This is needed against NT 4.0 and old Samba servers.
1641 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1642 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1643 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1644 * with the next request as the sequence number processing
1647 netlogon_creds_cli_check_cleanup(req, status);
1648 tevent_req_done(req);
1651 if (tevent_req_nterror(req, status)) {
1652 netlogon_creds_cli_check_cleanup(req, status);
1656 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1658 * Note that the negotiated flags are already checked
1659 * for our required flags after the ServerAuthenticate3/2 call.
1661 uint32_t negotiated = state->creds->negotiate_flags;
1663 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1665 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1666 * already, we expect this to work!
1668 status = NT_STATUS_DOWNGRADE_DETECTED;
1669 tevent_req_nterror(req, status);
1670 netlogon_creds_cli_check_cleanup(req, status);
1675 * This is ok, the server does not support
1676 * NETLOGON_NEG_SUPPORTS_AES.
1678 * netr_LogonGetCapabilities() was
1679 * netr_LogonDummyRoutine1() before
1680 * NETLOGON_NEG_SUPPORTS_AES was invented.
1682 netlogon_creds_cli_check_cleanup(req, result);
1683 tevent_req_done(req);
1687 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1689 status = NT_STATUS_ACCESS_DENIED;
1690 tevent_req_nterror(req, status);
1691 netlogon_creds_cli_check_cleanup(req, status);
1695 if (tevent_req_nterror(req, result)) {
1696 netlogon_creds_cli_check_cleanup(req, result);
1700 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1701 status = NT_STATUS_DOWNGRADE_DETECTED;
1702 tevent_req_nterror(req, status);
1703 netlogon_creds_cli_check_cleanup(req, status);
1708 * This is the key check that makes this check secure. If we
1709 * get OK here (rather than NOT_SUPPORTED), then the server
1710 * did support AES. If the server only proposed STRONG_KEYS
1711 * and not AES, then it should have failed with
1712 * NOT_IMPLEMENTED. We always send AES as a client, so the
1713 * server should always have returned it.
1715 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1716 status = NT_STATUS_DOWNGRADE_DETECTED;
1717 tevent_req_nterror(req, status);
1718 netlogon_creds_cli_check_cleanup(req, status);
1722 status = netlogon_creds_cli_store_internal(state->context,
1724 if (tevent_req_nterror(req, status)) {
1728 tevent_req_done(req);
1731 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1735 if (tevent_req_is_nterror(req, &status)) {
1736 netlogon_creds_cli_check_cleanup(req, status);
1737 tevent_req_received(req);
1741 tevent_req_received(req);
1742 return NT_STATUS_OK;
1745 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1746 struct dcerpc_binding_handle *b)
1748 TALLOC_CTX *frame = talloc_stackframe();
1749 struct tevent_context *ev;
1750 struct tevent_req *req;
1751 NTSTATUS status = NT_STATUS_NO_MEMORY;
1753 ev = samba_tevent_context_init(frame);
1757 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1761 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1764 status = netlogon_creds_cli_check_recv(req);
1770 struct netlogon_creds_cli_ServerPasswordSet_state {
1771 struct tevent_context *ev;
1772 struct netlogon_creds_cli_context *context;
1773 struct dcerpc_binding_handle *binding_handle;
1774 uint32_t old_timeout;
1776 char *srv_name_slash;
1777 enum dcerpc_AuthType auth_type;
1778 enum dcerpc_AuthLevel auth_level;
1780 struct samr_CryptPassword samr_crypt_password;
1781 struct netr_CryptPassword netr_crypt_password;
1782 struct samr_Password samr_password;
1784 struct netlogon_creds_CredentialState *creds;
1785 struct netlogon_creds_CredentialState tmp_creds;
1786 struct netr_Authenticator req_auth;
1787 struct netr_Authenticator rep_auth;
1790 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1792 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1794 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1795 struct tevent_context *ev,
1796 struct netlogon_creds_cli_context *context,
1797 struct dcerpc_binding_handle *b,
1798 const DATA_BLOB *new_password,
1799 const uint32_t *new_version)
1801 struct tevent_req *req;
1802 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1803 struct tevent_req *subreq;
1806 req = tevent_req_create(mem_ctx, &state,
1807 struct netlogon_creds_cli_ServerPasswordSet_state);
1813 state->context = context;
1814 state->binding_handle = b;
1816 if (new_password->length < 14) {
1817 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1818 return tevent_req_post(req, ev);
1822 * netr_ServerPasswordSet
1824 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1827 * netr_ServerPasswordSet2
1829 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1832 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1833 return tevent_req_post(req, ev);
1836 if (new_version != NULL) {
1837 struct NL_PASSWORD_VERSION version;
1838 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1839 uint32_t ofs = 512 - len;
1843 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1844 return tevent_req_post(req, ev);
1848 version.ReservedField = 0;
1849 version.PasswordVersionNumber = *new_version;
1850 version.PasswordVersionPresent =
1851 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1853 p = state->samr_crypt_password.data + ofs;
1854 SIVAL(p, 0, version.ReservedField);
1855 SIVAL(p, 4, version.PasswordVersionNumber);
1856 SIVAL(p, 8, version.PasswordVersionPresent);
1859 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1860 context->server.computer);
1861 if (tevent_req_nomem(state->srv_name_slash, req)) {
1862 return tevent_req_post(req, ev);
1865 dcerpc_binding_handle_auth_info(state->binding_handle,
1867 &state->auth_level);
1869 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1871 if (tevent_req_nomem(subreq, req)) {
1872 return tevent_req_post(req, ev);
1875 tevent_req_set_callback(subreq,
1876 netlogon_creds_cli_ServerPasswordSet_locked,
1882 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1885 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1886 tevent_req_data(req,
1887 struct netlogon_creds_cli_ServerPasswordSet_state);
1889 if (state->creds == NULL) {
1893 dcerpc_binding_handle_set_timeout(state->binding_handle,
1894 state->old_timeout);
1896 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1897 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1898 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1899 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1900 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1901 TALLOC_FREE(state->creds);
1905 netlogon_creds_cli_delete(state->context, state->creds);
1906 TALLOC_FREE(state->creds);
1909 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1911 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1913 struct tevent_req *req =
1914 tevent_req_callback_data(subreq,
1916 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1917 tevent_req_data(req,
1918 struct netlogon_creds_cli_ServerPasswordSet_state);
1921 status = netlogon_creds_cli_lock_recv(subreq, state,
1923 TALLOC_FREE(subreq);
1924 if (tevent_req_nterror(req, status)) {
1928 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1929 switch (state->auth_level) {
1930 case DCERPC_AUTH_LEVEL_INTEGRITY:
1931 case DCERPC_AUTH_LEVEL_PRIVACY:
1934 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1938 uint32_t tmp = state->creds->negotiate_flags;
1940 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1942 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1943 * it should be used, which means
1944 * we had a chance to verify no downgrade
1947 * This relies on netlogon_creds_cli_check*
1948 * being called before, as first request after
1951 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1956 state->old_timeout = dcerpc_binding_handle_set_timeout(
1957 state->binding_handle, 600000);
1960 * we defer all callbacks in order to cleanup
1961 * the database record.
1963 tevent_req_defer_callback(req, state->ev);
1965 state->tmp_creds = *state->creds;
1966 netlogon_creds_client_authenticator(&state->tmp_creds,
1968 ZERO_STRUCT(state->rep_auth);
1970 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1972 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1973 netlogon_creds_aes_encrypt(&state->tmp_creds,
1974 state->samr_crypt_password.data,
1977 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1978 state->samr_crypt_password.data,
1982 memcpy(state->netr_crypt_password.data,
1983 state->samr_crypt_password.data, 512);
1984 state->netr_crypt_password.length =
1985 IVAL(state->samr_crypt_password.data, 512);
1987 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1988 state->binding_handle,
1989 state->srv_name_slash,
1990 state->tmp_creds.account_name,
1991 state->tmp_creds.secure_channel_type,
1992 state->tmp_creds.computer_name,
1995 &state->netr_crypt_password);
1996 if (tevent_req_nomem(subreq, req)) {
1997 status = NT_STATUS_NO_MEMORY;
1998 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2002 netlogon_creds_des_encrypt(&state->tmp_creds,
2003 &state->samr_password);
2005 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2006 state->binding_handle,
2007 state->srv_name_slash,
2008 state->tmp_creds.account_name,
2009 state->tmp_creds.secure_channel_type,
2010 state->tmp_creds.computer_name,
2013 &state->samr_password);
2014 if (tevent_req_nomem(subreq, req)) {
2015 status = NT_STATUS_NO_MEMORY;
2016 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2021 tevent_req_set_callback(subreq,
2022 netlogon_creds_cli_ServerPasswordSet_done,
2026 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2028 struct tevent_req *req =
2029 tevent_req_callback_data(subreq,
2031 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2032 tevent_req_data(req,
2033 struct netlogon_creds_cli_ServerPasswordSet_state);
2038 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2039 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2041 TALLOC_FREE(subreq);
2042 if (tevent_req_nterror(req, status)) {
2043 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2047 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2049 TALLOC_FREE(subreq);
2050 if (tevent_req_nterror(req, status)) {
2051 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2056 ok = netlogon_creds_client_check(&state->tmp_creds,
2057 &state->rep_auth.cred);
2059 status = NT_STATUS_ACCESS_DENIED;
2060 tevent_req_nterror(req, status);
2061 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2065 if (tevent_req_nterror(req, result)) {
2066 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2070 dcerpc_binding_handle_set_timeout(state->binding_handle,
2071 state->old_timeout);
2073 *state->creds = state->tmp_creds;
2074 status = netlogon_creds_cli_store(state->context,
2076 TALLOC_FREE(state->creds);
2077 if (tevent_req_nterror(req, status)) {
2078 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2082 tevent_req_done(req);
2085 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2089 if (tevent_req_is_nterror(req, &status)) {
2090 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2091 tevent_req_received(req);
2095 tevent_req_received(req);
2096 return NT_STATUS_OK;
2099 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2100 struct netlogon_creds_cli_context *context,
2101 struct dcerpc_binding_handle *b,
2102 const DATA_BLOB *new_password,
2103 const uint32_t *new_version)
2105 TALLOC_CTX *frame = talloc_stackframe();
2106 struct tevent_context *ev;
2107 struct tevent_req *req;
2108 NTSTATUS status = NT_STATUS_NO_MEMORY;
2110 ev = samba_tevent_context_init(frame);
2114 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2120 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2123 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2129 struct netlogon_creds_cli_LogonSamLogon_state {
2130 struct tevent_context *ev;
2131 struct netlogon_creds_cli_context *context;
2132 struct dcerpc_binding_handle *binding_handle;
2134 char *srv_name_slash;
2136 enum netr_LogonInfoClass logon_level;
2137 const union netr_LogonLevel *const_logon;
2138 union netr_LogonLevel *logon;
2141 uint16_t validation_level;
2142 union netr_Validation *validation;
2143 uint8_t authoritative;
2146 * do we need encryption at the application layer?
2150 bool try_validation6;
2153 * the read only credentials before we started the operation
2154 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2156 struct netlogon_creds_CredentialState *ro_creds;
2159 * The (locked) credentials used for the credential chain
2160 * used for netr_LogonSamLogonWithFlags() or
2161 * netr_LogonSamLogonWith().
2163 struct netlogon_creds_CredentialState *lk_creds;
2166 * While we have locked the global credentials (lk_creds above)
2167 * we operate an a temporary copy, because a server
2168 * may not support netr_LogonSamLogonWithFlags() and
2169 * didn't process our netr_Authenticator, so we need to
2170 * restart from lk_creds.
2172 struct netlogon_creds_CredentialState tmp_creds;
2173 struct netr_Authenticator req_auth;
2174 struct netr_Authenticator rep_auth;
2177 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2178 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2181 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2182 struct tevent_context *ev,
2183 struct netlogon_creds_cli_context *context,
2184 struct dcerpc_binding_handle *b,
2185 enum netr_LogonInfoClass logon_level,
2186 const union netr_LogonLevel *logon,
2189 struct tevent_req *req;
2190 struct netlogon_creds_cli_LogonSamLogon_state *state;
2192 req = tevent_req_create(mem_ctx, &state,
2193 struct netlogon_creds_cli_LogonSamLogon_state);
2199 state->context = context;
2200 state->binding_handle = b;
2202 state->logon_level = logon_level;
2203 state->const_logon = logon;
2204 state->flags = flags;
2206 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2207 context->server.computer);
2208 if (tevent_req_nomem(state->srv_name_slash, req)) {
2209 return tevent_req_post(req, ev);
2212 switch (logon_level) {
2213 case NetlogonInteractiveInformation:
2214 case NetlogonInteractiveTransitiveInformation:
2215 case NetlogonServiceInformation:
2216 case NetlogonServiceTransitiveInformation:
2217 case NetlogonGenericInformation:
2218 state->user_encrypt = true;
2221 case NetlogonNetworkInformation:
2222 case NetlogonNetworkTransitiveInformation:
2226 state->validation = talloc_zero(state, union netr_Validation);
2227 if (tevent_req_nomem(state->validation, req)) {
2228 return tevent_req_post(req, ev);
2231 netlogon_creds_cli_LogonSamLogon_start(req);
2232 if (!tevent_req_is_in_progress(req)) {
2233 return tevent_req_post(req, ev);
2237 * we defer all callbacks in order to cleanup
2238 * the database record.
2240 tevent_req_defer_callback(req, state->ev);
2244 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2247 struct netlogon_creds_cli_LogonSamLogon_state *state =
2248 tevent_req_data(req,
2249 struct netlogon_creds_cli_LogonSamLogon_state);
2251 if (state->lk_creds == NULL) {
2255 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2257 * This is a hack to recover from a bug in old
2258 * Samba servers, when LogonSamLogonEx() fails:
2260 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2262 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2264 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2265 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2266 * If the sign/seal check fails.
2268 * In that case we need to cleanup the netlogon session.
2270 * It's the job of the caller to disconnect the current
2271 * connection, if netlogon_creds_cli_LogonSamLogon()
2272 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2274 if (!state->context->server.try_logon_with) {
2275 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2279 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2280 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2281 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2282 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2283 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2284 TALLOC_FREE(state->lk_creds);
2288 netlogon_creds_cli_delete(state->context, state->lk_creds);
2289 TALLOC_FREE(state->lk_creds);
2292 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2294 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2296 struct netlogon_creds_cli_LogonSamLogon_state *state =
2297 tevent_req_data(req,
2298 struct netlogon_creds_cli_LogonSamLogon_state);
2299 struct tevent_req *subreq;
2301 enum dcerpc_AuthType auth_type;
2302 enum dcerpc_AuthLevel auth_level;
2304 TALLOC_FREE(state->ro_creds);
2305 TALLOC_FREE(state->logon);
2306 ZERO_STRUCTP(state->validation);
2308 dcerpc_binding_handle_auth_info(state->binding_handle,
2309 &auth_type, &auth_level);
2311 state->try_logon_ex = state->context->server.try_logon_ex;
2312 state->try_validation6 = state->context->server.try_validation6;
2314 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2315 state->try_logon_ex = false;
2318 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2319 state->try_validation6 = false;
2322 if (state->try_logon_ex) {
2323 if (state->try_validation6) {
2324 state->validation_level = 6;
2326 state->validation_level = 3;
2327 state->user_encrypt = true;
2330 state->logon = netlogon_creds_shallow_copy_logon(state,
2332 state->const_logon);
2333 if (tevent_req_nomem(state->logon, req)) {
2334 status = NT_STATUS_NO_MEMORY;
2335 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2339 if (state->user_encrypt) {
2340 status = netlogon_creds_cli_get(state->context,
2343 if (!NT_STATUS_IS_OK(status)) {
2344 status = NT_STATUS_ACCESS_DENIED;
2345 tevent_req_nterror(req, status);
2346 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2350 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2355 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2356 state->binding_handle,
2357 state->srv_name_slash,
2358 state->context->client.computer,
2361 state->validation_level,
2363 &state->authoritative,
2365 if (tevent_req_nomem(subreq, req)) {
2366 status = NT_STATUS_NO_MEMORY;
2367 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2370 tevent_req_set_callback(subreq,
2371 netlogon_creds_cli_LogonSamLogon_done,
2376 if (state->lk_creds == NULL) {
2377 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2379 if (tevent_req_nomem(subreq, req)) {
2380 status = NT_STATUS_NO_MEMORY;
2381 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2384 tevent_req_set_callback(subreq,
2385 netlogon_creds_cli_LogonSamLogon_done,
2390 state->tmp_creds = *state->lk_creds;
2391 netlogon_creds_client_authenticator(&state->tmp_creds,
2393 ZERO_STRUCT(state->rep_auth);
2395 state->logon = netlogon_creds_shallow_copy_logon(state,
2397 state->const_logon);
2398 if (tevent_req_nomem(state->logon, req)) {
2399 status = NT_STATUS_NO_MEMORY;
2400 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2404 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2408 state->validation_level = 3;
2410 if (state->context->server.try_logon_with) {
2411 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2412 state->binding_handle,
2413 state->srv_name_slash,
2414 state->context->client.computer,
2419 state->validation_level,
2421 &state->authoritative,
2423 if (tevent_req_nomem(subreq, req)) {
2424 status = NT_STATUS_NO_MEMORY;
2425 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2431 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2432 state->binding_handle,
2433 state->srv_name_slash,
2434 state->context->client.computer,
2439 state->validation_level,
2441 &state->authoritative);
2442 if (tevent_req_nomem(subreq, req)) {
2443 status = NT_STATUS_NO_MEMORY;
2444 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2449 tevent_req_set_callback(subreq,
2450 netlogon_creds_cli_LogonSamLogon_done,
2454 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2456 struct tevent_req *req =
2457 tevent_req_callback_data(subreq,
2459 struct netlogon_creds_cli_LogonSamLogon_state *state =
2460 tevent_req_data(req,
2461 struct netlogon_creds_cli_LogonSamLogon_state);
2466 if (state->try_logon_ex) {
2467 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2470 TALLOC_FREE(subreq);
2471 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2472 state->context->server.try_validation6 = false;
2473 state->context->server.try_logon_ex = false;
2474 netlogon_creds_cli_LogonSamLogon_start(req);
2477 if (tevent_req_nterror(req, status)) {
2478 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2482 if ((state->validation_level == 6) &&
2483 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2484 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2485 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2487 state->context->server.try_validation6 = false;
2488 netlogon_creds_cli_LogonSamLogon_start(req);
2492 if (tevent_req_nterror(req, result)) {
2493 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2497 if (state->ro_creds == NULL) {
2498 tevent_req_done(req);
2502 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2505 * We got a race, lets retry with on authenticator
2508 * netlogon_creds_cli_LogonSamLogon_start()
2509 * will TALLOC_FREE(state->ro_creds);
2511 state->try_logon_ex = false;
2512 netlogon_creds_cli_LogonSamLogon_start(req);
2516 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2517 state->validation_level,
2520 tevent_req_done(req);
2524 if (state->lk_creds == NULL) {
2525 status = netlogon_creds_cli_lock_recv(subreq, state,
2527 TALLOC_FREE(subreq);
2528 if (tevent_req_nterror(req, status)) {
2529 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2533 netlogon_creds_cli_LogonSamLogon_start(req);
2537 if (state->context->server.try_logon_with) {
2538 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2541 TALLOC_FREE(subreq);
2542 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2543 state->context->server.try_logon_with = false;
2544 netlogon_creds_cli_LogonSamLogon_start(req);
2547 if (tevent_req_nterror(req, status)) {
2548 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2552 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2555 TALLOC_FREE(subreq);
2556 if (tevent_req_nterror(req, status)) {
2557 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2562 ok = netlogon_creds_client_check(&state->tmp_creds,
2563 &state->rep_auth.cred);
2565 status = NT_STATUS_ACCESS_DENIED;
2566 tevent_req_nterror(req, status);
2567 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2571 *state->lk_creds = state->tmp_creds;
2572 status = netlogon_creds_cli_store(state->context,
2574 TALLOC_FREE(state->lk_creds);
2576 if (tevent_req_nterror(req, status)) {
2577 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2581 if (tevent_req_nterror(req, result)) {
2582 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2586 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2587 state->validation_level,
2590 tevent_req_done(req);
2593 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2594 TALLOC_CTX *mem_ctx,
2595 uint16_t *validation_level,
2596 union netr_Validation **validation,
2597 uint8_t *authoritative,
2600 struct netlogon_creds_cli_LogonSamLogon_state *state =
2601 tevent_req_data(req,
2602 struct netlogon_creds_cli_LogonSamLogon_state);
2605 /* authoritative is also returned on error */
2606 *authoritative = state->authoritative;
2608 if (tevent_req_is_nterror(req, &status)) {
2609 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2610 tevent_req_received(req);
2614 *validation_level = state->validation_level;
2615 *validation = talloc_move(mem_ctx, &state->validation);
2616 *flags = state->flags;
2618 tevent_req_received(req);
2619 return NT_STATUS_OK;
2622 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2623 struct netlogon_creds_cli_context *context,
2624 struct dcerpc_binding_handle *b,
2625 enum netr_LogonInfoClass logon_level,
2626 const union netr_LogonLevel *logon,
2627 TALLOC_CTX *mem_ctx,
2628 uint16_t *validation_level,
2629 union netr_Validation **validation,
2630 uint8_t *authoritative,
2633 TALLOC_CTX *frame = talloc_stackframe();
2634 struct tevent_context *ev;
2635 struct tevent_req *req;
2636 NTSTATUS status = NT_STATUS_NO_MEMORY;
2638 ev = samba_tevent_context_init(frame);
2642 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2648 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2651 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2661 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2662 struct tevent_context *ev;
2663 struct netlogon_creds_cli_context *context;
2664 struct dcerpc_binding_handle *binding_handle;
2666 char *srv_name_slash;
2667 enum dcerpc_AuthType auth_type;
2668 enum dcerpc_AuthLevel auth_level;
2670 const char *site_name;
2672 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2674 struct netlogon_creds_CredentialState *creds;
2675 struct netlogon_creds_CredentialState tmp_creds;
2676 struct netr_Authenticator req_auth;
2677 struct netr_Authenticator rep_auth;
2680 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2682 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2684 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2685 struct tevent_context *ev,
2686 struct netlogon_creds_cli_context *context,
2687 struct dcerpc_binding_handle *b,
2688 const char *site_name,
2690 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2692 struct tevent_req *req;
2693 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2694 struct tevent_req *subreq;
2696 req = tevent_req_create(mem_ctx, &state,
2697 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2703 state->context = context;
2704 state->binding_handle = b;
2706 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2707 context->server.computer);
2708 if (tevent_req_nomem(state->srv_name_slash, req)) {
2709 return tevent_req_post(req, ev);
2712 state->site_name = site_name;
2713 state->dns_ttl = dns_ttl;
2714 state->dns_names = dns_names;
2716 dcerpc_binding_handle_auth_info(state->binding_handle,
2718 &state->auth_level);
2720 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2722 if (tevent_req_nomem(subreq, req)) {
2723 return tevent_req_post(req, ev);
2726 tevent_req_set_callback(subreq,
2727 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2733 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2736 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2737 tevent_req_data(req,
2738 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2740 if (state->creds == NULL) {
2744 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2745 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2746 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2747 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2748 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2749 TALLOC_FREE(state->creds);
2753 netlogon_creds_cli_delete(state->context, state->creds);
2754 TALLOC_FREE(state->creds);
2757 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2759 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2761 struct tevent_req *req =
2762 tevent_req_callback_data(subreq,
2764 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2765 tevent_req_data(req,
2766 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2769 status = netlogon_creds_cli_lock_recv(subreq, state,
2771 TALLOC_FREE(subreq);
2772 if (tevent_req_nterror(req, status)) {
2776 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2777 switch (state->auth_level) {
2778 case DCERPC_AUTH_LEVEL_INTEGRITY:
2779 case DCERPC_AUTH_LEVEL_PRIVACY:
2782 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2786 uint32_t tmp = state->creds->negotiate_flags;
2788 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2790 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2791 * it should be used, which means
2792 * we had a chance to verify no downgrade
2795 * This relies on netlogon_creds_cli_check*
2796 * being called before, as first request after
2799 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2805 * we defer all callbacks in order to cleanup
2806 * the database record.
2808 tevent_req_defer_callback(req, state->ev);
2810 state->tmp_creds = *state->creds;
2811 netlogon_creds_client_authenticator(&state->tmp_creds,
2813 ZERO_STRUCT(state->rep_auth);
2815 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2816 state->binding_handle,
2817 state->srv_name_slash,
2818 state->tmp_creds.computer_name,
2824 if (tevent_req_nomem(subreq, req)) {
2825 status = NT_STATUS_NO_MEMORY;
2826 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2830 tevent_req_set_callback(subreq,
2831 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2835 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2837 struct tevent_req *req =
2838 tevent_req_callback_data(subreq,
2840 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2841 tevent_req_data(req,
2842 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2848 * We use state->dns_names as the memory context, as this is
2849 * the only in/out variable and it has been overwritten by the
2850 * out parameter from the server.
2852 * We need to preserve the return value until the caller can use it.
2854 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2856 TALLOC_FREE(subreq);
2857 if (tevent_req_nterror(req, status)) {
2858 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2862 ok = netlogon_creds_client_check(&state->tmp_creds,
2863 &state->rep_auth.cred);
2865 status = NT_STATUS_ACCESS_DENIED;
2866 tevent_req_nterror(req, status);
2867 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2871 *state->creds = state->tmp_creds;
2872 status = netlogon_creds_cli_store(state->context,
2874 TALLOC_FREE(state->creds);
2876 if (tevent_req_nterror(req, status)) {
2877 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2881 if (tevent_req_nterror(req, result)) {
2882 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2886 tevent_req_done(req);
2889 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2893 if (tevent_req_is_nterror(req, &status)) {
2894 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2895 tevent_req_received(req);
2899 tevent_req_received(req);
2900 return NT_STATUS_OK;
2903 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2904 struct netlogon_creds_cli_context *context,
2905 struct dcerpc_binding_handle *b,
2906 const char *site_name,
2908 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2910 TALLOC_CTX *frame = talloc_stackframe();
2911 struct tevent_context *ev;
2912 struct tevent_req *req;
2913 NTSTATUS status = NT_STATUS_NO_MEMORY;
2915 ev = samba_tevent_context_init(frame);
2919 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2926 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2929 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2935 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2936 struct tevent_context *ev;
2937 struct netlogon_creds_cli_context *context;
2938 struct dcerpc_binding_handle *binding_handle;
2940 char *srv_name_slash;
2941 enum dcerpc_AuthType auth_type;
2942 enum dcerpc_AuthLevel auth_level;
2944 struct samr_Password new_owf_password;
2945 struct samr_Password old_owf_password;
2946 struct netr_TrustInfo *trust_info;
2948 struct netlogon_creds_CredentialState *creds;
2949 struct netlogon_creds_CredentialState tmp_creds;
2950 struct netr_Authenticator req_auth;
2951 struct netr_Authenticator rep_auth;
2954 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2956 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2958 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2959 struct tevent_context *ev,
2960 struct netlogon_creds_cli_context *context,
2961 struct dcerpc_binding_handle *b)
2963 struct tevent_req *req;
2964 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2965 struct tevent_req *subreq;
2967 req = tevent_req_create(mem_ctx, &state,
2968 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2974 state->context = context;
2975 state->binding_handle = b;
2977 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2978 context->server.computer);
2979 if (tevent_req_nomem(state->srv_name_slash, req)) {
2980 return tevent_req_post(req, ev);
2983 dcerpc_binding_handle_auth_info(state->binding_handle,
2985 &state->auth_level);
2987 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2989 if (tevent_req_nomem(subreq, req)) {
2990 return tevent_req_post(req, ev);
2993 tevent_req_set_callback(subreq,
2994 netlogon_creds_cli_ServerGetTrustInfo_locked,
3000 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3003 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3004 tevent_req_data(req,
3005 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3007 if (state->creds == NULL) {
3011 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3012 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3013 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3014 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3015 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3016 TALLOC_FREE(state->creds);
3020 netlogon_creds_cli_delete(state->context, state->creds);
3021 TALLOC_FREE(state->creds);
3024 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3026 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3028 struct tevent_req *req =
3029 tevent_req_callback_data(subreq,
3031 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3032 tevent_req_data(req,
3033 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3036 status = netlogon_creds_cli_lock_recv(subreq, state,
3038 TALLOC_FREE(subreq);
3039 if (tevent_req_nterror(req, status)) {
3043 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3044 switch (state->auth_level) {
3045 case DCERPC_AUTH_LEVEL_PRIVACY:
3048 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3052 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3057 * we defer all callbacks in order to cleanup
3058 * the database record.
3060 tevent_req_defer_callback(req, state->ev);
3062 state->tmp_creds = *state->creds;
3063 netlogon_creds_client_authenticator(&state->tmp_creds,
3065 ZERO_STRUCT(state->rep_auth);
3067 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3068 state->binding_handle,
3069 state->srv_name_slash,
3070 state->tmp_creds.account_name,
3071 state->tmp_creds.secure_channel_type,
3072 state->tmp_creds.computer_name,
3075 &state->new_owf_password,
3076 &state->old_owf_password,
3077 &state->trust_info);
3078 if (tevent_req_nomem(subreq, req)) {
3079 status = NT_STATUS_NO_MEMORY;
3080 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3084 tevent_req_set_callback(subreq,
3085 netlogon_creds_cli_ServerGetTrustInfo_done,
3089 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3091 struct tevent_req *req =
3092 tevent_req_callback_data(subreq,
3094 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3095 tevent_req_data(req,
3096 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3099 const struct samr_Password zero = {};
3104 * We use state->dns_names as the memory context, as this is
3105 * the only in/out variable and it has been overwritten by the
3106 * out parameter from the server.
3108 * We need to preserve the return value until the caller can use it.
3110 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3111 TALLOC_FREE(subreq);
3112 if (tevent_req_nterror(req, status)) {
3113 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3117 ok = netlogon_creds_client_check(&state->tmp_creds,
3118 &state->rep_auth.cred);
3120 status = NT_STATUS_ACCESS_DENIED;
3121 tevent_req_nterror(req, status);
3122 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3126 cmp = memcmp(state->new_owf_password.hash,
3127 zero.hash, sizeof(zero.hash));
3129 netlogon_creds_des_decrypt(&state->tmp_creds,
3130 &state->new_owf_password);
3132 cmp = memcmp(state->old_owf_password.hash,
3133 zero.hash, sizeof(zero.hash));
3135 netlogon_creds_des_decrypt(&state->tmp_creds,
3136 &state->old_owf_password);
3139 *state->creds = state->tmp_creds;
3140 status = netlogon_creds_cli_store(state->context,
3142 TALLOC_FREE(state->creds);
3143 if (tevent_req_nterror(req, status)) {
3144 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3148 if (tevent_req_nterror(req, result)) {
3149 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3153 tevent_req_done(req);
3156 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3157 TALLOC_CTX *mem_ctx,
3158 struct samr_Password *new_owf_password,
3159 struct samr_Password *old_owf_password,
3160 struct netr_TrustInfo **trust_info)
3162 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3163 tevent_req_data(req,
3164 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3167 if (tevent_req_is_nterror(req, &status)) {
3168 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3169 tevent_req_received(req);
3173 if (new_owf_password != NULL) {
3174 *new_owf_password = state->new_owf_password;
3176 if (old_owf_password != NULL) {
3177 *old_owf_password = state->old_owf_password;
3179 if (trust_info != NULL) {
3180 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3183 tevent_req_received(req);
3184 return NT_STATUS_OK;
3187 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3188 struct netlogon_creds_cli_context *context,
3189 struct dcerpc_binding_handle *b,
3190 TALLOC_CTX *mem_ctx,
3191 struct samr_Password *new_owf_password,
3192 struct samr_Password *old_owf_password,
3193 struct netr_TrustInfo **trust_info)
3195 TALLOC_CTX *frame = talloc_stackframe();
3196 struct tevent_context *ev;
3197 struct tevent_req *req;
3198 NTSTATUS status = NT_STATUS_NO_MEMORY;
3200 ev = samba_tevent_context_init(frame);
3204 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3208 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3211 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3221 struct netlogon_creds_cli_GetForestTrustInformation_state {
3222 struct tevent_context *ev;
3223 struct netlogon_creds_cli_context *context;
3224 struct dcerpc_binding_handle *binding_handle;
3226 char *srv_name_slash;
3227 enum dcerpc_AuthType auth_type;
3228 enum dcerpc_AuthLevel auth_level;
3231 struct lsa_ForestTrustInformation *forest_trust_info;
3233 struct netlogon_creds_CredentialState *creds;
3234 struct netlogon_creds_CredentialState tmp_creds;
3235 struct netr_Authenticator req_auth;
3236 struct netr_Authenticator rep_auth;
3239 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3241 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3243 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3244 struct tevent_context *ev,
3245 struct netlogon_creds_cli_context *context,
3246 struct dcerpc_binding_handle *b)
3248 struct tevent_req *req;
3249 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3250 struct tevent_req *subreq;
3252 req = tevent_req_create(mem_ctx, &state,
3253 struct netlogon_creds_cli_GetForestTrustInformation_state);
3259 state->context = context;
3260 state->binding_handle = b;
3262 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3263 context->server.computer);
3264 if (tevent_req_nomem(state->srv_name_slash, req)) {
3265 return tevent_req_post(req, ev);
3270 dcerpc_binding_handle_auth_info(state->binding_handle,
3272 &state->auth_level);
3274 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3276 if (tevent_req_nomem(subreq, req)) {
3277 return tevent_req_post(req, ev);
3280 tevent_req_set_callback(subreq,
3281 netlogon_creds_cli_GetForestTrustInformation_locked,
3287 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3290 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3291 tevent_req_data(req,
3292 struct netlogon_creds_cli_GetForestTrustInformation_state);
3294 if (state->creds == NULL) {
3298 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3299 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3300 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3301 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3302 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3303 TALLOC_FREE(state->creds);
3307 netlogon_creds_cli_delete(state->context, state->creds);
3308 TALLOC_FREE(state->creds);
3311 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3313 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3315 struct tevent_req *req =
3316 tevent_req_callback_data(subreq,
3318 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3319 tevent_req_data(req,
3320 struct netlogon_creds_cli_GetForestTrustInformation_state);
3323 status = netlogon_creds_cli_lock_recv(subreq, state,
3325 TALLOC_FREE(subreq);
3326 if (tevent_req_nterror(req, status)) {
3330 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3331 switch (state->auth_level) {
3332 case DCERPC_AUTH_LEVEL_INTEGRITY:
3333 case DCERPC_AUTH_LEVEL_PRIVACY:
3336 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3340 uint32_t tmp = state->creds->negotiate_flags;
3342 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3344 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3345 * it should be used, which means
3346 * we had a chance to verify no downgrade
3349 * This relies on netlogon_creds_cli_check*
3350 * being called before, as first request after
3353 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3359 * we defer all callbacks in order to cleanup
3360 * the database record.
3362 tevent_req_defer_callback(req, state->ev);
3364 state->tmp_creds = *state->creds;
3365 netlogon_creds_client_authenticator(&state->tmp_creds,
3367 ZERO_STRUCT(state->rep_auth);
3369 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3370 state->binding_handle,
3371 state->srv_name_slash,
3372 state->tmp_creds.computer_name,
3376 &state->forest_trust_info);
3377 if (tevent_req_nomem(subreq, req)) {
3378 status = NT_STATUS_NO_MEMORY;
3379 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3383 tevent_req_set_callback(subreq,
3384 netlogon_creds_cli_GetForestTrustInformation_done,
3388 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3390 struct tevent_req *req =
3391 tevent_req_callback_data(subreq,
3393 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3394 tevent_req_data(req,
3395 struct netlogon_creds_cli_GetForestTrustInformation_state);
3401 * We use state->dns_names as the memory context, as this is
3402 * the only in/out variable and it has been overwritten by the
3403 * out parameter from the server.
3405 * We need to preserve the return value until the caller can use it.
3407 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3408 TALLOC_FREE(subreq);
3409 if (tevent_req_nterror(req, status)) {
3410 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3414 ok = netlogon_creds_client_check(&state->tmp_creds,
3415 &state->rep_auth.cred);
3417 status = NT_STATUS_ACCESS_DENIED;
3418 tevent_req_nterror(req, status);
3419 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3423 *state->creds = state->tmp_creds;
3424 status = netlogon_creds_cli_store(state->context,
3426 TALLOC_FREE(state->creds);
3428 if (tevent_req_nterror(req, status)) {
3429 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3433 if (tevent_req_nterror(req, result)) {
3434 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3438 tevent_req_done(req);
3441 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3442 TALLOC_CTX *mem_ctx,
3443 struct lsa_ForestTrustInformation **forest_trust_info)
3445 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3446 tevent_req_data(req,
3447 struct netlogon_creds_cli_GetForestTrustInformation_state);
3450 if (tevent_req_is_nterror(req, &status)) {
3451 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3452 tevent_req_received(req);
3456 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3458 tevent_req_received(req);
3459 return NT_STATUS_OK;
3462 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3463 struct netlogon_creds_cli_context *context,
3464 struct dcerpc_binding_handle *b,
3465 TALLOC_CTX *mem_ctx,
3466 struct lsa_ForestTrustInformation **forest_trust_info)
3468 TALLOC_CTX *frame = talloc_stackframe();
3469 struct tevent_context *ev;
3470 struct tevent_req *req;
3471 NTSTATUS status = NT_STATUS_NO_MEMORY;
3473 ev = samba_tevent_context_init(frame);
3477 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3481 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3484 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3492 struct netlogon_creds_cli_SendToSam_state {
3493 struct tevent_context *ev;
3494 struct netlogon_creds_cli_context *context;
3495 struct dcerpc_binding_handle *binding_handle;
3497 char *srv_name_slash;
3498 enum dcerpc_AuthType auth_type;
3499 enum dcerpc_AuthLevel auth_level;
3503 struct netlogon_creds_CredentialState *creds;
3504 struct netlogon_creds_CredentialState tmp_creds;
3505 struct netr_Authenticator req_auth;
3506 struct netr_Authenticator rep_auth;
3509 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3511 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3513 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3514 struct tevent_context *ev,
3515 struct netlogon_creds_cli_context *context,
3516 struct dcerpc_binding_handle *b,
3517 struct netr_SendToSamBase *message)
3519 struct tevent_req *req;
3520 struct netlogon_creds_cli_SendToSam_state *state;
3521 struct tevent_req *subreq;
3522 enum ndr_err_code ndr_err;
3524 req = tevent_req_create(mem_ctx, &state,
3525 struct netlogon_creds_cli_SendToSam_state);
3531 state->context = context;
3532 state->binding_handle = b;
3534 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3535 context->server.computer);
3536 if (tevent_req_nomem(state->srv_name_slash, req)) {
3537 return tevent_req_post(req, ev);
3540 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3541 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3542 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3543 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3544 tevent_req_nterror(req, status);
3545 return tevent_req_post(req, ev);
3548 dcerpc_binding_handle_auth_info(state->binding_handle,
3550 &state->auth_level);
3552 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3554 if (tevent_req_nomem(subreq, req)) {
3555 return tevent_req_post(req, ev);
3558 tevent_req_set_callback(subreq,
3559 netlogon_creds_cli_SendToSam_locked,
3565 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3568 struct netlogon_creds_cli_SendToSam_state *state =
3569 tevent_req_data(req,
3570 struct netlogon_creds_cli_SendToSam_state);
3572 if (state->creds == NULL) {
3576 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3577 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3578 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3579 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3580 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3581 TALLOC_FREE(state->creds);
3585 netlogon_creds_cli_delete(state->context, state->creds);
3586 TALLOC_FREE(state->creds);
3589 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3591 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3593 struct tevent_req *req =
3594 tevent_req_callback_data(subreq,
3596 struct netlogon_creds_cli_SendToSam_state *state =
3597 tevent_req_data(req,
3598 struct netlogon_creds_cli_SendToSam_state);
3601 status = netlogon_creds_cli_lock_recv(subreq, state,
3603 TALLOC_FREE(subreq);
3604 if (tevent_req_nterror(req, status)) {
3608 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3609 switch (state->auth_level) {
3610 case DCERPC_AUTH_LEVEL_INTEGRITY:
3611 case DCERPC_AUTH_LEVEL_PRIVACY:
3614 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3618 uint32_t tmp = state->creds->negotiate_flags;
3620 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3622 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3623 * it should be used, which means
3624 * we had a chance to verify no downgrade
3627 * This relies on netlogon_creds_cli_check*
3628 * being called before, as first request after
3631 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3637 * we defer all callbacks in order to cleanup
3638 * the database record.
3640 tevent_req_defer_callback(req, state->ev);
3642 state->tmp_creds = *state->creds;
3643 netlogon_creds_client_authenticator(&state->tmp_creds,
3645 ZERO_STRUCT(state->rep_auth);
3647 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3648 netlogon_creds_aes_encrypt(&state->tmp_creds,
3650 state->opaque.length);
3652 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3654 state->opaque.length);
3657 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3658 state->binding_handle,
3659 state->srv_name_slash,
3660 state->tmp_creds.computer_name,
3664 state->opaque.length);
3665 if (tevent_req_nomem(subreq, req)) {
3666 status = NT_STATUS_NO_MEMORY;
3667 netlogon_creds_cli_SendToSam_cleanup(req, status);
3671 tevent_req_set_callback(subreq,
3672 netlogon_creds_cli_SendToSam_done,
3676 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3678 struct tevent_req *req =
3679 tevent_req_callback_data(subreq,
3681 struct netlogon_creds_cli_SendToSam_state *state =
3682 tevent_req_data(req,
3683 struct netlogon_creds_cli_SendToSam_state);
3688 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3689 TALLOC_FREE(subreq);
3690 if (tevent_req_nterror(req, status)) {
3691 netlogon_creds_cli_SendToSam_cleanup(req, status);
3695 ok = netlogon_creds_client_check(&state->tmp_creds,
3696 &state->rep_auth.cred);
3698 status = NT_STATUS_ACCESS_DENIED;
3699 tevent_req_nterror(req, status);
3700 netlogon_creds_cli_SendToSam_cleanup(req, status);
3704 *state->creds = state->tmp_creds;
3705 status = netlogon_creds_cli_store(state->context,
3707 TALLOC_FREE(state->creds);
3709 if (tevent_req_nterror(req, status)) {
3710 netlogon_creds_cli_SendToSam_cleanup(req, status);
3715 * Creds must be stored before we send back application errors
3716 * e.g. NT_STATUS_NOT_IMPLEMENTED
3718 if (tevent_req_nterror(req, result)) {
3719 netlogon_creds_cli_SendToSam_cleanup(req, result);
3723 tevent_req_done(req);
3726 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3727 struct dcerpc_binding_handle *b,
3728 struct netr_SendToSamBase *message)
3730 TALLOC_CTX *frame = talloc_stackframe();
3731 struct tevent_context *ev;
3732 struct tevent_req *req;
3733 NTSTATUS status = NT_STATUS_OK;
3735 ev = samba_tevent_context_init(frame);
3739 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3743 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3747 /* Ignore the result */