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"
42 struct netlogon_creds_cli_locked_state;
44 struct netlogon_creds_cli_context {
48 uint32_t proposed_flags;
49 uint32_t required_flags;
50 enum netr_SchannelType type;
51 enum dcerpc_AuthLevel auth_level;
56 const char *netbios_domain;
57 uint32_t cached_flags;
66 struct db_context *ctx;
67 struct g_lock_ctx *g_ctx;
68 struct netlogon_creds_cli_locked_state *locked_state;
72 struct netlogon_creds_cli_locked_state {
73 struct netlogon_creds_cli_context *context;
75 struct netlogon_creds_CredentialState *creds;
78 static int netlogon_creds_cli_locked_state_destructor(
79 struct netlogon_creds_cli_locked_state *state)
81 struct netlogon_creds_cli_context *context = state->context;
83 if (context == NULL) {
87 if (context->db.locked_state == state) {
88 context->db.locked_state = NULL;
91 if (state->is_glocked) {
92 g_lock_unlock(context->db.g_ctx,
93 context->db.key_name);
99 static NTSTATUS netlogon_creds_cli_context_common(
100 const char *client_computer,
101 const char *client_account,
102 enum netr_SchannelType type,
103 enum dcerpc_AuthLevel auth_level,
104 uint32_t proposed_flags,
105 uint32_t required_flags,
106 const char *server_computer,
107 const char *server_netbios_domain,
109 struct netlogon_creds_cli_context **_context)
111 struct netlogon_creds_cli_context *context = NULL;
112 TALLOC_CTX *frame = talloc_stackframe();
113 char *_key_name = NULL;
114 char *server_netbios_name = NULL;
119 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
120 if (context == NULL) {
122 return NT_STATUS_NO_MEMORY;
125 context->client.computer = talloc_strdup(context, client_computer);
126 if (context->client.computer == NULL) {
127 TALLOC_FREE(context);
129 return NT_STATUS_NO_MEMORY;
132 context->client.account = talloc_strdup(context, client_account);
133 if (context->client.account == NULL) {
134 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);
148 return NT_STATUS_NO_MEMORY;
151 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
152 if (context->server.netbios_domain == NULL) {
153 TALLOC_FREE(context);
155 return NT_STATUS_NO_MEMORY;
160 * Force the callers to provide a unique
161 * value for server_computer and use this directly.
163 * For now we have to deal with
164 * "HOSTNAME" vs. "hostname.example.com".
166 server_netbios_name = talloc_strdup(frame, server_computer);
167 if (server_netbios_name == NULL) {
168 TALLOC_FREE(context);
170 return NT_STATUS_NO_MEMORY;
173 p = strchr(server_netbios_name, '.');
178 _key_name = talloc_asprintf(frame, "CLI[%s/%s]/SRV[%s/%s]",
182 server_netbios_domain);
183 if (_key_name == NULL) {
184 TALLOC_FREE(context);
186 return NT_STATUS_NO_MEMORY;
189 context->db.key_name = talloc_strdup_upper(context, _key_name);
190 if (context->db.key_name == NULL) {
191 TALLOC_FREE(context);
193 return NT_STATUS_NO_MEMORY;
196 context->db.key_data = string_term_tdb_data(context->db.key_name);
203 static struct db_context *netlogon_creds_cli_global_db;
205 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
207 if (netlogon_creds_cli_global_db != NULL) {
208 return NT_STATUS_INVALID_PARAMETER_MIX;
211 netlogon_creds_cli_global_db = talloc_move(NULL, db);
215 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
218 struct db_context *global_db;
220 if (netlogon_creds_cli_global_db != NULL) {
224 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
226 return NT_STATUS_NO_MEMORY;
229 global_db = dbwrap_local_open(NULL, lp_ctx,
231 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
233 0600, DBWRAP_LOCK_ORDER_2,
235 if (global_db == NULL) {
236 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
237 fname, strerror(errno)));
239 return NT_STATUS_NO_MEMORY;
243 netlogon_creds_cli_global_db = global_db;
247 void netlogon_creds_cli_close_global_db(void)
249 TALLOC_FREE(netlogon_creds_cli_global_db);
252 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
253 struct messaging_context *msg_ctx,
254 const char *client_account,
255 enum netr_SchannelType type,
256 const char *server_computer,
257 const char *server_netbios_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 client_computer = lpcfg_netbios_name(lp_ctx);
277 if (strlen(client_computer) > 15) {
278 return NT_STATUS_INVALID_PARAMETER_MIX;
282 * allow overwrite per domain
283 * reject md5 servers:<netbios_domain>
285 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
286 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
287 "reject md5 servers",
288 server_netbios_domain,
292 * allow overwrite per domain
293 * require strong key:<netbios_domain>
295 require_strong_key = lpcfg_require_strong_key(lp_ctx);
296 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
297 "require strong key",
298 server_netbios_domain,
302 * allow overwrite per domain
303 * client schannel:<netbios_domain>
305 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
306 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
308 server_netbios_domain,
309 require_sign_or_seal);
312 * allow overwrite per domain
313 * winbind sealed pipes:<netbios_domain>
315 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
316 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
317 "winbind sealed pipes",
318 server_netbios_domain,
319 seal_secure_channel);
322 * allow overwrite per domain
323 * neutralize nt4 emulation:<netbios_domain>
325 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
326 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
327 "neutralize nt4 emulation",
328 server_netbios_domain,
329 neutralize_nt4_emulation);
331 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
332 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
336 if (lpcfg_security(lp_ctx) == SEC_ADS) {
338 * AD domains should be secure
340 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
341 require_sign_or_seal = true;
342 require_strong_key = true;
346 case SEC_CHAN_DOMAIN:
349 case SEC_CHAN_DNS_DOMAIN:
351 * AD domains should be secure
353 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
354 require_sign_or_seal = true;
355 require_strong_key = true;
356 neutralize_nt4_emulation = true;
360 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
361 require_sign_or_seal = true;
362 require_strong_key = true;
366 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
367 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
368 require_sign_or_seal = true;
369 require_strong_key = true;
370 neutralize_nt4_emulation = true;
375 return NT_STATUS_INVALID_PARAMETER;
378 if (neutralize_nt4_emulation) {
379 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
382 if (require_sign_or_seal == false) {
383 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
385 required_flags |= NETLOGON_NEG_ARCFOUR;
386 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
389 if (reject_md5_servers) {
390 required_flags |= NETLOGON_NEG_ARCFOUR;
391 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
392 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
393 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
396 if (require_strong_key) {
397 required_flags |= NETLOGON_NEG_ARCFOUR;
398 required_flags |= NETLOGON_NEG_STRONG_KEYS;
399 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
402 proposed_flags |= required_flags;
404 if (seal_secure_channel) {
405 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
407 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
410 status = netlogon_creds_cli_context_common(client_computer,
417 server_netbios_domain,
420 if (!NT_STATUS_IS_OK(status)) {
425 if (msg_ctx != NULL) {
426 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
427 if (context->db.g_ctx == NULL) {
428 TALLOC_FREE(context);
430 return NT_STATUS_NO_MEMORY;
434 if (netlogon_creds_cli_global_db != NULL) {
435 context->db.ctx = netlogon_creds_cli_global_db;
441 status = netlogon_creds_cli_open_global_db(lp_ctx);
442 if (!NT_STATUS_IS_OK(status)) {
443 TALLOC_FREE(context);
445 return NT_STATUS_NO_MEMORY;
448 context->db.ctx = netlogon_creds_cli_global_db;
454 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
455 const char *client_account,
456 enum netr_SchannelType type,
457 uint32_t proposed_flags,
458 uint32_t required_flags,
459 enum dcerpc_AuthLevel auth_level,
460 const char *server_computer,
461 const char *server_netbios_domain,
463 struct netlogon_creds_cli_context **_context)
466 struct netlogon_creds_cli_context *context = NULL;
470 status = netlogon_creds_cli_context_common(client_computer,
477 server_netbios_domain,
480 if (!NT_STATUS_IS_OK(status)) {
484 context->db.ctx = db_open_rbt(context);
485 if (context->db.ctx == NULL) {
486 talloc_free(context);
487 return NT_STATUS_NO_MEMORY;
494 char *netlogon_creds_cli_debug_string(
495 const struct netlogon_creds_cli_context *context,
498 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
499 context->db.key_name);
502 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
503 struct netlogon_creds_cli_context *context)
505 return context->client.auth_level;
508 struct netlogon_creds_cli_fetch_state {
510 struct netlogon_creds_CredentialState *creds;
511 uint32_t required_flags;
515 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
518 struct netlogon_creds_cli_fetch_state *state =
519 (struct netlogon_creds_cli_fetch_state *)private_data;
520 enum ndr_err_code ndr_err;
524 state->creds = talloc_zero(state->mem_ctx,
525 struct netlogon_creds_CredentialState);
526 if (state->creds == NULL) {
527 state->status = NT_STATUS_NO_MEMORY;
531 blob.data = data.dptr;
532 blob.length = data.dsize;
534 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
535 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
536 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
537 TALLOC_FREE(state->creds);
538 state->status = ndr_map_error2ntstatus(ndr_err);
542 tmp_flags = state->creds->negotiate_flags;
543 tmp_flags &= state->required_flags;
544 if (tmp_flags != state->required_flags) {
545 TALLOC_FREE(state->creds);
546 state->status = NT_STATUS_DOWNGRADE_DETECTED;
550 state->status = NT_STATUS_OK;
553 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
555 struct netlogon_creds_CredentialState **_creds)
558 struct netlogon_creds_cli_fetch_state fstate = {
560 .status = NT_STATUS_INTERNAL_ERROR,
561 .required_flags = context->client.required_flags,
563 static const struct netr_Credential zero_creds;
567 status = dbwrap_parse_record(context->db.ctx,
568 context->db.key_data,
569 netlogon_creds_cli_fetch_parser,
571 if (!NT_STATUS_IS_OK(status)) {
574 status = fstate.status;
575 if (!NT_STATUS_IS_OK(status)) {
580 * mark it as invalid for step operations.
582 fstate.creds->sequence = 0;
583 fstate.creds->seed = zero_creds;
584 fstate.creds->client = zero_creds;
585 fstate.creds->server = zero_creds;
587 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
588 *_creds = fstate.creds;
593 * It is really important to try SamLogonEx here,
594 * because multiple processes can talk to the same
595 * domain controller, without using the credential
598 * With a normal SamLogon call, we must keep the
599 * credentials chain updated and intact between all
600 * users of the machine account (which would imply
601 * cross-node communication for every NTLM logon).
603 * The credentials chain is not per NETLOGON pipe
604 * connection, but globally on the server/client pair
605 * by computer name, while the client is free to use
606 * any computer name. We include the cluster node number
607 * in our computer name in order to avoid cross node
608 * coordination of the credential chain.
610 * It's also important to use NetlogonValidationSamInfo4 (6),
611 * because it relies on the rpc transport encryption
612 * and avoids using the global netlogon schannel
613 * session key to en/decrypt secret information
614 * like the user_session_key for network logons.
616 * [MS-APDS] 3.1.5.2 NTLM Network Logon
617 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
618 * NETLOGON_NEG_AUTHENTICATED_RPC set together
619 * are the indication that the server supports
620 * NetlogonValidationSamInfo4 (6). And it must only
621 * be used if "SealSecureChannel" is used.
623 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
624 * check is done in netlogon_creds_cli_LogonSamLogon*().
626 context->server.cached_flags = fstate.creds->negotiate_flags;
627 context->server.try_validation6 = true;
628 context->server.try_logon_ex = true;
629 context->server.try_logon_with = true;
631 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
632 context->server.try_validation6 = false;
633 context->server.try_logon_ex = false;
635 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
636 context->server.try_validation6 = false;
639 *_creds = fstate.creds;
643 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
644 const struct netlogon_creds_CredentialState *creds1)
646 TALLOC_CTX *frame = talloc_stackframe();
647 struct netlogon_creds_CredentialState *creds2;
651 enum ndr_err_code ndr_err;
654 status = netlogon_creds_cli_get(context, frame, &creds2);
655 if (!NT_STATUS_IS_OK(status)) {
660 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
661 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
662 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
667 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
668 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
669 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
674 if (blob1.length != blob2.length) {
679 cmp = memcmp(blob1.data, blob2.data, blob1.length);
689 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
690 struct netlogon_creds_CredentialState **_creds)
692 struct netlogon_creds_CredentialState *creds = *_creds;
694 enum ndr_err_code ndr_err;
700 if (context->db.locked_state == NULL) {
702 * this was not the result of netlogon_creds_cli_lock*()
705 return NT_STATUS_INVALID_PAGE_PROTECTION;
708 if (context->db.locked_state->creds != creds) {
710 * this was not the result of netlogon_creds_cli_lock*()
713 return NT_STATUS_INVALID_PAGE_PROTECTION;
716 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
717 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
718 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
720 status = ndr_map_error2ntstatus(ndr_err);
724 data.dptr = blob.data;
725 data.dsize = blob.length;
727 status = dbwrap_store(context->db.ctx,
728 context->db.key_data,
731 if (!NT_STATUS_IS_OK(status)) {
738 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
739 struct netlogon_creds_CredentialState **_creds)
741 struct netlogon_creds_CredentialState *creds = *_creds;
746 if (context->db.locked_state == NULL) {
748 * this was not the result of netlogon_creds_cli_lock*()
751 return NT_STATUS_INVALID_PAGE_PROTECTION;
754 if (context->db.locked_state->creds != creds) {
756 * this was not the result of netlogon_creds_cli_lock*()
759 return NT_STATUS_INVALID_PAGE_PROTECTION;
762 status = dbwrap_delete(context->db.ctx,
763 context->db.key_data);
765 if (!NT_STATUS_IS_OK(status)) {
772 struct netlogon_creds_cli_lock_state {
773 struct netlogon_creds_cli_locked_state *locked_state;
774 struct netlogon_creds_CredentialState *creds;
777 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
778 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
780 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
781 struct tevent_context *ev,
782 struct netlogon_creds_cli_context *context)
784 struct tevent_req *req;
785 struct netlogon_creds_cli_lock_state *state;
786 struct netlogon_creds_cli_locked_state *locked_state;
787 struct tevent_req *subreq;
789 req = tevent_req_create(mem_ctx, &state,
790 struct netlogon_creds_cli_lock_state);
795 if (context->db.locked_state != NULL) {
796 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
797 return tevent_req_post(req, ev);
800 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
801 if (tevent_req_nomem(locked_state, req)) {
802 return tevent_req_post(req, ev);
804 talloc_set_destructor(locked_state,
805 netlogon_creds_cli_locked_state_destructor);
806 locked_state->context = context;
808 context->db.locked_state = locked_state;
809 state->locked_state = locked_state;
811 if (context->db.g_ctx == NULL) {
812 netlogon_creds_cli_lock_fetch(req);
813 if (!tevent_req_is_in_progress(req)) {
814 return tevent_req_post(req, ev);
820 subreq = g_lock_lock_send(state, ev,
822 context->db.key_name,
824 if (tevent_req_nomem(subreq, req)) {
825 return tevent_req_post(req, ev);
827 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
832 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
834 struct tevent_req *req =
835 tevent_req_callback_data(subreq,
837 struct netlogon_creds_cli_lock_state *state =
839 struct netlogon_creds_cli_lock_state);
842 status = g_lock_lock_recv(subreq);
844 if (tevent_req_nterror(req, status)) {
847 state->locked_state->is_glocked = true;
849 netlogon_creds_cli_lock_fetch(req);
852 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
854 struct netlogon_creds_cli_lock_state *state =
856 struct netlogon_creds_cli_lock_state);
857 struct netlogon_creds_cli_context *context = state->locked_state->context;
858 struct netlogon_creds_cli_fetch_state fstate = {
859 .status = NT_STATUS_INTERNAL_ERROR,
860 .required_flags = context->client.required_flags,
864 fstate.mem_ctx = state;
865 status = dbwrap_parse_record(context->db.ctx,
866 context->db.key_data,
867 netlogon_creds_cli_fetch_parser,
869 if (tevent_req_nterror(req, status)) {
872 status = fstate.status;
873 if (tevent_req_nterror(req, status)) {
877 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
878 state->creds = fstate.creds;
879 tevent_req_done(req);
883 context->server.cached_flags = fstate.creds->negotiate_flags;
884 context->server.try_validation6 = true;
885 context->server.try_logon_ex = true;
886 context->server.try_logon_with = true;
888 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
889 context->server.try_validation6 = false;
890 context->server.try_logon_ex = false;
892 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
893 context->server.try_validation6 = false;
896 state->creds = fstate.creds;
897 tevent_req_done(req);
901 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
903 struct netlogon_creds_CredentialState **creds)
905 struct netlogon_creds_cli_lock_state *state =
907 struct netlogon_creds_cli_lock_state);
910 if (tevent_req_is_nterror(req, &status)) {
911 tevent_req_received(req);
915 talloc_steal(state->creds, state->locked_state);
916 state->locked_state->creds = state->creds;
917 *creds = talloc_move(mem_ctx, &state->creds);
918 tevent_req_received(req);
922 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
924 struct netlogon_creds_CredentialState **creds)
926 TALLOC_CTX *frame = talloc_stackframe();
927 struct tevent_context *ev;
928 struct tevent_req *req;
929 NTSTATUS status = NT_STATUS_NO_MEMORY;
931 ev = samba_tevent_context_init(frame);
935 req = netlogon_creds_cli_lock_send(frame, ev, context);
939 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
942 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
948 struct netlogon_creds_cli_auth_state {
949 struct tevent_context *ev;
950 struct netlogon_creds_cli_context *context;
951 struct dcerpc_binding_handle *binding_handle;
952 uint8_t num_nt_hashes;
953 uint8_t idx_nt_hashes;
954 const struct samr_Password * const *nt_hashes;
955 const struct samr_Password *used_nt_hash;
956 char *srv_name_slash;
957 uint32_t current_flags;
958 struct netr_Credential client_challenge;
959 struct netr_Credential server_challenge;
960 struct netlogon_creds_CredentialState *creds;
961 struct netr_Credential client_credential;
962 struct netr_Credential server_credential;
967 struct netlogon_creds_cli_locked_state *locked_state;
970 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
971 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
973 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
974 struct tevent_context *ev,
975 struct netlogon_creds_cli_context *context,
976 struct dcerpc_binding_handle *b,
977 uint8_t num_nt_hashes,
978 const struct samr_Password * const *nt_hashes)
980 struct tevent_req *req;
981 struct netlogon_creds_cli_auth_state *state;
982 struct netlogon_creds_cli_locked_state *locked_state;
985 req = tevent_req_create(mem_ctx, &state,
986 struct netlogon_creds_cli_auth_state);
992 state->context = context;
993 state->binding_handle = b;
994 if (num_nt_hashes < 1) {
995 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
996 return tevent_req_post(req, ev);
998 if (num_nt_hashes > 4) {
999 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1000 return tevent_req_post(req, ev);
1003 state->num_nt_hashes = num_nt_hashes;
1004 state->idx_nt_hashes = 0;
1005 state->nt_hashes = nt_hashes;
1007 if (context->db.locked_state != NULL) {
1008 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
1009 return tevent_req_post(req, ev);
1012 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
1013 if (tevent_req_nomem(locked_state, req)) {
1014 return tevent_req_post(req, ev);
1016 talloc_set_destructor(locked_state,
1017 netlogon_creds_cli_locked_state_destructor);
1018 locked_state->context = context;
1020 context->db.locked_state = locked_state;
1021 state->locked_state = locked_state;
1023 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1024 context->server.computer);
1025 if (tevent_req_nomem(state->srv_name_slash, req)) {
1026 return tevent_req_post(req, ev);
1029 state->try_auth3 = true;
1030 state->try_auth2 = true;
1032 if (context->client.required_flags != 0) {
1033 state->require_auth2 = true;
1036 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1037 state->current_flags = context->client.proposed_flags;
1039 if (context->db.g_ctx != NULL) {
1040 struct tevent_req *subreq;
1042 subreq = g_lock_lock_send(state, ev,
1044 context->db.key_name,
1046 if (tevent_req_nomem(subreq, req)) {
1047 return tevent_req_post(req, ev);
1049 tevent_req_set_callback(subreq,
1050 netlogon_creds_cli_auth_locked,
1056 status = dbwrap_purge(state->context->db.ctx,
1057 state->context->db.key_data);
1058 if (tevent_req_nterror(req, status)) {
1059 return tevent_req_post(req, ev);
1062 netlogon_creds_cli_auth_challenge_start(req);
1063 if (!tevent_req_is_in_progress(req)) {
1064 return tevent_req_post(req, ev);
1070 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1072 struct tevent_req *req =
1073 tevent_req_callback_data(subreq,
1075 struct netlogon_creds_cli_auth_state *state =
1076 tevent_req_data(req,
1077 struct netlogon_creds_cli_auth_state);
1080 status = g_lock_lock_recv(subreq);
1081 TALLOC_FREE(subreq);
1082 if (tevent_req_nterror(req, status)) {
1085 state->locked_state->is_glocked = true;
1087 status = dbwrap_purge(state->context->db.ctx,
1088 state->context->db.key_data);
1089 if (tevent_req_nterror(req, status)) {
1093 netlogon_creds_cli_auth_challenge_start(req);
1096 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1098 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1100 struct netlogon_creds_cli_auth_state *state =
1101 tevent_req_data(req,
1102 struct netlogon_creds_cli_auth_state);
1103 struct tevent_req *subreq;
1105 TALLOC_FREE(state->creds);
1107 generate_random_buffer(state->client_challenge.data,
1108 sizeof(state->client_challenge.data));
1110 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1111 state->binding_handle,
1112 state->srv_name_slash,
1113 state->context->client.computer,
1114 &state->client_challenge,
1115 &state->server_challenge);
1116 if (tevent_req_nomem(subreq, req)) {
1119 tevent_req_set_callback(subreq,
1120 netlogon_creds_cli_auth_challenge_done,
1124 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1126 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1128 struct tevent_req *req =
1129 tevent_req_callback_data(subreq,
1131 struct netlogon_creds_cli_auth_state *state =
1132 tevent_req_data(req,
1133 struct netlogon_creds_cli_auth_state);
1137 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1138 TALLOC_FREE(subreq);
1139 if (tevent_req_nterror(req, status)) {
1142 if (tevent_req_nterror(req, result)) {
1146 if (!state->try_auth3 && !state->try_auth2) {
1147 state->current_flags = 0;
1150 /* Calculate the session key and client credentials */
1152 state->creds = netlogon_creds_client_init(state,
1153 state->context->client.account,
1154 state->context->client.computer,
1155 state->context->client.type,
1156 &state->client_challenge,
1157 &state->server_challenge,
1158 state->used_nt_hash,
1159 &state->client_credential,
1160 state->current_flags);
1161 if (tevent_req_nomem(state->creds, req)) {
1165 if (state->try_auth3) {
1166 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1167 state->binding_handle,
1168 state->srv_name_slash,
1169 state->context->client.account,
1170 state->context->client.type,
1171 state->context->client.computer,
1172 &state->client_credential,
1173 &state->server_credential,
1174 &state->creds->negotiate_flags,
1176 if (tevent_req_nomem(subreq, req)) {
1179 } else if (state->try_auth2) {
1182 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1183 state->binding_handle,
1184 state->srv_name_slash,
1185 state->context->client.account,
1186 state->context->client.type,
1187 state->context->client.computer,
1188 &state->client_credential,
1189 &state->server_credential,
1190 &state->creds->negotiate_flags);
1191 if (tevent_req_nomem(subreq, req)) {
1197 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1198 state->binding_handle,
1199 state->srv_name_slash,
1200 state->context->client.account,
1201 state->context->client.type,
1202 state->context->client.computer,
1203 &state->client_credential,
1204 &state->server_credential);
1205 if (tevent_req_nomem(subreq, req)) {
1209 tevent_req_set_callback(subreq,
1210 netlogon_creds_cli_auth_srvauth_done,
1214 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1216 struct tevent_req *req =
1217 tevent_req_callback_data(subreq,
1219 struct netlogon_creds_cli_auth_state *state =
1220 tevent_req_data(req,
1221 struct netlogon_creds_cli_auth_state);
1225 enum ndr_err_code ndr_err;
1230 if (state->try_auth3) {
1231 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1233 TALLOC_FREE(subreq);
1234 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1235 state->try_auth3 = false;
1236 netlogon_creds_cli_auth_challenge_start(req);
1239 if (tevent_req_nterror(req, status)) {
1242 } else if (state->try_auth2) {
1243 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1245 TALLOC_FREE(subreq);
1246 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1247 state->try_auth2 = false;
1248 if (state->require_auth2) {
1249 status = NT_STATUS_DOWNGRADE_DETECTED;
1250 tevent_req_nterror(req, status);
1253 netlogon_creds_cli_auth_challenge_start(req);
1256 if (tevent_req_nterror(req, status)) {
1260 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1262 TALLOC_FREE(subreq);
1263 if (tevent_req_nterror(req, status)) {
1268 if (!NT_STATUS_IS_OK(result) &&
1269 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1271 tevent_req_nterror(req, result);
1275 tmp_flags = state->creds->negotiate_flags;
1276 tmp_flags &= state->context->client.required_flags;
1277 if (tmp_flags != state->context->client.required_flags) {
1278 if (NT_STATUS_IS_OK(result)) {
1279 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1282 tevent_req_nterror(req, result);
1286 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1288 tmp_flags = state->context->client.proposed_flags;
1289 if ((state->current_flags == tmp_flags) &&
1290 (state->creds->negotiate_flags != tmp_flags))
1293 * lets retry with the negotiated flags
1295 state->current_flags = state->creds->negotiate_flags;
1296 netlogon_creds_cli_auth_challenge_start(req);
1300 state->idx_nt_hashes += 1;
1301 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1303 * we already retried, giving up...
1305 tevent_req_nterror(req, result);
1310 * lets retry with the old nt hash.
1312 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1313 state->current_flags = state->context->client.proposed_flags;
1314 netlogon_creds_cli_auth_challenge_start(req);
1318 ok = netlogon_creds_client_check(state->creds,
1319 &state->server_credential);
1321 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1325 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1326 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1327 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1328 status = ndr_map_error2ntstatus(ndr_err);
1329 tevent_req_nterror(req, status);
1333 data.dptr = blob.data;
1334 data.dsize = blob.length;
1336 status = dbwrap_store(state->context->db.ctx,
1337 state->context->db.key_data,
1339 TALLOC_FREE(state->locked_state);
1340 if (tevent_req_nterror(req, status)) {
1344 tevent_req_done(req);
1347 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1348 uint8_t *idx_nt_hashes)
1350 struct netlogon_creds_cli_auth_state *state =
1351 tevent_req_data(req,
1352 struct netlogon_creds_cli_auth_state);
1357 if (tevent_req_is_nterror(req, &status)) {
1358 tevent_req_received(req);
1362 *idx_nt_hashes = state->idx_nt_hashes;
1363 tevent_req_received(req);
1364 return NT_STATUS_OK;
1367 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1368 struct dcerpc_binding_handle *b,
1369 uint8_t num_nt_hashes,
1370 const struct samr_Password * const *nt_hashes,
1371 uint8_t *idx_nt_hashes)
1373 TALLOC_CTX *frame = talloc_stackframe();
1374 struct tevent_context *ev;
1375 struct tevent_req *req;
1376 NTSTATUS status = NT_STATUS_NO_MEMORY;
1380 ev = samba_tevent_context_init(frame);
1384 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1385 num_nt_hashes, nt_hashes);
1389 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1392 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1398 struct netlogon_creds_cli_check_state {
1399 struct tevent_context *ev;
1400 struct netlogon_creds_cli_context *context;
1401 struct dcerpc_binding_handle *binding_handle;
1403 char *srv_name_slash;
1405 union netr_Capabilities caps;
1407 struct netlogon_creds_CredentialState *creds;
1408 struct netlogon_creds_CredentialState tmp_creds;
1409 struct netr_Authenticator req_auth;
1410 struct netr_Authenticator rep_auth;
1413 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1415 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1417 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1418 struct tevent_context *ev,
1419 struct netlogon_creds_cli_context *context,
1420 struct dcerpc_binding_handle *b)
1422 struct tevent_req *req;
1423 struct netlogon_creds_cli_check_state *state;
1424 struct tevent_req *subreq;
1425 enum dcerpc_AuthType auth_type;
1426 enum dcerpc_AuthLevel auth_level;
1428 req = tevent_req_create(mem_ctx, &state,
1429 struct netlogon_creds_cli_check_state);
1435 state->context = context;
1436 state->binding_handle = b;
1438 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1439 context->server.computer);
1440 if (tevent_req_nomem(state->srv_name_slash, req)) {
1441 return tevent_req_post(req, ev);
1444 dcerpc_binding_handle_auth_info(state->binding_handle,
1445 &auth_type, &auth_level);
1447 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1448 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1449 return tevent_req_post(req, ev);
1452 switch (auth_level) {
1453 case DCERPC_AUTH_LEVEL_INTEGRITY:
1454 case DCERPC_AUTH_LEVEL_PRIVACY:
1457 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1458 return tevent_req_post(req, ev);
1461 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1463 if (tevent_req_nomem(subreq, req)) {
1464 return tevent_req_post(req, ev);
1467 tevent_req_set_callback(subreq,
1468 netlogon_creds_cli_check_locked,
1474 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1477 struct netlogon_creds_cli_check_state *state =
1478 tevent_req_data(req,
1479 struct netlogon_creds_cli_check_state);
1481 if (state->creds == NULL) {
1485 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1486 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1487 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1488 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1489 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1490 TALLOC_FREE(state->creds);
1494 netlogon_creds_cli_delete(state->context, &state->creds);
1497 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1499 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1501 struct tevent_req *req =
1502 tevent_req_callback_data(subreq,
1504 struct netlogon_creds_cli_check_state *state =
1505 tevent_req_data(req,
1506 struct netlogon_creds_cli_check_state);
1509 status = netlogon_creds_cli_lock_recv(subreq, state,
1511 TALLOC_FREE(subreq);
1512 if (tevent_req_nterror(req, status)) {
1517 * we defer all callbacks in order to cleanup
1518 * the database record.
1520 tevent_req_defer_callback(req, state->ev);
1522 state->tmp_creds = *state->creds;
1523 netlogon_creds_client_authenticator(&state->tmp_creds,
1525 ZERO_STRUCT(state->rep_auth);
1527 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1528 state->binding_handle,
1529 state->srv_name_slash,
1530 state->context->client.computer,
1535 if (tevent_req_nomem(subreq, req)) {
1536 status = NT_STATUS_NO_MEMORY;
1537 netlogon_creds_cli_check_cleanup(req, status);
1540 tevent_req_set_callback(subreq,
1541 netlogon_creds_cli_check_caps,
1545 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1547 struct tevent_req *req =
1548 tevent_req_callback_data(subreq,
1550 struct netlogon_creds_cli_check_state *state =
1551 tevent_req_data(req,
1552 struct netlogon_creds_cli_check_state);
1557 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1559 TALLOC_FREE(subreq);
1560 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1562 * Note that the negotiated flags are already checked
1563 * for our required flags after the ServerAuthenticate3/2 call.
1565 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1567 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1569 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1570 * already, we expect this to work!
1572 status = NT_STATUS_DOWNGRADE_DETECTED;
1573 tevent_req_nterror(req, status);
1574 netlogon_creds_cli_check_cleanup(req, status);
1578 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1580 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1581 * we expect this to work at least as far as the
1582 * NOT_SUPPORTED error handled below!
1584 * NT 4.0 and Old Samba servers are not
1585 * allowed without "require strong key = no"
1587 status = NT_STATUS_DOWNGRADE_DETECTED;
1588 tevent_req_nterror(req, status);
1589 netlogon_creds_cli_check_cleanup(req, status);
1594 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1595 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1596 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1598 * This is needed against NT 4.0 and old Samba servers.
1600 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1601 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1602 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1603 * with the next request as the sequence number processing
1606 netlogon_creds_cli_check_cleanup(req, status);
1607 tevent_req_done(req);
1610 if (tevent_req_nterror(req, status)) {
1611 netlogon_creds_cli_check_cleanup(req, status);
1615 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1617 * Note that the negotiated flags are already checked
1618 * for our required flags after the ServerAuthenticate3/2 call.
1620 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1622 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1624 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1625 * already, we expect this to work!
1627 status = NT_STATUS_DOWNGRADE_DETECTED;
1628 tevent_req_nterror(req, status);
1629 netlogon_creds_cli_check_cleanup(req, status);
1634 * This is ok, the server does not support
1635 * NETLOGON_NEG_SUPPORTS_AES.
1637 * netr_LogonGetCapabilities() was
1638 * netr_LogonDummyRoutine1() before
1639 * NETLOGON_NEG_SUPPORTS_AES was invented.
1641 netlogon_creds_cli_check_cleanup(req, result);
1642 tevent_req_done(req);
1646 ok = netlogon_creds_client_check(&state->tmp_creds,
1647 &state->rep_auth.cred);
1649 status = NT_STATUS_ACCESS_DENIED;
1650 tevent_req_nterror(req, status);
1651 netlogon_creds_cli_check_cleanup(req, status);
1655 if (tevent_req_nterror(req, result)) {
1656 netlogon_creds_cli_check_cleanup(req, result);
1660 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1661 status = NT_STATUS_DOWNGRADE_DETECTED;
1662 tevent_req_nterror(req, status);
1663 netlogon_creds_cli_check_cleanup(req, status);
1668 * This is the key check that makes this check secure. If we
1669 * get OK here (rather than NOT_SUPPORTED), then the server
1670 * did support AES. If the server only proposed STRONG_KEYS
1671 * and not AES, then it should have failed with
1672 * NOT_IMPLEMENTED. We always send AES as a client, so the
1673 * server should always have returned it.
1675 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1676 status = NT_STATUS_DOWNGRADE_DETECTED;
1677 tevent_req_nterror(req, status);
1678 netlogon_creds_cli_check_cleanup(req, status);
1682 *state->creds = state->tmp_creds;
1683 status = netlogon_creds_cli_store(state->context,
1685 netlogon_creds_cli_check_cleanup(req, status);
1686 if (tevent_req_nterror(req, status)) {
1690 tevent_req_done(req);
1693 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1697 if (tevent_req_is_nterror(req, &status)) {
1698 netlogon_creds_cli_check_cleanup(req, status);
1699 tevent_req_received(req);
1703 tevent_req_received(req);
1704 return NT_STATUS_OK;
1707 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1708 struct dcerpc_binding_handle *b)
1710 TALLOC_CTX *frame = talloc_stackframe();
1711 struct tevent_context *ev;
1712 struct tevent_req *req;
1713 NTSTATUS status = NT_STATUS_NO_MEMORY;
1715 ev = samba_tevent_context_init(frame);
1719 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1723 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1726 status = netlogon_creds_cli_check_recv(req);
1732 struct netlogon_creds_cli_ServerPasswordSet_state {
1733 struct tevent_context *ev;
1734 struct netlogon_creds_cli_context *context;
1735 struct dcerpc_binding_handle *binding_handle;
1736 uint32_t old_timeout;
1738 char *srv_name_slash;
1739 enum dcerpc_AuthType auth_type;
1740 enum dcerpc_AuthLevel auth_level;
1742 struct samr_CryptPassword samr_crypt_password;
1743 struct netr_CryptPassword netr_crypt_password;
1744 struct samr_Password samr_password;
1746 struct netlogon_creds_CredentialState *creds;
1747 struct netlogon_creds_CredentialState tmp_creds;
1748 struct netr_Authenticator req_auth;
1749 struct netr_Authenticator rep_auth;
1752 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1754 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1756 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1757 struct tevent_context *ev,
1758 struct netlogon_creds_cli_context *context,
1759 struct dcerpc_binding_handle *b,
1760 const DATA_BLOB *new_password,
1761 const uint32_t *new_version)
1763 struct tevent_req *req;
1764 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1765 struct tevent_req *subreq;
1768 req = tevent_req_create(mem_ctx, &state,
1769 struct netlogon_creds_cli_ServerPasswordSet_state);
1775 state->context = context;
1776 state->binding_handle = b;
1778 if (new_password->length < 14) {
1779 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1780 return tevent_req_post(req, ev);
1784 * netr_ServerPasswordSet
1786 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1789 * netr_ServerPasswordSet2
1791 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1794 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1795 return tevent_req_post(req, ev);
1798 if (new_version != NULL) {
1799 struct NL_PASSWORD_VERSION version;
1800 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1801 uint32_t ofs = 512 - len;
1805 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1806 return tevent_req_post(req, ev);
1810 version.ReservedField = 0;
1811 version.PasswordVersionNumber = *new_version;
1812 version.PasswordVersionPresent =
1813 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1815 p = state->samr_crypt_password.data + ofs;
1816 SIVAL(p, 0, version.ReservedField);
1817 SIVAL(p, 4, version.PasswordVersionNumber);
1818 SIVAL(p, 8, version.PasswordVersionPresent);
1821 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1822 context->server.computer);
1823 if (tevent_req_nomem(state->srv_name_slash, req)) {
1824 return tevent_req_post(req, ev);
1827 dcerpc_binding_handle_auth_info(state->binding_handle,
1829 &state->auth_level);
1831 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1833 if (tevent_req_nomem(subreq, req)) {
1834 return tevent_req_post(req, ev);
1837 tevent_req_set_callback(subreq,
1838 netlogon_creds_cli_ServerPasswordSet_locked,
1844 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1847 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1848 tevent_req_data(req,
1849 struct netlogon_creds_cli_ServerPasswordSet_state);
1851 if (state->creds == NULL) {
1855 dcerpc_binding_handle_set_timeout(state->binding_handle,
1856 state->old_timeout);
1858 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1859 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1860 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1861 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1862 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1863 TALLOC_FREE(state->creds);
1867 netlogon_creds_cli_delete(state->context, &state->creds);
1870 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1872 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1874 struct tevent_req *req =
1875 tevent_req_callback_data(subreq,
1877 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1878 tevent_req_data(req,
1879 struct netlogon_creds_cli_ServerPasswordSet_state);
1882 status = netlogon_creds_cli_lock_recv(subreq, state,
1884 TALLOC_FREE(subreq);
1885 if (tevent_req_nterror(req, status)) {
1889 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1890 switch (state->auth_level) {
1891 case DCERPC_AUTH_LEVEL_INTEGRITY:
1892 case DCERPC_AUTH_LEVEL_PRIVACY:
1895 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1899 uint32_t tmp = state->creds->negotiate_flags;
1901 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1903 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1904 * it should be used, which means
1905 * we had a chance to verify no downgrade
1908 * This relies on netlogon_creds_cli_check*
1909 * being called before, as first request after
1912 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1917 state->old_timeout = dcerpc_binding_handle_set_timeout(
1918 state->binding_handle, 600000);
1921 * we defer all callbacks in order to cleanup
1922 * the database record.
1924 tevent_req_defer_callback(req, state->ev);
1926 state->tmp_creds = *state->creds;
1927 netlogon_creds_client_authenticator(&state->tmp_creds,
1929 ZERO_STRUCT(state->rep_auth);
1931 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1933 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1934 netlogon_creds_aes_encrypt(&state->tmp_creds,
1935 state->samr_crypt_password.data,
1938 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1939 state->samr_crypt_password.data,
1943 memcpy(state->netr_crypt_password.data,
1944 state->samr_crypt_password.data, 512);
1945 state->netr_crypt_password.length =
1946 IVAL(state->samr_crypt_password.data, 512);
1948 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1949 state->binding_handle,
1950 state->srv_name_slash,
1951 state->tmp_creds.account_name,
1952 state->tmp_creds.secure_channel_type,
1953 state->tmp_creds.computer_name,
1956 &state->netr_crypt_password);
1957 if (tevent_req_nomem(subreq, req)) {
1958 status = NT_STATUS_NO_MEMORY;
1959 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1963 netlogon_creds_des_encrypt(&state->tmp_creds,
1964 &state->samr_password);
1966 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1967 state->binding_handle,
1968 state->srv_name_slash,
1969 state->tmp_creds.account_name,
1970 state->tmp_creds.secure_channel_type,
1971 state->tmp_creds.computer_name,
1974 &state->samr_password);
1975 if (tevent_req_nomem(subreq, req)) {
1976 status = NT_STATUS_NO_MEMORY;
1977 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1982 tevent_req_set_callback(subreq,
1983 netlogon_creds_cli_ServerPasswordSet_done,
1987 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1989 struct tevent_req *req =
1990 tevent_req_callback_data(subreq,
1992 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1993 tevent_req_data(req,
1994 struct netlogon_creds_cli_ServerPasswordSet_state);
1999 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2000 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2002 TALLOC_FREE(subreq);
2003 if (tevent_req_nterror(req, status)) {
2004 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2008 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2010 TALLOC_FREE(subreq);
2011 if (tevent_req_nterror(req, status)) {
2012 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2017 ok = netlogon_creds_client_check(&state->tmp_creds,
2018 &state->rep_auth.cred);
2020 status = NT_STATUS_ACCESS_DENIED;
2021 tevent_req_nterror(req, status);
2022 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2026 if (tevent_req_nterror(req, result)) {
2027 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2031 dcerpc_binding_handle_set_timeout(state->binding_handle,
2032 state->old_timeout);
2034 *state->creds = state->tmp_creds;
2035 status = netlogon_creds_cli_store(state->context,
2037 if (tevent_req_nterror(req, status)) {
2038 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2042 tevent_req_done(req);
2045 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2049 if (tevent_req_is_nterror(req, &status)) {
2050 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2051 tevent_req_received(req);
2055 tevent_req_received(req);
2056 return NT_STATUS_OK;
2059 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2060 struct netlogon_creds_cli_context *context,
2061 struct dcerpc_binding_handle *b,
2062 const DATA_BLOB *new_password,
2063 const uint32_t *new_version)
2065 TALLOC_CTX *frame = talloc_stackframe();
2066 struct tevent_context *ev;
2067 struct tevent_req *req;
2068 NTSTATUS status = NT_STATUS_NO_MEMORY;
2070 ev = samba_tevent_context_init(frame);
2074 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2080 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2083 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2089 struct netlogon_creds_cli_LogonSamLogon_state {
2090 struct tevent_context *ev;
2091 struct netlogon_creds_cli_context *context;
2092 struct dcerpc_binding_handle *binding_handle;
2094 char *srv_name_slash;
2096 enum netr_LogonInfoClass logon_level;
2097 const union netr_LogonLevel *const_logon;
2098 union netr_LogonLevel *logon;
2101 uint16_t validation_level;
2102 union netr_Validation *validation;
2103 uint8_t authoritative;
2106 * do we need encryption at the application layer?
2110 bool try_validation6;
2113 * the read only credentials before we started the operation
2114 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2116 struct netlogon_creds_CredentialState *ro_creds;
2119 * The (locked) credentials used for the credential chain
2120 * used for netr_LogonSamLogonWithFlags() or
2121 * netr_LogonSamLogonWith().
2123 struct netlogon_creds_CredentialState *lk_creds;
2126 * While we have locked the global credentials (lk_creds above)
2127 * we operate an a temporary copy, because a server
2128 * may not support netr_LogonSamLogonWithFlags() and
2129 * didn't process our netr_Authenticator, so we need to
2130 * restart from lk_creds.
2132 struct netlogon_creds_CredentialState tmp_creds;
2133 struct netr_Authenticator req_auth;
2134 struct netr_Authenticator rep_auth;
2137 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2138 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2141 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2142 struct tevent_context *ev,
2143 struct netlogon_creds_cli_context *context,
2144 struct dcerpc_binding_handle *b,
2145 enum netr_LogonInfoClass logon_level,
2146 const union netr_LogonLevel *logon,
2149 struct tevent_req *req;
2150 struct netlogon_creds_cli_LogonSamLogon_state *state;
2152 req = tevent_req_create(mem_ctx, &state,
2153 struct netlogon_creds_cli_LogonSamLogon_state);
2159 state->context = context;
2160 state->binding_handle = b;
2162 state->logon_level = logon_level;
2163 state->const_logon = logon;
2164 state->flags = flags;
2166 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2167 context->server.computer);
2168 if (tevent_req_nomem(state->srv_name_slash, req)) {
2169 return tevent_req_post(req, ev);
2172 switch (logon_level) {
2173 case NetlogonInteractiveInformation:
2174 case NetlogonInteractiveTransitiveInformation:
2175 case NetlogonServiceInformation:
2176 case NetlogonServiceTransitiveInformation:
2177 case NetlogonGenericInformation:
2178 state->user_encrypt = true;
2181 case NetlogonNetworkInformation:
2182 case NetlogonNetworkTransitiveInformation:
2186 state->validation = talloc_zero(state, union netr_Validation);
2187 if (tevent_req_nomem(state->validation, req)) {
2188 return tevent_req_post(req, ev);
2191 netlogon_creds_cli_LogonSamLogon_start(req);
2192 if (!tevent_req_is_in_progress(req)) {
2193 return tevent_req_post(req, ev);
2197 * we defer all callbacks in order to cleanup
2198 * the database record.
2200 tevent_req_defer_callback(req, state->ev);
2204 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2207 struct netlogon_creds_cli_LogonSamLogon_state *state =
2208 tevent_req_data(req,
2209 struct netlogon_creds_cli_LogonSamLogon_state);
2211 if (state->lk_creds == NULL) {
2215 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2217 * This is a hack to recover from a bug in old
2218 * Samba servers, when LogonSamLogonEx() fails:
2220 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2222 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2224 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2225 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2226 * If the sign/seal check fails.
2228 * In that case we need to cleanup the netlogon session.
2230 * It's the job of the caller to disconnect the current
2231 * connection, if netlogon_creds_cli_LogonSamLogon()
2232 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2234 if (!state->context->server.try_logon_with) {
2235 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2239 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2240 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2241 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2242 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2243 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2244 TALLOC_FREE(state->lk_creds);
2248 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2251 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2253 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2255 struct netlogon_creds_cli_LogonSamLogon_state *state =
2256 tevent_req_data(req,
2257 struct netlogon_creds_cli_LogonSamLogon_state);
2258 struct tevent_req *subreq;
2260 enum dcerpc_AuthType auth_type;
2261 enum dcerpc_AuthLevel auth_level;
2263 TALLOC_FREE(state->ro_creds);
2264 TALLOC_FREE(state->logon);
2265 ZERO_STRUCTP(state->validation);
2267 dcerpc_binding_handle_auth_info(state->binding_handle,
2268 &auth_type, &auth_level);
2270 state->try_logon_ex = state->context->server.try_logon_ex;
2271 state->try_validation6 = state->context->server.try_validation6;
2273 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2274 state->try_logon_ex = false;
2277 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2278 state->try_validation6 = false;
2281 if (state->try_logon_ex) {
2282 if (state->try_validation6) {
2283 state->validation_level = 6;
2285 state->validation_level = 3;
2286 state->user_encrypt = true;
2289 state->logon = netlogon_creds_shallow_copy_logon(state,
2291 state->const_logon);
2292 if (tevent_req_nomem(state->logon, req)) {
2293 status = NT_STATUS_NO_MEMORY;
2294 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2298 if (state->user_encrypt) {
2299 status = netlogon_creds_cli_get(state->context,
2302 if (!NT_STATUS_IS_OK(status)) {
2303 status = NT_STATUS_ACCESS_DENIED;
2304 tevent_req_nterror(req, status);
2305 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2309 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2314 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2315 state->binding_handle,
2316 state->srv_name_slash,
2317 state->context->client.computer,
2320 state->validation_level,
2322 &state->authoritative,
2324 if (tevent_req_nomem(subreq, req)) {
2325 status = NT_STATUS_NO_MEMORY;
2326 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2329 tevent_req_set_callback(subreq,
2330 netlogon_creds_cli_LogonSamLogon_done,
2335 if (state->lk_creds == NULL) {
2336 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2338 if (tevent_req_nomem(subreq, req)) {
2339 status = NT_STATUS_NO_MEMORY;
2340 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2343 tevent_req_set_callback(subreq,
2344 netlogon_creds_cli_LogonSamLogon_done,
2349 state->tmp_creds = *state->lk_creds;
2350 netlogon_creds_client_authenticator(&state->tmp_creds,
2352 ZERO_STRUCT(state->rep_auth);
2354 state->logon = netlogon_creds_shallow_copy_logon(state,
2356 state->const_logon);
2357 if (tevent_req_nomem(state->logon, req)) {
2358 status = NT_STATUS_NO_MEMORY;
2359 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2363 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2367 state->validation_level = 3;
2369 if (state->context->server.try_logon_with) {
2370 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2371 state->binding_handle,
2372 state->srv_name_slash,
2373 state->context->client.computer,
2378 state->validation_level,
2380 &state->authoritative,
2382 if (tevent_req_nomem(subreq, req)) {
2383 status = NT_STATUS_NO_MEMORY;
2384 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2390 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2391 state->binding_handle,
2392 state->srv_name_slash,
2393 state->context->client.computer,
2398 state->validation_level,
2400 &state->authoritative);
2401 if (tevent_req_nomem(subreq, req)) {
2402 status = NT_STATUS_NO_MEMORY;
2403 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2408 tevent_req_set_callback(subreq,
2409 netlogon_creds_cli_LogonSamLogon_done,
2413 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2415 struct tevent_req *req =
2416 tevent_req_callback_data(subreq,
2418 struct netlogon_creds_cli_LogonSamLogon_state *state =
2419 tevent_req_data(req,
2420 struct netlogon_creds_cli_LogonSamLogon_state);
2425 if (state->try_logon_ex) {
2426 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2429 TALLOC_FREE(subreq);
2430 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2431 state->context->server.try_validation6 = false;
2432 state->context->server.try_logon_ex = false;
2433 netlogon_creds_cli_LogonSamLogon_start(req);
2436 if (tevent_req_nterror(req, status)) {
2437 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2441 if ((state->validation_level == 6) &&
2442 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2443 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2444 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2446 state->context->server.try_validation6 = false;
2447 netlogon_creds_cli_LogonSamLogon_start(req);
2451 if (tevent_req_nterror(req, result)) {
2452 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2456 if (state->ro_creds == NULL) {
2457 tevent_req_done(req);
2461 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2464 * We got a race, lets retry with on authenticator
2467 * netlogon_creds_cli_LogonSamLogon_start()
2468 * will TALLOC_FREE(state->ro_creds);
2470 state->try_logon_ex = false;
2471 netlogon_creds_cli_LogonSamLogon_start(req);
2475 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2476 state->validation_level,
2479 tevent_req_done(req);
2483 if (state->lk_creds == NULL) {
2484 status = netlogon_creds_cli_lock_recv(subreq, state,
2486 TALLOC_FREE(subreq);
2487 if (tevent_req_nterror(req, status)) {
2488 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2492 netlogon_creds_cli_LogonSamLogon_start(req);
2496 if (state->context->server.try_logon_with) {
2497 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2500 TALLOC_FREE(subreq);
2501 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2502 state->context->server.try_logon_with = false;
2503 netlogon_creds_cli_LogonSamLogon_start(req);
2506 if (tevent_req_nterror(req, status)) {
2507 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2511 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2514 TALLOC_FREE(subreq);
2515 if (tevent_req_nterror(req, status)) {
2516 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2521 ok = netlogon_creds_client_check(&state->tmp_creds,
2522 &state->rep_auth.cred);
2524 status = NT_STATUS_ACCESS_DENIED;
2525 tevent_req_nterror(req, status);
2526 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2530 *state->lk_creds = state->tmp_creds;
2531 status = netlogon_creds_cli_store(state->context,
2533 if (tevent_req_nterror(req, status)) {
2534 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2538 if (tevent_req_nterror(req, result)) {
2539 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2543 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2544 state->validation_level,
2547 tevent_req_done(req);
2550 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2551 TALLOC_CTX *mem_ctx,
2552 uint16_t *validation_level,
2553 union netr_Validation **validation,
2554 uint8_t *authoritative,
2557 struct netlogon_creds_cli_LogonSamLogon_state *state =
2558 tevent_req_data(req,
2559 struct netlogon_creds_cli_LogonSamLogon_state);
2562 /* authoritative is also returned on error */
2563 *authoritative = state->authoritative;
2565 if (tevent_req_is_nterror(req, &status)) {
2566 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2567 tevent_req_received(req);
2571 *validation_level = state->validation_level;
2572 *validation = talloc_move(mem_ctx, &state->validation);
2573 *flags = state->flags;
2575 tevent_req_received(req);
2576 return NT_STATUS_OK;
2579 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2580 struct netlogon_creds_cli_context *context,
2581 struct dcerpc_binding_handle *b,
2582 enum netr_LogonInfoClass logon_level,
2583 const union netr_LogonLevel *logon,
2584 TALLOC_CTX *mem_ctx,
2585 uint16_t *validation_level,
2586 union netr_Validation **validation,
2587 uint8_t *authoritative,
2590 TALLOC_CTX *frame = talloc_stackframe();
2591 struct tevent_context *ev;
2592 struct tevent_req *req;
2593 NTSTATUS status = NT_STATUS_NO_MEMORY;
2595 ev = samba_tevent_context_init(frame);
2599 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2605 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2608 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2618 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2619 struct tevent_context *ev;
2620 struct netlogon_creds_cli_context *context;
2621 struct dcerpc_binding_handle *binding_handle;
2623 char *srv_name_slash;
2624 enum dcerpc_AuthType auth_type;
2625 enum dcerpc_AuthLevel auth_level;
2627 const char *site_name;
2629 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2631 struct netlogon_creds_CredentialState *creds;
2632 struct netlogon_creds_CredentialState tmp_creds;
2633 struct netr_Authenticator req_auth;
2634 struct netr_Authenticator rep_auth;
2637 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2639 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2641 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2642 struct tevent_context *ev,
2643 struct netlogon_creds_cli_context *context,
2644 struct dcerpc_binding_handle *b,
2645 const char *site_name,
2647 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2649 struct tevent_req *req;
2650 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2651 struct tevent_req *subreq;
2653 req = tevent_req_create(mem_ctx, &state,
2654 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2660 state->context = context;
2661 state->binding_handle = b;
2663 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2664 context->server.computer);
2665 if (tevent_req_nomem(state->srv_name_slash, req)) {
2666 return tevent_req_post(req, ev);
2669 state->site_name = site_name;
2670 state->dns_ttl = dns_ttl;
2671 state->dns_names = dns_names;
2673 dcerpc_binding_handle_auth_info(state->binding_handle,
2675 &state->auth_level);
2677 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2679 if (tevent_req_nomem(subreq, req)) {
2680 return tevent_req_post(req, ev);
2683 tevent_req_set_callback(subreq,
2684 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2690 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2693 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2694 tevent_req_data(req,
2695 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2697 if (state->creds == NULL) {
2701 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2702 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2703 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2704 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2705 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2706 TALLOC_FREE(state->creds);
2710 netlogon_creds_cli_delete(state->context, &state->creds);
2713 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2715 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2717 struct tevent_req *req =
2718 tevent_req_callback_data(subreq,
2720 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2721 tevent_req_data(req,
2722 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2725 status = netlogon_creds_cli_lock_recv(subreq, state,
2727 TALLOC_FREE(subreq);
2728 if (tevent_req_nterror(req, status)) {
2732 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2733 switch (state->auth_level) {
2734 case DCERPC_AUTH_LEVEL_INTEGRITY:
2735 case DCERPC_AUTH_LEVEL_PRIVACY:
2738 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2742 uint32_t tmp = state->creds->negotiate_flags;
2744 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2746 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2747 * it should be used, which means
2748 * we had a chance to verify no downgrade
2751 * This relies on netlogon_creds_cli_check*
2752 * being called before, as first request after
2755 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2761 * we defer all callbacks in order to cleanup
2762 * the database record.
2764 tevent_req_defer_callback(req, state->ev);
2766 state->tmp_creds = *state->creds;
2767 netlogon_creds_client_authenticator(&state->tmp_creds,
2769 ZERO_STRUCT(state->rep_auth);
2771 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2772 state->binding_handle,
2773 state->srv_name_slash,
2774 state->tmp_creds.computer_name,
2780 if (tevent_req_nomem(subreq, req)) {
2781 status = NT_STATUS_NO_MEMORY;
2782 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2786 tevent_req_set_callback(subreq,
2787 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2791 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2793 struct tevent_req *req =
2794 tevent_req_callback_data(subreq,
2796 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2797 tevent_req_data(req,
2798 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2804 * We use state->dns_names as the memory context, as this is
2805 * the only in/out variable and it has been overwritten by the
2806 * out parameter from the server.
2808 * We need to preserve the return value until the caller can use it.
2810 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2812 TALLOC_FREE(subreq);
2813 if (tevent_req_nterror(req, status)) {
2814 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2818 ok = netlogon_creds_client_check(&state->tmp_creds,
2819 &state->rep_auth.cred);
2821 status = NT_STATUS_ACCESS_DENIED;
2822 tevent_req_nterror(req, status);
2823 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2827 *state->creds = state->tmp_creds;
2828 status = netlogon_creds_cli_store(state->context,
2831 if (tevent_req_nterror(req, status)) {
2832 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2836 if (tevent_req_nterror(req, result)) {
2837 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2841 tevent_req_done(req);
2844 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2848 if (tevent_req_is_nterror(req, &status)) {
2849 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2850 tevent_req_received(req);
2854 tevent_req_received(req);
2855 return NT_STATUS_OK;
2858 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2859 struct netlogon_creds_cli_context *context,
2860 struct dcerpc_binding_handle *b,
2861 const char *site_name,
2863 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2865 TALLOC_CTX *frame = talloc_stackframe();
2866 struct tevent_context *ev;
2867 struct tevent_req *req;
2868 NTSTATUS status = NT_STATUS_NO_MEMORY;
2870 ev = samba_tevent_context_init(frame);
2874 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2881 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2884 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2890 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2891 struct tevent_context *ev;
2892 struct netlogon_creds_cli_context *context;
2893 struct dcerpc_binding_handle *binding_handle;
2895 char *srv_name_slash;
2896 enum dcerpc_AuthType auth_type;
2897 enum dcerpc_AuthLevel auth_level;
2899 struct samr_Password new_owf_password;
2900 struct samr_Password old_owf_password;
2901 struct netr_TrustInfo *trust_info;
2903 struct netlogon_creds_CredentialState *creds;
2904 struct netlogon_creds_CredentialState tmp_creds;
2905 struct netr_Authenticator req_auth;
2906 struct netr_Authenticator rep_auth;
2909 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2911 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2913 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2914 struct tevent_context *ev,
2915 struct netlogon_creds_cli_context *context,
2916 struct dcerpc_binding_handle *b)
2918 struct tevent_req *req;
2919 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2920 struct tevent_req *subreq;
2922 req = tevent_req_create(mem_ctx, &state,
2923 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2929 state->context = context;
2930 state->binding_handle = b;
2932 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2933 context->server.computer);
2934 if (tevent_req_nomem(state->srv_name_slash, req)) {
2935 return tevent_req_post(req, ev);
2938 dcerpc_binding_handle_auth_info(state->binding_handle,
2940 &state->auth_level);
2942 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2944 if (tevent_req_nomem(subreq, req)) {
2945 return tevent_req_post(req, ev);
2948 tevent_req_set_callback(subreq,
2949 netlogon_creds_cli_ServerGetTrustInfo_locked,
2955 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2958 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2959 tevent_req_data(req,
2960 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2962 if (state->creds == NULL) {
2966 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2967 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2968 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2969 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2970 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2971 TALLOC_FREE(state->creds);
2975 netlogon_creds_cli_delete(state->context, &state->creds);
2978 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2980 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2982 struct tevent_req *req =
2983 tevent_req_callback_data(subreq,
2985 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2986 tevent_req_data(req,
2987 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2990 status = netlogon_creds_cli_lock_recv(subreq, state,
2992 TALLOC_FREE(subreq);
2993 if (tevent_req_nterror(req, status)) {
2997 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2998 switch (state->auth_level) {
2999 case DCERPC_AUTH_LEVEL_PRIVACY:
3002 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3006 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3011 * we defer all callbacks in order to cleanup
3012 * the database record.
3014 tevent_req_defer_callback(req, state->ev);
3016 state->tmp_creds = *state->creds;
3017 netlogon_creds_client_authenticator(&state->tmp_creds,
3019 ZERO_STRUCT(state->rep_auth);
3021 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3022 state->binding_handle,
3023 state->srv_name_slash,
3024 state->tmp_creds.account_name,
3025 state->tmp_creds.secure_channel_type,
3026 state->tmp_creds.computer_name,
3029 &state->new_owf_password,
3030 &state->old_owf_password,
3031 &state->trust_info);
3032 if (tevent_req_nomem(subreq, req)) {
3033 status = NT_STATUS_NO_MEMORY;
3034 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3038 tevent_req_set_callback(subreq,
3039 netlogon_creds_cli_ServerGetTrustInfo_done,
3043 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3045 struct tevent_req *req =
3046 tevent_req_callback_data(subreq,
3048 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3049 tevent_req_data(req,
3050 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3053 const struct samr_Password zero = {};
3058 * We use state->dns_names as the memory context, as this is
3059 * the only in/out variable and it has been overwritten by the
3060 * out parameter from the server.
3062 * We need to preserve the return value until the caller can use it.
3064 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3065 TALLOC_FREE(subreq);
3066 if (tevent_req_nterror(req, status)) {
3067 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3071 ok = netlogon_creds_client_check(&state->tmp_creds,
3072 &state->rep_auth.cred);
3074 status = NT_STATUS_ACCESS_DENIED;
3075 tevent_req_nterror(req, status);
3076 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3080 cmp = memcmp(state->new_owf_password.hash,
3081 zero.hash, sizeof(zero.hash));
3083 netlogon_creds_des_decrypt(&state->tmp_creds,
3084 &state->new_owf_password);
3086 cmp = memcmp(state->old_owf_password.hash,
3087 zero.hash, sizeof(zero.hash));
3089 netlogon_creds_des_decrypt(&state->tmp_creds,
3090 &state->old_owf_password);
3093 *state->creds = state->tmp_creds;
3094 status = netlogon_creds_cli_store(state->context,
3096 if (tevent_req_nterror(req, status)) {
3097 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3101 if (tevent_req_nterror(req, result)) {
3102 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3106 tevent_req_done(req);
3109 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3110 TALLOC_CTX *mem_ctx,
3111 struct samr_Password *new_owf_password,
3112 struct samr_Password *old_owf_password,
3113 struct netr_TrustInfo **trust_info)
3115 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3116 tevent_req_data(req,
3117 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3120 if (tevent_req_is_nterror(req, &status)) {
3121 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3122 tevent_req_received(req);
3126 if (new_owf_password != NULL) {
3127 *new_owf_password = state->new_owf_password;
3129 if (old_owf_password != NULL) {
3130 *old_owf_password = state->old_owf_password;
3132 if (trust_info != NULL) {
3133 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3136 tevent_req_received(req);
3137 return NT_STATUS_OK;
3140 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3141 struct netlogon_creds_cli_context *context,
3142 struct dcerpc_binding_handle *b,
3143 TALLOC_CTX *mem_ctx,
3144 struct samr_Password *new_owf_password,
3145 struct samr_Password *old_owf_password,
3146 struct netr_TrustInfo **trust_info)
3148 TALLOC_CTX *frame = talloc_stackframe();
3149 struct tevent_context *ev;
3150 struct tevent_req *req;
3151 NTSTATUS status = NT_STATUS_NO_MEMORY;
3153 ev = samba_tevent_context_init(frame);
3157 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3161 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3164 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3174 struct netlogon_creds_cli_GetForestTrustInformation_state {
3175 struct tevent_context *ev;
3176 struct netlogon_creds_cli_context *context;
3177 struct dcerpc_binding_handle *binding_handle;
3179 char *srv_name_slash;
3180 enum dcerpc_AuthType auth_type;
3181 enum dcerpc_AuthLevel auth_level;
3184 struct lsa_ForestTrustInformation *forest_trust_info;
3186 struct netlogon_creds_CredentialState *creds;
3187 struct netlogon_creds_CredentialState tmp_creds;
3188 struct netr_Authenticator req_auth;
3189 struct netr_Authenticator rep_auth;
3192 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3194 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3196 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3197 struct tevent_context *ev,
3198 struct netlogon_creds_cli_context *context,
3199 struct dcerpc_binding_handle *b)
3201 struct tevent_req *req;
3202 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3203 struct tevent_req *subreq;
3205 req = tevent_req_create(mem_ctx, &state,
3206 struct netlogon_creds_cli_GetForestTrustInformation_state);
3212 state->context = context;
3213 state->binding_handle = b;
3215 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3216 context->server.computer);
3217 if (tevent_req_nomem(state->srv_name_slash, req)) {
3218 return tevent_req_post(req, ev);
3223 dcerpc_binding_handle_auth_info(state->binding_handle,
3225 &state->auth_level);
3227 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3229 if (tevent_req_nomem(subreq, req)) {
3230 return tevent_req_post(req, ev);
3233 tevent_req_set_callback(subreq,
3234 netlogon_creds_cli_GetForestTrustInformation_locked,
3240 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3243 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3244 tevent_req_data(req,
3245 struct netlogon_creds_cli_GetForestTrustInformation_state);
3247 if (state->creds == NULL) {
3251 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3252 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3253 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3254 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3255 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3256 TALLOC_FREE(state->creds);
3260 netlogon_creds_cli_delete(state->context, &state->creds);
3263 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3265 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3267 struct tevent_req *req =
3268 tevent_req_callback_data(subreq,
3270 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3271 tevent_req_data(req,
3272 struct netlogon_creds_cli_GetForestTrustInformation_state);
3275 status = netlogon_creds_cli_lock_recv(subreq, state,
3277 TALLOC_FREE(subreq);
3278 if (tevent_req_nterror(req, status)) {
3282 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3283 switch (state->auth_level) {
3284 case DCERPC_AUTH_LEVEL_INTEGRITY:
3285 case DCERPC_AUTH_LEVEL_PRIVACY:
3288 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3292 uint32_t tmp = state->creds->negotiate_flags;
3294 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3296 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3297 * it should be used, which means
3298 * we had a chance to verify no downgrade
3301 * This relies on netlogon_creds_cli_check*
3302 * being called before, as first request after
3305 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3311 * we defer all callbacks in order to cleanup
3312 * the database record.
3314 tevent_req_defer_callback(req, state->ev);
3316 state->tmp_creds = *state->creds;
3317 netlogon_creds_client_authenticator(&state->tmp_creds,
3319 ZERO_STRUCT(state->rep_auth);
3321 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3322 state->binding_handle,
3323 state->srv_name_slash,
3324 state->tmp_creds.computer_name,
3328 &state->forest_trust_info);
3329 if (tevent_req_nomem(subreq, req)) {
3330 status = NT_STATUS_NO_MEMORY;
3331 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3335 tevent_req_set_callback(subreq,
3336 netlogon_creds_cli_GetForestTrustInformation_done,
3340 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3342 struct tevent_req *req =
3343 tevent_req_callback_data(subreq,
3345 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3346 tevent_req_data(req,
3347 struct netlogon_creds_cli_GetForestTrustInformation_state);
3353 * We use state->dns_names as the memory context, as this is
3354 * the only in/out variable and it has been overwritten by the
3355 * out parameter from the server.
3357 * We need to preserve the return value until the caller can use it.
3359 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3360 TALLOC_FREE(subreq);
3361 if (tevent_req_nterror(req, status)) {
3362 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3366 ok = netlogon_creds_client_check(&state->tmp_creds,
3367 &state->rep_auth.cred);
3369 status = NT_STATUS_ACCESS_DENIED;
3370 tevent_req_nterror(req, status);
3371 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3375 *state->creds = state->tmp_creds;
3376 status = netlogon_creds_cli_store(state->context,
3379 if (tevent_req_nterror(req, status)) {
3380 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3384 if (tevent_req_nterror(req, result)) {
3385 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3389 tevent_req_done(req);
3392 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3393 TALLOC_CTX *mem_ctx,
3394 struct lsa_ForestTrustInformation **forest_trust_info)
3396 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3397 tevent_req_data(req,
3398 struct netlogon_creds_cli_GetForestTrustInformation_state);
3401 if (tevent_req_is_nterror(req, &status)) {
3402 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3403 tevent_req_received(req);
3407 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3409 tevent_req_received(req);
3410 return NT_STATUS_OK;
3413 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3414 struct netlogon_creds_cli_context *context,
3415 struct dcerpc_binding_handle *b,
3416 TALLOC_CTX *mem_ctx,
3417 struct lsa_ForestTrustInformation **forest_trust_info)
3419 TALLOC_CTX *frame = talloc_stackframe();
3420 struct tevent_context *ev;
3421 struct tevent_req *req;
3422 NTSTATUS status = NT_STATUS_NO_MEMORY;
3424 ev = samba_tevent_context_init(frame);
3428 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3432 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3435 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3443 struct netlogon_creds_cli_SendToSam_state {
3444 struct tevent_context *ev;
3445 struct netlogon_creds_cli_context *context;
3446 struct dcerpc_binding_handle *binding_handle;
3448 char *srv_name_slash;
3449 enum dcerpc_AuthType auth_type;
3450 enum dcerpc_AuthLevel auth_level;
3454 struct netlogon_creds_CredentialState *creds;
3455 struct netlogon_creds_CredentialState tmp_creds;
3456 struct netr_Authenticator req_auth;
3457 struct netr_Authenticator rep_auth;
3460 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3462 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3464 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3465 struct tevent_context *ev,
3466 struct netlogon_creds_cli_context *context,
3467 struct dcerpc_binding_handle *b,
3468 struct netr_SendToSamBase *message)
3470 struct tevent_req *req;
3471 struct netlogon_creds_cli_SendToSam_state *state;
3472 struct tevent_req *subreq;
3473 enum ndr_err_code ndr_err;
3475 req = tevent_req_create(mem_ctx, &state,
3476 struct netlogon_creds_cli_SendToSam_state);
3482 state->context = context;
3483 state->binding_handle = b;
3485 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3486 context->server.computer);
3487 if (tevent_req_nomem(state->srv_name_slash, req)) {
3488 return tevent_req_post(req, ev);
3491 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3492 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3493 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3494 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3495 tevent_req_nterror(req, status);
3496 return tevent_req_post(req, ev);
3499 dcerpc_binding_handle_auth_info(state->binding_handle,
3501 &state->auth_level);
3503 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3505 if (tevent_req_nomem(subreq, req)) {
3506 return tevent_req_post(req, ev);
3509 tevent_req_set_callback(subreq,
3510 netlogon_creds_cli_SendToSam_locked,
3516 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3519 struct netlogon_creds_cli_SendToSam_state *state =
3520 tevent_req_data(req,
3521 struct netlogon_creds_cli_SendToSam_state);
3523 if (state->creds == NULL) {
3527 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3528 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3529 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3530 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3531 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3532 TALLOC_FREE(state->creds);
3536 netlogon_creds_cli_delete(state->context, &state->creds);
3539 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3541 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3543 struct tevent_req *req =
3544 tevent_req_callback_data(subreq,
3546 struct netlogon_creds_cli_SendToSam_state *state =
3547 tevent_req_data(req,
3548 struct netlogon_creds_cli_SendToSam_state);
3551 status = netlogon_creds_cli_lock_recv(subreq, state,
3553 TALLOC_FREE(subreq);
3554 if (tevent_req_nterror(req, status)) {
3558 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3559 switch (state->auth_level) {
3560 case DCERPC_AUTH_LEVEL_INTEGRITY:
3561 case DCERPC_AUTH_LEVEL_PRIVACY:
3564 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3568 uint32_t tmp = state->creds->negotiate_flags;
3570 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3572 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3573 * it should be used, which means
3574 * we had a chance to verify no downgrade
3577 * This relies on netlogon_creds_cli_check*
3578 * being called before, as first request after
3581 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3587 * we defer all callbacks in order to cleanup
3588 * the database record.
3590 tevent_req_defer_callback(req, state->ev);
3592 state->tmp_creds = *state->creds;
3593 netlogon_creds_client_authenticator(&state->tmp_creds,
3595 ZERO_STRUCT(state->rep_auth);
3597 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3598 netlogon_creds_aes_encrypt(&state->tmp_creds,
3600 state->opaque.length);
3602 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3604 state->opaque.length);
3607 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3608 state->binding_handle,
3609 state->srv_name_slash,
3610 state->tmp_creds.computer_name,
3614 state->opaque.length);
3615 if (tevent_req_nomem(subreq, req)) {
3616 status = NT_STATUS_NO_MEMORY;
3617 netlogon_creds_cli_SendToSam_cleanup(req, status);
3621 tevent_req_set_callback(subreq,
3622 netlogon_creds_cli_SendToSam_done,
3626 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3628 struct tevent_req *req =
3629 tevent_req_callback_data(subreq,
3631 struct netlogon_creds_cli_SendToSam_state *state =
3632 tevent_req_data(req,
3633 struct netlogon_creds_cli_SendToSam_state);
3638 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3639 TALLOC_FREE(subreq);
3640 if (tevent_req_nterror(req, status)) {
3641 netlogon_creds_cli_SendToSam_cleanup(req, status);
3645 ok = netlogon_creds_client_check(&state->tmp_creds,
3646 &state->rep_auth.cred);
3648 status = NT_STATUS_ACCESS_DENIED;
3649 tevent_req_nterror(req, status);
3650 netlogon_creds_cli_SendToSam_cleanup(req, status);
3654 *state->creds = state->tmp_creds;
3655 status = netlogon_creds_cli_store(state->context,
3658 if (tevent_req_nterror(req, status)) {
3659 netlogon_creds_cli_SendToSam_cleanup(req, status);
3664 * Creds must be stored before we send back application errors
3665 * e.g. NT_STATUS_NOT_IMPLEMENTED
3667 if (tevent_req_nterror(req, result)) {
3668 netlogon_creds_cli_SendToSam_cleanup(req, result);
3672 tevent_req_done(req);
3675 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3676 struct dcerpc_binding_handle *b,
3677 struct netr_SendToSamBase *message)
3679 TALLOC_CTX *frame = talloc_stackframe();
3680 struct tevent_context *ev;
3681 struct tevent_req *req;
3682 NTSTATUS status = NT_STATUS_OK;
3684 ev = samba_tevent_context_init(frame);
3688 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3692 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3696 /* Ignore the result */