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 const char *dns_domain;
58 uint32_t cached_flags;
67 struct db_context *ctx;
68 struct g_lock_ctx *g_ctx;
69 struct netlogon_creds_cli_locked_state *locked_state;
73 struct netlogon_creds_cli_locked_state {
74 struct netlogon_creds_cli_context *context;
76 struct netlogon_creds_CredentialState *creds;
79 static int netlogon_creds_cli_locked_state_destructor(
80 struct netlogon_creds_cli_locked_state *state)
82 struct netlogon_creds_cli_context *context = state->context;
84 if (context == NULL) {
88 if (context->db.locked_state == state) {
89 context->db.locked_state = NULL;
92 if (state->is_glocked) {
93 g_lock_unlock(context->db.g_ctx,
94 context->db.key_name);
100 static NTSTATUS netlogon_creds_cli_context_common(
101 const char *client_computer,
102 const char *client_account,
103 enum netr_SchannelType type,
104 enum dcerpc_AuthLevel auth_level,
105 uint32_t proposed_flags,
106 uint32_t required_flags,
107 const char *server_computer,
108 const char *server_netbios_domain,
109 const char *server_dns_domain,
111 struct netlogon_creds_cli_context **_context)
113 struct netlogon_creds_cli_context *context = NULL;
114 char *_key_name = NULL;
115 size_t server_netbios_name_len;
120 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
121 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);
128 return NT_STATUS_NO_MEMORY;
131 context->client.account = talloc_strdup(context, client_account);
132 if (context->client.account == NULL) {
133 TALLOC_FREE(context);
134 return NT_STATUS_NO_MEMORY;
137 context->client.proposed_flags = proposed_flags;
138 context->client.required_flags = required_flags;
139 context->client.type = type;
140 context->client.auth_level = auth_level;
142 context->server.computer = talloc_strdup(context, server_computer);
143 if (context->server.computer == NULL) {
144 TALLOC_FREE(context);
145 return NT_STATUS_NO_MEMORY;
148 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
149 if (context->server.netbios_domain == NULL) {
150 TALLOC_FREE(context);
151 return NT_STATUS_NO_MEMORY;
154 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
155 if (context->server.dns_domain == NULL) {
156 TALLOC_FREE(context);
157 return NT_STATUS_NO_MEMORY;
162 * Force the callers to provide a unique
163 * value for server_computer and use this directly.
165 * For now we have to deal with
166 * "HOSTNAME" vs. "hostname.example.com".
169 p = strchr(server_computer, '.');
171 server_netbios_name_len = p-server_computer;
173 server_netbios_name_len = strlen(server_computer);
176 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
179 (int)server_netbios_name_len,
181 server_netbios_domain);
182 if (_key_name == NULL) {
183 TALLOC_FREE(context);
184 return NT_STATUS_NO_MEMORY;
187 context->db.key_name = talloc_strdup_upper(context, _key_name);
188 TALLOC_FREE(_key_name);
189 if (context->db.key_name == NULL) {
190 TALLOC_FREE(context);
191 return NT_STATUS_NO_MEMORY;
194 context->db.key_data = string_term_tdb_data(context->db.key_name);
200 static struct db_context *netlogon_creds_cli_global_db;
202 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
204 if (netlogon_creds_cli_global_db != NULL) {
205 return NT_STATUS_INVALID_PARAMETER_MIX;
208 netlogon_creds_cli_global_db = talloc_move(NULL, db);
212 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
215 struct db_context *global_db;
217 if (netlogon_creds_cli_global_db != NULL) {
221 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
223 return NT_STATUS_NO_MEMORY;
226 global_db = dbwrap_local_open(NULL, lp_ctx,
228 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
230 0600, DBWRAP_LOCK_ORDER_2,
232 if (global_db == NULL) {
233 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
234 fname, strerror(errno)));
236 return NT_STATUS_NO_MEMORY;
240 netlogon_creds_cli_global_db = global_db;
244 void netlogon_creds_cli_close_global_db(void)
246 TALLOC_FREE(netlogon_creds_cli_global_db);
249 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
250 struct messaging_context *msg_ctx,
251 const char *client_account,
252 enum netr_SchannelType type,
253 const char *server_computer,
254 const char *server_netbios_domain,
255 const char *server_dns_domain,
257 struct netlogon_creds_cli_context **_context)
259 TALLOC_CTX *frame = talloc_stackframe();
261 struct netlogon_creds_cli_context *context = NULL;
262 const char *client_computer;
263 uint32_t proposed_flags;
264 uint32_t required_flags = 0;
265 bool reject_md5_servers = false;
266 bool require_strong_key = false;
267 int require_sign_or_seal = true;
268 bool seal_secure_channel = true;
269 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
270 bool neutralize_nt4_emulation = false;
274 if (msg_ctx == NULL) {
276 return NT_STATUS_INVALID_PARAMETER_MIX;
279 client_computer = lpcfg_netbios_name(lp_ctx);
280 if (strlen(client_computer) > 15) {
282 return NT_STATUS_INVALID_PARAMETER_MIX;
286 * allow overwrite per domain
287 * reject md5 servers:<netbios_domain>
289 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
290 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
291 "reject md5 servers",
292 server_netbios_domain,
296 * allow overwrite per domain
297 * require strong key:<netbios_domain>
299 require_strong_key = lpcfg_require_strong_key(lp_ctx);
300 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
301 "require strong key",
302 server_netbios_domain,
306 * allow overwrite per domain
307 * client schannel:<netbios_domain>
309 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
310 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
312 server_netbios_domain,
313 require_sign_or_seal);
316 * allow overwrite per domain
317 * winbind sealed pipes:<netbios_domain>
319 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
320 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
321 "winbind sealed pipes",
322 server_netbios_domain,
323 seal_secure_channel);
326 * allow overwrite per domain
327 * neutralize nt4 emulation:<netbios_domain>
329 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
330 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
331 "neutralize nt4 emulation",
332 server_netbios_domain,
333 neutralize_nt4_emulation);
335 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
336 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
340 if (lpcfg_security(lp_ctx) == SEC_ADS) {
342 * AD domains should be secure
344 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
345 require_sign_or_seal = true;
346 require_strong_key = true;
350 case SEC_CHAN_DOMAIN:
353 case SEC_CHAN_DNS_DOMAIN:
355 * AD domains should be secure
357 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
358 require_sign_or_seal = true;
359 require_strong_key = true;
360 neutralize_nt4_emulation = true;
364 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
365 require_sign_or_seal = true;
366 require_strong_key = true;
370 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
371 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
372 require_sign_or_seal = true;
373 require_strong_key = true;
374 neutralize_nt4_emulation = true;
379 return NT_STATUS_INVALID_PARAMETER;
382 if (neutralize_nt4_emulation) {
383 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
386 if (require_sign_or_seal) {
387 required_flags |= NETLOGON_NEG_ARCFOUR;
388 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
390 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
393 if (reject_md5_servers) {
394 required_flags |= NETLOGON_NEG_ARCFOUR;
395 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
396 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
397 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
400 if (require_strong_key) {
401 required_flags |= NETLOGON_NEG_ARCFOUR;
402 required_flags |= NETLOGON_NEG_STRONG_KEYS;
403 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
406 proposed_flags |= required_flags;
408 if (seal_secure_channel) {
409 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
411 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
414 status = netlogon_creds_cli_context_common(client_computer,
421 server_netbios_domain,
425 if (!NT_STATUS_IS_OK(status)) {
430 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
431 if (context->db.g_ctx == NULL) {
432 TALLOC_FREE(context);
434 return NT_STATUS_NO_MEMORY;
437 if (netlogon_creds_cli_global_db != NULL) {
438 context->db.ctx = netlogon_creds_cli_global_db;
444 status = netlogon_creds_cli_open_global_db(lp_ctx);
445 if (!NT_STATUS_IS_OK(status)) {
446 TALLOC_FREE(context);
448 return NT_STATUS_NO_MEMORY;
451 context->db.ctx = netlogon_creds_cli_global_db;
457 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
458 const char *client_account,
459 enum netr_SchannelType type,
460 uint32_t proposed_flags,
461 uint32_t required_flags,
462 enum dcerpc_AuthLevel auth_level,
463 const char *server_computer,
464 const char *server_netbios_domain,
466 struct netlogon_creds_cli_context **_context)
469 struct netlogon_creds_cli_context *context = NULL;
473 status = netlogon_creds_cli_context_common(client_computer,
480 server_netbios_domain,
484 if (!NT_STATUS_IS_OK(status)) {
488 context->db.ctx = db_open_rbt(context);
489 if (context->db.ctx == NULL) {
490 talloc_free(context);
491 return NT_STATUS_NO_MEMORY;
498 char *netlogon_creds_cli_debug_string(
499 const struct netlogon_creds_cli_context *context,
502 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
503 context->db.key_name);
506 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
507 struct netlogon_creds_cli_context *context)
509 return context->client.auth_level;
512 struct netlogon_creds_cli_fetch_state {
514 struct netlogon_creds_CredentialState *creds;
515 uint32_t required_flags;
519 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
522 struct netlogon_creds_cli_fetch_state *state =
523 (struct netlogon_creds_cli_fetch_state *)private_data;
524 enum ndr_err_code ndr_err;
528 state->creds = talloc_zero(state->mem_ctx,
529 struct netlogon_creds_CredentialState);
530 if (state->creds == NULL) {
531 state->status = NT_STATUS_NO_MEMORY;
535 blob.data = data.dptr;
536 blob.length = data.dsize;
538 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
539 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
540 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
541 TALLOC_FREE(state->creds);
542 state->status = ndr_map_error2ntstatus(ndr_err);
546 tmp_flags = state->creds->negotiate_flags;
547 tmp_flags &= state->required_flags;
548 if (tmp_flags != state->required_flags) {
549 TALLOC_FREE(state->creds);
550 state->status = NT_STATUS_DOWNGRADE_DETECTED;
554 state->status = NT_STATUS_OK;
557 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
559 struct netlogon_creds_CredentialState **_creds)
562 struct netlogon_creds_cli_fetch_state fstate = {
564 .status = NT_STATUS_INTERNAL_ERROR,
565 .required_flags = context->client.required_flags,
570 status = dbwrap_parse_record(context->db.ctx,
571 context->db.key_data,
572 netlogon_creds_cli_fetch_parser,
574 if (!NT_STATUS_IS_OK(status)) {
577 status = fstate.status;
578 if (!NT_STATUS_IS_OK(status)) {
583 * mark it as invalid for step operations.
585 fstate.creds->sequence = 0;
586 fstate.creds->seed = (struct netr_Credential) {{0}};
587 fstate.creds->client = (struct netr_Credential) {{0}};
588 fstate.creds->server = (struct netr_Credential) {{0}};
590 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
591 *_creds = fstate.creds;
596 * It is really important to try SamLogonEx here,
597 * because multiple processes can talk to the same
598 * domain controller, without using the credential
601 * With a normal SamLogon call, we must keep the
602 * credentials chain updated and intact between all
603 * users of the machine account (which would imply
604 * cross-node communication for every NTLM logon).
606 * The credentials chain is not per NETLOGON pipe
607 * connection, but globally on the server/client pair
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 cmp = data_blob_cmp(&blob1, &blob2);
681 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
682 struct netlogon_creds_CredentialState **_creds)
684 struct netlogon_creds_CredentialState *creds = *_creds;
686 enum ndr_err_code ndr_err;
692 if (context->db.locked_state == NULL) {
694 * this was not the result of netlogon_creds_cli_lock*()
697 return NT_STATUS_INVALID_PAGE_PROTECTION;
700 if (context->db.locked_state->creds != creds) {
702 * this was not the result of netlogon_creds_cli_lock*()
705 return NT_STATUS_INVALID_PAGE_PROTECTION;
708 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
709 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
710 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
712 status = ndr_map_error2ntstatus(ndr_err);
716 data.dptr = blob.data;
717 data.dsize = blob.length;
719 status = dbwrap_store(context->db.ctx,
720 context->db.key_data,
723 if (!NT_STATUS_IS_OK(status)) {
730 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
731 struct netlogon_creds_CredentialState **_creds)
733 struct netlogon_creds_CredentialState *creds = *_creds;
738 if (context->db.locked_state == NULL) {
740 * this was not the result of netlogon_creds_cli_lock*()
743 return NT_STATUS_INVALID_PAGE_PROTECTION;
746 if (context->db.locked_state->creds != creds) {
748 * this was not the result of netlogon_creds_cli_lock*()
751 return NT_STATUS_INVALID_PAGE_PROTECTION;
754 status = dbwrap_delete(context->db.ctx,
755 context->db.key_data);
757 if (!NT_STATUS_IS_OK(status)) {
764 struct netlogon_creds_cli_lock_state {
765 struct netlogon_creds_cli_locked_state *locked_state;
766 struct netlogon_creds_CredentialState *creds;
769 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
770 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
772 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
773 struct tevent_context *ev,
774 struct netlogon_creds_cli_context *context)
776 struct tevent_req *req;
777 struct netlogon_creds_cli_lock_state *state;
778 struct netlogon_creds_cli_locked_state *locked_state;
779 struct tevent_req *subreq;
781 req = tevent_req_create(mem_ctx, &state,
782 struct netlogon_creds_cli_lock_state);
787 if (context->db.locked_state != NULL) {
788 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
789 return tevent_req_post(req, ev);
792 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
793 if (tevent_req_nomem(locked_state, req)) {
794 return tevent_req_post(req, ev);
796 talloc_set_destructor(locked_state,
797 netlogon_creds_cli_locked_state_destructor);
798 locked_state->context = context;
800 context->db.locked_state = locked_state;
801 state->locked_state = locked_state;
803 if (context->db.g_ctx == NULL) {
804 netlogon_creds_cli_lock_fetch(req);
805 if (!tevent_req_is_in_progress(req)) {
806 return tevent_req_post(req, ev);
812 subreq = g_lock_lock_send(state, ev,
814 context->db.key_name,
816 if (tevent_req_nomem(subreq, req)) {
817 return tevent_req_post(req, ev);
819 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
824 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
826 struct tevent_req *req =
827 tevent_req_callback_data(subreq,
829 struct netlogon_creds_cli_lock_state *state =
831 struct netlogon_creds_cli_lock_state);
834 status = g_lock_lock_recv(subreq);
836 if (tevent_req_nterror(req, status)) {
839 state->locked_state->is_glocked = true;
841 netlogon_creds_cli_lock_fetch(req);
844 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
846 struct netlogon_creds_cli_lock_state *state =
848 struct netlogon_creds_cli_lock_state);
849 struct netlogon_creds_cli_context *context = state->locked_state->context;
850 struct netlogon_creds_cli_fetch_state fstate = {
851 .status = NT_STATUS_INTERNAL_ERROR,
852 .required_flags = context->client.required_flags,
856 fstate.mem_ctx = state;
857 status = dbwrap_parse_record(context->db.ctx,
858 context->db.key_data,
859 netlogon_creds_cli_fetch_parser,
861 if (tevent_req_nterror(req, status)) {
864 status = fstate.status;
865 if (tevent_req_nterror(req, status)) {
869 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
870 state->creds = fstate.creds;
871 tevent_req_done(req);
875 context->server.cached_flags = fstate.creds->negotiate_flags;
876 context->server.try_validation6 = true;
877 context->server.try_logon_ex = true;
878 context->server.try_logon_with = true;
880 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
881 context->server.try_validation6 = false;
882 context->server.try_logon_ex = false;
884 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
885 context->server.try_validation6 = false;
888 state->creds = fstate.creds;
889 tevent_req_done(req);
893 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
895 struct netlogon_creds_CredentialState **creds)
897 struct netlogon_creds_cli_lock_state *state =
899 struct netlogon_creds_cli_lock_state);
902 if (tevent_req_is_nterror(req, &status)) {
903 tevent_req_received(req);
907 talloc_steal(state->creds, state->locked_state);
908 state->locked_state->creds = state->creds;
909 *creds = talloc_move(mem_ctx, &state->creds);
910 tevent_req_received(req);
914 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
916 struct netlogon_creds_CredentialState **creds)
918 TALLOC_CTX *frame = talloc_stackframe();
919 struct tevent_context *ev;
920 struct tevent_req *req;
921 NTSTATUS status = NT_STATUS_NO_MEMORY;
923 ev = samba_tevent_context_init(frame);
927 req = netlogon_creds_cli_lock_send(frame, ev, context);
931 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
934 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
940 struct netlogon_creds_cli_auth_state {
941 struct tevent_context *ev;
942 struct netlogon_creds_cli_context *context;
943 struct dcerpc_binding_handle *binding_handle;
944 uint8_t num_nt_hashes;
945 uint8_t idx_nt_hashes;
946 const struct samr_Password * const *nt_hashes;
947 const struct samr_Password *used_nt_hash;
948 char *srv_name_slash;
949 uint32_t current_flags;
950 struct netr_Credential client_challenge;
951 struct netr_Credential server_challenge;
952 struct netlogon_creds_CredentialState *creds;
953 struct netr_Credential client_credential;
954 struct netr_Credential server_credential;
959 struct netlogon_creds_cli_locked_state *locked_state;
962 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
963 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
965 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
966 struct tevent_context *ev,
967 struct netlogon_creds_cli_context *context,
968 struct dcerpc_binding_handle *b,
969 uint8_t num_nt_hashes,
970 const struct samr_Password * const *nt_hashes)
972 struct tevent_req *req;
973 struct netlogon_creds_cli_auth_state *state;
974 struct netlogon_creds_cli_locked_state *locked_state;
977 req = tevent_req_create(mem_ctx, &state,
978 struct netlogon_creds_cli_auth_state);
984 state->context = context;
985 state->binding_handle = b;
986 if (num_nt_hashes < 1) {
987 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
988 return tevent_req_post(req, ev);
990 if (num_nt_hashes > 4) {
991 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
992 return tevent_req_post(req, ev);
995 state->num_nt_hashes = num_nt_hashes;
996 state->idx_nt_hashes = 0;
997 state->nt_hashes = nt_hashes;
999 if (context->db.locked_state != NULL) {
1000 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
1001 return tevent_req_post(req, ev);
1004 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
1005 if (tevent_req_nomem(locked_state, req)) {
1006 return tevent_req_post(req, ev);
1008 talloc_set_destructor(locked_state,
1009 netlogon_creds_cli_locked_state_destructor);
1010 locked_state->context = context;
1012 context->db.locked_state = locked_state;
1013 state->locked_state = locked_state;
1015 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1016 context->server.computer);
1017 if (tevent_req_nomem(state->srv_name_slash, req)) {
1018 return tevent_req_post(req, ev);
1021 state->try_auth3 = true;
1022 state->try_auth2 = true;
1024 if (context->client.required_flags != 0) {
1025 state->require_auth2 = true;
1028 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1029 state->current_flags = context->client.proposed_flags;
1031 if (context->db.g_ctx != NULL) {
1032 struct tevent_req *subreq;
1034 subreq = g_lock_lock_send(state, ev,
1036 context->db.key_name,
1038 if (tevent_req_nomem(subreq, req)) {
1039 return tevent_req_post(req, ev);
1041 tevent_req_set_callback(subreq,
1042 netlogon_creds_cli_auth_locked,
1048 status = dbwrap_purge(state->context->db.ctx,
1049 state->context->db.key_data);
1050 if (tevent_req_nterror(req, status)) {
1051 return tevent_req_post(req, ev);
1054 netlogon_creds_cli_auth_challenge_start(req);
1055 if (!tevent_req_is_in_progress(req)) {
1056 return tevent_req_post(req, ev);
1062 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1064 struct tevent_req *req =
1065 tevent_req_callback_data(subreq,
1067 struct netlogon_creds_cli_auth_state *state =
1068 tevent_req_data(req,
1069 struct netlogon_creds_cli_auth_state);
1072 status = g_lock_lock_recv(subreq);
1073 TALLOC_FREE(subreq);
1074 if (tevent_req_nterror(req, status)) {
1077 state->locked_state->is_glocked = true;
1079 status = dbwrap_purge(state->context->db.ctx,
1080 state->context->db.key_data);
1081 if (tevent_req_nterror(req, status)) {
1085 netlogon_creds_cli_auth_challenge_start(req);
1088 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1090 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1092 struct netlogon_creds_cli_auth_state *state =
1093 tevent_req_data(req,
1094 struct netlogon_creds_cli_auth_state);
1095 struct tevent_req *subreq;
1097 TALLOC_FREE(state->creds);
1099 generate_random_buffer(state->client_challenge.data,
1100 sizeof(state->client_challenge.data));
1102 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1103 state->binding_handle,
1104 state->srv_name_slash,
1105 state->context->client.computer,
1106 &state->client_challenge,
1107 &state->server_challenge);
1108 if (tevent_req_nomem(subreq, req)) {
1111 tevent_req_set_callback(subreq,
1112 netlogon_creds_cli_auth_challenge_done,
1116 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1118 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1120 struct tevent_req *req =
1121 tevent_req_callback_data(subreq,
1123 struct netlogon_creds_cli_auth_state *state =
1124 tevent_req_data(req,
1125 struct netlogon_creds_cli_auth_state);
1129 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1130 TALLOC_FREE(subreq);
1131 if (tevent_req_nterror(req, status)) {
1134 if (tevent_req_nterror(req, result)) {
1138 if (!state->try_auth3 && !state->try_auth2) {
1139 state->current_flags = 0;
1142 /* Calculate the session key and client credentials */
1144 state->creds = netlogon_creds_client_init(state,
1145 state->context->client.account,
1146 state->context->client.computer,
1147 state->context->client.type,
1148 &state->client_challenge,
1149 &state->server_challenge,
1150 state->used_nt_hash,
1151 &state->client_credential,
1152 state->current_flags);
1153 if (tevent_req_nomem(state->creds, req)) {
1157 if (state->try_auth3) {
1158 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1159 state->binding_handle,
1160 state->srv_name_slash,
1161 state->context->client.account,
1162 state->context->client.type,
1163 state->context->client.computer,
1164 &state->client_credential,
1165 &state->server_credential,
1166 &state->creds->negotiate_flags,
1168 if (tevent_req_nomem(subreq, req)) {
1171 } else if (state->try_auth2) {
1174 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1175 state->binding_handle,
1176 state->srv_name_slash,
1177 state->context->client.account,
1178 state->context->client.type,
1179 state->context->client.computer,
1180 &state->client_credential,
1181 &state->server_credential,
1182 &state->creds->negotiate_flags);
1183 if (tevent_req_nomem(subreq, req)) {
1189 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1190 state->binding_handle,
1191 state->srv_name_slash,
1192 state->context->client.account,
1193 state->context->client.type,
1194 state->context->client.computer,
1195 &state->client_credential,
1196 &state->server_credential);
1197 if (tevent_req_nomem(subreq, req)) {
1201 tevent_req_set_callback(subreq,
1202 netlogon_creds_cli_auth_srvauth_done,
1206 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1208 struct tevent_req *req =
1209 tevent_req_callback_data(subreq,
1211 struct netlogon_creds_cli_auth_state *state =
1212 tevent_req_data(req,
1213 struct netlogon_creds_cli_auth_state);
1217 enum ndr_err_code ndr_err;
1222 if (state->try_auth3) {
1223 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1225 TALLOC_FREE(subreq);
1226 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1227 state->try_auth3 = false;
1228 netlogon_creds_cli_auth_challenge_start(req);
1231 if (tevent_req_nterror(req, status)) {
1234 } else if (state->try_auth2) {
1235 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1237 TALLOC_FREE(subreq);
1238 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1239 state->try_auth2 = false;
1240 if (state->require_auth2) {
1241 status = NT_STATUS_DOWNGRADE_DETECTED;
1242 tevent_req_nterror(req, status);
1245 netlogon_creds_cli_auth_challenge_start(req);
1248 if (tevent_req_nterror(req, status)) {
1252 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1254 TALLOC_FREE(subreq);
1255 if (tevent_req_nterror(req, status)) {
1260 if (!NT_STATUS_IS_OK(result) &&
1261 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1263 tevent_req_nterror(req, result);
1267 tmp_flags = state->creds->negotiate_flags;
1268 tmp_flags &= state->context->client.required_flags;
1269 if (tmp_flags != state->context->client.required_flags) {
1270 if (NT_STATUS_IS_OK(result)) {
1271 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1274 tevent_req_nterror(req, result);
1278 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1280 tmp_flags = state->context->client.proposed_flags;
1281 if ((state->current_flags == tmp_flags) &&
1282 (state->creds->negotiate_flags != tmp_flags))
1285 * lets retry with the negotiated flags
1287 state->current_flags = state->creds->negotiate_flags;
1288 netlogon_creds_cli_auth_challenge_start(req);
1292 state->idx_nt_hashes += 1;
1293 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1295 * we already retried, giving up...
1297 tevent_req_nterror(req, result);
1302 * lets retry with the old nt hash.
1304 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1305 state->current_flags = state->context->client.proposed_flags;
1306 netlogon_creds_cli_auth_challenge_start(req);
1310 ok = netlogon_creds_client_check(state->creds,
1311 &state->server_credential);
1313 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1317 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1318 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1319 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1320 status = ndr_map_error2ntstatus(ndr_err);
1321 tevent_req_nterror(req, status);
1325 data.dptr = blob.data;
1326 data.dsize = blob.length;
1328 status = dbwrap_store(state->context->db.ctx,
1329 state->context->db.key_data,
1331 TALLOC_FREE(state->locked_state);
1332 if (tevent_req_nterror(req, status)) {
1336 tevent_req_done(req);
1339 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1340 uint8_t *idx_nt_hashes)
1342 struct netlogon_creds_cli_auth_state *state =
1343 tevent_req_data(req,
1344 struct netlogon_creds_cli_auth_state);
1349 if (tevent_req_is_nterror(req, &status)) {
1350 tevent_req_received(req);
1354 *idx_nt_hashes = state->idx_nt_hashes;
1355 tevent_req_received(req);
1356 return NT_STATUS_OK;
1359 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1360 struct dcerpc_binding_handle *b,
1361 uint8_t num_nt_hashes,
1362 const struct samr_Password * const *nt_hashes,
1363 uint8_t *idx_nt_hashes)
1365 TALLOC_CTX *frame = talloc_stackframe();
1366 struct tevent_context *ev;
1367 struct tevent_req *req;
1368 NTSTATUS status = NT_STATUS_NO_MEMORY;
1372 ev = samba_tevent_context_init(frame);
1376 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1377 num_nt_hashes, nt_hashes);
1381 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1384 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1390 struct netlogon_creds_cli_check_state {
1391 struct tevent_context *ev;
1392 struct netlogon_creds_cli_context *context;
1393 struct dcerpc_binding_handle *binding_handle;
1395 char *srv_name_slash;
1397 union netr_Capabilities caps;
1399 struct netlogon_creds_CredentialState *creds;
1400 struct netlogon_creds_CredentialState tmp_creds;
1401 struct netr_Authenticator req_auth;
1402 struct netr_Authenticator rep_auth;
1405 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1407 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1409 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1410 struct tevent_context *ev,
1411 struct netlogon_creds_cli_context *context,
1412 struct dcerpc_binding_handle *b)
1414 struct tevent_req *req;
1415 struct netlogon_creds_cli_check_state *state;
1416 struct tevent_req *subreq;
1417 enum dcerpc_AuthType auth_type;
1418 enum dcerpc_AuthLevel auth_level;
1420 req = tevent_req_create(mem_ctx, &state,
1421 struct netlogon_creds_cli_check_state);
1427 state->context = context;
1428 state->binding_handle = b;
1430 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1431 context->server.computer);
1432 if (tevent_req_nomem(state->srv_name_slash, req)) {
1433 return tevent_req_post(req, ev);
1436 dcerpc_binding_handle_auth_info(state->binding_handle,
1437 &auth_type, &auth_level);
1439 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1440 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1441 return tevent_req_post(req, ev);
1444 switch (auth_level) {
1445 case DCERPC_AUTH_LEVEL_INTEGRITY:
1446 case DCERPC_AUTH_LEVEL_PRIVACY:
1449 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1450 return tevent_req_post(req, ev);
1453 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1455 if (tevent_req_nomem(subreq, req)) {
1456 return tevent_req_post(req, ev);
1459 tevent_req_set_callback(subreq,
1460 netlogon_creds_cli_check_locked,
1466 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1469 struct netlogon_creds_cli_check_state *state =
1470 tevent_req_data(req,
1471 struct netlogon_creds_cli_check_state);
1473 if (state->creds == NULL) {
1477 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1478 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1479 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1480 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1481 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1482 TALLOC_FREE(state->creds);
1486 netlogon_creds_cli_delete(state->context, &state->creds);
1489 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1491 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1493 struct tevent_req *req =
1494 tevent_req_callback_data(subreq,
1496 struct netlogon_creds_cli_check_state *state =
1497 tevent_req_data(req,
1498 struct netlogon_creds_cli_check_state);
1501 status = netlogon_creds_cli_lock_recv(subreq, state,
1503 TALLOC_FREE(subreq);
1504 if (tevent_req_nterror(req, status)) {
1509 * we defer all callbacks in order to cleanup
1510 * the database record.
1512 tevent_req_defer_callback(req, state->ev);
1514 state->tmp_creds = *state->creds;
1515 netlogon_creds_client_authenticator(&state->tmp_creds,
1517 ZERO_STRUCT(state->rep_auth);
1519 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1520 state->binding_handle,
1521 state->srv_name_slash,
1522 state->context->client.computer,
1527 if (tevent_req_nomem(subreq, req)) {
1528 status = NT_STATUS_NO_MEMORY;
1529 netlogon_creds_cli_check_cleanup(req, status);
1532 tevent_req_set_callback(subreq,
1533 netlogon_creds_cli_check_caps,
1537 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1539 struct tevent_req *req =
1540 tevent_req_callback_data(subreq,
1542 struct netlogon_creds_cli_check_state *state =
1543 tevent_req_data(req,
1544 struct netlogon_creds_cli_check_state);
1549 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1551 TALLOC_FREE(subreq);
1552 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1554 * Note that the negotiated flags are already checked
1555 * for our required flags after the ServerAuthenticate3/2 call.
1557 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1559 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1561 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1562 * already, we expect this to work!
1564 status = NT_STATUS_DOWNGRADE_DETECTED;
1565 tevent_req_nterror(req, status);
1566 netlogon_creds_cli_check_cleanup(req, status);
1570 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1572 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1573 * we expect this to work at least as far as the
1574 * NOT_SUPPORTED error handled below!
1576 * NT 4.0 and Old Samba servers are not
1577 * allowed without "require strong key = no"
1579 status = NT_STATUS_DOWNGRADE_DETECTED;
1580 tevent_req_nterror(req, status);
1581 netlogon_creds_cli_check_cleanup(req, status);
1586 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1587 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1588 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1590 * This is needed against NT 4.0 and old Samba servers.
1592 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1593 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1594 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1595 * with the next request as the sequence number processing
1598 netlogon_creds_cli_check_cleanup(req, status);
1599 tevent_req_done(req);
1602 if (tevent_req_nterror(req, status)) {
1603 netlogon_creds_cli_check_cleanup(req, status);
1607 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1609 * Note that the negotiated flags are already checked
1610 * for our required flags after the ServerAuthenticate3/2 call.
1612 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1614 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1616 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1617 * already, we expect this to work!
1619 status = NT_STATUS_DOWNGRADE_DETECTED;
1620 tevent_req_nterror(req, status);
1621 netlogon_creds_cli_check_cleanup(req, status);
1626 * This is ok, the server does not support
1627 * NETLOGON_NEG_SUPPORTS_AES.
1629 * netr_LogonGetCapabilities() was
1630 * netr_LogonDummyRoutine1() before
1631 * NETLOGON_NEG_SUPPORTS_AES was invented.
1633 netlogon_creds_cli_check_cleanup(req, result);
1634 tevent_req_done(req);
1638 ok = netlogon_creds_client_check(&state->tmp_creds,
1639 &state->rep_auth.cred);
1641 status = NT_STATUS_ACCESS_DENIED;
1642 tevent_req_nterror(req, status);
1643 netlogon_creds_cli_check_cleanup(req, status);
1647 if (tevent_req_nterror(req, result)) {
1648 netlogon_creds_cli_check_cleanup(req, result);
1652 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1653 status = NT_STATUS_DOWNGRADE_DETECTED;
1654 tevent_req_nterror(req, status);
1655 netlogon_creds_cli_check_cleanup(req, status);
1660 * This is the key check that makes this check secure. If we
1661 * get OK here (rather than NOT_SUPPORTED), then the server
1662 * did support AES. If the server only proposed STRONG_KEYS
1663 * and not AES, then it should have failed with
1664 * NOT_IMPLEMENTED. We always send AES as a client, so the
1665 * server should always have returned it.
1667 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1668 status = NT_STATUS_DOWNGRADE_DETECTED;
1669 tevent_req_nterror(req, status);
1670 netlogon_creds_cli_check_cleanup(req, status);
1674 *state->creds = state->tmp_creds;
1675 status = netlogon_creds_cli_store(state->context,
1677 netlogon_creds_cli_check_cleanup(req, status);
1678 if (tevent_req_nterror(req, status)) {
1682 tevent_req_done(req);
1685 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1689 if (tevent_req_is_nterror(req, &status)) {
1690 netlogon_creds_cli_check_cleanup(req, status);
1691 tevent_req_received(req);
1695 tevent_req_received(req);
1696 return NT_STATUS_OK;
1699 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1700 struct dcerpc_binding_handle *b)
1702 TALLOC_CTX *frame = talloc_stackframe();
1703 struct tevent_context *ev;
1704 struct tevent_req *req;
1705 NTSTATUS status = NT_STATUS_NO_MEMORY;
1707 ev = samba_tevent_context_init(frame);
1711 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1715 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1718 status = netlogon_creds_cli_check_recv(req);
1724 struct netlogon_creds_cli_ServerPasswordSet_state {
1725 struct tevent_context *ev;
1726 struct netlogon_creds_cli_context *context;
1727 struct dcerpc_binding_handle *binding_handle;
1728 uint32_t old_timeout;
1730 char *srv_name_slash;
1731 enum dcerpc_AuthType auth_type;
1732 enum dcerpc_AuthLevel auth_level;
1734 struct samr_CryptPassword samr_crypt_password;
1735 struct netr_CryptPassword netr_crypt_password;
1736 struct samr_Password samr_password;
1738 struct netlogon_creds_CredentialState *creds;
1739 struct netlogon_creds_CredentialState tmp_creds;
1740 struct netr_Authenticator req_auth;
1741 struct netr_Authenticator rep_auth;
1744 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1746 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1748 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1749 struct tevent_context *ev,
1750 struct netlogon_creds_cli_context *context,
1751 struct dcerpc_binding_handle *b,
1752 const DATA_BLOB *new_password,
1753 const uint32_t *new_version)
1755 struct tevent_req *req;
1756 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1757 struct tevent_req *subreq;
1760 req = tevent_req_create(mem_ctx, &state,
1761 struct netlogon_creds_cli_ServerPasswordSet_state);
1767 state->context = context;
1768 state->binding_handle = b;
1770 if (new_password->length < 14) {
1771 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1772 return tevent_req_post(req, ev);
1776 * netr_ServerPasswordSet
1778 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1781 * netr_ServerPasswordSet2
1783 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1786 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1787 return tevent_req_post(req, ev);
1790 if (new_version != NULL) {
1791 struct NL_PASSWORD_VERSION version;
1792 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1793 uint32_t ofs = 512 - len;
1797 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1798 return tevent_req_post(req, ev);
1802 version.ReservedField = 0;
1803 version.PasswordVersionNumber = *new_version;
1804 version.PasswordVersionPresent =
1805 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1807 p = state->samr_crypt_password.data + ofs;
1808 SIVAL(p, 0, version.ReservedField);
1809 SIVAL(p, 4, version.PasswordVersionNumber);
1810 SIVAL(p, 8, version.PasswordVersionPresent);
1813 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1814 context->server.computer);
1815 if (tevent_req_nomem(state->srv_name_slash, req)) {
1816 return tevent_req_post(req, ev);
1819 dcerpc_binding_handle_auth_info(state->binding_handle,
1821 &state->auth_level);
1823 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1825 if (tevent_req_nomem(subreq, req)) {
1826 return tevent_req_post(req, ev);
1829 tevent_req_set_callback(subreq,
1830 netlogon_creds_cli_ServerPasswordSet_locked,
1836 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1839 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1840 tevent_req_data(req,
1841 struct netlogon_creds_cli_ServerPasswordSet_state);
1843 if (state->creds == NULL) {
1847 dcerpc_binding_handle_set_timeout(state->binding_handle,
1848 state->old_timeout);
1850 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1851 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1852 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1853 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1854 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1855 TALLOC_FREE(state->creds);
1859 netlogon_creds_cli_delete(state->context, &state->creds);
1862 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1864 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1866 struct tevent_req *req =
1867 tevent_req_callback_data(subreq,
1869 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1870 tevent_req_data(req,
1871 struct netlogon_creds_cli_ServerPasswordSet_state);
1874 status = netlogon_creds_cli_lock_recv(subreq, state,
1876 TALLOC_FREE(subreq);
1877 if (tevent_req_nterror(req, status)) {
1881 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1882 switch (state->auth_level) {
1883 case DCERPC_AUTH_LEVEL_INTEGRITY:
1884 case DCERPC_AUTH_LEVEL_PRIVACY:
1887 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1891 uint32_t tmp = state->creds->negotiate_flags;
1893 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1895 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1896 * it should be used, which means
1897 * we had a chance to verify no downgrade
1900 * This relies on netlogon_creds_cli_check*
1901 * being called before, as first request after
1904 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1909 state->old_timeout = dcerpc_binding_handle_set_timeout(
1910 state->binding_handle, 600000);
1913 * we defer all callbacks in order to cleanup
1914 * the database record.
1916 tevent_req_defer_callback(req, state->ev);
1918 state->tmp_creds = *state->creds;
1919 netlogon_creds_client_authenticator(&state->tmp_creds,
1921 ZERO_STRUCT(state->rep_auth);
1923 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1925 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1926 netlogon_creds_aes_encrypt(&state->tmp_creds,
1927 state->samr_crypt_password.data,
1930 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1931 state->samr_crypt_password.data,
1935 memcpy(state->netr_crypt_password.data,
1936 state->samr_crypt_password.data, 512);
1937 state->netr_crypt_password.length =
1938 IVAL(state->samr_crypt_password.data, 512);
1940 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1941 state->binding_handle,
1942 state->srv_name_slash,
1943 state->tmp_creds.account_name,
1944 state->tmp_creds.secure_channel_type,
1945 state->tmp_creds.computer_name,
1948 &state->netr_crypt_password);
1949 if (tevent_req_nomem(subreq, req)) {
1950 status = NT_STATUS_NO_MEMORY;
1951 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1955 netlogon_creds_des_encrypt(&state->tmp_creds,
1956 &state->samr_password);
1958 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1959 state->binding_handle,
1960 state->srv_name_slash,
1961 state->tmp_creds.account_name,
1962 state->tmp_creds.secure_channel_type,
1963 state->tmp_creds.computer_name,
1966 &state->samr_password);
1967 if (tevent_req_nomem(subreq, req)) {
1968 status = NT_STATUS_NO_MEMORY;
1969 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1974 tevent_req_set_callback(subreq,
1975 netlogon_creds_cli_ServerPasswordSet_done,
1979 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1981 struct tevent_req *req =
1982 tevent_req_callback_data(subreq,
1984 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1985 tevent_req_data(req,
1986 struct netlogon_creds_cli_ServerPasswordSet_state);
1991 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1992 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1994 TALLOC_FREE(subreq);
1995 if (tevent_req_nterror(req, status)) {
1996 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2000 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2002 TALLOC_FREE(subreq);
2003 if (tevent_req_nterror(req, status)) {
2004 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2009 ok = netlogon_creds_client_check(&state->tmp_creds,
2010 &state->rep_auth.cred);
2012 status = NT_STATUS_ACCESS_DENIED;
2013 tevent_req_nterror(req, status);
2014 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2018 if (tevent_req_nterror(req, result)) {
2019 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2023 dcerpc_binding_handle_set_timeout(state->binding_handle,
2024 state->old_timeout);
2026 *state->creds = state->tmp_creds;
2027 status = netlogon_creds_cli_store(state->context,
2029 if (tevent_req_nterror(req, status)) {
2030 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2034 tevent_req_done(req);
2037 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2041 if (tevent_req_is_nterror(req, &status)) {
2042 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2043 tevent_req_received(req);
2047 tevent_req_received(req);
2048 return NT_STATUS_OK;
2051 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2052 struct netlogon_creds_cli_context *context,
2053 struct dcerpc_binding_handle *b,
2054 const DATA_BLOB *new_password,
2055 const uint32_t *new_version)
2057 TALLOC_CTX *frame = talloc_stackframe();
2058 struct tevent_context *ev;
2059 struct tevent_req *req;
2060 NTSTATUS status = NT_STATUS_NO_MEMORY;
2062 ev = samba_tevent_context_init(frame);
2066 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2072 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2075 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2081 struct netlogon_creds_cli_LogonSamLogon_state {
2082 struct tevent_context *ev;
2083 struct netlogon_creds_cli_context *context;
2084 struct dcerpc_binding_handle *binding_handle;
2086 char *srv_name_slash;
2088 enum netr_LogonInfoClass logon_level;
2089 const union netr_LogonLevel *const_logon;
2090 union netr_LogonLevel *logon;
2093 uint16_t validation_level;
2094 union netr_Validation *validation;
2095 uint8_t authoritative;
2098 * do we need encryption at the application layer?
2102 bool try_validation6;
2105 * the read only credentials before we started the operation
2106 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2108 struct netlogon_creds_CredentialState *ro_creds;
2111 * The (locked) credentials used for the credential chain
2112 * used for netr_LogonSamLogonWithFlags() or
2113 * netr_LogonSamLogonWith().
2115 struct netlogon_creds_CredentialState *lk_creds;
2118 * While we have locked the global credentials (lk_creds above)
2119 * we operate an a temporary copy, because a server
2120 * may not support netr_LogonSamLogonWithFlags() and
2121 * didn't process our netr_Authenticator, so we need to
2122 * restart from lk_creds.
2124 struct netlogon_creds_CredentialState tmp_creds;
2125 struct netr_Authenticator req_auth;
2126 struct netr_Authenticator rep_auth;
2129 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2130 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2133 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2134 struct tevent_context *ev,
2135 struct netlogon_creds_cli_context *context,
2136 struct dcerpc_binding_handle *b,
2137 enum netr_LogonInfoClass logon_level,
2138 const union netr_LogonLevel *logon,
2141 struct tevent_req *req;
2142 struct netlogon_creds_cli_LogonSamLogon_state *state;
2144 req = tevent_req_create(mem_ctx, &state,
2145 struct netlogon_creds_cli_LogonSamLogon_state);
2151 state->context = context;
2152 state->binding_handle = b;
2154 state->logon_level = logon_level;
2155 state->const_logon = logon;
2156 state->flags = flags;
2158 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2159 context->server.computer);
2160 if (tevent_req_nomem(state->srv_name_slash, req)) {
2161 return tevent_req_post(req, ev);
2164 switch (logon_level) {
2165 case NetlogonInteractiveInformation:
2166 case NetlogonInteractiveTransitiveInformation:
2167 case NetlogonServiceInformation:
2168 case NetlogonServiceTransitiveInformation:
2169 case NetlogonGenericInformation:
2170 state->user_encrypt = true;
2173 case NetlogonNetworkInformation:
2174 case NetlogonNetworkTransitiveInformation:
2178 state->validation = talloc_zero(state, union netr_Validation);
2179 if (tevent_req_nomem(state->validation, req)) {
2180 return tevent_req_post(req, ev);
2183 netlogon_creds_cli_LogonSamLogon_start(req);
2184 if (!tevent_req_is_in_progress(req)) {
2185 return tevent_req_post(req, ev);
2189 * we defer all callbacks in order to cleanup
2190 * the database record.
2192 tevent_req_defer_callback(req, state->ev);
2196 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2199 struct netlogon_creds_cli_LogonSamLogon_state *state =
2200 tevent_req_data(req,
2201 struct netlogon_creds_cli_LogonSamLogon_state);
2203 if (state->lk_creds == NULL) {
2207 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2209 * This is a hack to recover from a bug in old
2210 * Samba servers, when LogonSamLogonEx() fails:
2212 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2214 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2216 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2217 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2218 * If the sign/seal check fails.
2220 * In that case we need to cleanup the netlogon session.
2222 * It's the job of the caller to disconnect the current
2223 * connection, if netlogon_creds_cli_LogonSamLogon()
2224 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2226 if (!state->context->server.try_logon_with) {
2227 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2231 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2232 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2233 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2234 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2235 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2236 TALLOC_FREE(state->lk_creds);
2240 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2243 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2245 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2247 struct netlogon_creds_cli_LogonSamLogon_state *state =
2248 tevent_req_data(req,
2249 struct netlogon_creds_cli_LogonSamLogon_state);
2250 struct tevent_req *subreq;
2252 enum dcerpc_AuthType auth_type;
2253 enum dcerpc_AuthLevel auth_level;
2255 TALLOC_FREE(state->ro_creds);
2256 TALLOC_FREE(state->logon);
2257 ZERO_STRUCTP(state->validation);
2259 dcerpc_binding_handle_auth_info(state->binding_handle,
2260 &auth_type, &auth_level);
2262 state->try_logon_ex = state->context->server.try_logon_ex;
2263 state->try_validation6 = state->context->server.try_validation6;
2265 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2266 state->try_logon_ex = false;
2269 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2270 state->try_validation6 = false;
2273 if (state->try_logon_ex) {
2274 if (state->try_validation6) {
2275 state->validation_level = 6;
2277 state->validation_level = 3;
2278 state->user_encrypt = true;
2281 state->logon = netlogon_creds_shallow_copy_logon(state,
2283 state->const_logon);
2284 if (tevent_req_nomem(state->logon, req)) {
2285 status = NT_STATUS_NO_MEMORY;
2286 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2290 if (state->user_encrypt) {
2291 status = netlogon_creds_cli_get(state->context,
2294 if (!NT_STATUS_IS_OK(status)) {
2295 status = NT_STATUS_ACCESS_DENIED;
2296 tevent_req_nterror(req, status);
2297 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2301 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2306 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2307 state->binding_handle,
2308 state->srv_name_slash,
2309 state->context->client.computer,
2312 state->validation_level,
2314 &state->authoritative,
2316 if (tevent_req_nomem(subreq, req)) {
2317 status = NT_STATUS_NO_MEMORY;
2318 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2321 tevent_req_set_callback(subreq,
2322 netlogon_creds_cli_LogonSamLogon_done,
2327 if (state->lk_creds == NULL) {
2328 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2330 if (tevent_req_nomem(subreq, req)) {
2331 status = NT_STATUS_NO_MEMORY;
2332 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2335 tevent_req_set_callback(subreq,
2336 netlogon_creds_cli_LogonSamLogon_done,
2341 state->tmp_creds = *state->lk_creds;
2342 netlogon_creds_client_authenticator(&state->tmp_creds,
2344 ZERO_STRUCT(state->rep_auth);
2346 state->logon = netlogon_creds_shallow_copy_logon(state,
2348 state->const_logon);
2349 if (tevent_req_nomem(state->logon, req)) {
2350 status = NT_STATUS_NO_MEMORY;
2351 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2355 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2359 state->validation_level = 3;
2361 if (state->context->server.try_logon_with) {
2362 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2363 state->binding_handle,
2364 state->srv_name_slash,
2365 state->context->client.computer,
2370 state->validation_level,
2372 &state->authoritative,
2374 if (tevent_req_nomem(subreq, req)) {
2375 status = NT_STATUS_NO_MEMORY;
2376 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2382 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2383 state->binding_handle,
2384 state->srv_name_slash,
2385 state->context->client.computer,
2390 state->validation_level,
2392 &state->authoritative);
2393 if (tevent_req_nomem(subreq, req)) {
2394 status = NT_STATUS_NO_MEMORY;
2395 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2400 tevent_req_set_callback(subreq,
2401 netlogon_creds_cli_LogonSamLogon_done,
2405 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2407 struct tevent_req *req =
2408 tevent_req_callback_data(subreq,
2410 struct netlogon_creds_cli_LogonSamLogon_state *state =
2411 tevent_req_data(req,
2412 struct netlogon_creds_cli_LogonSamLogon_state);
2417 if (state->try_logon_ex) {
2418 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2421 TALLOC_FREE(subreq);
2422 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2423 state->context->server.try_validation6 = false;
2424 state->context->server.try_logon_ex = false;
2425 netlogon_creds_cli_LogonSamLogon_start(req);
2428 if (tevent_req_nterror(req, status)) {
2429 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2433 if ((state->validation_level == 6) &&
2434 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2435 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2436 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2438 state->context->server.try_validation6 = false;
2439 netlogon_creds_cli_LogonSamLogon_start(req);
2443 if (tevent_req_nterror(req, result)) {
2444 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2448 if (state->ro_creds == NULL) {
2449 tevent_req_done(req);
2453 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2456 * We got a race, lets retry with on authenticator
2459 * netlogon_creds_cli_LogonSamLogon_start()
2460 * will TALLOC_FREE(state->ro_creds);
2462 state->try_logon_ex = false;
2463 netlogon_creds_cli_LogonSamLogon_start(req);
2467 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2468 state->validation_level,
2471 tevent_req_done(req);
2475 if (state->lk_creds == NULL) {
2476 status = netlogon_creds_cli_lock_recv(subreq, state,
2478 TALLOC_FREE(subreq);
2479 if (tevent_req_nterror(req, status)) {
2480 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2484 netlogon_creds_cli_LogonSamLogon_start(req);
2488 if (state->context->server.try_logon_with) {
2489 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2492 TALLOC_FREE(subreq);
2493 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2494 state->context->server.try_logon_with = false;
2495 netlogon_creds_cli_LogonSamLogon_start(req);
2498 if (tevent_req_nterror(req, status)) {
2499 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2503 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2506 TALLOC_FREE(subreq);
2507 if (tevent_req_nterror(req, status)) {
2508 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2513 ok = netlogon_creds_client_check(&state->tmp_creds,
2514 &state->rep_auth.cred);
2516 status = NT_STATUS_ACCESS_DENIED;
2517 tevent_req_nterror(req, status);
2518 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2522 *state->lk_creds = state->tmp_creds;
2523 status = netlogon_creds_cli_store(state->context,
2525 if (tevent_req_nterror(req, status)) {
2526 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2530 if (tevent_req_nterror(req, result)) {
2531 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2535 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2536 state->validation_level,
2539 tevent_req_done(req);
2542 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2543 TALLOC_CTX *mem_ctx,
2544 uint16_t *validation_level,
2545 union netr_Validation **validation,
2546 uint8_t *authoritative,
2549 struct netlogon_creds_cli_LogonSamLogon_state *state =
2550 tevent_req_data(req,
2551 struct netlogon_creds_cli_LogonSamLogon_state);
2554 /* authoritative is also returned on error */
2555 *authoritative = state->authoritative;
2557 if (tevent_req_is_nterror(req, &status)) {
2558 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2559 tevent_req_received(req);
2563 *validation_level = state->validation_level;
2564 *validation = talloc_move(mem_ctx, &state->validation);
2565 *flags = state->flags;
2567 tevent_req_received(req);
2568 return NT_STATUS_OK;
2571 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2572 struct netlogon_creds_cli_context *context,
2573 struct dcerpc_binding_handle *b,
2574 enum netr_LogonInfoClass logon_level,
2575 const union netr_LogonLevel *logon,
2576 TALLOC_CTX *mem_ctx,
2577 uint16_t *validation_level,
2578 union netr_Validation **validation,
2579 uint8_t *authoritative,
2582 TALLOC_CTX *frame = talloc_stackframe();
2583 struct tevent_context *ev;
2584 struct tevent_req *req;
2585 NTSTATUS status = NT_STATUS_NO_MEMORY;
2587 ev = samba_tevent_context_init(frame);
2591 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2597 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2600 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2610 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2611 struct tevent_context *ev;
2612 struct netlogon_creds_cli_context *context;
2613 struct dcerpc_binding_handle *binding_handle;
2615 char *srv_name_slash;
2616 enum dcerpc_AuthType auth_type;
2617 enum dcerpc_AuthLevel auth_level;
2619 const char *site_name;
2621 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2623 struct netlogon_creds_CredentialState *creds;
2624 struct netlogon_creds_CredentialState tmp_creds;
2625 struct netr_Authenticator req_auth;
2626 struct netr_Authenticator rep_auth;
2629 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2631 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2633 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2634 struct tevent_context *ev,
2635 struct netlogon_creds_cli_context *context,
2636 struct dcerpc_binding_handle *b,
2637 const char *site_name,
2639 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2641 struct tevent_req *req;
2642 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2643 struct tevent_req *subreq;
2645 req = tevent_req_create(mem_ctx, &state,
2646 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2652 state->context = context;
2653 state->binding_handle = b;
2655 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2656 context->server.computer);
2657 if (tevent_req_nomem(state->srv_name_slash, req)) {
2658 return tevent_req_post(req, ev);
2661 state->site_name = site_name;
2662 state->dns_ttl = dns_ttl;
2663 state->dns_names = dns_names;
2665 dcerpc_binding_handle_auth_info(state->binding_handle,
2667 &state->auth_level);
2669 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2671 if (tevent_req_nomem(subreq, req)) {
2672 return tevent_req_post(req, ev);
2675 tevent_req_set_callback(subreq,
2676 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2682 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2685 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2686 tevent_req_data(req,
2687 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2689 if (state->creds == NULL) {
2693 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2694 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2695 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2696 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2697 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2698 TALLOC_FREE(state->creds);
2702 netlogon_creds_cli_delete(state->context, &state->creds);
2705 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2707 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2709 struct tevent_req *req =
2710 tevent_req_callback_data(subreq,
2712 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2713 tevent_req_data(req,
2714 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2717 status = netlogon_creds_cli_lock_recv(subreq, state,
2719 TALLOC_FREE(subreq);
2720 if (tevent_req_nterror(req, status)) {
2724 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2725 switch (state->auth_level) {
2726 case DCERPC_AUTH_LEVEL_INTEGRITY:
2727 case DCERPC_AUTH_LEVEL_PRIVACY:
2730 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2734 uint32_t tmp = state->creds->negotiate_flags;
2736 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2738 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2739 * it should be used, which means
2740 * we had a chance to verify no downgrade
2743 * This relies on netlogon_creds_cli_check*
2744 * being called before, as first request after
2747 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2753 * we defer all callbacks in order to cleanup
2754 * the database record.
2756 tevent_req_defer_callback(req, state->ev);
2758 state->tmp_creds = *state->creds;
2759 netlogon_creds_client_authenticator(&state->tmp_creds,
2761 ZERO_STRUCT(state->rep_auth);
2763 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2764 state->binding_handle,
2765 state->srv_name_slash,
2766 state->tmp_creds.computer_name,
2772 if (tevent_req_nomem(subreq, req)) {
2773 status = NT_STATUS_NO_MEMORY;
2774 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2778 tevent_req_set_callback(subreq,
2779 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2783 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2785 struct tevent_req *req =
2786 tevent_req_callback_data(subreq,
2788 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2789 tevent_req_data(req,
2790 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2796 * We use state->dns_names as the memory context, as this is
2797 * the only in/out variable and it has been overwritten by the
2798 * out parameter from the server.
2800 * We need to preserve the return value until the caller can use it.
2802 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2804 TALLOC_FREE(subreq);
2805 if (tevent_req_nterror(req, status)) {
2806 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2810 ok = netlogon_creds_client_check(&state->tmp_creds,
2811 &state->rep_auth.cred);
2813 status = NT_STATUS_ACCESS_DENIED;
2814 tevent_req_nterror(req, status);
2815 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2819 *state->creds = state->tmp_creds;
2820 status = netlogon_creds_cli_store(state->context,
2823 if (tevent_req_nterror(req, status)) {
2824 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2828 if (tevent_req_nterror(req, result)) {
2829 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2833 tevent_req_done(req);
2836 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2840 if (tevent_req_is_nterror(req, &status)) {
2841 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2842 tevent_req_received(req);
2846 tevent_req_received(req);
2847 return NT_STATUS_OK;
2850 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2851 struct netlogon_creds_cli_context *context,
2852 struct dcerpc_binding_handle *b,
2853 const char *site_name,
2855 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2857 TALLOC_CTX *frame = talloc_stackframe();
2858 struct tevent_context *ev;
2859 struct tevent_req *req;
2860 NTSTATUS status = NT_STATUS_NO_MEMORY;
2862 ev = samba_tevent_context_init(frame);
2866 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2873 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2876 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2882 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2883 struct tevent_context *ev;
2884 struct netlogon_creds_cli_context *context;
2885 struct dcerpc_binding_handle *binding_handle;
2887 char *srv_name_slash;
2888 enum dcerpc_AuthType auth_type;
2889 enum dcerpc_AuthLevel auth_level;
2891 struct samr_Password new_owf_password;
2892 struct samr_Password old_owf_password;
2893 struct netr_TrustInfo *trust_info;
2895 struct netlogon_creds_CredentialState *creds;
2896 struct netlogon_creds_CredentialState tmp_creds;
2897 struct netr_Authenticator req_auth;
2898 struct netr_Authenticator rep_auth;
2901 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2903 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2905 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2906 struct tevent_context *ev,
2907 struct netlogon_creds_cli_context *context,
2908 struct dcerpc_binding_handle *b)
2910 struct tevent_req *req;
2911 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2912 struct tevent_req *subreq;
2914 req = tevent_req_create(mem_ctx, &state,
2915 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2921 state->context = context;
2922 state->binding_handle = b;
2924 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2925 context->server.computer);
2926 if (tevent_req_nomem(state->srv_name_slash, req)) {
2927 return tevent_req_post(req, ev);
2930 dcerpc_binding_handle_auth_info(state->binding_handle,
2932 &state->auth_level);
2934 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2936 if (tevent_req_nomem(subreq, req)) {
2937 return tevent_req_post(req, ev);
2940 tevent_req_set_callback(subreq,
2941 netlogon_creds_cli_ServerGetTrustInfo_locked,
2947 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2950 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2951 tevent_req_data(req,
2952 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2954 if (state->creds == NULL) {
2958 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2959 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2960 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2961 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2962 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2963 TALLOC_FREE(state->creds);
2967 netlogon_creds_cli_delete(state->context, &state->creds);
2970 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2972 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2974 struct tevent_req *req =
2975 tevent_req_callback_data(subreq,
2977 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2978 tevent_req_data(req,
2979 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2982 status = netlogon_creds_cli_lock_recv(subreq, state,
2984 TALLOC_FREE(subreq);
2985 if (tevent_req_nterror(req, status)) {
2989 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2990 switch (state->auth_level) {
2991 case DCERPC_AUTH_LEVEL_PRIVACY:
2994 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2998 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3003 * we defer all callbacks in order to cleanup
3004 * the database record.
3006 tevent_req_defer_callback(req, state->ev);
3008 state->tmp_creds = *state->creds;
3009 netlogon_creds_client_authenticator(&state->tmp_creds,
3011 ZERO_STRUCT(state->rep_auth);
3013 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3014 state->binding_handle,
3015 state->srv_name_slash,
3016 state->tmp_creds.account_name,
3017 state->tmp_creds.secure_channel_type,
3018 state->tmp_creds.computer_name,
3021 &state->new_owf_password,
3022 &state->old_owf_password,
3023 &state->trust_info);
3024 if (tevent_req_nomem(subreq, req)) {
3025 status = NT_STATUS_NO_MEMORY;
3026 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3030 tevent_req_set_callback(subreq,
3031 netlogon_creds_cli_ServerGetTrustInfo_done,
3035 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3037 struct tevent_req *req =
3038 tevent_req_callback_data(subreq,
3040 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3041 tevent_req_data(req,
3042 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3045 const struct samr_Password zero = {};
3050 * We use state->dns_names as the memory context, as this is
3051 * the only in/out variable and it has been overwritten by the
3052 * out parameter from the server.
3054 * We need to preserve the return value until the caller can use it.
3056 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3057 TALLOC_FREE(subreq);
3058 if (tevent_req_nterror(req, status)) {
3059 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3063 ok = netlogon_creds_client_check(&state->tmp_creds,
3064 &state->rep_auth.cred);
3066 status = NT_STATUS_ACCESS_DENIED;
3067 tevent_req_nterror(req, status);
3068 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3072 cmp = memcmp(state->new_owf_password.hash,
3073 zero.hash, sizeof(zero.hash));
3075 netlogon_creds_des_decrypt(&state->tmp_creds,
3076 &state->new_owf_password);
3078 cmp = memcmp(state->old_owf_password.hash,
3079 zero.hash, sizeof(zero.hash));
3081 netlogon_creds_des_decrypt(&state->tmp_creds,
3082 &state->old_owf_password);
3085 *state->creds = state->tmp_creds;
3086 status = netlogon_creds_cli_store(state->context,
3088 if (tevent_req_nterror(req, status)) {
3089 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3093 if (tevent_req_nterror(req, result)) {
3094 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3098 tevent_req_done(req);
3101 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3102 TALLOC_CTX *mem_ctx,
3103 struct samr_Password *new_owf_password,
3104 struct samr_Password *old_owf_password,
3105 struct netr_TrustInfo **trust_info)
3107 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3108 tevent_req_data(req,
3109 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3112 if (tevent_req_is_nterror(req, &status)) {
3113 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3114 tevent_req_received(req);
3118 if (new_owf_password != NULL) {
3119 *new_owf_password = state->new_owf_password;
3121 if (old_owf_password != NULL) {
3122 *old_owf_password = state->old_owf_password;
3124 if (trust_info != NULL) {
3125 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3128 tevent_req_received(req);
3129 return NT_STATUS_OK;
3132 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3133 struct netlogon_creds_cli_context *context,
3134 struct dcerpc_binding_handle *b,
3135 TALLOC_CTX *mem_ctx,
3136 struct samr_Password *new_owf_password,
3137 struct samr_Password *old_owf_password,
3138 struct netr_TrustInfo **trust_info)
3140 TALLOC_CTX *frame = talloc_stackframe();
3141 struct tevent_context *ev;
3142 struct tevent_req *req;
3143 NTSTATUS status = NT_STATUS_NO_MEMORY;
3145 ev = samba_tevent_context_init(frame);
3149 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3153 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3156 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3166 struct netlogon_creds_cli_GetForestTrustInformation_state {
3167 struct tevent_context *ev;
3168 struct netlogon_creds_cli_context *context;
3169 struct dcerpc_binding_handle *binding_handle;
3171 char *srv_name_slash;
3172 enum dcerpc_AuthType auth_type;
3173 enum dcerpc_AuthLevel auth_level;
3176 struct lsa_ForestTrustInformation *forest_trust_info;
3178 struct netlogon_creds_CredentialState *creds;
3179 struct netlogon_creds_CredentialState tmp_creds;
3180 struct netr_Authenticator req_auth;
3181 struct netr_Authenticator rep_auth;
3184 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3186 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3188 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3189 struct tevent_context *ev,
3190 struct netlogon_creds_cli_context *context,
3191 struct dcerpc_binding_handle *b)
3193 struct tevent_req *req;
3194 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3195 struct tevent_req *subreq;
3197 req = tevent_req_create(mem_ctx, &state,
3198 struct netlogon_creds_cli_GetForestTrustInformation_state);
3204 state->context = context;
3205 state->binding_handle = b;
3207 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3208 context->server.computer);
3209 if (tevent_req_nomem(state->srv_name_slash, req)) {
3210 return tevent_req_post(req, ev);
3215 dcerpc_binding_handle_auth_info(state->binding_handle,
3217 &state->auth_level);
3219 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3221 if (tevent_req_nomem(subreq, req)) {
3222 return tevent_req_post(req, ev);
3225 tevent_req_set_callback(subreq,
3226 netlogon_creds_cli_GetForestTrustInformation_locked,
3232 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3235 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3236 tevent_req_data(req,
3237 struct netlogon_creds_cli_GetForestTrustInformation_state);
3239 if (state->creds == NULL) {
3243 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3244 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3245 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3246 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3247 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3248 TALLOC_FREE(state->creds);
3252 netlogon_creds_cli_delete(state->context, &state->creds);
3255 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3257 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3259 struct tevent_req *req =
3260 tevent_req_callback_data(subreq,
3262 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3263 tevent_req_data(req,
3264 struct netlogon_creds_cli_GetForestTrustInformation_state);
3267 status = netlogon_creds_cli_lock_recv(subreq, state,
3269 TALLOC_FREE(subreq);
3270 if (tevent_req_nterror(req, status)) {
3274 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3275 switch (state->auth_level) {
3276 case DCERPC_AUTH_LEVEL_INTEGRITY:
3277 case DCERPC_AUTH_LEVEL_PRIVACY:
3280 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3284 uint32_t tmp = state->creds->negotiate_flags;
3286 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3288 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3289 * it should be used, which means
3290 * we had a chance to verify no downgrade
3293 * This relies on netlogon_creds_cli_check*
3294 * being called before, as first request after
3297 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3303 * we defer all callbacks in order to cleanup
3304 * the database record.
3306 tevent_req_defer_callback(req, state->ev);
3308 state->tmp_creds = *state->creds;
3309 netlogon_creds_client_authenticator(&state->tmp_creds,
3311 ZERO_STRUCT(state->rep_auth);
3313 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3314 state->binding_handle,
3315 state->srv_name_slash,
3316 state->tmp_creds.computer_name,
3320 &state->forest_trust_info);
3321 if (tevent_req_nomem(subreq, req)) {
3322 status = NT_STATUS_NO_MEMORY;
3323 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3327 tevent_req_set_callback(subreq,
3328 netlogon_creds_cli_GetForestTrustInformation_done,
3332 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3334 struct tevent_req *req =
3335 tevent_req_callback_data(subreq,
3337 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3338 tevent_req_data(req,
3339 struct netlogon_creds_cli_GetForestTrustInformation_state);
3345 * We use state->dns_names as the memory context, as this is
3346 * the only in/out variable and it has been overwritten by the
3347 * out parameter from the server.
3349 * We need to preserve the return value until the caller can use it.
3351 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3352 TALLOC_FREE(subreq);
3353 if (tevent_req_nterror(req, status)) {
3354 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3358 ok = netlogon_creds_client_check(&state->tmp_creds,
3359 &state->rep_auth.cred);
3361 status = NT_STATUS_ACCESS_DENIED;
3362 tevent_req_nterror(req, status);
3363 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3367 *state->creds = state->tmp_creds;
3368 status = netlogon_creds_cli_store(state->context,
3371 if (tevent_req_nterror(req, status)) {
3372 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3376 if (tevent_req_nterror(req, result)) {
3377 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3381 tevent_req_done(req);
3384 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3385 TALLOC_CTX *mem_ctx,
3386 struct lsa_ForestTrustInformation **forest_trust_info)
3388 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3389 tevent_req_data(req,
3390 struct netlogon_creds_cli_GetForestTrustInformation_state);
3393 if (tevent_req_is_nterror(req, &status)) {
3394 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3395 tevent_req_received(req);
3399 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3401 tevent_req_received(req);
3402 return NT_STATUS_OK;
3405 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3406 struct netlogon_creds_cli_context *context,
3407 struct dcerpc_binding_handle *b,
3408 TALLOC_CTX *mem_ctx,
3409 struct lsa_ForestTrustInformation **forest_trust_info)
3411 TALLOC_CTX *frame = talloc_stackframe();
3412 struct tevent_context *ev;
3413 struct tevent_req *req;
3414 NTSTATUS status = NT_STATUS_NO_MEMORY;
3416 ev = samba_tevent_context_init(frame);
3420 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3424 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3427 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3435 struct netlogon_creds_cli_SendToSam_state {
3436 struct tevent_context *ev;
3437 struct netlogon_creds_cli_context *context;
3438 struct dcerpc_binding_handle *binding_handle;
3440 char *srv_name_slash;
3441 enum dcerpc_AuthType auth_type;
3442 enum dcerpc_AuthLevel auth_level;
3446 struct netlogon_creds_CredentialState *creds;
3447 struct netlogon_creds_CredentialState tmp_creds;
3448 struct netr_Authenticator req_auth;
3449 struct netr_Authenticator rep_auth;
3452 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3454 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3456 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3457 struct tevent_context *ev,
3458 struct netlogon_creds_cli_context *context,
3459 struct dcerpc_binding_handle *b,
3460 struct netr_SendToSamBase *message)
3462 struct tevent_req *req;
3463 struct netlogon_creds_cli_SendToSam_state *state;
3464 struct tevent_req *subreq;
3465 enum ndr_err_code ndr_err;
3467 req = tevent_req_create(mem_ctx, &state,
3468 struct netlogon_creds_cli_SendToSam_state);
3474 state->context = context;
3475 state->binding_handle = b;
3477 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3478 context->server.computer);
3479 if (tevent_req_nomem(state->srv_name_slash, req)) {
3480 return tevent_req_post(req, ev);
3483 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3484 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3485 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3486 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3487 tevent_req_nterror(req, status);
3488 return tevent_req_post(req, ev);
3491 dcerpc_binding_handle_auth_info(state->binding_handle,
3493 &state->auth_level);
3495 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3497 if (tevent_req_nomem(subreq, req)) {
3498 return tevent_req_post(req, ev);
3501 tevent_req_set_callback(subreq,
3502 netlogon_creds_cli_SendToSam_locked,
3508 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3511 struct netlogon_creds_cli_SendToSam_state *state =
3512 tevent_req_data(req,
3513 struct netlogon_creds_cli_SendToSam_state);
3515 if (state->creds == NULL) {
3519 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3520 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3521 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3522 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3523 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3524 TALLOC_FREE(state->creds);
3528 netlogon_creds_cli_delete(state->context, &state->creds);
3531 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3533 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3535 struct tevent_req *req =
3536 tevent_req_callback_data(subreq,
3538 struct netlogon_creds_cli_SendToSam_state *state =
3539 tevent_req_data(req,
3540 struct netlogon_creds_cli_SendToSam_state);
3543 status = netlogon_creds_cli_lock_recv(subreq, state,
3545 TALLOC_FREE(subreq);
3546 if (tevent_req_nterror(req, status)) {
3550 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3551 switch (state->auth_level) {
3552 case DCERPC_AUTH_LEVEL_INTEGRITY:
3553 case DCERPC_AUTH_LEVEL_PRIVACY:
3556 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3560 uint32_t tmp = state->creds->negotiate_flags;
3562 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3564 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3565 * it should be used, which means
3566 * we had a chance to verify no downgrade
3569 * This relies on netlogon_creds_cli_check*
3570 * being called before, as first request after
3573 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3579 * we defer all callbacks in order to cleanup
3580 * the database record.
3582 tevent_req_defer_callback(req, state->ev);
3584 state->tmp_creds = *state->creds;
3585 netlogon_creds_client_authenticator(&state->tmp_creds,
3587 ZERO_STRUCT(state->rep_auth);
3589 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3590 netlogon_creds_aes_encrypt(&state->tmp_creds,
3592 state->opaque.length);
3594 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3596 state->opaque.length);
3599 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3600 state->binding_handle,
3601 state->srv_name_slash,
3602 state->tmp_creds.computer_name,
3606 state->opaque.length);
3607 if (tevent_req_nomem(subreq, req)) {
3608 status = NT_STATUS_NO_MEMORY;
3609 netlogon_creds_cli_SendToSam_cleanup(req, status);
3613 tevent_req_set_callback(subreq,
3614 netlogon_creds_cli_SendToSam_done,
3618 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3620 struct tevent_req *req =
3621 tevent_req_callback_data(subreq,
3623 struct netlogon_creds_cli_SendToSam_state *state =
3624 tevent_req_data(req,
3625 struct netlogon_creds_cli_SendToSam_state);
3630 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3631 TALLOC_FREE(subreq);
3632 if (tevent_req_nterror(req, status)) {
3633 netlogon_creds_cli_SendToSam_cleanup(req, status);
3637 ok = netlogon_creds_client_check(&state->tmp_creds,
3638 &state->rep_auth.cred);
3640 status = NT_STATUS_ACCESS_DENIED;
3641 tevent_req_nterror(req, status);
3642 netlogon_creds_cli_SendToSam_cleanup(req, status);
3646 *state->creds = state->tmp_creds;
3647 status = netlogon_creds_cli_store(state->context,
3650 if (tevent_req_nterror(req, status)) {
3651 netlogon_creds_cli_SendToSam_cleanup(req, status);
3656 * Creds must be stored before we send back application errors
3657 * e.g. NT_STATUS_NOT_IMPLEMENTED
3659 if (tevent_req_nterror(req, result)) {
3660 netlogon_creds_cli_SendToSam_cleanup(req, result);
3664 tevent_req_done(req);
3667 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3668 struct dcerpc_binding_handle *b,
3669 struct netr_SendToSamBase *message)
3671 TALLOC_CTX *frame = talloc_stackframe();
3672 struct tevent_context *ev;
3673 struct tevent_req *req;
3674 NTSTATUS status = NT_STATUS_OK;
3676 ev = samba_tevent_context_init(frame);
3680 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3684 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3688 /* Ignore the result */