2 Unix SMB/CIFS implementation.
4 module to store/fetch session keys for the schannel client
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "system/filesys.h"
25 #include "lib/util/tevent_ntstatus.h"
26 #include "lib/dbwrap/dbwrap.h"
27 #include "lib/dbwrap/dbwrap_rbt.h"
28 #include "lib/util/util_tdb.h"
29 #include "libcli/security/security.h"
30 #include "../lib/param/param.h"
31 #include "../libcli/auth/schannel.h"
32 #include "../librpc/gen_ndr/ndr_schannel.h"
33 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
34 #include "../librpc/gen_ndr/ndr_netlogon.h"
35 #include "../librpc/gen_ndr/server_id.h"
36 #include "netlogon_creds_cli.h"
37 #include "source3/include/messages.h"
38 #include "source3/include/g_lock.h"
39 #include "libds/common/roles.h"
40 #include "lib/crypto/crypto.h"
41 #include "auth/credentials/credentials.h"
43 struct netlogon_creds_cli_locked_state;
45 struct netlogon_creds_cli_context {
49 uint32_t proposed_flags;
50 uint32_t required_flags;
51 enum netr_SchannelType type;
52 enum dcerpc_AuthLevel auth_level;
57 const char *netbios_domain;
58 const char *dns_domain;
59 uint32_t cached_flags;
68 struct db_context *ctx;
69 struct g_lock_ctx *g_ctx;
70 struct netlogon_creds_cli_locked_state *locked_state;
71 enum netlogon_creds_cli_lck_type lock;
75 struct netlogon_creds_cli_locked_state {
76 struct netlogon_creds_cli_context *context;
78 struct netlogon_creds_CredentialState *creds;
81 static int netlogon_creds_cli_locked_state_destructor(
82 struct netlogon_creds_cli_locked_state *state)
84 struct netlogon_creds_cli_context *context = state->context;
86 if (context == NULL) {
90 if (context->db.locked_state == state) {
91 context->db.locked_state = NULL;
94 if (state->is_glocked) {
95 g_lock_unlock(context->db.g_ctx,
96 string_term_tdb_data(context->db.key_name));
102 static NTSTATUS netlogon_creds_cli_context_common(
103 const char *client_computer,
104 const char *client_account,
105 enum netr_SchannelType type,
106 enum dcerpc_AuthLevel auth_level,
107 uint32_t proposed_flags,
108 uint32_t required_flags,
109 const char *server_computer,
110 const char *server_netbios_domain,
111 const char *server_dns_domain,
113 struct netlogon_creds_cli_context **_context)
115 struct netlogon_creds_cli_context *context = NULL;
116 char *_key_name = NULL;
117 size_t server_netbios_name_len;
122 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
123 if (context == NULL) {
124 return NT_STATUS_NO_MEMORY;
127 context->client.computer = talloc_strdup(context, client_computer);
128 if (context->client.computer == NULL) {
129 TALLOC_FREE(context);
130 return NT_STATUS_NO_MEMORY;
133 context->client.account = talloc_strdup(context, client_account);
134 if (context->client.account == NULL) {
135 TALLOC_FREE(context);
136 return NT_STATUS_NO_MEMORY;
139 context->client.proposed_flags = proposed_flags;
140 context->client.required_flags = required_flags;
141 context->client.type = type;
142 context->client.auth_level = auth_level;
144 context->server.computer = talloc_strdup(context, server_computer);
145 if (context->server.computer == NULL) {
146 TALLOC_FREE(context);
147 return NT_STATUS_NO_MEMORY;
150 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
151 if (context->server.netbios_domain == NULL) {
152 TALLOC_FREE(context);
153 return NT_STATUS_NO_MEMORY;
156 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
157 if (context->server.dns_domain == NULL) {
158 TALLOC_FREE(context);
159 return NT_STATUS_NO_MEMORY;
164 * Force the callers to provide a unique
165 * value for server_computer and use this directly.
167 * For now we have to deal with
168 * "HOSTNAME" vs. "hostname.example.com".
171 p = strchr(server_computer, '.');
173 server_netbios_name_len = p-server_computer;
175 server_netbios_name_len = strlen(server_computer);
178 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
181 (int)server_netbios_name_len,
183 server_netbios_domain);
184 if (_key_name == NULL) {
185 TALLOC_FREE(context);
186 return NT_STATUS_NO_MEMORY;
189 context->db.key_name = talloc_strdup_upper(context, _key_name);
190 TALLOC_FREE(_key_name);
191 if (context->db.key_name == NULL) {
192 TALLOC_FREE(context);
193 return NT_STATUS_NO_MEMORY;
196 context->db.key_data = string_term_tdb_data(context->db.key_name);
202 static struct db_context *netlogon_creds_cli_global_db;
204 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
206 if (netlogon_creds_cli_global_db != NULL) {
207 return NT_STATUS_INVALID_PARAMETER_MIX;
210 netlogon_creds_cli_global_db = talloc_move(NULL, db);
214 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
217 struct db_context *global_db;
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,
306 require_strong_key = false;
309 * allow overwrite per domain
310 * client schannel:<netbios_domain>
312 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
313 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
315 server_netbios_domain,
316 require_sign_or_seal);
319 * allow overwrite per domain
320 * winbind sealed pipes:<netbios_domain>
322 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
323 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
324 "winbind sealed pipes",
325 server_netbios_domain,
326 seal_secure_channel);
329 * allow overwrite per domain
330 * neutralize nt4 emulation:<netbios_domain>
332 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
333 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
334 "neutralize nt4 emulation",
335 server_netbios_domain,
336 neutralize_nt4_emulation);
338 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
339 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
343 if (lpcfg_security(lp_ctx) == SEC_ADS) {
345 * AD domains should be secure
347 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
348 require_sign_or_seal = true;
349 require_strong_key = true;
353 case SEC_CHAN_DOMAIN:
356 case SEC_CHAN_DNS_DOMAIN:
358 * AD domains should be secure
360 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
361 require_sign_or_seal = true;
362 require_strong_key = true;
363 neutralize_nt4_emulation = true;
367 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
368 require_sign_or_seal = true;
369 require_strong_key = true;
373 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
374 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
375 require_sign_or_seal = true;
376 require_strong_key = true;
377 neutralize_nt4_emulation = true;
382 return NT_STATUS_INVALID_PARAMETER;
385 if (neutralize_nt4_emulation) {
386 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
389 if (require_sign_or_seal) {
390 required_flags |= NETLOGON_NEG_ARCFOUR;
391 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
393 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
396 if (reject_md5_servers) {
397 required_flags |= NETLOGON_NEG_ARCFOUR;
398 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
399 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
400 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
403 if (require_strong_key) {
404 required_flags |= NETLOGON_NEG_ARCFOUR;
405 required_flags |= NETLOGON_NEG_STRONG_KEYS;
406 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
409 proposed_flags |= required_flags;
411 if (seal_secure_channel) {
412 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
414 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
417 status = netlogon_creds_cli_context_common(client_computer,
424 server_netbios_domain,
428 if (!NT_STATUS_IS_OK(status)) {
433 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
434 if (context->db.g_ctx == NULL) {
435 TALLOC_FREE(context);
437 return NT_STATUS_NO_MEMORY;
440 status = netlogon_creds_cli_open_global_db(lp_ctx);
441 if (!NT_STATUS_IS_OK(status)) {
442 TALLOC_FREE(context);
444 return NT_STATUS_NO_MEMORY;
447 context->db.ctx = netlogon_creds_cli_global_db;
453 NTSTATUS netlogon_creds_bind_cli_credentials(
454 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
455 struct cli_credentials **pcli_creds)
457 struct cli_credentials *cli_creds;
458 struct netlogon_creds_CredentialState *ncreds;
461 cli_creds = cli_credentials_init(mem_ctx);
462 if (cli_creds == NULL) {
463 return NT_STATUS_NO_MEMORY;
465 cli_credentials_set_secure_channel_type(cli_creds,
466 context->client.type);
467 cli_credentials_set_username(cli_creds, context->client.account,
469 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
471 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
474 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
475 if (!NT_STATUS_IS_OK(status)) {
476 TALLOC_FREE(cli_creds);
479 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
481 *pcli_creds = cli_creds;
485 char *netlogon_creds_cli_debug_string(
486 const struct netlogon_creds_cli_context *context,
489 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
490 context->db.key_name);
493 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
494 struct netlogon_creds_cli_context *context)
496 return context->client.auth_level;
499 struct netlogon_creds_cli_fetch_state {
501 struct netlogon_creds_CredentialState *creds;
502 uint32_t required_flags;
506 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
509 struct netlogon_creds_cli_fetch_state *state =
510 (struct netlogon_creds_cli_fetch_state *)private_data;
511 enum ndr_err_code ndr_err;
515 state->creds = talloc_zero(state->mem_ctx,
516 struct netlogon_creds_CredentialState);
517 if (state->creds == NULL) {
518 state->status = NT_STATUS_NO_MEMORY;
522 blob.data = data.dptr;
523 blob.length = data.dsize;
525 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
526 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
527 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
528 TALLOC_FREE(state->creds);
529 state->status = ndr_map_error2ntstatus(ndr_err);
533 if (DEBUGLEVEL >= 10) {
534 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
537 tmp_flags = state->creds->negotiate_flags;
538 tmp_flags &= state->required_flags;
539 if (tmp_flags != state->required_flags) {
540 TALLOC_FREE(state->creds);
541 state->status = NT_STATUS_DOWNGRADE_DETECTED;
545 state->status = NT_STATUS_OK;
548 static NTSTATUS netlogon_creds_cli_get_internal(
549 struct netlogon_creds_cli_context *context,
550 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
552 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
554 struct netlogon_creds_CredentialState **_creds)
557 struct netlogon_creds_CredentialState *creds;
561 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
562 if (!NT_STATUS_IS_OK(status)) {
567 * mark it as invalid for step operations.
570 creds->seed = (struct netr_Credential) {{0}};
571 creds->client = (struct netr_Credential) {{0}};
572 creds->server = (struct netr_Credential) {{0}};
578 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
579 const struct netlogon_creds_CredentialState *creds1)
581 TALLOC_CTX *frame = talloc_stackframe();
582 struct netlogon_creds_CredentialState *creds2;
586 enum ndr_err_code ndr_err;
589 status = netlogon_creds_cli_get(context, frame, &creds2);
590 if (!NT_STATUS_IS_OK(status)) {
595 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
596 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
597 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
602 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
603 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
604 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
609 cmp = data_blob_cmp(&blob1, &blob2);
616 static NTSTATUS netlogon_creds_cli_store_internal(
617 struct netlogon_creds_cli_context *context,
618 struct netlogon_creds_CredentialState *creds)
621 enum ndr_err_code ndr_err;
625 if (DEBUGLEVEL >= 10) {
626 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
629 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
630 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
631 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
632 status = ndr_map_error2ntstatus(ndr_err);
636 data.dptr = blob.data;
637 data.dsize = blob.length;
639 status = dbwrap_store(context->db.ctx,
640 context->db.key_data,
642 TALLOC_FREE(data.dptr);
643 if (!NT_STATUS_IS_OK(status)) {
650 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
651 struct netlogon_creds_CredentialState *creds)
655 if (context->db.locked_state == NULL) {
657 * this was not the result of netlogon_creds_cli_lock*()
659 return NT_STATUS_INVALID_PAGE_PROTECTION;
662 if (context->db.locked_state->creds != creds) {
664 * this was not the result of netlogon_creds_cli_lock*()
666 return NT_STATUS_INVALID_PAGE_PROTECTION;
669 status = netlogon_creds_cli_store_internal(context, creds);
673 static NTSTATUS netlogon_creds_cli_delete_internal(
674 struct netlogon_creds_cli_context *context)
677 status = dbwrap_delete(context->db.ctx, context->db.key_data);
681 NTSTATUS netlogon_creds_cli_delete_lck(
682 struct netlogon_creds_cli_context *context)
686 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
687 return NT_STATUS_NOT_LOCKED;
690 status = netlogon_creds_cli_delete_internal(context);
694 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
695 struct netlogon_creds_CredentialState *creds)
699 if (context->db.locked_state == NULL) {
701 * this was not the result of netlogon_creds_cli_lock*()
703 return NT_STATUS_INVALID_PAGE_PROTECTION;
706 if (context->db.locked_state->creds != creds) {
708 * this was not the result of netlogon_creds_cli_lock*()
710 return NT_STATUS_INVALID_PAGE_PROTECTION;
713 status = netlogon_creds_cli_delete_internal(context);
717 struct netlogon_creds_cli_lock_state {
718 struct netlogon_creds_cli_locked_state *locked_state;
719 struct netlogon_creds_CredentialState *creds;
722 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
724 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
725 struct tevent_context *ev,
726 struct netlogon_creds_cli_context *context)
728 struct tevent_req *req;
729 struct netlogon_creds_cli_lock_state *state;
730 struct netlogon_creds_cli_locked_state *locked_state;
731 struct tevent_req *subreq;
733 req = tevent_req_create(mem_ctx, &state,
734 struct netlogon_creds_cli_lock_state);
739 if (context->db.locked_state != NULL) {
740 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
741 return tevent_req_post(req, ev);
744 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
745 if (tevent_req_nomem(locked_state, req)) {
746 return tevent_req_post(req, ev);
748 talloc_set_destructor(locked_state,
749 netlogon_creds_cli_locked_state_destructor);
750 locked_state->context = context;
752 context->db.locked_state = locked_state;
753 state->locked_state = locked_state;
755 if (context->db.g_ctx == NULL) {
758 status = netlogon_creds_cli_get_internal(
759 context, state, &state->creds);
760 if (tevent_req_nterror(req, status)) {
761 return tevent_req_post(req, ev);
767 subreq = g_lock_lock_send(state, ev,
769 string_term_tdb_data(context->db.key_name),
771 if (tevent_req_nomem(subreq, req)) {
772 return tevent_req_post(req, ev);
774 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
779 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
781 struct tevent_req *req =
782 tevent_req_callback_data(subreq,
784 struct netlogon_creds_cli_lock_state *state =
786 struct netlogon_creds_cli_lock_state);
789 status = g_lock_lock_recv(subreq);
791 if (tevent_req_nterror(req, status)) {
794 state->locked_state->is_glocked = true;
796 status = netlogon_creds_cli_get_internal(state->locked_state->context,
797 state, &state->creds);
798 if (tevent_req_nterror(req, status)) {
801 tevent_req_done(req);
804 static NTSTATUS netlogon_creds_cli_get_internal(
805 struct netlogon_creds_cli_context *context,
806 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
808 struct netlogon_creds_cli_fetch_state fstate = {
809 .status = NT_STATUS_INTERNAL_ERROR,
810 .required_flags = context->client.required_flags,
814 fstate.mem_ctx = mem_ctx;
815 status = dbwrap_parse_record(context->db.ctx,
816 context->db.key_data,
817 netlogon_creds_cli_fetch_parser,
819 if (!NT_STATUS_IS_OK(status)) {
822 if (!NT_STATUS_IS_OK(fstate.status)) {
823 return fstate.status;
826 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
827 *pcreds = fstate.creds;
832 * It is really important to try SamLogonEx here,
833 * because multiple processes can talk to the same
834 * domain controller, without using the credential
837 * With a normal SamLogon call, we must keep the
838 * credentials chain updated and intact between all
839 * users of the machine account (which would imply
840 * cross-node communication for every NTLM logon).
842 * The credentials chain is not per NETLOGON pipe
843 * connection, but globally on the server/client pair
846 * It's also important to use NetlogonValidationSamInfo4 (6),
847 * because it relies on the rpc transport encryption
848 * and avoids using the global netlogon schannel
849 * session key to en/decrypt secret information
850 * like the user_session_key for network logons.
852 * [MS-APDS] 3.1.5.2 NTLM Network Logon
853 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
854 * NETLOGON_NEG_AUTHENTICATED_RPC set together
855 * are the indication that the server supports
856 * NetlogonValidationSamInfo4 (6). And it must only
857 * be used if "SealSecureChannel" is used.
859 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
860 * check is done in netlogon_creds_cli_LogonSamLogon*().
863 context->server.cached_flags = fstate.creds->negotiate_flags;
864 context->server.try_validation6 = true;
865 context->server.try_logon_ex = true;
866 context->server.try_logon_with = true;
868 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
869 context->server.try_validation6 = false;
870 context->server.try_logon_ex = false;
872 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
873 context->server.try_validation6 = false;
876 *pcreds = fstate.creds;
880 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
882 struct netlogon_creds_CredentialState **creds)
884 struct netlogon_creds_cli_lock_state *state =
886 struct netlogon_creds_cli_lock_state);
889 if (tevent_req_is_nterror(req, &status)) {
890 tevent_req_received(req);
894 talloc_steal(state->creds, state->locked_state);
895 state->locked_state->creds = state->creds;
896 *creds = talloc_move(mem_ctx, &state->creds);
897 tevent_req_received(req);
901 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
903 struct netlogon_creds_CredentialState **creds)
905 TALLOC_CTX *frame = talloc_stackframe();
906 struct tevent_context *ev;
907 struct tevent_req *req;
908 NTSTATUS status = NT_STATUS_NO_MEMORY;
910 ev = samba_tevent_context_init(frame);
914 req = netlogon_creds_cli_lock_send(frame, ev, context);
918 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
921 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
927 struct netlogon_creds_cli_lck {
928 struct netlogon_creds_cli_context *context;
931 struct netlogon_creds_cli_lck_state {
932 struct netlogon_creds_cli_lck *lck;
933 enum netlogon_creds_cli_lck_type type;
936 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
937 static int netlogon_creds_cli_lck_destructor(
938 struct netlogon_creds_cli_lck *lck);
940 struct tevent_req *netlogon_creds_cli_lck_send(
941 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
942 struct netlogon_creds_cli_context *context,
943 enum netlogon_creds_cli_lck_type type)
945 struct tevent_req *req, *subreq;
946 struct netlogon_creds_cli_lck_state *state;
947 enum g_lock_type gtype;
949 req = tevent_req_create(mem_ctx, &state,
950 struct netlogon_creds_cli_lck_state);
955 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
956 DBG_DEBUG("context already locked\n");
957 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
958 return tevent_req_post(req, ev);
962 case NETLOGON_CREDS_CLI_LCK_SHARED:
965 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
966 gtype = G_LOCK_WRITE;
969 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
970 return tevent_req_post(req, ev);
973 state->lck = talloc(state, struct netlogon_creds_cli_lck);
974 if (tevent_req_nomem(state->lck, req)) {
975 return tevent_req_post(req, ev);
977 state->lck->context = context;
980 subreq = g_lock_lock_send(state, ev,
982 string_term_tdb_data(context->db.key_name),
984 if (tevent_req_nomem(subreq, req)) {
985 return tevent_req_post(req, ev);
987 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
992 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
994 struct tevent_req *req = tevent_req_callback_data(
995 subreq, struct tevent_req);
996 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
997 req, struct netlogon_creds_cli_lck_state);
1000 status = g_lock_lock_recv(subreq);
1001 TALLOC_FREE(subreq);
1002 if (tevent_req_nterror(req, status)) {
1006 state->lck->context->db.lock = state->type;
1007 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1009 tevent_req_done(req);
1012 static int netlogon_creds_cli_lck_destructor(
1013 struct netlogon_creds_cli_lck *lck)
1015 struct netlogon_creds_cli_context *ctx = lck->context;
1018 status = g_lock_unlock(ctx->db.g_ctx,
1019 string_term_tdb_data(ctx->db.key_name));
1020 if (!NT_STATUS_IS_OK(status)) {
1021 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1022 smb_panic("g_lock_unlock failed");
1024 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1028 NTSTATUS netlogon_creds_cli_lck_recv(
1029 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1030 struct netlogon_creds_cli_lck **lck)
1032 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1033 req, struct netlogon_creds_cli_lck_state);
1036 if (tevent_req_is_nterror(req, &status)) {
1039 *lck = talloc_move(mem_ctx, &state->lck);
1040 return NT_STATUS_OK;
1043 NTSTATUS netlogon_creds_cli_lck(
1044 struct netlogon_creds_cli_context *context,
1045 enum netlogon_creds_cli_lck_type type,
1046 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1048 TALLOC_CTX *frame = talloc_stackframe();
1049 struct tevent_context *ev;
1050 struct tevent_req *req;
1051 NTSTATUS status = NT_STATUS_NO_MEMORY;
1053 ev = samba_tevent_context_init(frame);
1057 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1061 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1064 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1070 struct netlogon_creds_cli_auth_state {
1071 struct tevent_context *ev;
1072 struct netlogon_creds_cli_context *context;
1073 struct dcerpc_binding_handle *binding_handle;
1074 uint8_t num_nt_hashes;
1075 uint8_t idx_nt_hashes;
1076 const struct samr_Password * const *nt_hashes;
1077 const struct samr_Password *used_nt_hash;
1078 char *srv_name_slash;
1079 uint32_t current_flags;
1080 struct netr_Credential client_challenge;
1081 struct netr_Credential server_challenge;
1082 struct netlogon_creds_CredentialState *creds;
1083 struct netr_Credential client_credential;
1084 struct netr_Credential server_credential;
1091 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1093 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1094 struct tevent_context *ev,
1095 struct netlogon_creds_cli_context *context,
1096 struct dcerpc_binding_handle *b,
1097 uint8_t num_nt_hashes,
1098 const struct samr_Password * const *nt_hashes)
1100 struct tevent_req *req;
1101 struct netlogon_creds_cli_auth_state *state;
1104 req = tevent_req_create(mem_ctx, &state,
1105 struct netlogon_creds_cli_auth_state);
1111 state->context = context;
1112 state->binding_handle = b;
1113 if (num_nt_hashes < 1) {
1114 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1115 return tevent_req_post(req, ev);
1117 if (num_nt_hashes > 4) {
1118 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1119 return tevent_req_post(req, ev);
1122 state->num_nt_hashes = num_nt_hashes;
1123 state->idx_nt_hashes = 0;
1124 state->nt_hashes = nt_hashes;
1126 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1127 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1128 return tevent_req_post(req, ev);
1131 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1132 context->server.computer);
1133 if (tevent_req_nomem(state->srv_name_slash, req)) {
1134 return tevent_req_post(req, ev);
1137 state->try_auth3 = true;
1138 state->try_auth2 = true;
1140 if (context->client.required_flags != 0) {
1141 state->require_auth2 = true;
1144 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1145 state->current_flags = context->client.proposed_flags;
1147 status = dbwrap_purge(state->context->db.ctx,
1148 state->context->db.key_data);
1149 if (tevent_req_nterror(req, status)) {
1150 return tevent_req_post(req, ev);
1153 netlogon_creds_cli_auth_challenge_start(req);
1154 if (!tevent_req_is_in_progress(req)) {
1155 return tevent_req_post(req, ev);
1161 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1163 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1165 struct netlogon_creds_cli_auth_state *state =
1166 tevent_req_data(req,
1167 struct netlogon_creds_cli_auth_state);
1168 struct tevent_req *subreq;
1170 TALLOC_FREE(state->creds);
1172 generate_random_buffer(state->client_challenge.data,
1173 sizeof(state->client_challenge.data));
1175 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1176 state->binding_handle,
1177 state->srv_name_slash,
1178 state->context->client.computer,
1179 &state->client_challenge,
1180 &state->server_challenge);
1181 if (tevent_req_nomem(subreq, req)) {
1184 tevent_req_set_callback(subreq,
1185 netlogon_creds_cli_auth_challenge_done,
1189 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1191 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1193 struct tevent_req *req =
1194 tevent_req_callback_data(subreq,
1196 struct netlogon_creds_cli_auth_state *state =
1197 tevent_req_data(req,
1198 struct netlogon_creds_cli_auth_state);
1202 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1203 TALLOC_FREE(subreq);
1204 if (tevent_req_nterror(req, status)) {
1207 if (tevent_req_nterror(req, result)) {
1211 if (!state->try_auth3 && !state->try_auth2) {
1212 state->current_flags = 0;
1215 /* Calculate the session key and client credentials */
1217 state->creds = netlogon_creds_client_init(state,
1218 state->context->client.account,
1219 state->context->client.computer,
1220 state->context->client.type,
1221 &state->client_challenge,
1222 &state->server_challenge,
1223 state->used_nt_hash,
1224 &state->client_credential,
1225 state->current_flags);
1226 if (tevent_req_nomem(state->creds, req)) {
1230 if (state->try_auth3) {
1231 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1232 state->binding_handle,
1233 state->srv_name_slash,
1234 state->context->client.account,
1235 state->context->client.type,
1236 state->context->client.computer,
1237 &state->client_credential,
1238 &state->server_credential,
1239 &state->creds->negotiate_flags,
1241 if (tevent_req_nomem(subreq, req)) {
1244 } else if (state->try_auth2) {
1247 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1248 state->binding_handle,
1249 state->srv_name_slash,
1250 state->context->client.account,
1251 state->context->client.type,
1252 state->context->client.computer,
1253 &state->client_credential,
1254 &state->server_credential,
1255 &state->creds->negotiate_flags);
1256 if (tevent_req_nomem(subreq, req)) {
1262 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1263 state->binding_handle,
1264 state->srv_name_slash,
1265 state->context->client.account,
1266 state->context->client.type,
1267 state->context->client.computer,
1268 &state->client_credential,
1269 &state->server_credential);
1270 if (tevent_req_nomem(subreq, req)) {
1274 tevent_req_set_callback(subreq,
1275 netlogon_creds_cli_auth_srvauth_done,
1279 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1281 struct tevent_req *req =
1282 tevent_req_callback_data(subreq,
1284 struct netlogon_creds_cli_auth_state *state =
1285 tevent_req_data(req,
1286 struct netlogon_creds_cli_auth_state);
1290 enum ndr_err_code ndr_err;
1295 if (state->try_auth3) {
1296 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1298 TALLOC_FREE(subreq);
1299 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1300 state->try_auth3 = false;
1301 netlogon_creds_cli_auth_challenge_start(req);
1304 if (tevent_req_nterror(req, status)) {
1307 } else if (state->try_auth2) {
1308 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1310 TALLOC_FREE(subreq);
1311 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1312 state->try_auth2 = false;
1313 if (state->require_auth2) {
1314 status = NT_STATUS_DOWNGRADE_DETECTED;
1315 tevent_req_nterror(req, status);
1318 netlogon_creds_cli_auth_challenge_start(req);
1321 if (tevent_req_nterror(req, status)) {
1325 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1327 TALLOC_FREE(subreq);
1328 if (tevent_req_nterror(req, status)) {
1333 if (!NT_STATUS_IS_OK(result) &&
1334 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1336 tevent_req_nterror(req, result);
1340 tmp_flags = state->creds->negotiate_flags;
1341 tmp_flags &= state->context->client.required_flags;
1342 if (tmp_flags != state->context->client.required_flags) {
1343 if (NT_STATUS_IS_OK(result)) {
1344 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1347 tevent_req_nterror(req, result);
1351 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1353 tmp_flags = state->context->client.proposed_flags;
1354 if ((state->current_flags == tmp_flags) &&
1355 (state->creds->negotiate_flags != tmp_flags))
1358 * lets retry with the negotiated flags
1360 state->current_flags = state->creds->negotiate_flags;
1361 netlogon_creds_cli_auth_challenge_start(req);
1365 state->idx_nt_hashes += 1;
1366 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1368 * we already retried, giving up...
1370 tevent_req_nterror(req, result);
1375 * lets retry with the old nt hash.
1377 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1378 state->current_flags = state->context->client.proposed_flags;
1379 netlogon_creds_cli_auth_challenge_start(req);
1383 ok = netlogon_creds_client_check(state->creds,
1384 &state->server_credential);
1386 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1390 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1391 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1392 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1393 status = ndr_map_error2ntstatus(ndr_err);
1394 tevent_req_nterror(req, status);
1398 data.dptr = blob.data;
1399 data.dsize = blob.length;
1401 status = dbwrap_store(state->context->db.ctx,
1402 state->context->db.key_data,
1404 if (tevent_req_nterror(req, status)) {
1408 tevent_req_done(req);
1411 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1412 uint8_t *idx_nt_hashes)
1414 struct netlogon_creds_cli_auth_state *state =
1415 tevent_req_data(req,
1416 struct netlogon_creds_cli_auth_state);
1421 if (tevent_req_is_nterror(req, &status)) {
1422 tevent_req_received(req);
1426 *idx_nt_hashes = state->idx_nt_hashes;
1427 tevent_req_received(req);
1428 return NT_STATUS_OK;
1431 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1432 struct dcerpc_binding_handle *b,
1433 uint8_t num_nt_hashes,
1434 const struct samr_Password * const *nt_hashes,
1435 uint8_t *idx_nt_hashes)
1437 TALLOC_CTX *frame = talloc_stackframe();
1438 struct tevent_context *ev;
1439 struct tevent_req *req;
1440 NTSTATUS status = NT_STATUS_NO_MEMORY;
1444 ev = samba_tevent_context_init(frame);
1448 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1449 num_nt_hashes, nt_hashes);
1453 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1456 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1462 struct netlogon_creds_cli_check_state {
1463 struct tevent_context *ev;
1464 struct netlogon_creds_cli_context *context;
1465 struct dcerpc_binding_handle *binding_handle;
1467 char *srv_name_slash;
1469 union netr_Capabilities caps;
1471 struct netlogon_creds_CredentialState *creds;
1472 struct netr_Authenticator req_auth;
1473 struct netr_Authenticator rep_auth;
1476 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1478 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1480 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1481 struct tevent_context *ev,
1482 struct netlogon_creds_cli_context *context,
1483 struct dcerpc_binding_handle *b)
1485 struct tevent_req *req;
1486 struct netlogon_creds_cli_check_state *state;
1487 struct tevent_req *subreq;
1488 enum dcerpc_AuthType auth_type;
1489 enum dcerpc_AuthLevel auth_level;
1492 req = tevent_req_create(mem_ctx, &state,
1493 struct netlogon_creds_cli_check_state);
1499 state->context = context;
1500 state->binding_handle = b;
1502 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1503 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1504 return tevent_req_post(req, ev);
1507 status = netlogon_creds_cli_get_internal(context, state,
1509 if (tevent_req_nterror(req, status)) {
1510 return tevent_req_post(req, ev);
1513 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1514 context->server.computer);
1515 if (tevent_req_nomem(state->srv_name_slash, req)) {
1516 return tevent_req_post(req, ev);
1519 dcerpc_binding_handle_auth_info(state->binding_handle,
1520 &auth_type, &auth_level);
1522 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1523 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1524 return tevent_req_post(req, ev);
1527 switch (auth_level) {
1528 case DCERPC_AUTH_LEVEL_INTEGRITY:
1529 case DCERPC_AUTH_LEVEL_PRIVACY:
1532 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1533 return tevent_req_post(req, ev);
1537 * we defer all callbacks in order to cleanup
1538 * the database record.
1540 tevent_req_defer_callback(req, state->ev);
1542 netlogon_creds_client_authenticator(state->creds, &state->req_auth);
1543 ZERO_STRUCT(state->rep_auth);
1545 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1546 state->binding_handle,
1547 state->srv_name_slash,
1548 state->context->client.computer,
1553 if (tevent_req_nomem(subreq, req)) {
1554 return tevent_req_post(req, ev);
1557 tevent_req_set_callback(subreq,
1558 netlogon_creds_cli_check_caps,
1564 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1567 struct netlogon_creds_cli_check_state *state =
1568 tevent_req_data(req,
1569 struct netlogon_creds_cli_check_state);
1571 if (state->creds == NULL) {
1575 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1576 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1577 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1578 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1579 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1580 TALLOC_FREE(state->creds);
1584 netlogon_creds_cli_delete_lck(state->context);
1585 TALLOC_FREE(state->creds);
1588 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1590 struct tevent_req *req =
1591 tevent_req_callback_data(subreq,
1593 struct netlogon_creds_cli_check_state *state =
1594 tevent_req_data(req,
1595 struct netlogon_creds_cli_check_state);
1600 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1602 TALLOC_FREE(subreq);
1603 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1605 * Note that the negotiated flags are already checked
1606 * for our required flags after the ServerAuthenticate3/2 call.
1608 uint32_t negotiated = state->creds->negotiate_flags;
1610 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1612 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1613 * already, we expect this to work!
1615 status = NT_STATUS_DOWNGRADE_DETECTED;
1616 tevent_req_nterror(req, status);
1617 netlogon_creds_cli_check_cleanup(req, status);
1621 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1623 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1624 * we expect this to work at least as far as the
1625 * NOT_SUPPORTED error handled below!
1627 * NT 4.0 and Old Samba servers are not
1628 * allowed without "require strong key = no"
1630 status = NT_STATUS_DOWNGRADE_DETECTED;
1631 tevent_req_nterror(req, status);
1632 netlogon_creds_cli_check_cleanup(req, status);
1637 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1638 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1639 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1641 * This is needed against NT 4.0 and old Samba servers.
1643 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1644 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1645 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1646 * with the next request as the sequence number processing
1649 netlogon_creds_cli_check_cleanup(req, status);
1650 tevent_req_done(req);
1653 if (tevent_req_nterror(req, status)) {
1654 netlogon_creds_cli_check_cleanup(req, status);
1658 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1660 * Note that the negotiated flags are already checked
1661 * for our required flags after the ServerAuthenticate3/2 call.
1663 uint32_t negotiated = state->creds->negotiate_flags;
1665 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1667 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1668 * already, we expect this to work!
1670 status = NT_STATUS_DOWNGRADE_DETECTED;
1671 tevent_req_nterror(req, status);
1672 netlogon_creds_cli_check_cleanup(req, status);
1677 * This is ok, the server does not support
1678 * NETLOGON_NEG_SUPPORTS_AES.
1680 * netr_LogonGetCapabilities() was
1681 * netr_LogonDummyRoutine1() before
1682 * NETLOGON_NEG_SUPPORTS_AES was invented.
1684 netlogon_creds_cli_check_cleanup(req, result);
1685 tevent_req_done(req);
1689 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1691 status = NT_STATUS_ACCESS_DENIED;
1692 tevent_req_nterror(req, status);
1693 netlogon_creds_cli_check_cleanup(req, status);
1697 if (tevent_req_nterror(req, result)) {
1698 netlogon_creds_cli_check_cleanup(req, result);
1702 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1703 status = NT_STATUS_DOWNGRADE_DETECTED;
1704 tevent_req_nterror(req, status);
1705 netlogon_creds_cli_check_cleanup(req, status);
1710 * This is the key check that makes this check secure. If we
1711 * get OK here (rather than NOT_SUPPORTED), then the server
1712 * did support AES. If the server only proposed STRONG_KEYS
1713 * and not AES, then it should have failed with
1714 * NOT_IMPLEMENTED. We always send AES as a client, so the
1715 * server should always have returned it.
1717 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1718 status = NT_STATUS_DOWNGRADE_DETECTED;
1719 tevent_req_nterror(req, status);
1720 netlogon_creds_cli_check_cleanup(req, status);
1724 status = netlogon_creds_cli_store_internal(state->context,
1726 if (tevent_req_nterror(req, status)) {
1730 tevent_req_done(req);
1733 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1734 union netr_Capabilities *capabilities)
1736 struct netlogon_creds_cli_check_state *state = tevent_req_data(
1737 req, struct netlogon_creds_cli_check_state);
1740 if (tevent_req_is_nterror(req, &status)) {
1741 netlogon_creds_cli_check_cleanup(req, status);
1742 tevent_req_received(req);
1746 if (capabilities != NULL) {
1747 *capabilities = state->caps;
1750 tevent_req_received(req);
1751 return NT_STATUS_OK;
1754 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1755 struct dcerpc_binding_handle *b,
1756 union netr_Capabilities *capabilities)
1758 TALLOC_CTX *frame = talloc_stackframe();
1759 struct tevent_context *ev;
1760 struct tevent_req *req;
1761 NTSTATUS status = NT_STATUS_NO_MEMORY;
1763 ev = samba_tevent_context_init(frame);
1767 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1771 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1774 status = netlogon_creds_cli_check_recv(req, capabilities);
1780 struct netlogon_creds_cli_ServerPasswordSet_state {
1781 struct tevent_context *ev;
1782 struct netlogon_creds_cli_context *context;
1783 struct dcerpc_binding_handle *binding_handle;
1784 uint32_t old_timeout;
1786 char *srv_name_slash;
1787 enum dcerpc_AuthType auth_type;
1788 enum dcerpc_AuthLevel auth_level;
1790 struct samr_CryptPassword samr_crypt_password;
1791 struct netr_CryptPassword netr_crypt_password;
1792 struct samr_Password samr_password;
1794 struct netlogon_creds_CredentialState *creds;
1795 struct netlogon_creds_CredentialState tmp_creds;
1796 struct netr_Authenticator req_auth;
1797 struct netr_Authenticator rep_auth;
1800 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1802 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1804 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1805 struct tevent_context *ev,
1806 struct netlogon_creds_cli_context *context,
1807 struct dcerpc_binding_handle *b,
1808 const DATA_BLOB *new_password,
1809 const uint32_t *new_version)
1811 struct tevent_req *req;
1812 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1813 struct tevent_req *subreq;
1816 req = tevent_req_create(mem_ctx, &state,
1817 struct netlogon_creds_cli_ServerPasswordSet_state);
1823 state->context = context;
1824 state->binding_handle = b;
1826 if (new_password->length < 14) {
1827 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1828 return tevent_req_post(req, ev);
1832 * netr_ServerPasswordSet
1834 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1837 * netr_ServerPasswordSet2
1839 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1842 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1843 return tevent_req_post(req, ev);
1846 if (new_version != NULL) {
1847 struct NL_PASSWORD_VERSION version;
1848 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1849 uint32_t ofs = 512 - len;
1853 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1854 return tevent_req_post(req, ev);
1858 version.ReservedField = 0;
1859 version.PasswordVersionNumber = *new_version;
1860 version.PasswordVersionPresent =
1861 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1863 p = state->samr_crypt_password.data + ofs;
1864 SIVAL(p, 0, version.ReservedField);
1865 SIVAL(p, 4, version.PasswordVersionNumber);
1866 SIVAL(p, 8, version.PasswordVersionPresent);
1869 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1870 context->server.computer);
1871 if (tevent_req_nomem(state->srv_name_slash, req)) {
1872 return tevent_req_post(req, ev);
1875 dcerpc_binding_handle_auth_info(state->binding_handle,
1877 &state->auth_level);
1879 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1881 if (tevent_req_nomem(subreq, req)) {
1882 return tevent_req_post(req, ev);
1885 tevent_req_set_callback(subreq,
1886 netlogon_creds_cli_ServerPasswordSet_locked,
1892 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1895 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1896 tevent_req_data(req,
1897 struct netlogon_creds_cli_ServerPasswordSet_state);
1899 if (state->creds == NULL) {
1903 dcerpc_binding_handle_set_timeout(state->binding_handle,
1904 state->old_timeout);
1906 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1907 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1908 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1909 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1910 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1911 TALLOC_FREE(state->creds);
1915 netlogon_creds_cli_delete(state->context, state->creds);
1916 TALLOC_FREE(state->creds);
1919 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1921 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1923 struct tevent_req *req =
1924 tevent_req_callback_data(subreq,
1926 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1927 tevent_req_data(req,
1928 struct netlogon_creds_cli_ServerPasswordSet_state);
1931 status = netlogon_creds_cli_lock_recv(subreq, state,
1933 TALLOC_FREE(subreq);
1934 if (tevent_req_nterror(req, status)) {
1938 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1939 switch (state->auth_level) {
1940 case DCERPC_AUTH_LEVEL_INTEGRITY:
1941 case DCERPC_AUTH_LEVEL_PRIVACY:
1944 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1948 uint32_t tmp = state->creds->negotiate_flags;
1950 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1952 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1953 * it should be used, which means
1954 * we had a chance to verify no downgrade
1957 * This relies on netlogon_creds_cli_check*
1958 * being called before, as first request after
1961 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1966 state->old_timeout = dcerpc_binding_handle_set_timeout(
1967 state->binding_handle, 600000);
1970 * we defer all callbacks in order to cleanup
1971 * the database record.
1973 tevent_req_defer_callback(req, state->ev);
1975 state->tmp_creds = *state->creds;
1976 netlogon_creds_client_authenticator(&state->tmp_creds,
1978 ZERO_STRUCT(state->rep_auth);
1980 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1982 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1983 netlogon_creds_aes_encrypt(&state->tmp_creds,
1984 state->samr_crypt_password.data,
1987 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1988 state->samr_crypt_password.data,
1992 memcpy(state->netr_crypt_password.data,
1993 state->samr_crypt_password.data, 512);
1994 state->netr_crypt_password.length =
1995 IVAL(state->samr_crypt_password.data, 512);
1997 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1998 state->binding_handle,
1999 state->srv_name_slash,
2000 state->tmp_creds.account_name,
2001 state->tmp_creds.secure_channel_type,
2002 state->tmp_creds.computer_name,
2005 &state->netr_crypt_password);
2006 if (tevent_req_nomem(subreq, req)) {
2007 status = NT_STATUS_NO_MEMORY;
2008 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2012 netlogon_creds_des_encrypt(&state->tmp_creds,
2013 &state->samr_password);
2015 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2016 state->binding_handle,
2017 state->srv_name_slash,
2018 state->tmp_creds.account_name,
2019 state->tmp_creds.secure_channel_type,
2020 state->tmp_creds.computer_name,
2023 &state->samr_password);
2024 if (tevent_req_nomem(subreq, req)) {
2025 status = NT_STATUS_NO_MEMORY;
2026 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2031 tevent_req_set_callback(subreq,
2032 netlogon_creds_cli_ServerPasswordSet_done,
2036 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2038 struct tevent_req *req =
2039 tevent_req_callback_data(subreq,
2041 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2042 tevent_req_data(req,
2043 struct netlogon_creds_cli_ServerPasswordSet_state);
2048 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2049 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2051 TALLOC_FREE(subreq);
2052 if (tevent_req_nterror(req, status)) {
2053 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2057 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2059 TALLOC_FREE(subreq);
2060 if (tevent_req_nterror(req, status)) {
2061 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2066 ok = netlogon_creds_client_check(&state->tmp_creds,
2067 &state->rep_auth.cred);
2069 status = NT_STATUS_ACCESS_DENIED;
2070 tevent_req_nterror(req, status);
2071 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2075 if (tevent_req_nterror(req, result)) {
2076 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2080 dcerpc_binding_handle_set_timeout(state->binding_handle,
2081 state->old_timeout);
2083 *state->creds = state->tmp_creds;
2084 status = netlogon_creds_cli_store(state->context,
2086 TALLOC_FREE(state->creds);
2087 if (tevent_req_nterror(req, status)) {
2088 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2092 tevent_req_done(req);
2095 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2099 if (tevent_req_is_nterror(req, &status)) {
2100 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2101 tevent_req_received(req);
2105 tevent_req_received(req);
2106 return NT_STATUS_OK;
2109 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2110 struct netlogon_creds_cli_context *context,
2111 struct dcerpc_binding_handle *b,
2112 const DATA_BLOB *new_password,
2113 const uint32_t *new_version)
2115 TALLOC_CTX *frame = talloc_stackframe();
2116 struct tevent_context *ev;
2117 struct tevent_req *req;
2118 NTSTATUS status = NT_STATUS_NO_MEMORY;
2120 ev = samba_tevent_context_init(frame);
2124 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2130 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2133 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2139 struct netlogon_creds_cli_LogonSamLogon_state {
2140 struct tevent_context *ev;
2141 struct netlogon_creds_cli_context *context;
2142 struct dcerpc_binding_handle *binding_handle;
2144 char *srv_name_slash;
2146 enum netr_LogonInfoClass logon_level;
2147 const union netr_LogonLevel *const_logon;
2148 union netr_LogonLevel *logon;
2151 uint16_t validation_level;
2152 union netr_Validation *validation;
2153 uint8_t authoritative;
2156 * do we need encryption at the application layer?
2160 bool try_validation6;
2163 * the read only credentials before we started the operation
2164 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2166 struct netlogon_creds_CredentialState *ro_creds;
2169 * The (locked) credentials used for the credential chain
2170 * used for netr_LogonSamLogonWithFlags() or
2171 * netr_LogonSamLogonWith().
2173 struct netlogon_creds_CredentialState *lk_creds;
2176 * While we have locked the global credentials (lk_creds above)
2177 * we operate an a temporary copy, because a server
2178 * may not support netr_LogonSamLogonWithFlags() and
2179 * didn't process our netr_Authenticator, so we need to
2180 * restart from lk_creds.
2182 struct netlogon_creds_CredentialState tmp_creds;
2183 struct netr_Authenticator req_auth;
2184 struct netr_Authenticator rep_auth;
2187 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2188 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2191 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2192 struct tevent_context *ev,
2193 struct netlogon_creds_cli_context *context,
2194 struct dcerpc_binding_handle *b,
2195 enum netr_LogonInfoClass logon_level,
2196 const union netr_LogonLevel *logon,
2199 struct tevent_req *req;
2200 struct netlogon_creds_cli_LogonSamLogon_state *state;
2202 req = tevent_req_create(mem_ctx, &state,
2203 struct netlogon_creds_cli_LogonSamLogon_state);
2209 state->context = context;
2210 state->binding_handle = b;
2212 state->logon_level = logon_level;
2213 state->const_logon = logon;
2214 state->flags = flags;
2216 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2217 context->server.computer);
2218 if (tevent_req_nomem(state->srv_name_slash, req)) {
2219 return tevent_req_post(req, ev);
2222 switch (logon_level) {
2223 case NetlogonInteractiveInformation:
2224 case NetlogonInteractiveTransitiveInformation:
2225 case NetlogonServiceInformation:
2226 case NetlogonServiceTransitiveInformation:
2227 case NetlogonGenericInformation:
2228 state->user_encrypt = true;
2231 case NetlogonNetworkInformation:
2232 case NetlogonNetworkTransitiveInformation:
2236 state->validation = talloc_zero(state, union netr_Validation);
2237 if (tevent_req_nomem(state->validation, req)) {
2238 return tevent_req_post(req, ev);
2241 netlogon_creds_cli_LogonSamLogon_start(req);
2242 if (!tevent_req_is_in_progress(req)) {
2243 return tevent_req_post(req, ev);
2247 * we defer all callbacks in order to cleanup
2248 * the database record.
2250 tevent_req_defer_callback(req, state->ev);
2254 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2257 struct netlogon_creds_cli_LogonSamLogon_state *state =
2258 tevent_req_data(req,
2259 struct netlogon_creds_cli_LogonSamLogon_state);
2261 if (state->lk_creds == NULL) {
2265 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2267 * This is a hack to recover from a bug in old
2268 * Samba servers, when LogonSamLogonEx() fails:
2270 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2272 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2274 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2275 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2276 * If the sign/seal check fails.
2278 * In that case we need to cleanup the netlogon session.
2280 * It's the job of the caller to disconnect the current
2281 * connection, if netlogon_creds_cli_LogonSamLogon()
2282 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2284 if (!state->context->server.try_logon_with) {
2285 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2289 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2290 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2291 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2292 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2293 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2294 TALLOC_FREE(state->lk_creds);
2298 netlogon_creds_cli_delete(state->context, state->lk_creds);
2299 TALLOC_FREE(state->lk_creds);
2302 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2304 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2306 struct netlogon_creds_cli_LogonSamLogon_state *state =
2307 tevent_req_data(req,
2308 struct netlogon_creds_cli_LogonSamLogon_state);
2309 struct tevent_req *subreq;
2311 enum dcerpc_AuthType auth_type;
2312 enum dcerpc_AuthLevel auth_level;
2314 TALLOC_FREE(state->ro_creds);
2315 TALLOC_FREE(state->logon);
2316 ZERO_STRUCTP(state->validation);
2318 dcerpc_binding_handle_auth_info(state->binding_handle,
2319 &auth_type, &auth_level);
2321 state->try_logon_ex = state->context->server.try_logon_ex;
2322 state->try_validation6 = state->context->server.try_validation6;
2324 state->try_logon_ex = false;
2326 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2327 state->try_logon_ex = false;
2330 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2331 state->try_validation6 = false;
2334 if (state->try_logon_ex) {
2335 if (state->try_validation6) {
2336 state->validation_level = 6;
2338 state->validation_level = 3;
2339 state->user_encrypt = true;
2342 state->logon = netlogon_creds_shallow_copy_logon(state,
2344 state->const_logon);
2345 if (tevent_req_nomem(state->logon, req)) {
2346 status = NT_STATUS_NO_MEMORY;
2347 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2351 if (state->user_encrypt) {
2352 status = netlogon_creds_cli_get(state->context,
2355 if (!NT_STATUS_IS_OK(status)) {
2356 status = NT_STATUS_ACCESS_DENIED;
2357 tevent_req_nterror(req, status);
2358 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2362 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2367 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2368 state->binding_handle,
2369 state->srv_name_slash,
2370 state->context->client.computer,
2373 state->validation_level,
2375 &state->authoritative,
2377 if (tevent_req_nomem(subreq, req)) {
2378 status = NT_STATUS_NO_MEMORY;
2379 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2382 tevent_req_set_callback(subreq,
2383 netlogon_creds_cli_LogonSamLogon_done,
2388 if (state->lk_creds == NULL) {
2389 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2391 if (tevent_req_nomem(subreq, req)) {
2392 status = NT_STATUS_NO_MEMORY;
2393 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2396 tevent_req_set_callback(subreq,
2397 netlogon_creds_cli_LogonSamLogon_done,
2402 state->tmp_creds = *state->lk_creds;
2403 netlogon_creds_client_authenticator(&state->tmp_creds,
2405 ZERO_STRUCT(state->rep_auth);
2407 state->logon = netlogon_creds_shallow_copy_logon(state,
2409 state->const_logon);
2410 if (tevent_req_nomem(state->logon, req)) {
2411 status = NT_STATUS_NO_MEMORY;
2412 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2416 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2420 state->validation_level = 3;
2422 if (state->context->server.try_logon_with) {
2423 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2424 state->binding_handle,
2425 state->srv_name_slash,
2426 state->context->client.computer,
2431 state->validation_level,
2433 &state->authoritative,
2435 if (tevent_req_nomem(subreq, req)) {
2436 status = NT_STATUS_NO_MEMORY;
2437 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2443 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2444 state->binding_handle,
2445 state->srv_name_slash,
2446 state->context->client.computer,
2451 state->validation_level,
2453 &state->authoritative);
2454 if (tevent_req_nomem(subreq, req)) {
2455 status = NT_STATUS_NO_MEMORY;
2456 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2461 tevent_req_set_callback(subreq,
2462 netlogon_creds_cli_LogonSamLogon_done,
2466 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2468 struct tevent_req *req =
2469 tevent_req_callback_data(subreq,
2471 struct netlogon_creds_cli_LogonSamLogon_state *state =
2472 tevent_req_data(req,
2473 struct netlogon_creds_cli_LogonSamLogon_state);
2478 if (state->try_logon_ex) {
2479 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2482 TALLOC_FREE(subreq);
2483 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2484 state->context->server.try_validation6 = false;
2485 state->context->server.try_logon_ex = false;
2486 netlogon_creds_cli_LogonSamLogon_start(req);
2489 if (tevent_req_nterror(req, status)) {
2490 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2494 if ((state->validation_level == 6) &&
2495 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2496 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2497 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2499 state->context->server.try_validation6 = false;
2500 netlogon_creds_cli_LogonSamLogon_start(req);
2504 if (tevent_req_nterror(req, result)) {
2505 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2509 if (state->ro_creds == NULL) {
2510 tevent_req_done(req);
2514 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2517 * We got a race, lets retry with on authenticator
2520 * netlogon_creds_cli_LogonSamLogon_start()
2521 * will TALLOC_FREE(state->ro_creds);
2523 state->try_logon_ex = false;
2524 netlogon_creds_cli_LogonSamLogon_start(req);
2528 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2529 state->validation_level,
2532 tevent_req_done(req);
2536 if (state->lk_creds == NULL) {
2537 status = netlogon_creds_cli_lock_recv(subreq, state,
2539 TALLOC_FREE(subreq);
2540 if (tevent_req_nterror(req, status)) {
2541 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2545 netlogon_creds_cli_LogonSamLogon_start(req);
2549 if (state->context->server.try_logon_with) {
2550 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2553 TALLOC_FREE(subreq);
2554 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2555 state->context->server.try_logon_with = false;
2556 netlogon_creds_cli_LogonSamLogon_start(req);
2559 if (tevent_req_nterror(req, status)) {
2560 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2564 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2567 TALLOC_FREE(subreq);
2568 if (tevent_req_nterror(req, status)) {
2569 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2574 ok = netlogon_creds_client_check(&state->tmp_creds,
2575 &state->rep_auth.cred);
2577 status = NT_STATUS_ACCESS_DENIED;
2578 tevent_req_nterror(req, status);
2579 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2583 *state->lk_creds = state->tmp_creds;
2584 status = netlogon_creds_cli_store(state->context,
2586 TALLOC_FREE(state->lk_creds);
2588 if (tevent_req_nterror(req, status)) {
2589 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2593 if (tevent_req_nterror(req, result)) {
2594 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2598 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2599 state->validation_level,
2602 tevent_req_done(req);
2605 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2606 TALLOC_CTX *mem_ctx,
2607 uint16_t *validation_level,
2608 union netr_Validation **validation,
2609 uint8_t *authoritative,
2612 struct netlogon_creds_cli_LogonSamLogon_state *state =
2613 tevent_req_data(req,
2614 struct netlogon_creds_cli_LogonSamLogon_state);
2617 /* authoritative is also returned on error */
2618 *authoritative = state->authoritative;
2620 if (tevent_req_is_nterror(req, &status)) {
2621 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2622 tevent_req_received(req);
2626 *validation_level = state->validation_level;
2627 *validation = talloc_move(mem_ctx, &state->validation);
2628 *flags = state->flags;
2630 tevent_req_received(req);
2631 return NT_STATUS_OK;
2634 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2635 struct netlogon_creds_cli_context *context,
2636 struct dcerpc_binding_handle *b,
2637 enum netr_LogonInfoClass logon_level,
2638 const union netr_LogonLevel *logon,
2639 TALLOC_CTX *mem_ctx,
2640 uint16_t *validation_level,
2641 union netr_Validation **validation,
2642 uint8_t *authoritative,
2645 TALLOC_CTX *frame = talloc_stackframe();
2646 struct tevent_context *ev;
2647 struct tevent_req *req;
2648 NTSTATUS status = NT_STATUS_NO_MEMORY;
2650 ev = samba_tevent_context_init(frame);
2654 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2660 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2663 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2673 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2674 struct tevent_context *ev;
2675 struct netlogon_creds_cli_context *context;
2676 struct dcerpc_binding_handle *binding_handle;
2678 char *srv_name_slash;
2679 enum dcerpc_AuthType auth_type;
2680 enum dcerpc_AuthLevel auth_level;
2682 const char *site_name;
2684 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2686 struct netlogon_creds_CredentialState *creds;
2687 struct netlogon_creds_CredentialState tmp_creds;
2688 struct netr_Authenticator req_auth;
2689 struct netr_Authenticator rep_auth;
2692 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2694 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2696 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2697 struct tevent_context *ev,
2698 struct netlogon_creds_cli_context *context,
2699 struct dcerpc_binding_handle *b,
2700 const char *site_name,
2702 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2704 struct tevent_req *req;
2705 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2706 struct tevent_req *subreq;
2708 req = tevent_req_create(mem_ctx, &state,
2709 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2715 state->context = context;
2716 state->binding_handle = b;
2718 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2719 context->server.computer);
2720 if (tevent_req_nomem(state->srv_name_slash, req)) {
2721 return tevent_req_post(req, ev);
2724 state->site_name = site_name;
2725 state->dns_ttl = dns_ttl;
2726 state->dns_names = dns_names;
2728 dcerpc_binding_handle_auth_info(state->binding_handle,
2730 &state->auth_level);
2732 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2734 if (tevent_req_nomem(subreq, req)) {
2735 return tevent_req_post(req, ev);
2738 tevent_req_set_callback(subreq,
2739 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2745 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2748 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2749 tevent_req_data(req,
2750 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2752 if (state->creds == NULL) {
2756 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2757 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2758 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2759 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2760 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2761 TALLOC_FREE(state->creds);
2765 netlogon_creds_cli_delete(state->context, state->creds);
2766 TALLOC_FREE(state->creds);
2769 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2771 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2773 struct tevent_req *req =
2774 tevent_req_callback_data(subreq,
2776 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2777 tevent_req_data(req,
2778 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2781 status = netlogon_creds_cli_lock_recv(subreq, state,
2783 TALLOC_FREE(subreq);
2784 if (tevent_req_nterror(req, status)) {
2788 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2789 switch (state->auth_level) {
2790 case DCERPC_AUTH_LEVEL_INTEGRITY:
2791 case DCERPC_AUTH_LEVEL_PRIVACY:
2794 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2798 uint32_t tmp = state->creds->negotiate_flags;
2800 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2802 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2803 * it should be used, which means
2804 * we had a chance to verify no downgrade
2807 * This relies on netlogon_creds_cli_check*
2808 * being called before, as first request after
2811 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2817 * we defer all callbacks in order to cleanup
2818 * the database record.
2820 tevent_req_defer_callback(req, state->ev);
2822 state->tmp_creds = *state->creds;
2823 netlogon_creds_client_authenticator(&state->tmp_creds,
2825 ZERO_STRUCT(state->rep_auth);
2827 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2828 state->binding_handle,
2829 state->srv_name_slash,
2830 state->tmp_creds.computer_name,
2836 if (tevent_req_nomem(subreq, req)) {
2837 status = NT_STATUS_NO_MEMORY;
2838 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2842 tevent_req_set_callback(subreq,
2843 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2847 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2849 struct tevent_req *req =
2850 tevent_req_callback_data(subreq,
2852 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2853 tevent_req_data(req,
2854 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2860 * We use state->dns_names as the memory context, as this is
2861 * the only in/out variable and it has been overwritten by the
2862 * out parameter from the server.
2864 * We need to preserve the return value until the caller can use it.
2866 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2868 TALLOC_FREE(subreq);
2869 if (tevent_req_nterror(req, status)) {
2870 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2874 ok = netlogon_creds_client_check(&state->tmp_creds,
2875 &state->rep_auth.cred);
2877 status = NT_STATUS_ACCESS_DENIED;
2878 tevent_req_nterror(req, status);
2879 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2883 *state->creds = state->tmp_creds;
2884 status = netlogon_creds_cli_store(state->context,
2886 TALLOC_FREE(state->creds);
2888 if (tevent_req_nterror(req, status)) {
2889 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2893 if (tevent_req_nterror(req, result)) {
2894 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2898 tevent_req_done(req);
2901 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2905 if (tevent_req_is_nterror(req, &status)) {
2906 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2907 tevent_req_received(req);
2911 tevent_req_received(req);
2912 return NT_STATUS_OK;
2915 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2916 struct netlogon_creds_cli_context *context,
2917 struct dcerpc_binding_handle *b,
2918 const char *site_name,
2920 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2922 TALLOC_CTX *frame = talloc_stackframe();
2923 struct tevent_context *ev;
2924 struct tevent_req *req;
2925 NTSTATUS status = NT_STATUS_NO_MEMORY;
2927 ev = samba_tevent_context_init(frame);
2931 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2938 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2941 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2947 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2948 struct tevent_context *ev;
2949 struct netlogon_creds_cli_context *context;
2950 struct dcerpc_binding_handle *binding_handle;
2952 char *srv_name_slash;
2953 enum dcerpc_AuthType auth_type;
2954 enum dcerpc_AuthLevel auth_level;
2956 struct samr_Password new_owf_password;
2957 struct samr_Password old_owf_password;
2958 struct netr_TrustInfo *trust_info;
2960 struct netlogon_creds_CredentialState *creds;
2961 struct netlogon_creds_CredentialState tmp_creds;
2962 struct netr_Authenticator req_auth;
2963 struct netr_Authenticator rep_auth;
2966 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2968 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2970 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2971 struct tevent_context *ev,
2972 struct netlogon_creds_cli_context *context,
2973 struct dcerpc_binding_handle *b)
2975 struct tevent_req *req;
2976 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2977 struct tevent_req *subreq;
2979 req = tevent_req_create(mem_ctx, &state,
2980 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2986 state->context = context;
2987 state->binding_handle = b;
2989 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2990 context->server.computer);
2991 if (tevent_req_nomem(state->srv_name_slash, req)) {
2992 return tevent_req_post(req, ev);
2995 dcerpc_binding_handle_auth_info(state->binding_handle,
2997 &state->auth_level);
2999 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3001 if (tevent_req_nomem(subreq, req)) {
3002 return tevent_req_post(req, ev);
3005 tevent_req_set_callback(subreq,
3006 netlogon_creds_cli_ServerGetTrustInfo_locked,
3012 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3015 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3016 tevent_req_data(req,
3017 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3019 if (state->creds == NULL) {
3023 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3024 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3025 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3026 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3027 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3028 TALLOC_FREE(state->creds);
3032 netlogon_creds_cli_delete(state->context, state->creds);
3033 TALLOC_FREE(state->creds);
3036 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3038 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3040 struct tevent_req *req =
3041 tevent_req_callback_data(subreq,
3043 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3044 tevent_req_data(req,
3045 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3048 status = netlogon_creds_cli_lock_recv(subreq, state,
3050 TALLOC_FREE(subreq);
3051 if (tevent_req_nterror(req, status)) {
3055 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3056 switch (state->auth_level) {
3057 case DCERPC_AUTH_LEVEL_PRIVACY:
3060 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3064 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3069 * we defer all callbacks in order to cleanup
3070 * the database record.
3072 tevent_req_defer_callback(req, state->ev);
3074 state->tmp_creds = *state->creds;
3075 netlogon_creds_client_authenticator(&state->tmp_creds,
3077 ZERO_STRUCT(state->rep_auth);
3079 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3080 state->binding_handle,
3081 state->srv_name_slash,
3082 state->tmp_creds.account_name,
3083 state->tmp_creds.secure_channel_type,
3084 state->tmp_creds.computer_name,
3087 &state->new_owf_password,
3088 &state->old_owf_password,
3089 &state->trust_info);
3090 if (tevent_req_nomem(subreq, req)) {
3091 status = NT_STATUS_NO_MEMORY;
3092 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3096 tevent_req_set_callback(subreq,
3097 netlogon_creds_cli_ServerGetTrustInfo_done,
3101 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3103 struct tevent_req *req =
3104 tevent_req_callback_data(subreq,
3106 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3107 tevent_req_data(req,
3108 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3111 const struct samr_Password zero = {};
3116 * We use state->dns_names as the memory context, as this is
3117 * the only in/out variable and it has been overwritten by the
3118 * out parameter from the server.
3120 * We need to preserve the return value until the caller can use it.
3122 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3123 TALLOC_FREE(subreq);
3124 if (tevent_req_nterror(req, status)) {
3125 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3129 ok = netlogon_creds_client_check(&state->tmp_creds,
3130 &state->rep_auth.cred);
3132 status = NT_STATUS_ACCESS_DENIED;
3133 tevent_req_nterror(req, status);
3134 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3138 cmp = memcmp(state->new_owf_password.hash,
3139 zero.hash, sizeof(zero.hash));
3141 netlogon_creds_des_decrypt(&state->tmp_creds,
3142 &state->new_owf_password);
3144 cmp = memcmp(state->old_owf_password.hash,
3145 zero.hash, sizeof(zero.hash));
3147 netlogon_creds_des_decrypt(&state->tmp_creds,
3148 &state->old_owf_password);
3151 *state->creds = state->tmp_creds;
3152 status = netlogon_creds_cli_store(state->context,
3154 TALLOC_FREE(state->creds);
3155 if (tevent_req_nterror(req, status)) {
3156 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3160 if (tevent_req_nterror(req, result)) {
3161 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3165 tevent_req_done(req);
3168 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3169 TALLOC_CTX *mem_ctx,
3170 struct samr_Password *new_owf_password,
3171 struct samr_Password *old_owf_password,
3172 struct netr_TrustInfo **trust_info)
3174 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3175 tevent_req_data(req,
3176 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3179 if (tevent_req_is_nterror(req, &status)) {
3180 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3181 tevent_req_received(req);
3185 if (new_owf_password != NULL) {
3186 *new_owf_password = state->new_owf_password;
3188 if (old_owf_password != NULL) {
3189 *old_owf_password = state->old_owf_password;
3191 if (trust_info != NULL) {
3192 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3195 tevent_req_received(req);
3196 return NT_STATUS_OK;
3199 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3200 struct netlogon_creds_cli_context *context,
3201 struct dcerpc_binding_handle *b,
3202 TALLOC_CTX *mem_ctx,
3203 struct samr_Password *new_owf_password,
3204 struct samr_Password *old_owf_password,
3205 struct netr_TrustInfo **trust_info)
3207 TALLOC_CTX *frame = talloc_stackframe();
3208 struct tevent_context *ev;
3209 struct tevent_req *req;
3210 NTSTATUS status = NT_STATUS_NO_MEMORY;
3212 ev = samba_tevent_context_init(frame);
3216 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3220 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3223 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3233 struct netlogon_creds_cli_GetForestTrustInformation_state {
3234 struct tevent_context *ev;
3235 struct netlogon_creds_cli_context *context;
3236 struct dcerpc_binding_handle *binding_handle;
3238 char *srv_name_slash;
3239 enum dcerpc_AuthType auth_type;
3240 enum dcerpc_AuthLevel auth_level;
3243 struct lsa_ForestTrustInformation *forest_trust_info;
3245 struct netlogon_creds_CredentialState *creds;
3246 struct netlogon_creds_CredentialState tmp_creds;
3247 struct netr_Authenticator req_auth;
3248 struct netr_Authenticator rep_auth;
3251 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3253 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3255 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3256 struct tevent_context *ev,
3257 struct netlogon_creds_cli_context *context,
3258 struct dcerpc_binding_handle *b)
3260 struct tevent_req *req;
3261 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3262 struct tevent_req *subreq;
3264 req = tevent_req_create(mem_ctx, &state,
3265 struct netlogon_creds_cli_GetForestTrustInformation_state);
3271 state->context = context;
3272 state->binding_handle = b;
3274 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3275 context->server.computer);
3276 if (tevent_req_nomem(state->srv_name_slash, req)) {
3277 return tevent_req_post(req, ev);
3282 dcerpc_binding_handle_auth_info(state->binding_handle,
3284 &state->auth_level);
3286 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3288 if (tevent_req_nomem(subreq, req)) {
3289 return tevent_req_post(req, ev);
3292 tevent_req_set_callback(subreq,
3293 netlogon_creds_cli_GetForestTrustInformation_locked,
3299 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3302 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3303 tevent_req_data(req,
3304 struct netlogon_creds_cli_GetForestTrustInformation_state);
3306 if (state->creds == NULL) {
3310 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3311 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3312 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3313 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3314 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3315 TALLOC_FREE(state->creds);
3319 netlogon_creds_cli_delete(state->context, state->creds);
3320 TALLOC_FREE(state->creds);
3323 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3325 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3327 struct tevent_req *req =
3328 tevent_req_callback_data(subreq,
3330 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3331 tevent_req_data(req,
3332 struct netlogon_creds_cli_GetForestTrustInformation_state);
3335 status = netlogon_creds_cli_lock_recv(subreq, state,
3337 TALLOC_FREE(subreq);
3338 if (tevent_req_nterror(req, status)) {
3342 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3343 switch (state->auth_level) {
3344 case DCERPC_AUTH_LEVEL_INTEGRITY:
3345 case DCERPC_AUTH_LEVEL_PRIVACY:
3348 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3352 uint32_t tmp = state->creds->negotiate_flags;
3354 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3356 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3357 * it should be used, which means
3358 * we had a chance to verify no downgrade
3361 * This relies on netlogon_creds_cli_check*
3362 * being called before, as first request after
3365 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3371 * we defer all callbacks in order to cleanup
3372 * the database record.
3374 tevent_req_defer_callback(req, state->ev);
3376 state->tmp_creds = *state->creds;
3377 netlogon_creds_client_authenticator(&state->tmp_creds,
3379 ZERO_STRUCT(state->rep_auth);
3381 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3382 state->binding_handle,
3383 state->srv_name_slash,
3384 state->tmp_creds.computer_name,
3388 &state->forest_trust_info);
3389 if (tevent_req_nomem(subreq, req)) {
3390 status = NT_STATUS_NO_MEMORY;
3391 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3395 tevent_req_set_callback(subreq,
3396 netlogon_creds_cli_GetForestTrustInformation_done,
3400 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3402 struct tevent_req *req =
3403 tevent_req_callback_data(subreq,
3405 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3406 tevent_req_data(req,
3407 struct netlogon_creds_cli_GetForestTrustInformation_state);
3413 * We use state->dns_names as the memory context, as this is
3414 * the only in/out variable and it has been overwritten by the
3415 * out parameter from the server.
3417 * We need to preserve the return value until the caller can use it.
3419 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3420 TALLOC_FREE(subreq);
3421 if (tevent_req_nterror(req, status)) {
3422 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3426 ok = netlogon_creds_client_check(&state->tmp_creds,
3427 &state->rep_auth.cred);
3429 status = NT_STATUS_ACCESS_DENIED;
3430 tevent_req_nterror(req, status);
3431 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3435 *state->creds = state->tmp_creds;
3436 status = netlogon_creds_cli_store(state->context,
3438 TALLOC_FREE(state->creds);
3440 if (tevent_req_nterror(req, status)) {
3441 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3445 if (tevent_req_nterror(req, result)) {
3446 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3450 tevent_req_done(req);
3453 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3454 TALLOC_CTX *mem_ctx,
3455 struct lsa_ForestTrustInformation **forest_trust_info)
3457 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3458 tevent_req_data(req,
3459 struct netlogon_creds_cli_GetForestTrustInformation_state);
3462 if (tevent_req_is_nterror(req, &status)) {
3463 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3464 tevent_req_received(req);
3468 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3470 tevent_req_received(req);
3471 return NT_STATUS_OK;
3474 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3475 struct netlogon_creds_cli_context *context,
3476 struct dcerpc_binding_handle *b,
3477 TALLOC_CTX *mem_ctx,
3478 struct lsa_ForestTrustInformation **forest_trust_info)
3480 TALLOC_CTX *frame = talloc_stackframe();
3481 struct tevent_context *ev;
3482 struct tevent_req *req;
3483 NTSTATUS status = NT_STATUS_NO_MEMORY;
3485 ev = samba_tevent_context_init(frame);
3489 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3493 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3496 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3504 struct netlogon_creds_cli_SendToSam_state {
3505 struct tevent_context *ev;
3506 struct netlogon_creds_cli_context *context;
3507 struct dcerpc_binding_handle *binding_handle;
3509 char *srv_name_slash;
3510 enum dcerpc_AuthType auth_type;
3511 enum dcerpc_AuthLevel auth_level;
3515 struct netlogon_creds_CredentialState *creds;
3516 struct netlogon_creds_CredentialState tmp_creds;
3517 struct netr_Authenticator req_auth;
3518 struct netr_Authenticator rep_auth;
3521 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3523 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3525 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3526 struct tevent_context *ev,
3527 struct netlogon_creds_cli_context *context,
3528 struct dcerpc_binding_handle *b,
3529 struct netr_SendToSamBase *message)
3531 struct tevent_req *req;
3532 struct netlogon_creds_cli_SendToSam_state *state;
3533 struct tevent_req *subreq;
3534 enum ndr_err_code ndr_err;
3536 req = tevent_req_create(mem_ctx, &state,
3537 struct netlogon_creds_cli_SendToSam_state);
3543 state->context = context;
3544 state->binding_handle = b;
3546 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3547 context->server.computer);
3548 if (tevent_req_nomem(state->srv_name_slash, req)) {
3549 return tevent_req_post(req, ev);
3552 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3553 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3554 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3555 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3556 tevent_req_nterror(req, status);
3557 return tevent_req_post(req, ev);
3560 dcerpc_binding_handle_auth_info(state->binding_handle,
3562 &state->auth_level);
3564 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3566 if (tevent_req_nomem(subreq, req)) {
3567 return tevent_req_post(req, ev);
3570 tevent_req_set_callback(subreq,
3571 netlogon_creds_cli_SendToSam_locked,
3577 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3580 struct netlogon_creds_cli_SendToSam_state *state =
3581 tevent_req_data(req,
3582 struct netlogon_creds_cli_SendToSam_state);
3584 if (state->creds == NULL) {
3588 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3589 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3590 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3591 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3592 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3593 TALLOC_FREE(state->creds);
3597 netlogon_creds_cli_delete(state->context, state->creds);
3598 TALLOC_FREE(state->creds);
3601 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3603 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3605 struct tevent_req *req =
3606 tevent_req_callback_data(subreq,
3608 struct netlogon_creds_cli_SendToSam_state *state =
3609 tevent_req_data(req,
3610 struct netlogon_creds_cli_SendToSam_state);
3613 status = netlogon_creds_cli_lock_recv(subreq, state,
3615 TALLOC_FREE(subreq);
3616 if (tevent_req_nterror(req, status)) {
3620 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3621 switch (state->auth_level) {
3622 case DCERPC_AUTH_LEVEL_INTEGRITY:
3623 case DCERPC_AUTH_LEVEL_PRIVACY:
3626 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3630 uint32_t tmp = state->creds->negotiate_flags;
3632 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3634 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3635 * it should be used, which means
3636 * we had a chance to verify no downgrade
3639 * This relies on netlogon_creds_cli_check*
3640 * being called before, as first request after
3643 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3649 * we defer all callbacks in order to cleanup
3650 * the database record.
3652 tevent_req_defer_callback(req, state->ev);
3654 state->tmp_creds = *state->creds;
3655 netlogon_creds_client_authenticator(&state->tmp_creds,
3657 ZERO_STRUCT(state->rep_auth);
3659 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3660 netlogon_creds_aes_encrypt(&state->tmp_creds,
3662 state->opaque.length);
3664 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3666 state->opaque.length);
3669 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3670 state->binding_handle,
3671 state->srv_name_slash,
3672 state->tmp_creds.computer_name,
3676 state->opaque.length);
3677 if (tevent_req_nomem(subreq, req)) {
3678 status = NT_STATUS_NO_MEMORY;
3679 netlogon_creds_cli_SendToSam_cleanup(req, status);
3683 tevent_req_set_callback(subreq,
3684 netlogon_creds_cli_SendToSam_done,
3688 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3690 struct tevent_req *req =
3691 tevent_req_callback_data(subreq,
3693 struct netlogon_creds_cli_SendToSam_state *state =
3694 tevent_req_data(req,
3695 struct netlogon_creds_cli_SendToSam_state);
3700 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3701 TALLOC_FREE(subreq);
3702 if (tevent_req_nterror(req, status)) {
3703 netlogon_creds_cli_SendToSam_cleanup(req, status);
3707 ok = netlogon_creds_client_check(&state->tmp_creds,
3708 &state->rep_auth.cred);
3710 status = NT_STATUS_ACCESS_DENIED;
3711 tevent_req_nterror(req, status);
3712 netlogon_creds_cli_SendToSam_cleanup(req, status);
3716 *state->creds = state->tmp_creds;
3717 status = netlogon_creds_cli_store(state->context,
3719 TALLOC_FREE(state->creds);
3721 if (tevent_req_nterror(req, status)) {
3722 netlogon_creds_cli_SendToSam_cleanup(req, status);
3727 * Creds must be stored before we send back application errors
3728 * e.g. NT_STATUS_NOT_IMPLEMENTED
3730 if (tevent_req_nterror(req, result)) {
3731 netlogon_creds_cli_SendToSam_cleanup(req, result);
3735 tevent_req_done(req);
3738 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3739 struct dcerpc_binding_handle *b,
3740 struct netr_SendToSamBase *message)
3742 TALLOC_CTX *frame = talloc_stackframe();
3743 struct tevent_context *ev;
3744 struct tevent_req *req;
3745 NTSTATUS status = NT_STATUS_OK;
3747 ev = samba_tevent_context_init(frame);
3751 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3755 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3759 /* Ignore the result */