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 status = netlogon_creds_cli_open_global_db(lp_ctx);
438 if (!NT_STATUS_IS_OK(status)) {
439 TALLOC_FREE(context);
441 return NT_STATUS_NO_MEMORY;
444 context->db.ctx = netlogon_creds_cli_global_db;
450 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
451 const char *client_account,
452 enum netr_SchannelType type,
453 uint32_t proposed_flags,
454 uint32_t required_flags,
455 enum dcerpc_AuthLevel auth_level,
456 const char *server_computer,
457 const char *server_netbios_domain,
459 struct netlogon_creds_cli_context **_context)
462 struct netlogon_creds_cli_context *context = NULL;
466 status = netlogon_creds_cli_context_common(client_computer,
473 server_netbios_domain,
477 if (!NT_STATUS_IS_OK(status)) {
481 context->db.ctx = db_open_rbt(context);
482 if (context->db.ctx == NULL) {
483 talloc_free(context);
484 return NT_STATUS_NO_MEMORY;
491 char *netlogon_creds_cli_debug_string(
492 const struct netlogon_creds_cli_context *context,
495 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
496 context->db.key_name);
499 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
500 struct netlogon_creds_cli_context *context)
502 return context->client.auth_level;
505 struct netlogon_creds_cli_fetch_state {
507 struct netlogon_creds_CredentialState *creds;
508 uint32_t required_flags;
512 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
515 struct netlogon_creds_cli_fetch_state *state =
516 (struct netlogon_creds_cli_fetch_state *)private_data;
517 enum ndr_err_code ndr_err;
521 state->creds = talloc_zero(state->mem_ctx,
522 struct netlogon_creds_CredentialState);
523 if (state->creds == NULL) {
524 state->status = NT_STATUS_NO_MEMORY;
528 blob.data = data.dptr;
529 blob.length = data.dsize;
531 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
532 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
533 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
534 TALLOC_FREE(state->creds);
535 state->status = ndr_map_error2ntstatus(ndr_err);
539 tmp_flags = state->creds->negotiate_flags;
540 tmp_flags &= state->required_flags;
541 if (tmp_flags != state->required_flags) {
542 TALLOC_FREE(state->creds);
543 state->status = NT_STATUS_DOWNGRADE_DETECTED;
547 state->status = NT_STATUS_OK;
550 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
552 struct netlogon_creds_CredentialState **_creds)
555 struct netlogon_creds_cli_fetch_state fstate = {
557 .status = NT_STATUS_INTERNAL_ERROR,
558 .required_flags = context->client.required_flags,
563 status = dbwrap_parse_record(context->db.ctx,
564 context->db.key_data,
565 netlogon_creds_cli_fetch_parser,
567 if (!NT_STATUS_IS_OK(status)) {
570 status = fstate.status;
571 if (!NT_STATUS_IS_OK(status)) {
576 * mark it as invalid for step operations.
578 fstate.creds->sequence = 0;
579 fstate.creds->seed = (struct netr_Credential) {{0}};
580 fstate.creds->client = (struct netr_Credential) {{0}};
581 fstate.creds->server = (struct netr_Credential) {{0}};
583 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
584 *_creds = fstate.creds;
589 * It is really important to try SamLogonEx here,
590 * because multiple processes can talk to the same
591 * domain controller, without using the credential
594 * With a normal SamLogon call, we must keep the
595 * credentials chain updated and intact between all
596 * users of the machine account (which would imply
597 * cross-node communication for every NTLM logon).
599 * The credentials chain is not per NETLOGON pipe
600 * connection, but globally on the server/client pair
603 * It's also important to use NetlogonValidationSamInfo4 (6),
604 * because it relies on the rpc transport encryption
605 * and avoids using the global netlogon schannel
606 * session key to en/decrypt secret information
607 * like the user_session_key for network logons.
609 * [MS-APDS] 3.1.5.2 NTLM Network Logon
610 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
611 * NETLOGON_NEG_AUTHENTICATED_RPC set together
612 * are the indication that the server supports
613 * NetlogonValidationSamInfo4 (6). And it must only
614 * be used if "SealSecureChannel" is used.
616 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
617 * check is done in netlogon_creds_cli_LogonSamLogon*().
619 context->server.cached_flags = fstate.creds->negotiate_flags;
620 context->server.try_validation6 = true;
621 context->server.try_logon_ex = true;
622 context->server.try_logon_with = true;
624 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
625 context->server.try_validation6 = false;
626 context->server.try_logon_ex = false;
628 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
629 context->server.try_validation6 = false;
632 *_creds = fstate.creds;
636 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
637 const struct netlogon_creds_CredentialState *creds1)
639 TALLOC_CTX *frame = talloc_stackframe();
640 struct netlogon_creds_CredentialState *creds2;
644 enum ndr_err_code ndr_err;
647 status = netlogon_creds_cli_get(context, frame, &creds2);
648 if (!NT_STATUS_IS_OK(status)) {
653 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
654 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
655 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
660 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
661 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
662 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
667 cmp = data_blob_cmp(&blob1, &blob2);
674 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
675 struct netlogon_creds_CredentialState *creds)
678 enum ndr_err_code ndr_err;
682 if (context->db.locked_state == NULL) {
684 * this was not the result of netlogon_creds_cli_lock*()
686 return NT_STATUS_INVALID_PAGE_PROTECTION;
689 if (context->db.locked_state->creds != creds) {
691 * this was not the result of netlogon_creds_cli_lock*()
693 return NT_STATUS_INVALID_PAGE_PROTECTION;
696 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
697 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
698 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
699 status = ndr_map_error2ntstatus(ndr_err);
703 data.dptr = blob.data;
704 data.dsize = blob.length;
706 status = dbwrap_store(context->db.ctx,
707 context->db.key_data,
709 TALLOC_FREE(data.dptr);
710 if (!NT_STATUS_IS_OK(status)) {
717 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
718 struct netlogon_creds_CredentialState *creds)
722 if (context->db.locked_state == NULL) {
724 * this was not the result of netlogon_creds_cli_lock*()
726 return NT_STATUS_INVALID_PAGE_PROTECTION;
729 if (context->db.locked_state->creds != creds) {
731 * this was not the result of netlogon_creds_cli_lock*()
733 return NT_STATUS_INVALID_PAGE_PROTECTION;
736 status = dbwrap_delete(context->db.ctx,
737 context->db.key_data);
738 if (!NT_STATUS_IS_OK(status)) {
745 struct netlogon_creds_cli_lock_state {
746 struct netlogon_creds_cli_locked_state *locked_state;
747 struct netlogon_creds_CredentialState *creds;
750 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
751 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
753 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
754 struct tevent_context *ev,
755 struct netlogon_creds_cli_context *context)
757 struct tevent_req *req;
758 struct netlogon_creds_cli_lock_state *state;
759 struct netlogon_creds_cli_locked_state *locked_state;
760 struct tevent_req *subreq;
762 req = tevent_req_create(mem_ctx, &state,
763 struct netlogon_creds_cli_lock_state);
768 if (context->db.locked_state != NULL) {
769 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
770 return tevent_req_post(req, ev);
773 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
774 if (tevent_req_nomem(locked_state, req)) {
775 return tevent_req_post(req, ev);
777 talloc_set_destructor(locked_state,
778 netlogon_creds_cli_locked_state_destructor);
779 locked_state->context = context;
781 context->db.locked_state = locked_state;
782 state->locked_state = locked_state;
784 if (context->db.g_ctx == NULL) {
785 netlogon_creds_cli_lock_fetch(req);
786 if (!tevent_req_is_in_progress(req)) {
787 return tevent_req_post(req, ev);
793 subreq = g_lock_lock_send(state, ev,
795 context->db.key_name,
797 if (tevent_req_nomem(subreq, req)) {
798 return tevent_req_post(req, ev);
800 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
805 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
807 struct tevent_req *req =
808 tevent_req_callback_data(subreq,
810 struct netlogon_creds_cli_lock_state *state =
812 struct netlogon_creds_cli_lock_state);
815 status = g_lock_lock_recv(subreq);
817 if (tevent_req_nterror(req, status)) {
820 state->locked_state->is_glocked = true;
822 netlogon_creds_cli_lock_fetch(req);
825 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
827 struct netlogon_creds_cli_lock_state *state =
829 struct netlogon_creds_cli_lock_state);
830 struct netlogon_creds_cli_context *context = state->locked_state->context;
831 struct netlogon_creds_cli_fetch_state fstate = {
832 .status = NT_STATUS_INTERNAL_ERROR,
833 .required_flags = context->client.required_flags,
837 fstate.mem_ctx = state;
838 status = dbwrap_parse_record(context->db.ctx,
839 context->db.key_data,
840 netlogon_creds_cli_fetch_parser,
842 if (tevent_req_nterror(req, status)) {
845 status = fstate.status;
846 if (tevent_req_nterror(req, status)) {
850 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
851 state->creds = fstate.creds;
852 tevent_req_done(req);
856 context->server.cached_flags = fstate.creds->negotiate_flags;
857 context->server.try_validation6 = true;
858 context->server.try_logon_ex = true;
859 context->server.try_logon_with = true;
861 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
862 context->server.try_validation6 = false;
863 context->server.try_logon_ex = false;
865 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
866 context->server.try_validation6 = false;
869 state->creds = fstate.creds;
870 tevent_req_done(req);
874 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
876 struct netlogon_creds_CredentialState **creds)
878 struct netlogon_creds_cli_lock_state *state =
880 struct netlogon_creds_cli_lock_state);
883 if (tevent_req_is_nterror(req, &status)) {
884 tevent_req_received(req);
888 talloc_steal(state->creds, state->locked_state);
889 state->locked_state->creds = state->creds;
890 *creds = talloc_move(mem_ctx, &state->creds);
891 tevent_req_received(req);
895 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
897 struct netlogon_creds_CredentialState **creds)
899 TALLOC_CTX *frame = talloc_stackframe();
900 struct tevent_context *ev;
901 struct tevent_req *req;
902 NTSTATUS status = NT_STATUS_NO_MEMORY;
904 ev = samba_tevent_context_init(frame);
908 req = netlogon_creds_cli_lock_send(frame, ev, context);
912 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
915 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
921 struct netlogon_creds_cli_auth_state {
922 struct tevent_context *ev;
923 struct netlogon_creds_cli_context *context;
924 struct dcerpc_binding_handle *binding_handle;
925 uint8_t num_nt_hashes;
926 uint8_t idx_nt_hashes;
927 const struct samr_Password * const *nt_hashes;
928 const struct samr_Password *used_nt_hash;
929 char *srv_name_slash;
930 uint32_t current_flags;
931 struct netr_Credential client_challenge;
932 struct netr_Credential server_challenge;
933 struct netlogon_creds_CredentialState *creds;
934 struct netr_Credential client_credential;
935 struct netr_Credential server_credential;
940 struct netlogon_creds_cli_locked_state *locked_state;
943 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
944 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
946 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
947 struct tevent_context *ev,
948 struct netlogon_creds_cli_context *context,
949 struct dcerpc_binding_handle *b,
950 uint8_t num_nt_hashes,
951 const struct samr_Password * const *nt_hashes)
953 struct tevent_req *req;
954 struct netlogon_creds_cli_auth_state *state;
955 struct netlogon_creds_cli_locked_state *locked_state;
958 req = tevent_req_create(mem_ctx, &state,
959 struct netlogon_creds_cli_auth_state);
965 state->context = context;
966 state->binding_handle = b;
967 if (num_nt_hashes < 1) {
968 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
969 return tevent_req_post(req, ev);
971 if (num_nt_hashes > 4) {
972 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
973 return tevent_req_post(req, ev);
976 state->num_nt_hashes = num_nt_hashes;
977 state->idx_nt_hashes = 0;
978 state->nt_hashes = nt_hashes;
980 if (context->db.locked_state != NULL) {
981 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
982 return tevent_req_post(req, ev);
985 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
986 if (tevent_req_nomem(locked_state, req)) {
987 return tevent_req_post(req, ev);
989 talloc_set_destructor(locked_state,
990 netlogon_creds_cli_locked_state_destructor);
991 locked_state->context = context;
993 context->db.locked_state = locked_state;
994 state->locked_state = locked_state;
996 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
997 context->server.computer);
998 if (tevent_req_nomem(state->srv_name_slash, req)) {
999 return tevent_req_post(req, ev);
1002 state->try_auth3 = true;
1003 state->try_auth2 = true;
1005 if (context->client.required_flags != 0) {
1006 state->require_auth2 = true;
1009 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1010 state->current_flags = context->client.proposed_flags;
1012 if (context->db.g_ctx != NULL) {
1013 struct tevent_req *subreq;
1015 subreq = g_lock_lock_send(state, ev,
1017 context->db.key_name,
1019 if (tevent_req_nomem(subreq, req)) {
1020 return tevent_req_post(req, ev);
1022 tevent_req_set_callback(subreq,
1023 netlogon_creds_cli_auth_locked,
1029 status = dbwrap_purge(state->context->db.ctx,
1030 state->context->db.key_data);
1031 if (tevent_req_nterror(req, status)) {
1032 return tevent_req_post(req, ev);
1035 netlogon_creds_cli_auth_challenge_start(req);
1036 if (!tevent_req_is_in_progress(req)) {
1037 return tevent_req_post(req, ev);
1043 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1045 struct tevent_req *req =
1046 tevent_req_callback_data(subreq,
1048 struct netlogon_creds_cli_auth_state *state =
1049 tevent_req_data(req,
1050 struct netlogon_creds_cli_auth_state);
1053 status = g_lock_lock_recv(subreq);
1054 TALLOC_FREE(subreq);
1055 if (tevent_req_nterror(req, status)) {
1058 state->locked_state->is_glocked = true;
1060 status = dbwrap_purge(state->context->db.ctx,
1061 state->context->db.key_data);
1062 if (tevent_req_nterror(req, status)) {
1066 netlogon_creds_cli_auth_challenge_start(req);
1069 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1071 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1073 struct netlogon_creds_cli_auth_state *state =
1074 tevent_req_data(req,
1075 struct netlogon_creds_cli_auth_state);
1076 struct tevent_req *subreq;
1078 TALLOC_FREE(state->creds);
1080 generate_random_buffer(state->client_challenge.data,
1081 sizeof(state->client_challenge.data));
1083 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1084 state->binding_handle,
1085 state->srv_name_slash,
1086 state->context->client.computer,
1087 &state->client_challenge,
1088 &state->server_challenge);
1089 if (tevent_req_nomem(subreq, req)) {
1092 tevent_req_set_callback(subreq,
1093 netlogon_creds_cli_auth_challenge_done,
1097 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1099 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1101 struct tevent_req *req =
1102 tevent_req_callback_data(subreq,
1104 struct netlogon_creds_cli_auth_state *state =
1105 tevent_req_data(req,
1106 struct netlogon_creds_cli_auth_state);
1110 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1111 TALLOC_FREE(subreq);
1112 if (tevent_req_nterror(req, status)) {
1115 if (tevent_req_nterror(req, result)) {
1119 if (!state->try_auth3 && !state->try_auth2) {
1120 state->current_flags = 0;
1123 /* Calculate the session key and client credentials */
1125 state->creds = netlogon_creds_client_init(state,
1126 state->context->client.account,
1127 state->context->client.computer,
1128 state->context->client.type,
1129 &state->client_challenge,
1130 &state->server_challenge,
1131 state->used_nt_hash,
1132 &state->client_credential,
1133 state->current_flags);
1134 if (tevent_req_nomem(state->creds, req)) {
1138 if (state->try_auth3) {
1139 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1140 state->binding_handle,
1141 state->srv_name_slash,
1142 state->context->client.account,
1143 state->context->client.type,
1144 state->context->client.computer,
1145 &state->client_credential,
1146 &state->server_credential,
1147 &state->creds->negotiate_flags,
1149 if (tevent_req_nomem(subreq, req)) {
1152 } else if (state->try_auth2) {
1155 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1156 state->binding_handle,
1157 state->srv_name_slash,
1158 state->context->client.account,
1159 state->context->client.type,
1160 state->context->client.computer,
1161 &state->client_credential,
1162 &state->server_credential,
1163 &state->creds->negotiate_flags);
1164 if (tevent_req_nomem(subreq, req)) {
1170 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1171 state->binding_handle,
1172 state->srv_name_slash,
1173 state->context->client.account,
1174 state->context->client.type,
1175 state->context->client.computer,
1176 &state->client_credential,
1177 &state->server_credential);
1178 if (tevent_req_nomem(subreq, req)) {
1182 tevent_req_set_callback(subreq,
1183 netlogon_creds_cli_auth_srvauth_done,
1187 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1189 struct tevent_req *req =
1190 tevent_req_callback_data(subreq,
1192 struct netlogon_creds_cli_auth_state *state =
1193 tevent_req_data(req,
1194 struct netlogon_creds_cli_auth_state);
1198 enum ndr_err_code ndr_err;
1203 if (state->try_auth3) {
1204 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1206 TALLOC_FREE(subreq);
1207 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1208 state->try_auth3 = false;
1209 netlogon_creds_cli_auth_challenge_start(req);
1212 if (tevent_req_nterror(req, status)) {
1215 } else if (state->try_auth2) {
1216 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1218 TALLOC_FREE(subreq);
1219 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1220 state->try_auth2 = false;
1221 if (state->require_auth2) {
1222 status = NT_STATUS_DOWNGRADE_DETECTED;
1223 tevent_req_nterror(req, status);
1226 netlogon_creds_cli_auth_challenge_start(req);
1229 if (tevent_req_nterror(req, status)) {
1233 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1235 TALLOC_FREE(subreq);
1236 if (tevent_req_nterror(req, status)) {
1241 if (!NT_STATUS_IS_OK(result) &&
1242 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1244 tevent_req_nterror(req, result);
1248 tmp_flags = state->creds->negotiate_flags;
1249 tmp_flags &= state->context->client.required_flags;
1250 if (tmp_flags != state->context->client.required_flags) {
1251 if (NT_STATUS_IS_OK(result)) {
1252 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1255 tevent_req_nterror(req, result);
1259 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1261 tmp_flags = state->context->client.proposed_flags;
1262 if ((state->current_flags == tmp_flags) &&
1263 (state->creds->negotiate_flags != tmp_flags))
1266 * lets retry with the negotiated flags
1268 state->current_flags = state->creds->negotiate_flags;
1269 netlogon_creds_cli_auth_challenge_start(req);
1273 state->idx_nt_hashes += 1;
1274 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1276 * we already retried, giving up...
1278 tevent_req_nterror(req, result);
1283 * lets retry with the old nt hash.
1285 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1286 state->current_flags = state->context->client.proposed_flags;
1287 netlogon_creds_cli_auth_challenge_start(req);
1291 ok = netlogon_creds_client_check(state->creds,
1292 &state->server_credential);
1294 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1298 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1299 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1300 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1301 status = ndr_map_error2ntstatus(ndr_err);
1302 tevent_req_nterror(req, status);
1306 data.dptr = blob.data;
1307 data.dsize = blob.length;
1309 status = dbwrap_store(state->context->db.ctx,
1310 state->context->db.key_data,
1312 TALLOC_FREE(state->locked_state);
1313 if (tevent_req_nterror(req, status)) {
1317 tevent_req_done(req);
1320 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1321 uint8_t *idx_nt_hashes)
1323 struct netlogon_creds_cli_auth_state *state =
1324 tevent_req_data(req,
1325 struct netlogon_creds_cli_auth_state);
1330 if (tevent_req_is_nterror(req, &status)) {
1331 tevent_req_received(req);
1335 *idx_nt_hashes = state->idx_nt_hashes;
1336 tevent_req_received(req);
1337 return NT_STATUS_OK;
1340 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1341 struct dcerpc_binding_handle *b,
1342 uint8_t num_nt_hashes,
1343 const struct samr_Password * const *nt_hashes,
1344 uint8_t *idx_nt_hashes)
1346 TALLOC_CTX *frame = talloc_stackframe();
1347 struct tevent_context *ev;
1348 struct tevent_req *req;
1349 NTSTATUS status = NT_STATUS_NO_MEMORY;
1353 ev = samba_tevent_context_init(frame);
1357 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1358 num_nt_hashes, nt_hashes);
1362 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1365 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1371 struct netlogon_creds_cli_check_state {
1372 struct tevent_context *ev;
1373 struct netlogon_creds_cli_context *context;
1374 struct dcerpc_binding_handle *binding_handle;
1376 char *srv_name_slash;
1378 union netr_Capabilities caps;
1380 struct netlogon_creds_CredentialState *creds;
1381 struct netlogon_creds_CredentialState tmp_creds;
1382 struct netr_Authenticator req_auth;
1383 struct netr_Authenticator rep_auth;
1386 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1388 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1390 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1391 struct tevent_context *ev,
1392 struct netlogon_creds_cli_context *context,
1393 struct dcerpc_binding_handle *b)
1395 struct tevent_req *req;
1396 struct netlogon_creds_cli_check_state *state;
1397 struct tevent_req *subreq;
1398 enum dcerpc_AuthType auth_type;
1399 enum dcerpc_AuthLevel auth_level;
1401 req = tevent_req_create(mem_ctx, &state,
1402 struct netlogon_creds_cli_check_state);
1408 state->context = context;
1409 state->binding_handle = b;
1411 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1412 context->server.computer);
1413 if (tevent_req_nomem(state->srv_name_slash, req)) {
1414 return tevent_req_post(req, ev);
1417 dcerpc_binding_handle_auth_info(state->binding_handle,
1418 &auth_type, &auth_level);
1420 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1421 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1422 return tevent_req_post(req, ev);
1425 switch (auth_level) {
1426 case DCERPC_AUTH_LEVEL_INTEGRITY:
1427 case DCERPC_AUTH_LEVEL_PRIVACY:
1430 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1431 return tevent_req_post(req, ev);
1434 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1436 if (tevent_req_nomem(subreq, req)) {
1437 return tevent_req_post(req, ev);
1440 tevent_req_set_callback(subreq,
1441 netlogon_creds_cli_check_locked,
1447 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1450 struct netlogon_creds_cli_check_state *state =
1451 tevent_req_data(req,
1452 struct netlogon_creds_cli_check_state);
1454 if (state->creds == NULL) {
1458 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1459 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1460 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1461 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1462 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1463 TALLOC_FREE(state->creds);
1467 netlogon_creds_cli_delete(state->context, state->creds);
1468 TALLOC_FREE(state->creds);
1471 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1473 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1475 struct tevent_req *req =
1476 tevent_req_callback_data(subreq,
1478 struct netlogon_creds_cli_check_state *state =
1479 tevent_req_data(req,
1480 struct netlogon_creds_cli_check_state);
1483 status = netlogon_creds_cli_lock_recv(subreq, state,
1485 TALLOC_FREE(subreq);
1486 if (tevent_req_nterror(req, status)) {
1491 * we defer all callbacks in order to cleanup
1492 * the database record.
1494 tevent_req_defer_callback(req, state->ev);
1496 state->tmp_creds = *state->creds;
1497 netlogon_creds_client_authenticator(&state->tmp_creds,
1499 ZERO_STRUCT(state->rep_auth);
1501 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1502 state->binding_handle,
1503 state->srv_name_slash,
1504 state->context->client.computer,
1509 if (tevent_req_nomem(subreq, req)) {
1510 status = NT_STATUS_NO_MEMORY;
1511 netlogon_creds_cli_check_cleanup(req, status);
1514 tevent_req_set_callback(subreq,
1515 netlogon_creds_cli_check_caps,
1519 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1521 struct tevent_req *req =
1522 tevent_req_callback_data(subreq,
1524 struct netlogon_creds_cli_check_state *state =
1525 tevent_req_data(req,
1526 struct netlogon_creds_cli_check_state);
1531 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1533 TALLOC_FREE(subreq);
1534 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1536 * Note that the negotiated flags are already checked
1537 * for our required flags after the ServerAuthenticate3/2 call.
1539 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1541 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1543 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1544 * already, we expect this to work!
1546 status = NT_STATUS_DOWNGRADE_DETECTED;
1547 tevent_req_nterror(req, status);
1548 netlogon_creds_cli_check_cleanup(req, status);
1552 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1554 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1555 * we expect this to work at least as far as the
1556 * NOT_SUPPORTED error handled below!
1558 * NT 4.0 and Old Samba servers are not
1559 * allowed without "require strong key = no"
1561 status = NT_STATUS_DOWNGRADE_DETECTED;
1562 tevent_req_nterror(req, status);
1563 netlogon_creds_cli_check_cleanup(req, status);
1568 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1569 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1570 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1572 * This is needed against NT 4.0 and old Samba servers.
1574 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1575 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1576 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1577 * with the next request as the sequence number processing
1580 netlogon_creds_cli_check_cleanup(req, status);
1581 tevent_req_done(req);
1584 if (tevent_req_nterror(req, status)) {
1585 netlogon_creds_cli_check_cleanup(req, status);
1589 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1591 * Note that the negotiated flags are already checked
1592 * for our required flags after the ServerAuthenticate3/2 call.
1594 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1596 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1598 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1599 * already, we expect this to work!
1601 status = NT_STATUS_DOWNGRADE_DETECTED;
1602 tevent_req_nterror(req, status);
1603 netlogon_creds_cli_check_cleanup(req, status);
1608 * This is ok, the server does not support
1609 * NETLOGON_NEG_SUPPORTS_AES.
1611 * netr_LogonGetCapabilities() was
1612 * netr_LogonDummyRoutine1() before
1613 * NETLOGON_NEG_SUPPORTS_AES was invented.
1615 netlogon_creds_cli_check_cleanup(req, result);
1616 tevent_req_done(req);
1620 ok = netlogon_creds_client_check(&state->tmp_creds,
1621 &state->rep_auth.cred);
1623 status = NT_STATUS_ACCESS_DENIED;
1624 tevent_req_nterror(req, status);
1625 netlogon_creds_cli_check_cleanup(req, status);
1629 if (tevent_req_nterror(req, result)) {
1630 netlogon_creds_cli_check_cleanup(req, result);
1634 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1635 status = NT_STATUS_DOWNGRADE_DETECTED;
1636 tevent_req_nterror(req, status);
1637 netlogon_creds_cli_check_cleanup(req, status);
1642 * This is the key check that makes this check secure. If we
1643 * get OK here (rather than NOT_SUPPORTED), then the server
1644 * did support AES. If the server only proposed STRONG_KEYS
1645 * and not AES, then it should have failed with
1646 * NOT_IMPLEMENTED. We always send AES as a client, so the
1647 * server should always have returned it.
1649 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1650 status = NT_STATUS_DOWNGRADE_DETECTED;
1651 tevent_req_nterror(req, status);
1652 netlogon_creds_cli_check_cleanup(req, status);
1656 *state->creds = state->tmp_creds;
1657 status = netlogon_creds_cli_store(state->context,
1659 TALLOC_FREE(state->creds);
1660 if (tevent_req_nterror(req, status)) {
1664 tevent_req_done(req);
1667 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1671 if (tevent_req_is_nterror(req, &status)) {
1672 netlogon_creds_cli_check_cleanup(req, status);
1673 tevent_req_received(req);
1677 tevent_req_received(req);
1678 return NT_STATUS_OK;
1681 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1682 struct dcerpc_binding_handle *b)
1684 TALLOC_CTX *frame = talloc_stackframe();
1685 struct tevent_context *ev;
1686 struct tevent_req *req;
1687 NTSTATUS status = NT_STATUS_NO_MEMORY;
1689 ev = samba_tevent_context_init(frame);
1693 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1697 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1700 status = netlogon_creds_cli_check_recv(req);
1706 struct netlogon_creds_cli_ServerPasswordSet_state {
1707 struct tevent_context *ev;
1708 struct netlogon_creds_cli_context *context;
1709 struct dcerpc_binding_handle *binding_handle;
1710 uint32_t old_timeout;
1712 char *srv_name_slash;
1713 enum dcerpc_AuthType auth_type;
1714 enum dcerpc_AuthLevel auth_level;
1716 struct samr_CryptPassword samr_crypt_password;
1717 struct netr_CryptPassword netr_crypt_password;
1718 struct samr_Password samr_password;
1720 struct netlogon_creds_CredentialState *creds;
1721 struct netlogon_creds_CredentialState tmp_creds;
1722 struct netr_Authenticator req_auth;
1723 struct netr_Authenticator rep_auth;
1726 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1728 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1730 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1731 struct tevent_context *ev,
1732 struct netlogon_creds_cli_context *context,
1733 struct dcerpc_binding_handle *b,
1734 const DATA_BLOB *new_password,
1735 const uint32_t *new_version)
1737 struct tevent_req *req;
1738 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1739 struct tevent_req *subreq;
1742 req = tevent_req_create(mem_ctx, &state,
1743 struct netlogon_creds_cli_ServerPasswordSet_state);
1749 state->context = context;
1750 state->binding_handle = b;
1752 if (new_password->length < 14) {
1753 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1754 return tevent_req_post(req, ev);
1758 * netr_ServerPasswordSet
1760 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1763 * netr_ServerPasswordSet2
1765 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1768 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1769 return tevent_req_post(req, ev);
1772 if (new_version != NULL) {
1773 struct NL_PASSWORD_VERSION version;
1774 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1775 uint32_t ofs = 512 - len;
1779 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1780 return tevent_req_post(req, ev);
1784 version.ReservedField = 0;
1785 version.PasswordVersionNumber = *new_version;
1786 version.PasswordVersionPresent =
1787 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1789 p = state->samr_crypt_password.data + ofs;
1790 SIVAL(p, 0, version.ReservedField);
1791 SIVAL(p, 4, version.PasswordVersionNumber);
1792 SIVAL(p, 8, version.PasswordVersionPresent);
1795 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1796 context->server.computer);
1797 if (tevent_req_nomem(state->srv_name_slash, req)) {
1798 return tevent_req_post(req, ev);
1801 dcerpc_binding_handle_auth_info(state->binding_handle,
1803 &state->auth_level);
1805 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1807 if (tevent_req_nomem(subreq, req)) {
1808 return tevent_req_post(req, ev);
1811 tevent_req_set_callback(subreq,
1812 netlogon_creds_cli_ServerPasswordSet_locked,
1818 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1821 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1822 tevent_req_data(req,
1823 struct netlogon_creds_cli_ServerPasswordSet_state);
1825 if (state->creds == NULL) {
1829 dcerpc_binding_handle_set_timeout(state->binding_handle,
1830 state->old_timeout);
1832 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1833 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1834 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1835 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1836 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1837 TALLOC_FREE(state->creds);
1841 netlogon_creds_cli_delete(state->context, state->creds);
1842 TALLOC_FREE(state->creds);
1845 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1847 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1849 struct tevent_req *req =
1850 tevent_req_callback_data(subreq,
1852 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1853 tevent_req_data(req,
1854 struct netlogon_creds_cli_ServerPasswordSet_state);
1857 status = netlogon_creds_cli_lock_recv(subreq, state,
1859 TALLOC_FREE(subreq);
1860 if (tevent_req_nterror(req, status)) {
1864 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1865 switch (state->auth_level) {
1866 case DCERPC_AUTH_LEVEL_INTEGRITY:
1867 case DCERPC_AUTH_LEVEL_PRIVACY:
1870 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1874 uint32_t tmp = state->creds->negotiate_flags;
1876 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1878 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1879 * it should be used, which means
1880 * we had a chance to verify no downgrade
1883 * This relies on netlogon_creds_cli_check*
1884 * being called before, as first request after
1887 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1892 state->old_timeout = dcerpc_binding_handle_set_timeout(
1893 state->binding_handle, 600000);
1896 * we defer all callbacks in order to cleanup
1897 * the database record.
1899 tevent_req_defer_callback(req, state->ev);
1901 state->tmp_creds = *state->creds;
1902 netlogon_creds_client_authenticator(&state->tmp_creds,
1904 ZERO_STRUCT(state->rep_auth);
1906 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1908 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1909 netlogon_creds_aes_encrypt(&state->tmp_creds,
1910 state->samr_crypt_password.data,
1913 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1914 state->samr_crypt_password.data,
1918 memcpy(state->netr_crypt_password.data,
1919 state->samr_crypt_password.data, 512);
1920 state->netr_crypt_password.length =
1921 IVAL(state->samr_crypt_password.data, 512);
1923 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1924 state->binding_handle,
1925 state->srv_name_slash,
1926 state->tmp_creds.account_name,
1927 state->tmp_creds.secure_channel_type,
1928 state->tmp_creds.computer_name,
1931 &state->netr_crypt_password);
1932 if (tevent_req_nomem(subreq, req)) {
1933 status = NT_STATUS_NO_MEMORY;
1934 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1938 netlogon_creds_des_encrypt(&state->tmp_creds,
1939 &state->samr_password);
1941 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1942 state->binding_handle,
1943 state->srv_name_slash,
1944 state->tmp_creds.account_name,
1945 state->tmp_creds.secure_channel_type,
1946 state->tmp_creds.computer_name,
1949 &state->samr_password);
1950 if (tevent_req_nomem(subreq, req)) {
1951 status = NT_STATUS_NO_MEMORY;
1952 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1957 tevent_req_set_callback(subreq,
1958 netlogon_creds_cli_ServerPasswordSet_done,
1962 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1964 struct tevent_req *req =
1965 tevent_req_callback_data(subreq,
1967 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1968 tevent_req_data(req,
1969 struct netlogon_creds_cli_ServerPasswordSet_state);
1974 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1975 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1977 TALLOC_FREE(subreq);
1978 if (tevent_req_nterror(req, status)) {
1979 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1983 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1985 TALLOC_FREE(subreq);
1986 if (tevent_req_nterror(req, status)) {
1987 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1992 ok = netlogon_creds_client_check(&state->tmp_creds,
1993 &state->rep_auth.cred);
1995 status = NT_STATUS_ACCESS_DENIED;
1996 tevent_req_nterror(req, status);
1997 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2001 if (tevent_req_nterror(req, result)) {
2002 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2006 dcerpc_binding_handle_set_timeout(state->binding_handle,
2007 state->old_timeout);
2009 *state->creds = state->tmp_creds;
2010 status = netlogon_creds_cli_store(state->context,
2012 TALLOC_FREE(state->creds);
2013 if (tevent_req_nterror(req, status)) {
2014 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2018 tevent_req_done(req);
2021 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2025 if (tevent_req_is_nterror(req, &status)) {
2026 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2027 tevent_req_received(req);
2031 tevent_req_received(req);
2032 return NT_STATUS_OK;
2035 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2036 struct netlogon_creds_cli_context *context,
2037 struct dcerpc_binding_handle *b,
2038 const DATA_BLOB *new_password,
2039 const uint32_t *new_version)
2041 TALLOC_CTX *frame = talloc_stackframe();
2042 struct tevent_context *ev;
2043 struct tevent_req *req;
2044 NTSTATUS status = NT_STATUS_NO_MEMORY;
2046 ev = samba_tevent_context_init(frame);
2050 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2056 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2059 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2065 struct netlogon_creds_cli_LogonSamLogon_state {
2066 struct tevent_context *ev;
2067 struct netlogon_creds_cli_context *context;
2068 struct dcerpc_binding_handle *binding_handle;
2070 char *srv_name_slash;
2072 enum netr_LogonInfoClass logon_level;
2073 const union netr_LogonLevel *const_logon;
2074 union netr_LogonLevel *logon;
2077 uint16_t validation_level;
2078 union netr_Validation *validation;
2079 uint8_t authoritative;
2082 * do we need encryption at the application layer?
2086 bool try_validation6;
2089 * the read only credentials before we started the operation
2090 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2092 struct netlogon_creds_CredentialState *ro_creds;
2095 * The (locked) credentials used for the credential chain
2096 * used for netr_LogonSamLogonWithFlags() or
2097 * netr_LogonSamLogonWith().
2099 struct netlogon_creds_CredentialState *lk_creds;
2102 * While we have locked the global credentials (lk_creds above)
2103 * we operate an a temporary copy, because a server
2104 * may not support netr_LogonSamLogonWithFlags() and
2105 * didn't process our netr_Authenticator, so we need to
2106 * restart from lk_creds.
2108 struct netlogon_creds_CredentialState tmp_creds;
2109 struct netr_Authenticator req_auth;
2110 struct netr_Authenticator rep_auth;
2113 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2114 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2117 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2118 struct tevent_context *ev,
2119 struct netlogon_creds_cli_context *context,
2120 struct dcerpc_binding_handle *b,
2121 enum netr_LogonInfoClass logon_level,
2122 const union netr_LogonLevel *logon,
2125 struct tevent_req *req;
2126 struct netlogon_creds_cli_LogonSamLogon_state *state;
2128 req = tevent_req_create(mem_ctx, &state,
2129 struct netlogon_creds_cli_LogonSamLogon_state);
2135 state->context = context;
2136 state->binding_handle = b;
2138 state->logon_level = logon_level;
2139 state->const_logon = logon;
2140 state->flags = flags;
2142 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2143 context->server.computer);
2144 if (tevent_req_nomem(state->srv_name_slash, req)) {
2145 return tevent_req_post(req, ev);
2148 switch (logon_level) {
2149 case NetlogonInteractiveInformation:
2150 case NetlogonInteractiveTransitiveInformation:
2151 case NetlogonServiceInformation:
2152 case NetlogonServiceTransitiveInformation:
2153 case NetlogonGenericInformation:
2154 state->user_encrypt = true;
2157 case NetlogonNetworkInformation:
2158 case NetlogonNetworkTransitiveInformation:
2162 state->validation = talloc_zero(state, union netr_Validation);
2163 if (tevent_req_nomem(state->validation, req)) {
2164 return tevent_req_post(req, ev);
2167 netlogon_creds_cli_LogonSamLogon_start(req);
2168 if (!tevent_req_is_in_progress(req)) {
2169 return tevent_req_post(req, ev);
2173 * we defer all callbacks in order to cleanup
2174 * the database record.
2176 tevent_req_defer_callback(req, state->ev);
2180 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2183 struct netlogon_creds_cli_LogonSamLogon_state *state =
2184 tevent_req_data(req,
2185 struct netlogon_creds_cli_LogonSamLogon_state);
2187 if (state->lk_creds == NULL) {
2191 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2193 * This is a hack to recover from a bug in old
2194 * Samba servers, when LogonSamLogonEx() fails:
2196 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2198 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2200 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2201 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2202 * If the sign/seal check fails.
2204 * In that case we need to cleanup the netlogon session.
2206 * It's the job of the caller to disconnect the current
2207 * connection, if netlogon_creds_cli_LogonSamLogon()
2208 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2210 if (!state->context->server.try_logon_with) {
2211 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2215 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2216 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2217 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2218 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2219 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2220 TALLOC_FREE(state->lk_creds);
2224 netlogon_creds_cli_delete(state->context, state->lk_creds);
2225 TALLOC_FREE(state->lk_creds);
2228 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2230 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2232 struct netlogon_creds_cli_LogonSamLogon_state *state =
2233 tevent_req_data(req,
2234 struct netlogon_creds_cli_LogonSamLogon_state);
2235 struct tevent_req *subreq;
2237 enum dcerpc_AuthType auth_type;
2238 enum dcerpc_AuthLevel auth_level;
2240 TALLOC_FREE(state->ro_creds);
2241 TALLOC_FREE(state->logon);
2242 ZERO_STRUCTP(state->validation);
2244 dcerpc_binding_handle_auth_info(state->binding_handle,
2245 &auth_type, &auth_level);
2247 state->try_logon_ex = state->context->server.try_logon_ex;
2248 state->try_validation6 = state->context->server.try_validation6;
2250 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2251 state->try_logon_ex = false;
2254 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2255 state->try_validation6 = false;
2258 if (state->try_logon_ex) {
2259 if (state->try_validation6) {
2260 state->validation_level = 6;
2262 state->validation_level = 3;
2263 state->user_encrypt = true;
2266 state->logon = netlogon_creds_shallow_copy_logon(state,
2268 state->const_logon);
2269 if (tevent_req_nomem(state->logon, req)) {
2270 status = NT_STATUS_NO_MEMORY;
2271 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2275 if (state->user_encrypt) {
2276 status = netlogon_creds_cli_get(state->context,
2279 if (!NT_STATUS_IS_OK(status)) {
2280 status = NT_STATUS_ACCESS_DENIED;
2281 tevent_req_nterror(req, status);
2282 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2286 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2291 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2292 state->binding_handle,
2293 state->srv_name_slash,
2294 state->context->client.computer,
2297 state->validation_level,
2299 &state->authoritative,
2301 if (tevent_req_nomem(subreq, req)) {
2302 status = NT_STATUS_NO_MEMORY;
2303 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2306 tevent_req_set_callback(subreq,
2307 netlogon_creds_cli_LogonSamLogon_done,
2312 if (state->lk_creds == NULL) {
2313 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2315 if (tevent_req_nomem(subreq, req)) {
2316 status = NT_STATUS_NO_MEMORY;
2317 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2320 tevent_req_set_callback(subreq,
2321 netlogon_creds_cli_LogonSamLogon_done,
2326 state->tmp_creds = *state->lk_creds;
2327 netlogon_creds_client_authenticator(&state->tmp_creds,
2329 ZERO_STRUCT(state->rep_auth);
2331 state->logon = netlogon_creds_shallow_copy_logon(state,
2333 state->const_logon);
2334 if (tevent_req_nomem(state->logon, req)) {
2335 status = NT_STATUS_NO_MEMORY;
2336 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2340 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2344 state->validation_level = 3;
2346 if (state->context->server.try_logon_with) {
2347 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2348 state->binding_handle,
2349 state->srv_name_slash,
2350 state->context->client.computer,
2355 state->validation_level,
2357 &state->authoritative,
2359 if (tevent_req_nomem(subreq, req)) {
2360 status = NT_STATUS_NO_MEMORY;
2361 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2367 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2368 state->binding_handle,
2369 state->srv_name_slash,
2370 state->context->client.computer,
2375 state->validation_level,
2377 &state->authoritative);
2378 if (tevent_req_nomem(subreq, req)) {
2379 status = NT_STATUS_NO_MEMORY;
2380 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2385 tevent_req_set_callback(subreq,
2386 netlogon_creds_cli_LogonSamLogon_done,
2390 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2392 struct tevent_req *req =
2393 tevent_req_callback_data(subreq,
2395 struct netlogon_creds_cli_LogonSamLogon_state *state =
2396 tevent_req_data(req,
2397 struct netlogon_creds_cli_LogonSamLogon_state);
2402 if (state->try_logon_ex) {
2403 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2406 TALLOC_FREE(subreq);
2407 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2408 state->context->server.try_validation6 = false;
2409 state->context->server.try_logon_ex = false;
2410 netlogon_creds_cli_LogonSamLogon_start(req);
2413 if (tevent_req_nterror(req, status)) {
2414 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2418 if ((state->validation_level == 6) &&
2419 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2420 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2421 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2423 state->context->server.try_validation6 = false;
2424 netlogon_creds_cli_LogonSamLogon_start(req);
2428 if (tevent_req_nterror(req, result)) {
2429 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2433 if (state->ro_creds == NULL) {
2434 tevent_req_done(req);
2438 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2441 * We got a race, lets retry with on authenticator
2444 * netlogon_creds_cli_LogonSamLogon_start()
2445 * will TALLOC_FREE(state->ro_creds);
2447 state->try_logon_ex = false;
2448 netlogon_creds_cli_LogonSamLogon_start(req);
2452 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2453 state->validation_level,
2456 tevent_req_done(req);
2460 if (state->lk_creds == NULL) {
2461 status = netlogon_creds_cli_lock_recv(subreq, state,
2463 TALLOC_FREE(subreq);
2464 if (tevent_req_nterror(req, status)) {
2465 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2469 netlogon_creds_cli_LogonSamLogon_start(req);
2473 if (state->context->server.try_logon_with) {
2474 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2477 TALLOC_FREE(subreq);
2478 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2479 state->context->server.try_logon_with = false;
2480 netlogon_creds_cli_LogonSamLogon_start(req);
2483 if (tevent_req_nterror(req, status)) {
2484 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2488 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2491 TALLOC_FREE(subreq);
2492 if (tevent_req_nterror(req, status)) {
2493 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2498 ok = netlogon_creds_client_check(&state->tmp_creds,
2499 &state->rep_auth.cred);
2501 status = NT_STATUS_ACCESS_DENIED;
2502 tevent_req_nterror(req, status);
2503 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2507 *state->lk_creds = state->tmp_creds;
2508 status = netlogon_creds_cli_store(state->context,
2510 TALLOC_FREE(state->lk_creds);
2512 if (tevent_req_nterror(req, status)) {
2513 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2517 if (tevent_req_nterror(req, result)) {
2518 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2522 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2523 state->validation_level,
2526 tevent_req_done(req);
2529 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2530 TALLOC_CTX *mem_ctx,
2531 uint16_t *validation_level,
2532 union netr_Validation **validation,
2533 uint8_t *authoritative,
2536 struct netlogon_creds_cli_LogonSamLogon_state *state =
2537 tevent_req_data(req,
2538 struct netlogon_creds_cli_LogonSamLogon_state);
2541 /* authoritative is also returned on error */
2542 *authoritative = state->authoritative;
2544 if (tevent_req_is_nterror(req, &status)) {
2545 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2546 tevent_req_received(req);
2550 *validation_level = state->validation_level;
2551 *validation = talloc_move(mem_ctx, &state->validation);
2552 *flags = state->flags;
2554 tevent_req_received(req);
2555 return NT_STATUS_OK;
2558 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2559 struct netlogon_creds_cli_context *context,
2560 struct dcerpc_binding_handle *b,
2561 enum netr_LogonInfoClass logon_level,
2562 const union netr_LogonLevel *logon,
2563 TALLOC_CTX *mem_ctx,
2564 uint16_t *validation_level,
2565 union netr_Validation **validation,
2566 uint8_t *authoritative,
2569 TALLOC_CTX *frame = talloc_stackframe();
2570 struct tevent_context *ev;
2571 struct tevent_req *req;
2572 NTSTATUS status = NT_STATUS_NO_MEMORY;
2574 ev = samba_tevent_context_init(frame);
2578 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2584 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2587 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2597 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2598 struct tevent_context *ev;
2599 struct netlogon_creds_cli_context *context;
2600 struct dcerpc_binding_handle *binding_handle;
2602 char *srv_name_slash;
2603 enum dcerpc_AuthType auth_type;
2604 enum dcerpc_AuthLevel auth_level;
2606 const char *site_name;
2608 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2610 struct netlogon_creds_CredentialState *creds;
2611 struct netlogon_creds_CredentialState tmp_creds;
2612 struct netr_Authenticator req_auth;
2613 struct netr_Authenticator rep_auth;
2616 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2618 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2620 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2621 struct tevent_context *ev,
2622 struct netlogon_creds_cli_context *context,
2623 struct dcerpc_binding_handle *b,
2624 const char *site_name,
2626 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2628 struct tevent_req *req;
2629 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2630 struct tevent_req *subreq;
2632 req = tevent_req_create(mem_ctx, &state,
2633 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2639 state->context = context;
2640 state->binding_handle = b;
2642 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2643 context->server.computer);
2644 if (tevent_req_nomem(state->srv_name_slash, req)) {
2645 return tevent_req_post(req, ev);
2648 state->site_name = site_name;
2649 state->dns_ttl = dns_ttl;
2650 state->dns_names = dns_names;
2652 dcerpc_binding_handle_auth_info(state->binding_handle,
2654 &state->auth_level);
2656 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2658 if (tevent_req_nomem(subreq, req)) {
2659 return tevent_req_post(req, ev);
2662 tevent_req_set_callback(subreq,
2663 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2669 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2672 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2673 tevent_req_data(req,
2674 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2676 if (state->creds == NULL) {
2680 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2681 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2682 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2683 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2684 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2685 TALLOC_FREE(state->creds);
2689 netlogon_creds_cli_delete(state->context, state->creds);
2690 TALLOC_FREE(state->creds);
2693 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2695 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2697 struct tevent_req *req =
2698 tevent_req_callback_data(subreq,
2700 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2701 tevent_req_data(req,
2702 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2705 status = netlogon_creds_cli_lock_recv(subreq, state,
2707 TALLOC_FREE(subreq);
2708 if (tevent_req_nterror(req, status)) {
2712 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2713 switch (state->auth_level) {
2714 case DCERPC_AUTH_LEVEL_INTEGRITY:
2715 case DCERPC_AUTH_LEVEL_PRIVACY:
2718 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2722 uint32_t tmp = state->creds->negotiate_flags;
2724 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2726 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2727 * it should be used, which means
2728 * we had a chance to verify no downgrade
2731 * This relies on netlogon_creds_cli_check*
2732 * being called before, as first request after
2735 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2741 * we defer all callbacks in order to cleanup
2742 * the database record.
2744 tevent_req_defer_callback(req, state->ev);
2746 state->tmp_creds = *state->creds;
2747 netlogon_creds_client_authenticator(&state->tmp_creds,
2749 ZERO_STRUCT(state->rep_auth);
2751 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2752 state->binding_handle,
2753 state->srv_name_slash,
2754 state->tmp_creds.computer_name,
2760 if (tevent_req_nomem(subreq, req)) {
2761 status = NT_STATUS_NO_MEMORY;
2762 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2766 tevent_req_set_callback(subreq,
2767 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2771 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2773 struct tevent_req *req =
2774 tevent_req_callback_data(subreq,
2776 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2777 tevent_req_data(req,
2778 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2784 * We use state->dns_names as the memory context, as this is
2785 * the only in/out variable and it has been overwritten by the
2786 * out parameter from the server.
2788 * We need to preserve the return value until the caller can use it.
2790 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2792 TALLOC_FREE(subreq);
2793 if (tevent_req_nterror(req, status)) {
2794 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2798 ok = netlogon_creds_client_check(&state->tmp_creds,
2799 &state->rep_auth.cred);
2801 status = NT_STATUS_ACCESS_DENIED;
2802 tevent_req_nterror(req, status);
2803 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2807 *state->creds = state->tmp_creds;
2808 status = netlogon_creds_cli_store(state->context,
2810 TALLOC_FREE(state->creds);
2812 if (tevent_req_nterror(req, status)) {
2813 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2817 if (tevent_req_nterror(req, result)) {
2818 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2822 tevent_req_done(req);
2825 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2829 if (tevent_req_is_nterror(req, &status)) {
2830 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2831 tevent_req_received(req);
2835 tevent_req_received(req);
2836 return NT_STATUS_OK;
2839 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2840 struct netlogon_creds_cli_context *context,
2841 struct dcerpc_binding_handle *b,
2842 const char *site_name,
2844 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2846 TALLOC_CTX *frame = talloc_stackframe();
2847 struct tevent_context *ev;
2848 struct tevent_req *req;
2849 NTSTATUS status = NT_STATUS_NO_MEMORY;
2851 ev = samba_tevent_context_init(frame);
2855 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2862 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2865 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2871 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2872 struct tevent_context *ev;
2873 struct netlogon_creds_cli_context *context;
2874 struct dcerpc_binding_handle *binding_handle;
2876 char *srv_name_slash;
2877 enum dcerpc_AuthType auth_type;
2878 enum dcerpc_AuthLevel auth_level;
2880 struct samr_Password new_owf_password;
2881 struct samr_Password old_owf_password;
2882 struct netr_TrustInfo *trust_info;
2884 struct netlogon_creds_CredentialState *creds;
2885 struct netlogon_creds_CredentialState tmp_creds;
2886 struct netr_Authenticator req_auth;
2887 struct netr_Authenticator rep_auth;
2890 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2892 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2894 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2895 struct tevent_context *ev,
2896 struct netlogon_creds_cli_context *context,
2897 struct dcerpc_binding_handle *b)
2899 struct tevent_req *req;
2900 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2901 struct tevent_req *subreq;
2903 req = tevent_req_create(mem_ctx, &state,
2904 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2910 state->context = context;
2911 state->binding_handle = b;
2913 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2914 context->server.computer);
2915 if (tevent_req_nomem(state->srv_name_slash, req)) {
2916 return tevent_req_post(req, ev);
2919 dcerpc_binding_handle_auth_info(state->binding_handle,
2921 &state->auth_level);
2923 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2925 if (tevent_req_nomem(subreq, req)) {
2926 return tevent_req_post(req, ev);
2929 tevent_req_set_callback(subreq,
2930 netlogon_creds_cli_ServerGetTrustInfo_locked,
2936 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2939 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2940 tevent_req_data(req,
2941 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2943 if (state->creds == NULL) {
2947 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2948 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2949 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2950 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2951 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2952 TALLOC_FREE(state->creds);
2956 netlogon_creds_cli_delete(state->context, state->creds);
2957 TALLOC_FREE(state->creds);
2960 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2962 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2964 struct tevent_req *req =
2965 tevent_req_callback_data(subreq,
2967 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2968 tevent_req_data(req,
2969 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2972 status = netlogon_creds_cli_lock_recv(subreq, state,
2974 TALLOC_FREE(subreq);
2975 if (tevent_req_nterror(req, status)) {
2979 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2980 switch (state->auth_level) {
2981 case DCERPC_AUTH_LEVEL_PRIVACY:
2984 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2988 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2993 * we defer all callbacks in order to cleanup
2994 * the database record.
2996 tevent_req_defer_callback(req, state->ev);
2998 state->tmp_creds = *state->creds;
2999 netlogon_creds_client_authenticator(&state->tmp_creds,
3001 ZERO_STRUCT(state->rep_auth);
3003 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3004 state->binding_handle,
3005 state->srv_name_slash,
3006 state->tmp_creds.account_name,
3007 state->tmp_creds.secure_channel_type,
3008 state->tmp_creds.computer_name,
3011 &state->new_owf_password,
3012 &state->old_owf_password,
3013 &state->trust_info);
3014 if (tevent_req_nomem(subreq, req)) {
3015 status = NT_STATUS_NO_MEMORY;
3016 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3020 tevent_req_set_callback(subreq,
3021 netlogon_creds_cli_ServerGetTrustInfo_done,
3025 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3027 struct tevent_req *req =
3028 tevent_req_callback_data(subreq,
3030 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3031 tevent_req_data(req,
3032 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3035 const struct samr_Password zero = {};
3040 * We use state->dns_names as the memory context, as this is
3041 * the only in/out variable and it has been overwritten by the
3042 * out parameter from the server.
3044 * We need to preserve the return value until the caller can use it.
3046 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3047 TALLOC_FREE(subreq);
3048 if (tevent_req_nterror(req, status)) {
3049 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3053 ok = netlogon_creds_client_check(&state->tmp_creds,
3054 &state->rep_auth.cred);
3056 status = NT_STATUS_ACCESS_DENIED;
3057 tevent_req_nterror(req, status);
3058 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3062 cmp = memcmp(state->new_owf_password.hash,
3063 zero.hash, sizeof(zero.hash));
3065 netlogon_creds_des_decrypt(&state->tmp_creds,
3066 &state->new_owf_password);
3068 cmp = memcmp(state->old_owf_password.hash,
3069 zero.hash, sizeof(zero.hash));
3071 netlogon_creds_des_decrypt(&state->tmp_creds,
3072 &state->old_owf_password);
3075 *state->creds = state->tmp_creds;
3076 status = netlogon_creds_cli_store(state->context,
3078 TALLOC_FREE(state->creds);
3079 if (tevent_req_nterror(req, status)) {
3080 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3084 if (tevent_req_nterror(req, result)) {
3085 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3089 tevent_req_done(req);
3092 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3093 TALLOC_CTX *mem_ctx,
3094 struct samr_Password *new_owf_password,
3095 struct samr_Password *old_owf_password,
3096 struct netr_TrustInfo **trust_info)
3098 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3099 tevent_req_data(req,
3100 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3103 if (tevent_req_is_nterror(req, &status)) {
3104 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3105 tevent_req_received(req);
3109 if (new_owf_password != NULL) {
3110 *new_owf_password = state->new_owf_password;
3112 if (old_owf_password != NULL) {
3113 *old_owf_password = state->old_owf_password;
3115 if (trust_info != NULL) {
3116 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3119 tevent_req_received(req);
3120 return NT_STATUS_OK;
3123 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3124 struct netlogon_creds_cli_context *context,
3125 struct dcerpc_binding_handle *b,
3126 TALLOC_CTX *mem_ctx,
3127 struct samr_Password *new_owf_password,
3128 struct samr_Password *old_owf_password,
3129 struct netr_TrustInfo **trust_info)
3131 TALLOC_CTX *frame = talloc_stackframe();
3132 struct tevent_context *ev;
3133 struct tevent_req *req;
3134 NTSTATUS status = NT_STATUS_NO_MEMORY;
3136 ev = samba_tevent_context_init(frame);
3140 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3144 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3147 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3157 struct netlogon_creds_cli_GetForestTrustInformation_state {
3158 struct tevent_context *ev;
3159 struct netlogon_creds_cli_context *context;
3160 struct dcerpc_binding_handle *binding_handle;
3162 char *srv_name_slash;
3163 enum dcerpc_AuthType auth_type;
3164 enum dcerpc_AuthLevel auth_level;
3167 struct lsa_ForestTrustInformation *forest_trust_info;
3169 struct netlogon_creds_CredentialState *creds;
3170 struct netlogon_creds_CredentialState tmp_creds;
3171 struct netr_Authenticator req_auth;
3172 struct netr_Authenticator rep_auth;
3175 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3177 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3179 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3180 struct tevent_context *ev,
3181 struct netlogon_creds_cli_context *context,
3182 struct dcerpc_binding_handle *b)
3184 struct tevent_req *req;
3185 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3186 struct tevent_req *subreq;
3188 req = tevent_req_create(mem_ctx, &state,
3189 struct netlogon_creds_cli_GetForestTrustInformation_state);
3195 state->context = context;
3196 state->binding_handle = b;
3198 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3199 context->server.computer);
3200 if (tevent_req_nomem(state->srv_name_slash, req)) {
3201 return tevent_req_post(req, ev);
3206 dcerpc_binding_handle_auth_info(state->binding_handle,
3208 &state->auth_level);
3210 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3212 if (tevent_req_nomem(subreq, req)) {
3213 return tevent_req_post(req, ev);
3216 tevent_req_set_callback(subreq,
3217 netlogon_creds_cli_GetForestTrustInformation_locked,
3223 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3226 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3227 tevent_req_data(req,
3228 struct netlogon_creds_cli_GetForestTrustInformation_state);
3230 if (state->creds == NULL) {
3234 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3235 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3236 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3237 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3238 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3239 TALLOC_FREE(state->creds);
3243 netlogon_creds_cli_delete(state->context, state->creds);
3244 TALLOC_FREE(state->creds);
3247 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3249 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3251 struct tevent_req *req =
3252 tevent_req_callback_data(subreq,
3254 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3255 tevent_req_data(req,
3256 struct netlogon_creds_cli_GetForestTrustInformation_state);
3259 status = netlogon_creds_cli_lock_recv(subreq, state,
3261 TALLOC_FREE(subreq);
3262 if (tevent_req_nterror(req, status)) {
3266 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3267 switch (state->auth_level) {
3268 case DCERPC_AUTH_LEVEL_INTEGRITY:
3269 case DCERPC_AUTH_LEVEL_PRIVACY:
3272 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3276 uint32_t tmp = state->creds->negotiate_flags;
3278 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3280 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3281 * it should be used, which means
3282 * we had a chance to verify no downgrade
3285 * This relies on netlogon_creds_cli_check*
3286 * being called before, as first request after
3289 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3295 * we defer all callbacks in order to cleanup
3296 * the database record.
3298 tevent_req_defer_callback(req, state->ev);
3300 state->tmp_creds = *state->creds;
3301 netlogon_creds_client_authenticator(&state->tmp_creds,
3303 ZERO_STRUCT(state->rep_auth);
3305 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3306 state->binding_handle,
3307 state->srv_name_slash,
3308 state->tmp_creds.computer_name,
3312 &state->forest_trust_info);
3313 if (tevent_req_nomem(subreq, req)) {
3314 status = NT_STATUS_NO_MEMORY;
3315 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3319 tevent_req_set_callback(subreq,
3320 netlogon_creds_cli_GetForestTrustInformation_done,
3324 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3326 struct tevent_req *req =
3327 tevent_req_callback_data(subreq,
3329 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3330 tevent_req_data(req,
3331 struct netlogon_creds_cli_GetForestTrustInformation_state);
3337 * We use state->dns_names as the memory context, as this is
3338 * the only in/out variable and it has been overwritten by the
3339 * out parameter from the server.
3341 * We need to preserve the return value until the caller can use it.
3343 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3344 TALLOC_FREE(subreq);
3345 if (tevent_req_nterror(req, status)) {
3346 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3350 ok = netlogon_creds_client_check(&state->tmp_creds,
3351 &state->rep_auth.cred);
3353 status = NT_STATUS_ACCESS_DENIED;
3354 tevent_req_nterror(req, status);
3355 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3359 *state->creds = state->tmp_creds;
3360 status = netlogon_creds_cli_store(state->context,
3362 TALLOC_FREE(state->creds);
3364 if (tevent_req_nterror(req, status)) {
3365 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3369 if (tevent_req_nterror(req, result)) {
3370 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3374 tevent_req_done(req);
3377 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3378 TALLOC_CTX *mem_ctx,
3379 struct lsa_ForestTrustInformation **forest_trust_info)
3381 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3382 tevent_req_data(req,
3383 struct netlogon_creds_cli_GetForestTrustInformation_state);
3386 if (tevent_req_is_nterror(req, &status)) {
3387 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3388 tevent_req_received(req);
3392 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3394 tevent_req_received(req);
3395 return NT_STATUS_OK;
3398 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3399 struct netlogon_creds_cli_context *context,
3400 struct dcerpc_binding_handle *b,
3401 TALLOC_CTX *mem_ctx,
3402 struct lsa_ForestTrustInformation **forest_trust_info)
3404 TALLOC_CTX *frame = talloc_stackframe();
3405 struct tevent_context *ev;
3406 struct tevent_req *req;
3407 NTSTATUS status = NT_STATUS_NO_MEMORY;
3409 ev = samba_tevent_context_init(frame);
3413 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3417 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3420 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3428 struct netlogon_creds_cli_SendToSam_state {
3429 struct tevent_context *ev;
3430 struct netlogon_creds_cli_context *context;
3431 struct dcerpc_binding_handle *binding_handle;
3433 char *srv_name_slash;
3434 enum dcerpc_AuthType auth_type;
3435 enum dcerpc_AuthLevel auth_level;
3439 struct netlogon_creds_CredentialState *creds;
3440 struct netlogon_creds_CredentialState tmp_creds;
3441 struct netr_Authenticator req_auth;
3442 struct netr_Authenticator rep_auth;
3445 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3447 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3449 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3450 struct tevent_context *ev,
3451 struct netlogon_creds_cli_context *context,
3452 struct dcerpc_binding_handle *b,
3453 struct netr_SendToSamBase *message)
3455 struct tevent_req *req;
3456 struct netlogon_creds_cli_SendToSam_state *state;
3457 struct tevent_req *subreq;
3458 enum ndr_err_code ndr_err;
3460 req = tevent_req_create(mem_ctx, &state,
3461 struct netlogon_creds_cli_SendToSam_state);
3467 state->context = context;
3468 state->binding_handle = b;
3470 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3471 context->server.computer);
3472 if (tevent_req_nomem(state->srv_name_slash, req)) {
3473 return tevent_req_post(req, ev);
3476 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3477 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3478 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3479 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3480 tevent_req_nterror(req, status);
3481 return tevent_req_post(req, ev);
3484 dcerpc_binding_handle_auth_info(state->binding_handle,
3486 &state->auth_level);
3488 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3490 if (tevent_req_nomem(subreq, req)) {
3491 return tevent_req_post(req, ev);
3494 tevent_req_set_callback(subreq,
3495 netlogon_creds_cli_SendToSam_locked,
3501 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3504 struct netlogon_creds_cli_SendToSam_state *state =
3505 tevent_req_data(req,
3506 struct netlogon_creds_cli_SendToSam_state);
3508 if (state->creds == NULL) {
3512 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3513 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3514 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3515 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3516 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3517 TALLOC_FREE(state->creds);
3521 netlogon_creds_cli_delete(state->context, state->creds);
3522 TALLOC_FREE(state->creds);
3525 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3527 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3529 struct tevent_req *req =
3530 tevent_req_callback_data(subreq,
3532 struct netlogon_creds_cli_SendToSam_state *state =
3533 tevent_req_data(req,
3534 struct netlogon_creds_cli_SendToSam_state);
3537 status = netlogon_creds_cli_lock_recv(subreq, state,
3539 TALLOC_FREE(subreq);
3540 if (tevent_req_nterror(req, status)) {
3544 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3545 switch (state->auth_level) {
3546 case DCERPC_AUTH_LEVEL_INTEGRITY:
3547 case DCERPC_AUTH_LEVEL_PRIVACY:
3550 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3554 uint32_t tmp = state->creds->negotiate_flags;
3556 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3558 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3559 * it should be used, which means
3560 * we had a chance to verify no downgrade
3563 * This relies on netlogon_creds_cli_check*
3564 * being called before, as first request after
3567 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3573 * we defer all callbacks in order to cleanup
3574 * the database record.
3576 tevent_req_defer_callback(req, state->ev);
3578 state->tmp_creds = *state->creds;
3579 netlogon_creds_client_authenticator(&state->tmp_creds,
3581 ZERO_STRUCT(state->rep_auth);
3583 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3584 netlogon_creds_aes_encrypt(&state->tmp_creds,
3586 state->opaque.length);
3588 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3590 state->opaque.length);
3593 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3594 state->binding_handle,
3595 state->srv_name_slash,
3596 state->tmp_creds.computer_name,
3600 state->opaque.length);
3601 if (tevent_req_nomem(subreq, req)) {
3602 status = NT_STATUS_NO_MEMORY;
3603 netlogon_creds_cli_SendToSam_cleanup(req, status);
3607 tevent_req_set_callback(subreq,
3608 netlogon_creds_cli_SendToSam_done,
3612 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3614 struct tevent_req *req =
3615 tevent_req_callback_data(subreq,
3617 struct netlogon_creds_cli_SendToSam_state *state =
3618 tevent_req_data(req,
3619 struct netlogon_creds_cli_SendToSam_state);
3624 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3625 TALLOC_FREE(subreq);
3626 if (tevent_req_nterror(req, status)) {
3627 netlogon_creds_cli_SendToSam_cleanup(req, status);
3631 ok = netlogon_creds_client_check(&state->tmp_creds,
3632 &state->rep_auth.cred);
3634 status = NT_STATUS_ACCESS_DENIED;
3635 tevent_req_nterror(req, status);
3636 netlogon_creds_cli_SendToSam_cleanup(req, status);
3640 *state->creds = state->tmp_creds;
3641 status = netlogon_creds_cli_store(state->context,
3643 TALLOC_FREE(state->creds);
3645 if (tevent_req_nterror(req, status)) {
3646 netlogon_creds_cli_SendToSam_cleanup(req, status);
3651 * Creds must be stored before we send back application errors
3652 * e.g. NT_STATUS_NOT_IMPLEMENTED
3654 if (tevent_req_nterror(req, result)) {
3655 netlogon_creds_cli_SendToSam_cleanup(req, result);
3659 tevent_req_done(req);
3662 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3663 struct dcerpc_binding_handle *b,
3664 struct netr_SendToSamBase *message)
3666 TALLOC_CTX *frame = talloc_stackframe();
3667 struct tevent_context *ev;
3668 struct tevent_req *req;
3669 NTSTATUS status = NT_STATUS_OK;
3671 ev = samba_tevent_context_init(frame);
3675 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3679 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3683 /* Ignore the result */