2 Unix SMB/CIFS implementation.
4 module to store/fetch session keys for the schannel client
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "system/filesys.h"
25 #include "lib/util/tevent_ntstatus.h"
26 #include "lib/dbwrap/dbwrap.h"
27 #include "lib/dbwrap/dbwrap_rbt.h"
28 #include "lib/util/util_tdb.h"
29 #include "libcli/security/security.h"
30 #include "../lib/param/param.h"
31 #include "../libcli/auth/schannel.h"
32 #include "../librpc/gen_ndr/ndr_schannel.h"
33 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
34 #include "../librpc/gen_ndr/ndr_netlogon.h"
35 #include "../librpc/gen_ndr/server_id.h"
36 #include "netlogon_creds_cli.h"
37 #include "source3/include/messages.h"
38 #include "source3/include/g_lock.h"
39 #include "libds/common/roles.h"
40 #include "lib/crypto/crypto.h"
41 #include "auth/credentials/credentials.h"
43 struct netlogon_creds_cli_locked_state;
45 struct netlogon_creds_cli_context {
49 uint32_t proposed_flags;
50 uint32_t required_flags;
51 enum netr_SchannelType type;
52 enum dcerpc_AuthLevel auth_level;
57 const char *netbios_domain;
58 const char *dns_domain;
59 uint32_t cached_flags;
68 struct db_context *ctx;
69 struct g_lock_ctx *g_ctx;
70 struct netlogon_creds_cli_locked_state *locked_state;
71 enum netlogon_creds_cli_lck_type lock;
75 struct netlogon_creds_cli_locked_state {
76 struct netlogon_creds_cli_context *context;
78 struct netlogon_creds_CredentialState *creds;
81 static int netlogon_creds_cli_locked_state_destructor(
82 struct netlogon_creds_cli_locked_state *state)
84 struct netlogon_creds_cli_context *context = state->context;
86 if (context == NULL) {
90 if (context->db.locked_state == state) {
91 context->db.locked_state = NULL;
94 if (state->is_glocked) {
95 g_lock_unlock(context->db.g_ctx,
96 context->db.key_name);
102 static NTSTATUS netlogon_creds_cli_context_common(
103 const char *client_computer,
104 const char *client_account,
105 enum netr_SchannelType type,
106 enum dcerpc_AuthLevel auth_level,
107 uint32_t proposed_flags,
108 uint32_t required_flags,
109 const char *server_computer,
110 const char *server_netbios_domain,
111 const char *server_dns_domain,
113 struct netlogon_creds_cli_context **_context)
115 struct netlogon_creds_cli_context *context = NULL;
116 char *_key_name = NULL;
117 size_t server_netbios_name_len;
122 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
123 if (context == NULL) {
124 return NT_STATUS_NO_MEMORY;
127 context->client.computer = talloc_strdup(context, client_computer);
128 if (context->client.computer == NULL) {
129 TALLOC_FREE(context);
130 return NT_STATUS_NO_MEMORY;
133 context->client.account = talloc_strdup(context, client_account);
134 if (context->client.account == NULL) {
135 TALLOC_FREE(context);
136 return NT_STATUS_NO_MEMORY;
139 context->client.proposed_flags = proposed_flags;
140 context->client.required_flags = required_flags;
141 context->client.type = type;
142 context->client.auth_level = auth_level;
144 context->server.computer = talloc_strdup(context, server_computer);
145 if (context->server.computer == NULL) {
146 TALLOC_FREE(context);
147 return NT_STATUS_NO_MEMORY;
150 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
151 if (context->server.netbios_domain == NULL) {
152 TALLOC_FREE(context);
153 return NT_STATUS_NO_MEMORY;
156 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
157 if (context->server.dns_domain == NULL) {
158 TALLOC_FREE(context);
159 return NT_STATUS_NO_MEMORY;
164 * Force the callers to provide a unique
165 * value for server_computer and use this directly.
167 * For now we have to deal with
168 * "HOSTNAME" vs. "hostname.example.com".
171 p = strchr(server_computer, '.');
173 server_netbios_name_len = p-server_computer;
175 server_netbios_name_len = strlen(server_computer);
178 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
181 (int)server_netbios_name_len,
183 server_netbios_domain);
184 if (_key_name == NULL) {
185 TALLOC_FREE(context);
186 return NT_STATUS_NO_MEMORY;
189 context->db.key_name = talloc_strdup_upper(context, _key_name);
190 TALLOC_FREE(_key_name);
191 if (context->db.key_name == NULL) {
192 TALLOC_FREE(context);
193 return NT_STATUS_NO_MEMORY;
196 context->db.key_data = string_term_tdb_data(context->db.key_name);
202 static struct db_context *netlogon_creds_cli_global_db;
204 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
206 if (netlogon_creds_cli_global_db != NULL) {
207 return NT_STATUS_INVALID_PARAMETER_MIX;
210 netlogon_creds_cli_global_db = talloc_move(NULL, db);
214 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
217 struct db_context *global_db;
219 if (netlogon_creds_cli_global_db != NULL) {
223 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
225 return NT_STATUS_NO_MEMORY;
228 global_db = dbwrap_local_open(NULL, lp_ctx,
230 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
232 0600, DBWRAP_LOCK_ORDER_2,
234 if (global_db == NULL) {
235 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
236 fname, strerror(errno)));
238 return NT_STATUS_NO_MEMORY;
242 netlogon_creds_cli_global_db = global_db;
246 void netlogon_creds_cli_close_global_db(void)
248 TALLOC_FREE(netlogon_creds_cli_global_db);
251 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
252 struct messaging_context *msg_ctx,
253 const char *client_account,
254 enum netr_SchannelType type,
255 const char *server_computer,
256 const char *server_netbios_domain,
257 const char *server_dns_domain,
259 struct netlogon_creds_cli_context **_context)
261 TALLOC_CTX *frame = talloc_stackframe();
263 struct netlogon_creds_cli_context *context = NULL;
264 const char *client_computer;
265 uint32_t proposed_flags;
266 uint32_t required_flags = 0;
267 bool reject_md5_servers = false;
268 bool require_strong_key = false;
269 int require_sign_or_seal = true;
270 bool seal_secure_channel = true;
271 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
272 bool neutralize_nt4_emulation = false;
276 if (msg_ctx == NULL) {
278 return NT_STATUS_INVALID_PARAMETER_MIX;
281 client_computer = lpcfg_netbios_name(lp_ctx);
282 if (strlen(client_computer) > 15) {
284 return NT_STATUS_INVALID_PARAMETER_MIX;
288 * allow overwrite per domain
289 * reject md5 servers:<netbios_domain>
291 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
292 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
293 "reject md5 servers",
294 server_netbios_domain,
298 * allow overwrite per domain
299 * require strong key:<netbios_domain>
301 require_strong_key = lpcfg_require_strong_key(lp_ctx);
302 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
303 "require strong key",
304 server_netbios_domain,
308 * allow overwrite per domain
309 * client schannel:<netbios_domain>
311 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
312 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
314 server_netbios_domain,
315 require_sign_or_seal);
318 * allow overwrite per domain
319 * winbind sealed pipes:<netbios_domain>
321 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
322 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
323 "winbind sealed pipes",
324 server_netbios_domain,
325 seal_secure_channel);
328 * allow overwrite per domain
329 * neutralize nt4 emulation:<netbios_domain>
331 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
332 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
333 "neutralize nt4 emulation",
334 server_netbios_domain,
335 neutralize_nt4_emulation);
337 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
338 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
342 if (lpcfg_security(lp_ctx) == SEC_ADS) {
344 * AD domains should be secure
346 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
347 require_sign_or_seal = true;
348 require_strong_key = true;
352 case SEC_CHAN_DOMAIN:
355 case SEC_CHAN_DNS_DOMAIN:
357 * AD domains should be secure
359 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
360 require_sign_or_seal = true;
361 require_strong_key = true;
362 neutralize_nt4_emulation = true;
366 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
367 require_sign_or_seal = true;
368 require_strong_key = true;
372 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
373 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
374 require_sign_or_seal = true;
375 require_strong_key = true;
376 neutralize_nt4_emulation = true;
381 return NT_STATUS_INVALID_PARAMETER;
384 if (neutralize_nt4_emulation) {
385 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
388 if (require_sign_or_seal) {
389 required_flags |= NETLOGON_NEG_ARCFOUR;
390 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
392 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
395 if (reject_md5_servers) {
396 required_flags |= NETLOGON_NEG_ARCFOUR;
397 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
398 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
399 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
402 if (require_strong_key) {
403 required_flags |= NETLOGON_NEG_ARCFOUR;
404 required_flags |= NETLOGON_NEG_STRONG_KEYS;
405 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
408 proposed_flags |= required_flags;
410 if (seal_secure_channel) {
411 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
413 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
416 status = netlogon_creds_cli_context_common(client_computer,
423 server_netbios_domain,
427 if (!NT_STATUS_IS_OK(status)) {
432 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
433 if (context->db.g_ctx == NULL) {
434 TALLOC_FREE(context);
436 return NT_STATUS_NO_MEMORY;
439 status = netlogon_creds_cli_open_global_db(lp_ctx);
440 if (!NT_STATUS_IS_OK(status)) {
441 TALLOC_FREE(context);
443 return NT_STATUS_NO_MEMORY;
446 context->db.ctx = netlogon_creds_cli_global_db;
452 NTSTATUS netlogon_creds_bind_cli_credentials(
453 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
454 struct cli_credentials **pcli_creds)
456 struct cli_credentials *cli_creds;
457 struct netlogon_creds_CredentialState *ncreds;
460 cli_creds = cli_credentials_init(mem_ctx);
461 if (cli_creds == NULL) {
462 return NT_STATUS_NO_MEMORY;
464 cli_credentials_set_secure_channel_type(cli_creds,
465 context->client.type);
466 cli_credentials_set_username(cli_creds, context->client.account,
468 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
470 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
473 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
474 if (!NT_STATUS_IS_OK(status)) {
475 TALLOC_FREE(cli_creds);
478 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
480 *pcli_creds = cli_creds;
484 char *netlogon_creds_cli_debug_string(
485 const struct netlogon_creds_cli_context *context,
488 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
489 context->db.key_name);
492 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
493 struct netlogon_creds_cli_context *context)
495 return context->client.auth_level;
498 struct netlogon_creds_cli_fetch_state {
500 struct netlogon_creds_CredentialState *creds;
501 uint32_t required_flags;
505 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
508 struct netlogon_creds_cli_fetch_state *state =
509 (struct netlogon_creds_cli_fetch_state *)private_data;
510 enum ndr_err_code ndr_err;
514 state->creds = talloc_zero(state->mem_ctx,
515 struct netlogon_creds_CredentialState);
516 if (state->creds == NULL) {
517 state->status = NT_STATUS_NO_MEMORY;
521 blob.data = data.dptr;
522 blob.length = data.dsize;
524 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
525 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
526 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
527 TALLOC_FREE(state->creds);
528 state->status = ndr_map_error2ntstatus(ndr_err);
532 if (DEBUGLEVEL >= 10) {
533 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
536 tmp_flags = state->creds->negotiate_flags;
537 tmp_flags &= state->required_flags;
538 if (tmp_flags != state->required_flags) {
539 TALLOC_FREE(state->creds);
540 state->status = NT_STATUS_DOWNGRADE_DETECTED;
544 state->status = NT_STATUS_OK;
547 static NTSTATUS netlogon_creds_cli_get_internal(
548 struct netlogon_creds_cli_context *context,
549 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
551 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
553 struct netlogon_creds_CredentialState **_creds)
556 struct netlogon_creds_CredentialState *creds;
560 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
561 if (!NT_STATUS_IS_OK(status)) {
566 * mark it as invalid for step operations.
569 creds->seed = (struct netr_Credential) {{0}};
570 creds->client = (struct netr_Credential) {{0}};
571 creds->server = (struct netr_Credential) {{0}};
577 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
578 const struct netlogon_creds_CredentialState *creds1)
580 TALLOC_CTX *frame = talloc_stackframe();
581 struct netlogon_creds_CredentialState *creds2;
585 enum ndr_err_code ndr_err;
588 status = netlogon_creds_cli_get(context, frame, &creds2);
589 if (!NT_STATUS_IS_OK(status)) {
594 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
595 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
596 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
601 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
602 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
603 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
608 cmp = data_blob_cmp(&blob1, &blob2);
615 static NTSTATUS netlogon_creds_cli_store_internal(
616 struct netlogon_creds_cli_context *context,
617 struct netlogon_creds_CredentialState *creds)
620 enum ndr_err_code ndr_err;
624 if (DEBUGLEVEL >= 10) {
625 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
628 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
629 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
630 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
631 status = ndr_map_error2ntstatus(ndr_err);
635 data.dptr = blob.data;
636 data.dsize = blob.length;
638 status = dbwrap_store(context->db.ctx,
639 context->db.key_data,
641 TALLOC_FREE(data.dptr);
642 if (!NT_STATUS_IS_OK(status)) {
649 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
650 struct netlogon_creds_CredentialState *creds)
654 if (context->db.locked_state == NULL) {
656 * this was not the result of netlogon_creds_cli_lock*()
658 return NT_STATUS_INVALID_PAGE_PROTECTION;
661 if (context->db.locked_state->creds != creds) {
663 * this was not the result of netlogon_creds_cli_lock*()
665 return NT_STATUS_INVALID_PAGE_PROTECTION;
668 status = netlogon_creds_cli_store_internal(context, creds);
672 static NTSTATUS netlogon_creds_cli_delete_internal(
673 struct netlogon_creds_cli_context *context)
676 status = dbwrap_delete(context->db.ctx, context->db.key_data);
680 NTSTATUS netlogon_creds_cli_delete_lck(
681 struct netlogon_creds_cli_context *context)
685 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
686 return NT_STATUS_NOT_LOCKED;
689 status = netlogon_creds_cli_delete_internal(context);
693 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
694 struct netlogon_creds_CredentialState *creds)
698 if (context->db.locked_state == NULL) {
700 * this was not the result of netlogon_creds_cli_lock*()
702 return NT_STATUS_INVALID_PAGE_PROTECTION;
705 if (context->db.locked_state->creds != creds) {
707 * this was not the result of netlogon_creds_cli_lock*()
709 return NT_STATUS_INVALID_PAGE_PROTECTION;
712 status = netlogon_creds_cli_delete_internal(context);
716 struct netlogon_creds_cli_lock_state {
717 struct netlogon_creds_cli_locked_state *locked_state;
718 struct netlogon_creds_CredentialState *creds;
721 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
723 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
724 struct tevent_context *ev,
725 struct netlogon_creds_cli_context *context)
727 struct tevent_req *req;
728 struct netlogon_creds_cli_lock_state *state;
729 struct netlogon_creds_cli_locked_state *locked_state;
730 struct tevent_req *subreq;
732 req = tevent_req_create(mem_ctx, &state,
733 struct netlogon_creds_cli_lock_state);
738 if (context->db.locked_state != NULL) {
739 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
740 return tevent_req_post(req, ev);
743 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
744 if (tevent_req_nomem(locked_state, req)) {
745 return tevent_req_post(req, ev);
747 talloc_set_destructor(locked_state,
748 netlogon_creds_cli_locked_state_destructor);
749 locked_state->context = context;
751 context->db.locked_state = locked_state;
752 state->locked_state = locked_state;
754 if (context->db.g_ctx == NULL) {
757 status = netlogon_creds_cli_get_internal(
758 context, state, &state->creds);
759 if (tevent_req_nterror(req, status)) {
760 return tevent_req_post(req, ev);
766 subreq = g_lock_lock_send(state, ev,
768 context->db.key_name,
770 if (tevent_req_nomem(subreq, req)) {
771 return tevent_req_post(req, ev);
773 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
778 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
780 struct tevent_req *req =
781 tevent_req_callback_data(subreq,
783 struct netlogon_creds_cli_lock_state *state =
785 struct netlogon_creds_cli_lock_state);
788 status = g_lock_lock_recv(subreq);
790 if (tevent_req_nterror(req, status)) {
793 state->locked_state->is_glocked = true;
795 status = netlogon_creds_cli_get_internal(state->locked_state->context,
796 state, &state->creds);
797 if (tevent_req_nterror(req, status)) {
800 tevent_req_done(req);
803 static NTSTATUS netlogon_creds_cli_get_internal(
804 struct netlogon_creds_cli_context *context,
805 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
807 struct netlogon_creds_cli_fetch_state fstate = {
808 .status = NT_STATUS_INTERNAL_ERROR,
809 .required_flags = context->client.required_flags,
813 fstate.mem_ctx = mem_ctx;
814 status = dbwrap_parse_record(context->db.ctx,
815 context->db.key_data,
816 netlogon_creds_cli_fetch_parser,
818 if (!NT_STATUS_IS_OK(status)) {
821 if (!NT_STATUS_IS_OK(fstate.status)) {
822 return fstate.status;
825 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
826 *pcreds = fstate.creds;
831 * It is really important to try SamLogonEx here,
832 * because multiple processes can talk to the same
833 * domain controller, without using the credential
836 * With a normal SamLogon call, we must keep the
837 * credentials chain updated and intact between all
838 * users of the machine account (which would imply
839 * cross-node communication for every NTLM logon).
841 * The credentials chain is not per NETLOGON pipe
842 * connection, but globally on the server/client pair
845 * It's also important to use NetlogonValidationSamInfo4 (6),
846 * because it relies on the rpc transport encryption
847 * and avoids using the global netlogon schannel
848 * session key to en/decrypt secret information
849 * like the user_session_key for network logons.
851 * [MS-APDS] 3.1.5.2 NTLM Network Logon
852 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
853 * NETLOGON_NEG_AUTHENTICATED_RPC set together
854 * are the indication that the server supports
855 * NetlogonValidationSamInfo4 (6). And it must only
856 * be used if "SealSecureChannel" is used.
858 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
859 * check is done in netlogon_creds_cli_LogonSamLogon*().
862 context->server.cached_flags = fstate.creds->negotiate_flags;
863 context->server.try_validation6 = true;
864 context->server.try_logon_ex = true;
865 context->server.try_logon_with = true;
867 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
868 context->server.try_validation6 = false;
869 context->server.try_logon_ex = false;
871 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
872 context->server.try_validation6 = false;
875 *pcreds = fstate.creds;
879 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
881 struct netlogon_creds_CredentialState **creds)
883 struct netlogon_creds_cli_lock_state *state =
885 struct netlogon_creds_cli_lock_state);
888 if (tevent_req_is_nterror(req, &status)) {
889 tevent_req_received(req);
893 talloc_steal(state->creds, state->locked_state);
894 state->locked_state->creds = state->creds;
895 *creds = talloc_move(mem_ctx, &state->creds);
896 tevent_req_received(req);
900 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
902 struct netlogon_creds_CredentialState **creds)
904 TALLOC_CTX *frame = talloc_stackframe();
905 struct tevent_context *ev;
906 struct tevent_req *req;
907 NTSTATUS status = NT_STATUS_NO_MEMORY;
909 ev = samba_tevent_context_init(frame);
913 req = netlogon_creds_cli_lock_send(frame, ev, context);
917 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
920 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
926 struct netlogon_creds_cli_lck {
927 struct netlogon_creds_cli_context *context;
930 struct netlogon_creds_cli_lck_state {
931 struct netlogon_creds_cli_lck *lck;
932 enum netlogon_creds_cli_lck_type type;
935 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
936 static int netlogon_creds_cli_lck_destructor(
937 struct netlogon_creds_cli_lck *lck);
939 struct tevent_req *netlogon_creds_cli_lck_send(
940 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
941 struct netlogon_creds_cli_context *context,
942 enum netlogon_creds_cli_lck_type type)
944 struct tevent_req *req, *subreq;
945 struct netlogon_creds_cli_lck_state *state;
946 enum g_lock_type gtype;
948 req = tevent_req_create(mem_ctx, &state,
949 struct netlogon_creds_cli_lck_state);
954 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
955 DBG_DEBUG("context already locked\n");
956 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
957 return tevent_req_post(req, ev);
961 case NETLOGON_CREDS_CLI_LCK_SHARED:
964 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
965 gtype = G_LOCK_WRITE;
968 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
969 return tevent_req_post(req, ev);
972 state->lck = talloc(state, struct netlogon_creds_cli_lck);
973 if (tevent_req_nomem(state->lck, req)) {
974 return tevent_req_post(req, ev);
976 state->lck->context = context;
979 subreq = g_lock_lock_send(state, ev,
981 context->db.key_name,
983 if (tevent_req_nomem(subreq, req)) {
984 return tevent_req_post(req, ev);
986 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
991 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
993 struct tevent_req *req = tevent_req_callback_data(
994 subreq, struct tevent_req);
995 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
996 req, struct netlogon_creds_cli_lck_state);
999 status = g_lock_lock_recv(subreq);
1000 TALLOC_FREE(subreq);
1001 if (tevent_req_nterror(req, status)) {
1005 state->lck->context->db.lock = state->type;
1006 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1008 tevent_req_done(req);
1011 static int netlogon_creds_cli_lck_destructor(
1012 struct netlogon_creds_cli_lck *lck)
1014 struct netlogon_creds_cli_context *ctx = lck->context;
1017 status = g_lock_unlock(ctx->db.g_ctx, ctx->db.key_name);
1018 if (!NT_STATUS_IS_OK(status)) {
1019 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1020 smb_panic("g_lock_unlock failed");
1022 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1026 NTSTATUS netlogon_creds_cli_lck_recv(
1027 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1028 struct netlogon_creds_cli_lck **lck)
1030 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1031 req, struct netlogon_creds_cli_lck_state);
1034 if (tevent_req_is_nterror(req, &status)) {
1037 *lck = talloc_move(mem_ctx, &state->lck);
1038 return NT_STATUS_OK;
1041 NTSTATUS netlogon_creds_cli_lck(
1042 struct netlogon_creds_cli_context *context,
1043 enum netlogon_creds_cli_lck_type type,
1044 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1046 TALLOC_CTX *frame = talloc_stackframe();
1047 struct tevent_context *ev;
1048 struct tevent_req *req;
1049 NTSTATUS status = NT_STATUS_NO_MEMORY;
1051 ev = samba_tevent_context_init(frame);
1055 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1059 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1062 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1068 struct netlogon_creds_cli_auth_state {
1069 struct tevent_context *ev;
1070 struct netlogon_creds_cli_context *context;
1071 struct dcerpc_binding_handle *binding_handle;
1072 uint8_t num_nt_hashes;
1073 uint8_t idx_nt_hashes;
1074 const struct samr_Password * const *nt_hashes;
1075 const struct samr_Password *used_nt_hash;
1076 char *srv_name_slash;
1077 uint32_t current_flags;
1078 struct netr_Credential client_challenge;
1079 struct netr_Credential server_challenge;
1080 struct netlogon_creds_CredentialState *creds;
1081 struct netr_Credential client_credential;
1082 struct netr_Credential server_credential;
1087 struct netlogon_creds_cli_locked_state *locked_state;
1090 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
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;
1102 struct netlogon_creds_cli_locked_state *locked_state;
1105 req = tevent_req_create(mem_ctx, &state,
1106 struct netlogon_creds_cli_auth_state);
1112 state->context = context;
1113 state->binding_handle = b;
1114 if (num_nt_hashes < 1) {
1115 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1116 return tevent_req_post(req, ev);
1118 if (num_nt_hashes > 4) {
1119 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1120 return tevent_req_post(req, ev);
1123 state->num_nt_hashes = num_nt_hashes;
1124 state->idx_nt_hashes = 0;
1125 state->nt_hashes = nt_hashes;
1127 if (context->db.locked_state != NULL) {
1128 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
1129 return tevent_req_post(req, ev);
1132 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
1133 if (tevent_req_nomem(locked_state, req)) {
1134 return tevent_req_post(req, ev);
1136 talloc_set_destructor(locked_state,
1137 netlogon_creds_cli_locked_state_destructor);
1138 locked_state->context = context;
1140 context->db.locked_state = locked_state;
1141 state->locked_state = locked_state;
1143 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1144 context->server.computer);
1145 if (tevent_req_nomem(state->srv_name_slash, req)) {
1146 return tevent_req_post(req, ev);
1149 state->try_auth3 = true;
1150 state->try_auth2 = true;
1152 if (context->client.required_flags != 0) {
1153 state->require_auth2 = true;
1156 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1157 state->current_flags = context->client.proposed_flags;
1159 if (context->db.g_ctx != NULL) {
1160 struct tevent_req *subreq;
1162 subreq = g_lock_lock_send(state, ev,
1164 context->db.key_name,
1166 if (tevent_req_nomem(subreq, req)) {
1167 return tevent_req_post(req, ev);
1169 tevent_req_set_callback(subreq,
1170 netlogon_creds_cli_auth_locked,
1176 status = dbwrap_purge(state->context->db.ctx,
1177 state->context->db.key_data);
1178 if (tevent_req_nterror(req, status)) {
1179 return tevent_req_post(req, ev);
1182 netlogon_creds_cli_auth_challenge_start(req);
1183 if (!tevent_req_is_in_progress(req)) {
1184 return tevent_req_post(req, ev);
1190 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1192 struct tevent_req *req =
1193 tevent_req_callback_data(subreq,
1195 struct netlogon_creds_cli_auth_state *state =
1196 tevent_req_data(req,
1197 struct netlogon_creds_cli_auth_state);
1200 status = g_lock_lock_recv(subreq);
1201 TALLOC_FREE(subreq);
1202 if (tevent_req_nterror(req, status)) {
1205 state->locked_state->is_glocked = true;
1207 status = dbwrap_purge(state->context->db.ctx,
1208 state->context->db.key_data);
1209 if (tevent_req_nterror(req, status)) {
1213 netlogon_creds_cli_auth_challenge_start(req);
1216 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1218 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1220 struct netlogon_creds_cli_auth_state *state =
1221 tevent_req_data(req,
1222 struct netlogon_creds_cli_auth_state);
1223 struct tevent_req *subreq;
1225 TALLOC_FREE(state->creds);
1227 generate_random_buffer(state->client_challenge.data,
1228 sizeof(state->client_challenge.data));
1230 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1231 state->binding_handle,
1232 state->srv_name_slash,
1233 state->context->client.computer,
1234 &state->client_challenge,
1235 &state->server_challenge);
1236 if (tevent_req_nomem(subreq, req)) {
1239 tevent_req_set_callback(subreq,
1240 netlogon_creds_cli_auth_challenge_done,
1244 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1246 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1248 struct tevent_req *req =
1249 tevent_req_callback_data(subreq,
1251 struct netlogon_creds_cli_auth_state *state =
1252 tevent_req_data(req,
1253 struct netlogon_creds_cli_auth_state);
1257 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1258 TALLOC_FREE(subreq);
1259 if (tevent_req_nterror(req, status)) {
1262 if (tevent_req_nterror(req, result)) {
1266 if (!state->try_auth3 && !state->try_auth2) {
1267 state->current_flags = 0;
1270 /* Calculate the session key and client credentials */
1272 state->creds = netlogon_creds_client_init(state,
1273 state->context->client.account,
1274 state->context->client.computer,
1275 state->context->client.type,
1276 &state->client_challenge,
1277 &state->server_challenge,
1278 state->used_nt_hash,
1279 &state->client_credential,
1280 state->current_flags);
1281 if (tevent_req_nomem(state->creds, req)) {
1285 if (state->try_auth3) {
1286 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1287 state->binding_handle,
1288 state->srv_name_slash,
1289 state->context->client.account,
1290 state->context->client.type,
1291 state->context->client.computer,
1292 &state->client_credential,
1293 &state->server_credential,
1294 &state->creds->negotiate_flags,
1296 if (tevent_req_nomem(subreq, req)) {
1299 } else if (state->try_auth2) {
1302 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1303 state->binding_handle,
1304 state->srv_name_slash,
1305 state->context->client.account,
1306 state->context->client.type,
1307 state->context->client.computer,
1308 &state->client_credential,
1309 &state->server_credential,
1310 &state->creds->negotiate_flags);
1311 if (tevent_req_nomem(subreq, req)) {
1317 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1318 state->binding_handle,
1319 state->srv_name_slash,
1320 state->context->client.account,
1321 state->context->client.type,
1322 state->context->client.computer,
1323 &state->client_credential,
1324 &state->server_credential);
1325 if (tevent_req_nomem(subreq, req)) {
1329 tevent_req_set_callback(subreq,
1330 netlogon_creds_cli_auth_srvauth_done,
1334 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1336 struct tevent_req *req =
1337 tevent_req_callback_data(subreq,
1339 struct netlogon_creds_cli_auth_state *state =
1340 tevent_req_data(req,
1341 struct netlogon_creds_cli_auth_state);
1345 enum ndr_err_code ndr_err;
1350 if (state->try_auth3) {
1351 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1353 TALLOC_FREE(subreq);
1354 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1355 state->try_auth3 = false;
1356 netlogon_creds_cli_auth_challenge_start(req);
1359 if (tevent_req_nterror(req, status)) {
1362 } else if (state->try_auth2) {
1363 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1365 TALLOC_FREE(subreq);
1366 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1367 state->try_auth2 = false;
1368 if (state->require_auth2) {
1369 status = NT_STATUS_DOWNGRADE_DETECTED;
1370 tevent_req_nterror(req, status);
1373 netlogon_creds_cli_auth_challenge_start(req);
1376 if (tevent_req_nterror(req, status)) {
1380 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1382 TALLOC_FREE(subreq);
1383 if (tevent_req_nterror(req, status)) {
1388 if (!NT_STATUS_IS_OK(result) &&
1389 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1391 tevent_req_nterror(req, result);
1395 tmp_flags = state->creds->negotiate_flags;
1396 tmp_flags &= state->context->client.required_flags;
1397 if (tmp_flags != state->context->client.required_flags) {
1398 if (NT_STATUS_IS_OK(result)) {
1399 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1402 tevent_req_nterror(req, result);
1406 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1408 tmp_flags = state->context->client.proposed_flags;
1409 if ((state->current_flags == tmp_flags) &&
1410 (state->creds->negotiate_flags != tmp_flags))
1413 * lets retry with the negotiated flags
1415 state->current_flags = state->creds->negotiate_flags;
1416 netlogon_creds_cli_auth_challenge_start(req);
1420 state->idx_nt_hashes += 1;
1421 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1423 * we already retried, giving up...
1425 tevent_req_nterror(req, result);
1430 * lets retry with the old nt hash.
1432 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1433 state->current_flags = state->context->client.proposed_flags;
1434 netlogon_creds_cli_auth_challenge_start(req);
1438 ok = netlogon_creds_client_check(state->creds,
1439 &state->server_credential);
1441 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1445 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1446 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1447 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1448 status = ndr_map_error2ntstatus(ndr_err);
1449 tevent_req_nterror(req, status);
1453 data.dptr = blob.data;
1454 data.dsize = blob.length;
1456 status = dbwrap_store(state->context->db.ctx,
1457 state->context->db.key_data,
1459 TALLOC_FREE(state->locked_state);
1460 if (tevent_req_nterror(req, status)) {
1464 tevent_req_done(req);
1467 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1468 uint8_t *idx_nt_hashes)
1470 struct netlogon_creds_cli_auth_state *state =
1471 tevent_req_data(req,
1472 struct netlogon_creds_cli_auth_state);
1477 if (tevent_req_is_nterror(req, &status)) {
1478 tevent_req_received(req);
1482 *idx_nt_hashes = state->idx_nt_hashes;
1483 tevent_req_received(req);
1484 return NT_STATUS_OK;
1487 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1488 struct dcerpc_binding_handle *b,
1489 uint8_t num_nt_hashes,
1490 const struct samr_Password * const *nt_hashes,
1491 uint8_t *idx_nt_hashes)
1493 TALLOC_CTX *frame = talloc_stackframe();
1494 struct tevent_context *ev;
1495 struct tevent_req *req;
1496 NTSTATUS status = NT_STATUS_NO_MEMORY;
1500 ev = samba_tevent_context_init(frame);
1504 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1505 num_nt_hashes, nt_hashes);
1509 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1512 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1518 struct netlogon_creds_cli_check_state {
1519 struct tevent_context *ev;
1520 struct netlogon_creds_cli_context *context;
1521 struct dcerpc_binding_handle *binding_handle;
1523 char *srv_name_slash;
1525 union netr_Capabilities caps;
1527 struct netlogon_creds_CredentialState *creds;
1528 struct netr_Authenticator req_auth;
1529 struct netr_Authenticator rep_auth;
1532 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1534 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1536 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1537 struct tevent_context *ev,
1538 struct netlogon_creds_cli_context *context,
1539 struct dcerpc_binding_handle *b)
1541 struct tevent_req *req;
1542 struct netlogon_creds_cli_check_state *state;
1543 struct tevent_req *subreq;
1544 enum dcerpc_AuthType auth_type;
1545 enum dcerpc_AuthLevel auth_level;
1548 req = tevent_req_create(mem_ctx, &state,
1549 struct netlogon_creds_cli_check_state);
1555 state->context = context;
1556 state->binding_handle = b;
1558 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1559 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1560 return tevent_req_post(req, ev);
1563 status = netlogon_creds_cli_get_internal(context, state,
1565 if (tevent_req_nterror(req, status)) {
1566 return tevent_req_post(req, ev);
1569 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1570 context->server.computer);
1571 if (tevent_req_nomem(state->srv_name_slash, req)) {
1572 return tevent_req_post(req, ev);
1575 dcerpc_binding_handle_auth_info(state->binding_handle,
1576 &auth_type, &auth_level);
1578 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1579 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1580 return tevent_req_post(req, ev);
1583 switch (auth_level) {
1584 case DCERPC_AUTH_LEVEL_INTEGRITY:
1585 case DCERPC_AUTH_LEVEL_PRIVACY:
1588 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1589 return tevent_req_post(req, ev);
1593 * we defer all callbacks in order to cleanup
1594 * the database record.
1596 tevent_req_defer_callback(req, state->ev);
1598 netlogon_creds_client_authenticator(state->creds, &state->req_auth);
1599 ZERO_STRUCT(state->rep_auth);
1601 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1602 state->binding_handle,
1603 state->srv_name_slash,
1604 state->context->client.computer,
1609 if (tevent_req_nomem(subreq, req)) {
1610 return tevent_req_post(req, ev);
1613 tevent_req_set_callback(subreq,
1614 netlogon_creds_cli_check_caps,
1620 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1623 struct netlogon_creds_cli_check_state *state =
1624 tevent_req_data(req,
1625 struct netlogon_creds_cli_check_state);
1627 if (state->creds == NULL) {
1631 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1632 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1633 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1634 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1635 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1636 TALLOC_FREE(state->creds);
1640 netlogon_creds_cli_delete_lck(state->context);
1641 TALLOC_FREE(state->creds);
1644 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1646 struct tevent_req *req =
1647 tevent_req_callback_data(subreq,
1649 struct netlogon_creds_cli_check_state *state =
1650 tevent_req_data(req,
1651 struct netlogon_creds_cli_check_state);
1656 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1658 TALLOC_FREE(subreq);
1659 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1661 * Note that the negotiated flags are already checked
1662 * for our required flags after the ServerAuthenticate3/2 call.
1664 uint32_t negotiated = state->creds->negotiate_flags;
1666 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1668 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1669 * already, we expect this to work!
1671 status = NT_STATUS_DOWNGRADE_DETECTED;
1672 tevent_req_nterror(req, status);
1673 netlogon_creds_cli_check_cleanup(req, status);
1677 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1679 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1680 * we expect this to work at least as far as the
1681 * NOT_SUPPORTED error handled below!
1683 * NT 4.0 and Old Samba servers are not
1684 * allowed without "require strong key = no"
1686 status = NT_STATUS_DOWNGRADE_DETECTED;
1687 tevent_req_nterror(req, status);
1688 netlogon_creds_cli_check_cleanup(req, status);
1693 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1694 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1695 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1697 * This is needed against NT 4.0 and old Samba servers.
1699 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1700 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1701 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1702 * with the next request as the sequence number processing
1705 netlogon_creds_cli_check_cleanup(req, status);
1706 tevent_req_done(req);
1709 if (tevent_req_nterror(req, status)) {
1710 netlogon_creds_cli_check_cleanup(req, status);
1714 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1716 * Note that the negotiated flags are already checked
1717 * for our required flags after the ServerAuthenticate3/2 call.
1719 uint32_t negotiated = state->creds->negotiate_flags;
1721 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1723 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1724 * already, we expect this to work!
1726 status = NT_STATUS_DOWNGRADE_DETECTED;
1727 tevent_req_nterror(req, status);
1728 netlogon_creds_cli_check_cleanup(req, status);
1733 * This is ok, the server does not support
1734 * NETLOGON_NEG_SUPPORTS_AES.
1736 * netr_LogonGetCapabilities() was
1737 * netr_LogonDummyRoutine1() before
1738 * NETLOGON_NEG_SUPPORTS_AES was invented.
1740 netlogon_creds_cli_check_cleanup(req, result);
1741 tevent_req_done(req);
1745 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1747 status = NT_STATUS_ACCESS_DENIED;
1748 tevent_req_nterror(req, status);
1749 netlogon_creds_cli_check_cleanup(req, status);
1753 if (tevent_req_nterror(req, result)) {
1754 netlogon_creds_cli_check_cleanup(req, result);
1758 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1759 status = NT_STATUS_DOWNGRADE_DETECTED;
1760 tevent_req_nterror(req, status);
1761 netlogon_creds_cli_check_cleanup(req, status);
1766 * This is the key check that makes this check secure. If we
1767 * get OK here (rather than NOT_SUPPORTED), then the server
1768 * did support AES. If the server only proposed STRONG_KEYS
1769 * and not AES, then it should have failed with
1770 * NOT_IMPLEMENTED. We always send AES as a client, so the
1771 * server should always have returned it.
1773 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1774 status = NT_STATUS_DOWNGRADE_DETECTED;
1775 tevent_req_nterror(req, status);
1776 netlogon_creds_cli_check_cleanup(req, status);
1780 status = netlogon_creds_cli_store_internal(state->context,
1782 if (tevent_req_nterror(req, status)) {
1786 tevent_req_done(req);
1789 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1793 if (tevent_req_is_nterror(req, &status)) {
1794 netlogon_creds_cli_check_cleanup(req, status);
1795 tevent_req_received(req);
1799 tevent_req_received(req);
1800 return NT_STATUS_OK;
1803 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1804 struct dcerpc_binding_handle *b)
1806 TALLOC_CTX *frame = talloc_stackframe();
1807 struct tevent_context *ev;
1808 struct tevent_req *req;
1809 NTSTATUS status = NT_STATUS_NO_MEMORY;
1811 ev = samba_tevent_context_init(frame);
1815 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1819 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1822 status = netlogon_creds_cli_check_recv(req);
1828 struct netlogon_creds_cli_ServerPasswordSet_state {
1829 struct tevent_context *ev;
1830 struct netlogon_creds_cli_context *context;
1831 struct dcerpc_binding_handle *binding_handle;
1832 uint32_t old_timeout;
1834 char *srv_name_slash;
1835 enum dcerpc_AuthType auth_type;
1836 enum dcerpc_AuthLevel auth_level;
1838 struct samr_CryptPassword samr_crypt_password;
1839 struct netr_CryptPassword netr_crypt_password;
1840 struct samr_Password samr_password;
1842 struct netlogon_creds_CredentialState *creds;
1843 struct netlogon_creds_CredentialState tmp_creds;
1844 struct netr_Authenticator req_auth;
1845 struct netr_Authenticator rep_auth;
1848 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1850 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1852 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1853 struct tevent_context *ev,
1854 struct netlogon_creds_cli_context *context,
1855 struct dcerpc_binding_handle *b,
1856 const DATA_BLOB *new_password,
1857 const uint32_t *new_version)
1859 struct tevent_req *req;
1860 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1861 struct tevent_req *subreq;
1864 req = tevent_req_create(mem_ctx, &state,
1865 struct netlogon_creds_cli_ServerPasswordSet_state);
1871 state->context = context;
1872 state->binding_handle = b;
1874 if (new_password->length < 14) {
1875 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1876 return tevent_req_post(req, ev);
1880 * netr_ServerPasswordSet
1882 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1885 * netr_ServerPasswordSet2
1887 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1890 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1891 return tevent_req_post(req, ev);
1894 if (new_version != NULL) {
1895 struct NL_PASSWORD_VERSION version;
1896 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1897 uint32_t ofs = 512 - len;
1901 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1902 return tevent_req_post(req, ev);
1906 version.ReservedField = 0;
1907 version.PasswordVersionNumber = *new_version;
1908 version.PasswordVersionPresent =
1909 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1911 p = state->samr_crypt_password.data + ofs;
1912 SIVAL(p, 0, version.ReservedField);
1913 SIVAL(p, 4, version.PasswordVersionNumber);
1914 SIVAL(p, 8, version.PasswordVersionPresent);
1917 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1918 context->server.computer);
1919 if (tevent_req_nomem(state->srv_name_slash, req)) {
1920 return tevent_req_post(req, ev);
1923 dcerpc_binding_handle_auth_info(state->binding_handle,
1925 &state->auth_level);
1927 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1929 if (tevent_req_nomem(subreq, req)) {
1930 return tevent_req_post(req, ev);
1933 tevent_req_set_callback(subreq,
1934 netlogon_creds_cli_ServerPasswordSet_locked,
1940 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1943 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1944 tevent_req_data(req,
1945 struct netlogon_creds_cli_ServerPasswordSet_state);
1947 if (state->creds == NULL) {
1951 dcerpc_binding_handle_set_timeout(state->binding_handle,
1952 state->old_timeout);
1954 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1955 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1956 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1957 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1958 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1959 TALLOC_FREE(state->creds);
1963 netlogon_creds_cli_delete(state->context, state->creds);
1964 TALLOC_FREE(state->creds);
1967 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1969 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1971 struct tevent_req *req =
1972 tevent_req_callback_data(subreq,
1974 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1975 tevent_req_data(req,
1976 struct netlogon_creds_cli_ServerPasswordSet_state);
1979 status = netlogon_creds_cli_lock_recv(subreq, state,
1981 TALLOC_FREE(subreq);
1982 if (tevent_req_nterror(req, status)) {
1986 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1987 switch (state->auth_level) {
1988 case DCERPC_AUTH_LEVEL_INTEGRITY:
1989 case DCERPC_AUTH_LEVEL_PRIVACY:
1992 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1996 uint32_t tmp = state->creds->negotiate_flags;
1998 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2000 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2001 * it should be used, which means
2002 * we had a chance to verify no downgrade
2005 * This relies on netlogon_creds_cli_check*
2006 * being called before, as first request after
2009 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2014 state->old_timeout = dcerpc_binding_handle_set_timeout(
2015 state->binding_handle, 600000);
2018 * we defer all callbacks in order to cleanup
2019 * the database record.
2021 tevent_req_defer_callback(req, state->ev);
2023 state->tmp_creds = *state->creds;
2024 netlogon_creds_client_authenticator(&state->tmp_creds,
2026 ZERO_STRUCT(state->rep_auth);
2028 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2030 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
2031 netlogon_creds_aes_encrypt(&state->tmp_creds,
2032 state->samr_crypt_password.data,
2035 netlogon_creds_arcfour_crypt(&state->tmp_creds,
2036 state->samr_crypt_password.data,
2040 memcpy(state->netr_crypt_password.data,
2041 state->samr_crypt_password.data, 512);
2042 state->netr_crypt_password.length =
2043 IVAL(state->samr_crypt_password.data, 512);
2045 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2046 state->binding_handle,
2047 state->srv_name_slash,
2048 state->tmp_creds.account_name,
2049 state->tmp_creds.secure_channel_type,
2050 state->tmp_creds.computer_name,
2053 &state->netr_crypt_password);
2054 if (tevent_req_nomem(subreq, req)) {
2055 status = NT_STATUS_NO_MEMORY;
2056 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2060 netlogon_creds_des_encrypt(&state->tmp_creds,
2061 &state->samr_password);
2063 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2064 state->binding_handle,
2065 state->srv_name_slash,
2066 state->tmp_creds.account_name,
2067 state->tmp_creds.secure_channel_type,
2068 state->tmp_creds.computer_name,
2071 &state->samr_password);
2072 if (tevent_req_nomem(subreq, req)) {
2073 status = NT_STATUS_NO_MEMORY;
2074 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2079 tevent_req_set_callback(subreq,
2080 netlogon_creds_cli_ServerPasswordSet_done,
2084 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2086 struct tevent_req *req =
2087 tevent_req_callback_data(subreq,
2089 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2090 tevent_req_data(req,
2091 struct netlogon_creds_cli_ServerPasswordSet_state);
2096 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2097 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2099 TALLOC_FREE(subreq);
2100 if (tevent_req_nterror(req, status)) {
2101 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2105 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2107 TALLOC_FREE(subreq);
2108 if (tevent_req_nterror(req, status)) {
2109 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2114 ok = netlogon_creds_client_check(&state->tmp_creds,
2115 &state->rep_auth.cred);
2117 status = NT_STATUS_ACCESS_DENIED;
2118 tevent_req_nterror(req, status);
2119 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2123 if (tevent_req_nterror(req, result)) {
2124 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2128 dcerpc_binding_handle_set_timeout(state->binding_handle,
2129 state->old_timeout);
2131 *state->creds = state->tmp_creds;
2132 status = netlogon_creds_cli_store(state->context,
2134 TALLOC_FREE(state->creds);
2135 if (tevent_req_nterror(req, status)) {
2136 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2140 tevent_req_done(req);
2143 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2147 if (tevent_req_is_nterror(req, &status)) {
2148 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2149 tevent_req_received(req);
2153 tevent_req_received(req);
2154 return NT_STATUS_OK;
2157 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2158 struct netlogon_creds_cli_context *context,
2159 struct dcerpc_binding_handle *b,
2160 const DATA_BLOB *new_password,
2161 const uint32_t *new_version)
2163 TALLOC_CTX *frame = talloc_stackframe();
2164 struct tevent_context *ev;
2165 struct tevent_req *req;
2166 NTSTATUS status = NT_STATUS_NO_MEMORY;
2168 ev = samba_tevent_context_init(frame);
2172 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2178 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2181 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2187 struct netlogon_creds_cli_LogonSamLogon_state {
2188 struct tevent_context *ev;
2189 struct netlogon_creds_cli_context *context;
2190 struct dcerpc_binding_handle *binding_handle;
2192 char *srv_name_slash;
2194 enum netr_LogonInfoClass logon_level;
2195 const union netr_LogonLevel *const_logon;
2196 union netr_LogonLevel *logon;
2199 uint16_t validation_level;
2200 union netr_Validation *validation;
2201 uint8_t authoritative;
2204 * do we need encryption at the application layer?
2208 bool try_validation6;
2211 * the read only credentials before we started the operation
2212 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2214 struct netlogon_creds_CredentialState *ro_creds;
2217 * The (locked) credentials used for the credential chain
2218 * used for netr_LogonSamLogonWithFlags() or
2219 * netr_LogonSamLogonWith().
2221 struct netlogon_creds_CredentialState *lk_creds;
2224 * While we have locked the global credentials (lk_creds above)
2225 * we operate an a temporary copy, because a server
2226 * may not support netr_LogonSamLogonWithFlags() and
2227 * didn't process our netr_Authenticator, so we need to
2228 * restart from lk_creds.
2230 struct netlogon_creds_CredentialState tmp_creds;
2231 struct netr_Authenticator req_auth;
2232 struct netr_Authenticator rep_auth;
2235 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2236 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2239 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2240 struct tevent_context *ev,
2241 struct netlogon_creds_cli_context *context,
2242 struct dcerpc_binding_handle *b,
2243 enum netr_LogonInfoClass logon_level,
2244 const union netr_LogonLevel *logon,
2247 struct tevent_req *req;
2248 struct netlogon_creds_cli_LogonSamLogon_state *state;
2250 req = tevent_req_create(mem_ctx, &state,
2251 struct netlogon_creds_cli_LogonSamLogon_state);
2257 state->context = context;
2258 state->binding_handle = b;
2260 state->logon_level = logon_level;
2261 state->const_logon = logon;
2262 state->flags = flags;
2264 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2265 context->server.computer);
2266 if (tevent_req_nomem(state->srv_name_slash, req)) {
2267 return tevent_req_post(req, ev);
2270 switch (logon_level) {
2271 case NetlogonInteractiveInformation:
2272 case NetlogonInteractiveTransitiveInformation:
2273 case NetlogonServiceInformation:
2274 case NetlogonServiceTransitiveInformation:
2275 case NetlogonGenericInformation:
2276 state->user_encrypt = true;
2279 case NetlogonNetworkInformation:
2280 case NetlogonNetworkTransitiveInformation:
2284 state->validation = talloc_zero(state, union netr_Validation);
2285 if (tevent_req_nomem(state->validation, req)) {
2286 return tevent_req_post(req, ev);
2289 netlogon_creds_cli_LogonSamLogon_start(req);
2290 if (!tevent_req_is_in_progress(req)) {
2291 return tevent_req_post(req, ev);
2295 * we defer all callbacks in order to cleanup
2296 * the database record.
2298 tevent_req_defer_callback(req, state->ev);
2302 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2305 struct netlogon_creds_cli_LogonSamLogon_state *state =
2306 tevent_req_data(req,
2307 struct netlogon_creds_cli_LogonSamLogon_state);
2309 if (state->lk_creds == NULL) {
2313 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2315 * This is a hack to recover from a bug in old
2316 * Samba servers, when LogonSamLogonEx() fails:
2318 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2320 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2322 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2323 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2324 * If the sign/seal check fails.
2326 * In that case we need to cleanup the netlogon session.
2328 * It's the job of the caller to disconnect the current
2329 * connection, if netlogon_creds_cli_LogonSamLogon()
2330 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2332 if (!state->context->server.try_logon_with) {
2333 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2337 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2338 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2339 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2340 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2341 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2342 TALLOC_FREE(state->lk_creds);
2346 netlogon_creds_cli_delete(state->context, state->lk_creds);
2347 TALLOC_FREE(state->lk_creds);
2350 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2352 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2354 struct netlogon_creds_cli_LogonSamLogon_state *state =
2355 tevent_req_data(req,
2356 struct netlogon_creds_cli_LogonSamLogon_state);
2357 struct tevent_req *subreq;
2359 enum dcerpc_AuthType auth_type;
2360 enum dcerpc_AuthLevel auth_level;
2362 TALLOC_FREE(state->ro_creds);
2363 TALLOC_FREE(state->logon);
2364 ZERO_STRUCTP(state->validation);
2366 dcerpc_binding_handle_auth_info(state->binding_handle,
2367 &auth_type, &auth_level);
2369 state->try_logon_ex = state->context->server.try_logon_ex;
2370 state->try_validation6 = state->context->server.try_validation6;
2372 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2373 state->try_logon_ex = false;
2376 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2377 state->try_validation6 = false;
2380 if (state->try_logon_ex) {
2381 if (state->try_validation6) {
2382 state->validation_level = 6;
2384 state->validation_level = 3;
2385 state->user_encrypt = true;
2388 state->logon = netlogon_creds_shallow_copy_logon(state,
2390 state->const_logon);
2391 if (tevent_req_nomem(state->logon, req)) {
2392 status = NT_STATUS_NO_MEMORY;
2393 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2397 if (state->user_encrypt) {
2398 status = netlogon_creds_cli_get(state->context,
2401 if (!NT_STATUS_IS_OK(status)) {
2402 status = NT_STATUS_ACCESS_DENIED;
2403 tevent_req_nterror(req, status);
2404 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2408 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2413 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2414 state->binding_handle,
2415 state->srv_name_slash,
2416 state->context->client.computer,
2419 state->validation_level,
2421 &state->authoritative,
2423 if (tevent_req_nomem(subreq, req)) {
2424 status = NT_STATUS_NO_MEMORY;
2425 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2428 tevent_req_set_callback(subreq,
2429 netlogon_creds_cli_LogonSamLogon_done,
2434 if (state->lk_creds == NULL) {
2435 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2437 if (tevent_req_nomem(subreq, req)) {
2438 status = NT_STATUS_NO_MEMORY;
2439 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2442 tevent_req_set_callback(subreq,
2443 netlogon_creds_cli_LogonSamLogon_done,
2448 state->tmp_creds = *state->lk_creds;
2449 netlogon_creds_client_authenticator(&state->tmp_creds,
2451 ZERO_STRUCT(state->rep_auth);
2453 state->logon = netlogon_creds_shallow_copy_logon(state,
2455 state->const_logon);
2456 if (tevent_req_nomem(state->logon, req)) {
2457 status = NT_STATUS_NO_MEMORY;
2458 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2462 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2466 state->validation_level = 3;
2468 if (state->context->server.try_logon_with) {
2469 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2470 state->binding_handle,
2471 state->srv_name_slash,
2472 state->context->client.computer,
2477 state->validation_level,
2479 &state->authoritative,
2481 if (tevent_req_nomem(subreq, req)) {
2482 status = NT_STATUS_NO_MEMORY;
2483 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2489 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2490 state->binding_handle,
2491 state->srv_name_slash,
2492 state->context->client.computer,
2497 state->validation_level,
2499 &state->authoritative);
2500 if (tevent_req_nomem(subreq, req)) {
2501 status = NT_STATUS_NO_MEMORY;
2502 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2507 tevent_req_set_callback(subreq,
2508 netlogon_creds_cli_LogonSamLogon_done,
2512 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2514 struct tevent_req *req =
2515 tevent_req_callback_data(subreq,
2517 struct netlogon_creds_cli_LogonSamLogon_state *state =
2518 tevent_req_data(req,
2519 struct netlogon_creds_cli_LogonSamLogon_state);
2524 if (state->try_logon_ex) {
2525 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2528 TALLOC_FREE(subreq);
2529 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2530 state->context->server.try_validation6 = false;
2531 state->context->server.try_logon_ex = false;
2532 netlogon_creds_cli_LogonSamLogon_start(req);
2535 if (tevent_req_nterror(req, status)) {
2536 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2540 if ((state->validation_level == 6) &&
2541 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2542 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2543 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2545 state->context->server.try_validation6 = false;
2546 netlogon_creds_cli_LogonSamLogon_start(req);
2550 if (tevent_req_nterror(req, result)) {
2551 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2555 if (state->ro_creds == NULL) {
2556 tevent_req_done(req);
2560 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2563 * We got a race, lets retry with on authenticator
2566 * netlogon_creds_cli_LogonSamLogon_start()
2567 * will TALLOC_FREE(state->ro_creds);
2569 state->try_logon_ex = false;
2570 netlogon_creds_cli_LogonSamLogon_start(req);
2574 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2575 state->validation_level,
2578 tevent_req_done(req);
2582 if (state->lk_creds == NULL) {
2583 status = netlogon_creds_cli_lock_recv(subreq, state,
2585 TALLOC_FREE(subreq);
2586 if (tevent_req_nterror(req, status)) {
2587 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2591 netlogon_creds_cli_LogonSamLogon_start(req);
2595 if (state->context->server.try_logon_with) {
2596 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2599 TALLOC_FREE(subreq);
2600 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2601 state->context->server.try_logon_with = false;
2602 netlogon_creds_cli_LogonSamLogon_start(req);
2605 if (tevent_req_nterror(req, status)) {
2606 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2610 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2613 TALLOC_FREE(subreq);
2614 if (tevent_req_nterror(req, status)) {
2615 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2620 ok = netlogon_creds_client_check(&state->tmp_creds,
2621 &state->rep_auth.cred);
2623 status = NT_STATUS_ACCESS_DENIED;
2624 tevent_req_nterror(req, status);
2625 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2629 *state->lk_creds = state->tmp_creds;
2630 status = netlogon_creds_cli_store(state->context,
2632 TALLOC_FREE(state->lk_creds);
2634 if (tevent_req_nterror(req, status)) {
2635 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2639 if (tevent_req_nterror(req, result)) {
2640 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2644 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2645 state->validation_level,
2648 tevent_req_done(req);
2651 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2652 TALLOC_CTX *mem_ctx,
2653 uint16_t *validation_level,
2654 union netr_Validation **validation,
2655 uint8_t *authoritative,
2658 struct netlogon_creds_cli_LogonSamLogon_state *state =
2659 tevent_req_data(req,
2660 struct netlogon_creds_cli_LogonSamLogon_state);
2663 /* authoritative is also returned on error */
2664 *authoritative = state->authoritative;
2666 if (tevent_req_is_nterror(req, &status)) {
2667 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2668 tevent_req_received(req);
2672 *validation_level = state->validation_level;
2673 *validation = talloc_move(mem_ctx, &state->validation);
2674 *flags = state->flags;
2676 tevent_req_received(req);
2677 return NT_STATUS_OK;
2680 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2681 struct netlogon_creds_cli_context *context,
2682 struct dcerpc_binding_handle *b,
2683 enum netr_LogonInfoClass logon_level,
2684 const union netr_LogonLevel *logon,
2685 TALLOC_CTX *mem_ctx,
2686 uint16_t *validation_level,
2687 union netr_Validation **validation,
2688 uint8_t *authoritative,
2691 TALLOC_CTX *frame = talloc_stackframe();
2692 struct tevent_context *ev;
2693 struct tevent_req *req;
2694 NTSTATUS status = NT_STATUS_NO_MEMORY;
2696 ev = samba_tevent_context_init(frame);
2700 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2706 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2709 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2719 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2720 struct tevent_context *ev;
2721 struct netlogon_creds_cli_context *context;
2722 struct dcerpc_binding_handle *binding_handle;
2724 char *srv_name_slash;
2725 enum dcerpc_AuthType auth_type;
2726 enum dcerpc_AuthLevel auth_level;
2728 const char *site_name;
2730 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2732 struct netlogon_creds_CredentialState *creds;
2733 struct netlogon_creds_CredentialState tmp_creds;
2734 struct netr_Authenticator req_auth;
2735 struct netr_Authenticator rep_auth;
2738 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2740 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2742 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2743 struct tevent_context *ev,
2744 struct netlogon_creds_cli_context *context,
2745 struct dcerpc_binding_handle *b,
2746 const char *site_name,
2748 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2750 struct tevent_req *req;
2751 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2752 struct tevent_req *subreq;
2754 req = tevent_req_create(mem_ctx, &state,
2755 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2761 state->context = context;
2762 state->binding_handle = b;
2764 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2765 context->server.computer);
2766 if (tevent_req_nomem(state->srv_name_slash, req)) {
2767 return tevent_req_post(req, ev);
2770 state->site_name = site_name;
2771 state->dns_ttl = dns_ttl;
2772 state->dns_names = dns_names;
2774 dcerpc_binding_handle_auth_info(state->binding_handle,
2776 &state->auth_level);
2778 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2780 if (tevent_req_nomem(subreq, req)) {
2781 return tevent_req_post(req, ev);
2784 tevent_req_set_callback(subreq,
2785 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2791 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2794 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2795 tevent_req_data(req,
2796 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2798 if (state->creds == NULL) {
2802 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2803 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2804 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2805 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2806 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2807 TALLOC_FREE(state->creds);
2811 netlogon_creds_cli_delete(state->context, state->creds);
2812 TALLOC_FREE(state->creds);
2815 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2817 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2819 struct tevent_req *req =
2820 tevent_req_callback_data(subreq,
2822 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2823 tevent_req_data(req,
2824 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2827 status = netlogon_creds_cli_lock_recv(subreq, state,
2829 TALLOC_FREE(subreq);
2830 if (tevent_req_nterror(req, status)) {
2834 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2835 switch (state->auth_level) {
2836 case DCERPC_AUTH_LEVEL_INTEGRITY:
2837 case DCERPC_AUTH_LEVEL_PRIVACY:
2840 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2844 uint32_t tmp = state->creds->negotiate_flags;
2846 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2848 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2849 * it should be used, which means
2850 * we had a chance to verify no downgrade
2853 * This relies on netlogon_creds_cli_check*
2854 * being called before, as first request after
2857 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2863 * we defer all callbacks in order to cleanup
2864 * the database record.
2866 tevent_req_defer_callback(req, state->ev);
2868 state->tmp_creds = *state->creds;
2869 netlogon_creds_client_authenticator(&state->tmp_creds,
2871 ZERO_STRUCT(state->rep_auth);
2873 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2874 state->binding_handle,
2875 state->srv_name_slash,
2876 state->tmp_creds.computer_name,
2882 if (tevent_req_nomem(subreq, req)) {
2883 status = NT_STATUS_NO_MEMORY;
2884 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2888 tevent_req_set_callback(subreq,
2889 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2893 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2895 struct tevent_req *req =
2896 tevent_req_callback_data(subreq,
2898 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2899 tevent_req_data(req,
2900 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2906 * We use state->dns_names as the memory context, as this is
2907 * the only in/out variable and it has been overwritten by the
2908 * out parameter from the server.
2910 * We need to preserve the return value until the caller can use it.
2912 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2914 TALLOC_FREE(subreq);
2915 if (tevent_req_nterror(req, status)) {
2916 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2920 ok = netlogon_creds_client_check(&state->tmp_creds,
2921 &state->rep_auth.cred);
2923 status = NT_STATUS_ACCESS_DENIED;
2924 tevent_req_nterror(req, status);
2925 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2929 *state->creds = state->tmp_creds;
2930 status = netlogon_creds_cli_store(state->context,
2932 TALLOC_FREE(state->creds);
2934 if (tevent_req_nterror(req, status)) {
2935 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2939 if (tevent_req_nterror(req, result)) {
2940 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2944 tevent_req_done(req);
2947 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2951 if (tevent_req_is_nterror(req, &status)) {
2952 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2953 tevent_req_received(req);
2957 tevent_req_received(req);
2958 return NT_STATUS_OK;
2961 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2962 struct netlogon_creds_cli_context *context,
2963 struct dcerpc_binding_handle *b,
2964 const char *site_name,
2966 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2968 TALLOC_CTX *frame = talloc_stackframe();
2969 struct tevent_context *ev;
2970 struct tevent_req *req;
2971 NTSTATUS status = NT_STATUS_NO_MEMORY;
2973 ev = samba_tevent_context_init(frame);
2977 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2984 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2987 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2993 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2994 struct tevent_context *ev;
2995 struct netlogon_creds_cli_context *context;
2996 struct dcerpc_binding_handle *binding_handle;
2998 char *srv_name_slash;
2999 enum dcerpc_AuthType auth_type;
3000 enum dcerpc_AuthLevel auth_level;
3002 struct samr_Password new_owf_password;
3003 struct samr_Password old_owf_password;
3004 struct netr_TrustInfo *trust_info;
3006 struct netlogon_creds_CredentialState *creds;
3007 struct netlogon_creds_CredentialState tmp_creds;
3008 struct netr_Authenticator req_auth;
3009 struct netr_Authenticator rep_auth;
3012 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3014 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
3016 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
3017 struct tevent_context *ev,
3018 struct netlogon_creds_cli_context *context,
3019 struct dcerpc_binding_handle *b)
3021 struct tevent_req *req;
3022 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
3023 struct tevent_req *subreq;
3025 req = tevent_req_create(mem_ctx, &state,
3026 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3032 state->context = context;
3033 state->binding_handle = b;
3035 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3036 context->server.computer);
3037 if (tevent_req_nomem(state->srv_name_slash, req)) {
3038 return tevent_req_post(req, ev);
3041 dcerpc_binding_handle_auth_info(state->binding_handle,
3043 &state->auth_level);
3045 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3047 if (tevent_req_nomem(subreq, req)) {
3048 return tevent_req_post(req, ev);
3051 tevent_req_set_callback(subreq,
3052 netlogon_creds_cli_ServerGetTrustInfo_locked,
3058 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3061 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3062 tevent_req_data(req,
3063 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3065 if (state->creds == NULL) {
3069 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3070 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3071 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3072 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3073 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3074 TALLOC_FREE(state->creds);
3078 netlogon_creds_cli_delete(state->context, state->creds);
3079 TALLOC_FREE(state->creds);
3082 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3084 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3086 struct tevent_req *req =
3087 tevent_req_callback_data(subreq,
3089 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3090 tevent_req_data(req,
3091 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3094 status = netlogon_creds_cli_lock_recv(subreq, state,
3096 TALLOC_FREE(subreq);
3097 if (tevent_req_nterror(req, status)) {
3101 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3102 switch (state->auth_level) {
3103 case DCERPC_AUTH_LEVEL_PRIVACY:
3106 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3110 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3115 * we defer all callbacks in order to cleanup
3116 * the database record.
3118 tevent_req_defer_callback(req, state->ev);
3120 state->tmp_creds = *state->creds;
3121 netlogon_creds_client_authenticator(&state->tmp_creds,
3123 ZERO_STRUCT(state->rep_auth);
3125 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3126 state->binding_handle,
3127 state->srv_name_slash,
3128 state->tmp_creds.account_name,
3129 state->tmp_creds.secure_channel_type,
3130 state->tmp_creds.computer_name,
3133 &state->new_owf_password,
3134 &state->old_owf_password,
3135 &state->trust_info);
3136 if (tevent_req_nomem(subreq, req)) {
3137 status = NT_STATUS_NO_MEMORY;
3138 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3142 tevent_req_set_callback(subreq,
3143 netlogon_creds_cli_ServerGetTrustInfo_done,
3147 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3149 struct tevent_req *req =
3150 tevent_req_callback_data(subreq,
3152 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3153 tevent_req_data(req,
3154 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3157 const struct samr_Password zero = {};
3162 * We use state->dns_names as the memory context, as this is
3163 * the only in/out variable and it has been overwritten by the
3164 * out parameter from the server.
3166 * We need to preserve the return value until the caller can use it.
3168 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3169 TALLOC_FREE(subreq);
3170 if (tevent_req_nterror(req, status)) {
3171 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3175 ok = netlogon_creds_client_check(&state->tmp_creds,
3176 &state->rep_auth.cred);
3178 status = NT_STATUS_ACCESS_DENIED;
3179 tevent_req_nterror(req, status);
3180 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3184 cmp = memcmp(state->new_owf_password.hash,
3185 zero.hash, sizeof(zero.hash));
3187 netlogon_creds_des_decrypt(&state->tmp_creds,
3188 &state->new_owf_password);
3190 cmp = memcmp(state->old_owf_password.hash,
3191 zero.hash, sizeof(zero.hash));
3193 netlogon_creds_des_decrypt(&state->tmp_creds,
3194 &state->old_owf_password);
3197 *state->creds = state->tmp_creds;
3198 status = netlogon_creds_cli_store(state->context,
3200 TALLOC_FREE(state->creds);
3201 if (tevent_req_nterror(req, status)) {
3202 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3206 if (tevent_req_nterror(req, result)) {
3207 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3211 tevent_req_done(req);
3214 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3215 TALLOC_CTX *mem_ctx,
3216 struct samr_Password *new_owf_password,
3217 struct samr_Password *old_owf_password,
3218 struct netr_TrustInfo **trust_info)
3220 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3221 tevent_req_data(req,
3222 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3225 if (tevent_req_is_nterror(req, &status)) {
3226 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3227 tevent_req_received(req);
3231 if (new_owf_password != NULL) {
3232 *new_owf_password = state->new_owf_password;
3234 if (old_owf_password != NULL) {
3235 *old_owf_password = state->old_owf_password;
3237 if (trust_info != NULL) {
3238 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3241 tevent_req_received(req);
3242 return NT_STATUS_OK;
3245 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3246 struct netlogon_creds_cli_context *context,
3247 struct dcerpc_binding_handle *b,
3248 TALLOC_CTX *mem_ctx,
3249 struct samr_Password *new_owf_password,
3250 struct samr_Password *old_owf_password,
3251 struct netr_TrustInfo **trust_info)
3253 TALLOC_CTX *frame = talloc_stackframe();
3254 struct tevent_context *ev;
3255 struct tevent_req *req;
3256 NTSTATUS status = NT_STATUS_NO_MEMORY;
3258 ev = samba_tevent_context_init(frame);
3262 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3266 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3269 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3279 struct netlogon_creds_cli_GetForestTrustInformation_state {
3280 struct tevent_context *ev;
3281 struct netlogon_creds_cli_context *context;
3282 struct dcerpc_binding_handle *binding_handle;
3284 char *srv_name_slash;
3285 enum dcerpc_AuthType auth_type;
3286 enum dcerpc_AuthLevel auth_level;
3289 struct lsa_ForestTrustInformation *forest_trust_info;
3291 struct netlogon_creds_CredentialState *creds;
3292 struct netlogon_creds_CredentialState tmp_creds;
3293 struct netr_Authenticator req_auth;
3294 struct netr_Authenticator rep_auth;
3297 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3299 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3301 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3302 struct tevent_context *ev,
3303 struct netlogon_creds_cli_context *context,
3304 struct dcerpc_binding_handle *b)
3306 struct tevent_req *req;
3307 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3308 struct tevent_req *subreq;
3310 req = tevent_req_create(mem_ctx, &state,
3311 struct netlogon_creds_cli_GetForestTrustInformation_state);
3317 state->context = context;
3318 state->binding_handle = b;
3320 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3321 context->server.computer);
3322 if (tevent_req_nomem(state->srv_name_slash, req)) {
3323 return tevent_req_post(req, ev);
3328 dcerpc_binding_handle_auth_info(state->binding_handle,
3330 &state->auth_level);
3332 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3334 if (tevent_req_nomem(subreq, req)) {
3335 return tevent_req_post(req, ev);
3338 tevent_req_set_callback(subreq,
3339 netlogon_creds_cli_GetForestTrustInformation_locked,
3345 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3348 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3349 tevent_req_data(req,
3350 struct netlogon_creds_cli_GetForestTrustInformation_state);
3352 if (state->creds == NULL) {
3356 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3357 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3358 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3359 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3360 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3361 TALLOC_FREE(state->creds);
3365 netlogon_creds_cli_delete(state->context, state->creds);
3366 TALLOC_FREE(state->creds);
3369 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3371 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3373 struct tevent_req *req =
3374 tevent_req_callback_data(subreq,
3376 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3377 tevent_req_data(req,
3378 struct netlogon_creds_cli_GetForestTrustInformation_state);
3381 status = netlogon_creds_cli_lock_recv(subreq, state,
3383 TALLOC_FREE(subreq);
3384 if (tevent_req_nterror(req, status)) {
3388 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3389 switch (state->auth_level) {
3390 case DCERPC_AUTH_LEVEL_INTEGRITY:
3391 case DCERPC_AUTH_LEVEL_PRIVACY:
3394 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3398 uint32_t tmp = state->creds->negotiate_flags;
3400 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3402 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3403 * it should be used, which means
3404 * we had a chance to verify no downgrade
3407 * This relies on netlogon_creds_cli_check*
3408 * being called before, as first request after
3411 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3417 * we defer all callbacks in order to cleanup
3418 * the database record.
3420 tevent_req_defer_callback(req, state->ev);
3422 state->tmp_creds = *state->creds;
3423 netlogon_creds_client_authenticator(&state->tmp_creds,
3425 ZERO_STRUCT(state->rep_auth);
3427 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3428 state->binding_handle,
3429 state->srv_name_slash,
3430 state->tmp_creds.computer_name,
3434 &state->forest_trust_info);
3435 if (tevent_req_nomem(subreq, req)) {
3436 status = NT_STATUS_NO_MEMORY;
3437 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3441 tevent_req_set_callback(subreq,
3442 netlogon_creds_cli_GetForestTrustInformation_done,
3446 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3448 struct tevent_req *req =
3449 tevent_req_callback_data(subreq,
3451 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3452 tevent_req_data(req,
3453 struct netlogon_creds_cli_GetForestTrustInformation_state);
3459 * We use state->dns_names as the memory context, as this is
3460 * the only in/out variable and it has been overwritten by the
3461 * out parameter from the server.
3463 * We need to preserve the return value until the caller can use it.
3465 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3466 TALLOC_FREE(subreq);
3467 if (tevent_req_nterror(req, status)) {
3468 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3472 ok = netlogon_creds_client_check(&state->tmp_creds,
3473 &state->rep_auth.cred);
3475 status = NT_STATUS_ACCESS_DENIED;
3476 tevent_req_nterror(req, status);
3477 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3481 *state->creds = state->tmp_creds;
3482 status = netlogon_creds_cli_store(state->context,
3484 TALLOC_FREE(state->creds);
3486 if (tevent_req_nterror(req, status)) {
3487 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3491 if (tevent_req_nterror(req, result)) {
3492 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3496 tevent_req_done(req);
3499 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3500 TALLOC_CTX *mem_ctx,
3501 struct lsa_ForestTrustInformation **forest_trust_info)
3503 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3504 tevent_req_data(req,
3505 struct netlogon_creds_cli_GetForestTrustInformation_state);
3508 if (tevent_req_is_nterror(req, &status)) {
3509 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3510 tevent_req_received(req);
3514 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3516 tevent_req_received(req);
3517 return NT_STATUS_OK;
3520 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3521 struct netlogon_creds_cli_context *context,
3522 struct dcerpc_binding_handle *b,
3523 TALLOC_CTX *mem_ctx,
3524 struct lsa_ForestTrustInformation **forest_trust_info)
3526 TALLOC_CTX *frame = talloc_stackframe();
3527 struct tevent_context *ev;
3528 struct tevent_req *req;
3529 NTSTATUS status = NT_STATUS_NO_MEMORY;
3531 ev = samba_tevent_context_init(frame);
3535 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3539 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3542 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3550 struct netlogon_creds_cli_SendToSam_state {
3551 struct tevent_context *ev;
3552 struct netlogon_creds_cli_context *context;
3553 struct dcerpc_binding_handle *binding_handle;
3555 char *srv_name_slash;
3556 enum dcerpc_AuthType auth_type;
3557 enum dcerpc_AuthLevel auth_level;
3561 struct netlogon_creds_CredentialState *creds;
3562 struct netlogon_creds_CredentialState tmp_creds;
3563 struct netr_Authenticator req_auth;
3564 struct netr_Authenticator rep_auth;
3567 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3569 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3571 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3572 struct tevent_context *ev,
3573 struct netlogon_creds_cli_context *context,
3574 struct dcerpc_binding_handle *b,
3575 struct netr_SendToSamBase *message)
3577 struct tevent_req *req;
3578 struct netlogon_creds_cli_SendToSam_state *state;
3579 struct tevent_req *subreq;
3580 enum ndr_err_code ndr_err;
3582 req = tevent_req_create(mem_ctx, &state,
3583 struct netlogon_creds_cli_SendToSam_state);
3589 state->context = context;
3590 state->binding_handle = b;
3592 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3593 context->server.computer);
3594 if (tevent_req_nomem(state->srv_name_slash, req)) {
3595 return tevent_req_post(req, ev);
3598 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3599 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3600 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3601 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3602 tevent_req_nterror(req, status);
3603 return tevent_req_post(req, ev);
3606 dcerpc_binding_handle_auth_info(state->binding_handle,
3608 &state->auth_level);
3610 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3612 if (tevent_req_nomem(subreq, req)) {
3613 return tevent_req_post(req, ev);
3616 tevent_req_set_callback(subreq,
3617 netlogon_creds_cli_SendToSam_locked,
3623 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3626 struct netlogon_creds_cli_SendToSam_state *state =
3627 tevent_req_data(req,
3628 struct netlogon_creds_cli_SendToSam_state);
3630 if (state->creds == NULL) {
3634 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3635 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3636 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3637 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3638 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3639 TALLOC_FREE(state->creds);
3643 netlogon_creds_cli_delete(state->context, state->creds);
3644 TALLOC_FREE(state->creds);
3647 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3649 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3651 struct tevent_req *req =
3652 tevent_req_callback_data(subreq,
3654 struct netlogon_creds_cli_SendToSam_state *state =
3655 tevent_req_data(req,
3656 struct netlogon_creds_cli_SendToSam_state);
3659 status = netlogon_creds_cli_lock_recv(subreq, state,
3661 TALLOC_FREE(subreq);
3662 if (tevent_req_nterror(req, status)) {
3666 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3667 switch (state->auth_level) {
3668 case DCERPC_AUTH_LEVEL_INTEGRITY:
3669 case DCERPC_AUTH_LEVEL_PRIVACY:
3672 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3676 uint32_t tmp = state->creds->negotiate_flags;
3678 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3680 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3681 * it should be used, which means
3682 * we had a chance to verify no downgrade
3685 * This relies on netlogon_creds_cli_check*
3686 * being called before, as first request after
3689 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3695 * we defer all callbacks in order to cleanup
3696 * the database record.
3698 tevent_req_defer_callback(req, state->ev);
3700 state->tmp_creds = *state->creds;
3701 netlogon_creds_client_authenticator(&state->tmp_creds,
3703 ZERO_STRUCT(state->rep_auth);
3705 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3706 netlogon_creds_aes_encrypt(&state->tmp_creds,
3708 state->opaque.length);
3710 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3712 state->opaque.length);
3715 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3716 state->binding_handle,
3717 state->srv_name_slash,
3718 state->tmp_creds.computer_name,
3722 state->opaque.length);
3723 if (tevent_req_nomem(subreq, req)) {
3724 status = NT_STATUS_NO_MEMORY;
3725 netlogon_creds_cli_SendToSam_cleanup(req, status);
3729 tevent_req_set_callback(subreq,
3730 netlogon_creds_cli_SendToSam_done,
3734 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3736 struct tevent_req *req =
3737 tevent_req_callback_data(subreq,
3739 struct netlogon_creds_cli_SendToSam_state *state =
3740 tevent_req_data(req,
3741 struct netlogon_creds_cli_SendToSam_state);
3746 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3747 TALLOC_FREE(subreq);
3748 if (tevent_req_nterror(req, status)) {
3749 netlogon_creds_cli_SendToSam_cleanup(req, status);
3753 ok = netlogon_creds_client_check(&state->tmp_creds,
3754 &state->rep_auth.cred);
3756 status = NT_STATUS_ACCESS_DENIED;
3757 tevent_req_nterror(req, status);
3758 netlogon_creds_cli_SendToSam_cleanup(req, status);
3762 *state->creds = state->tmp_creds;
3763 status = netlogon_creds_cli_store(state->context,
3765 TALLOC_FREE(state->creds);
3767 if (tevent_req_nterror(req, status)) {
3768 netlogon_creds_cli_SendToSam_cleanup(req, status);
3773 * Creds must be stored before we send back application errors
3774 * e.g. NT_STATUS_NOT_IMPLEMENTED
3776 if (tevent_req_nterror(req, result)) {
3777 netlogon_creds_cli_SendToSam_cleanup(req, result);
3781 tevent_req_done(req);
3784 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3785 struct dcerpc_binding_handle *b,
3786 struct netr_SendToSamBase *message)
3788 TALLOC_CTX *frame = talloc_stackframe();
3789 struct tevent_context *ev;
3790 struct tevent_req *req;
3791 NTSTATUS status = NT_STATUS_OK;
3793 ev = samba_tevent_context_init(frame);
3797 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3801 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3805 /* Ignore the result */