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 TALLOC_CTX *frame = talloc_stackframe();
115 char *_key_name = NULL;
116 char *server_netbios_name = NULL;
121 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
122 if (context == NULL) {
124 return NT_STATUS_NO_MEMORY;
127 context->client.computer = talloc_strdup(context, client_computer);
128 if (context->client.computer == NULL) {
129 TALLOC_FREE(context);
131 return NT_STATUS_NO_MEMORY;
134 context->client.account = talloc_strdup(context, client_account);
135 if (context->client.account == NULL) {
136 TALLOC_FREE(context);
138 return NT_STATUS_NO_MEMORY;
141 context->client.proposed_flags = proposed_flags;
142 context->client.required_flags = required_flags;
143 context->client.type = type;
144 context->client.auth_level = auth_level;
146 context->server.computer = talloc_strdup(context, server_computer);
147 if (context->server.computer == NULL) {
148 TALLOC_FREE(context);
150 return NT_STATUS_NO_MEMORY;
153 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
154 if (context->server.netbios_domain == NULL) {
155 TALLOC_FREE(context);
157 return NT_STATUS_NO_MEMORY;
160 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
161 if (context->server.dns_domain == NULL) {
162 TALLOC_FREE(context);
164 return NT_STATUS_NO_MEMORY;
169 * Force the callers to provide a unique
170 * value for server_computer and use this directly.
172 * For now we have to deal with
173 * "HOSTNAME" vs. "hostname.example.com".
175 server_netbios_name = talloc_strdup(frame, server_computer);
176 if (server_netbios_name == NULL) {
177 TALLOC_FREE(context);
179 return NT_STATUS_NO_MEMORY;
182 p = strchr(server_netbios_name, '.');
187 _key_name = talloc_asprintf(frame, "CLI[%s/%s]/SRV[%s/%s]",
191 server_netbios_domain);
192 if (_key_name == NULL) {
193 TALLOC_FREE(context);
195 return NT_STATUS_NO_MEMORY;
198 context->db.key_name = talloc_strdup_upper(context, _key_name);
199 if (context->db.key_name == NULL) {
200 TALLOC_FREE(context);
202 return NT_STATUS_NO_MEMORY;
205 context->db.key_data = string_term_tdb_data(context->db.key_name);
212 static struct db_context *netlogon_creds_cli_global_db;
214 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
216 if (netlogon_creds_cli_global_db != NULL) {
217 return NT_STATUS_INVALID_PARAMETER_MIX;
220 netlogon_creds_cli_global_db = talloc_move(NULL, db);
224 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
227 struct db_context *global_db;
229 if (netlogon_creds_cli_global_db != NULL) {
233 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
235 return NT_STATUS_NO_MEMORY;
238 global_db = dbwrap_local_open(NULL, lp_ctx,
240 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
242 0600, DBWRAP_LOCK_ORDER_2,
244 if (global_db == NULL) {
245 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
246 fname, strerror(errno)));
248 return NT_STATUS_NO_MEMORY;
252 netlogon_creds_cli_global_db = global_db;
256 void netlogon_creds_cli_close_global_db(void)
258 TALLOC_FREE(netlogon_creds_cli_global_db);
261 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
262 struct messaging_context *msg_ctx,
263 const char *client_account,
264 enum netr_SchannelType type,
265 const char *server_computer,
266 const char *server_netbios_domain,
267 const char *server_dns_domain,
269 struct netlogon_creds_cli_context **_context)
271 TALLOC_CTX *frame = talloc_stackframe();
273 struct netlogon_creds_cli_context *context = NULL;
274 const char *client_computer;
275 uint32_t proposed_flags;
276 uint32_t required_flags = 0;
277 bool reject_md5_servers = false;
278 bool require_strong_key = false;
279 int require_sign_or_seal = true;
280 bool seal_secure_channel = true;
281 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
282 bool neutralize_nt4_emulation = false;
286 client_computer = lpcfg_netbios_name(lp_ctx);
287 if (strlen(client_computer) > 15) {
288 return NT_STATUS_INVALID_PARAMETER_MIX;
292 * allow overwrite per domain
293 * reject md5 servers:<netbios_domain>
295 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
296 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
297 "reject md5 servers",
298 server_netbios_domain,
302 * allow overwrite per domain
303 * require strong key:<netbios_domain>
305 require_strong_key = lpcfg_require_strong_key(lp_ctx);
306 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
307 "require strong key",
308 server_netbios_domain,
312 * allow overwrite per domain
313 * client schannel:<netbios_domain>
315 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
316 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
318 server_netbios_domain,
319 require_sign_or_seal);
322 * allow overwrite per domain
323 * winbind sealed pipes:<netbios_domain>
325 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
326 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
327 "winbind sealed pipes",
328 server_netbios_domain,
329 seal_secure_channel);
332 * allow overwrite per domain
333 * neutralize nt4 emulation:<netbios_domain>
335 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
336 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
337 "neutralize nt4 emulation",
338 server_netbios_domain,
339 neutralize_nt4_emulation);
341 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
342 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
346 if (lpcfg_security(lp_ctx) == SEC_ADS) {
348 * AD domains should be secure
350 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
351 require_sign_or_seal = true;
352 require_strong_key = true;
356 case SEC_CHAN_DOMAIN:
359 case SEC_CHAN_DNS_DOMAIN:
361 * AD domains should be secure
363 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
364 require_sign_or_seal = true;
365 require_strong_key = true;
366 neutralize_nt4_emulation = true;
370 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
371 require_sign_or_seal = true;
372 require_strong_key = true;
376 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
377 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
378 require_sign_or_seal = true;
379 require_strong_key = true;
380 neutralize_nt4_emulation = true;
385 return NT_STATUS_INVALID_PARAMETER;
388 if (neutralize_nt4_emulation) {
389 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
392 if (require_sign_or_seal == false) {
393 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
395 required_flags |= NETLOGON_NEG_ARCFOUR;
396 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
399 if (reject_md5_servers) {
400 required_flags |= NETLOGON_NEG_ARCFOUR;
401 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
402 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
403 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
406 if (require_strong_key) {
407 required_flags |= NETLOGON_NEG_ARCFOUR;
408 required_flags |= NETLOGON_NEG_STRONG_KEYS;
409 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
412 proposed_flags |= required_flags;
414 if (seal_secure_channel) {
415 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
417 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
420 status = netlogon_creds_cli_context_common(client_computer,
427 server_netbios_domain,
431 if (!NT_STATUS_IS_OK(status)) {
436 if (msg_ctx != NULL) {
437 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
438 if (context->db.g_ctx == NULL) {
439 TALLOC_FREE(context);
441 return NT_STATUS_NO_MEMORY;
445 if (netlogon_creds_cli_global_db != NULL) {
446 context->db.ctx = netlogon_creds_cli_global_db;
452 status = netlogon_creds_cli_open_global_db(lp_ctx);
453 if (!NT_STATUS_IS_OK(status)) {
454 TALLOC_FREE(context);
456 return NT_STATUS_NO_MEMORY;
459 context->db.ctx = netlogon_creds_cli_global_db;
465 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
466 const char *client_account,
467 enum netr_SchannelType type,
468 uint32_t proposed_flags,
469 uint32_t required_flags,
470 enum dcerpc_AuthLevel auth_level,
471 const char *server_computer,
472 const char *server_netbios_domain,
474 struct netlogon_creds_cli_context **_context)
477 struct netlogon_creds_cli_context *context = NULL;
481 status = netlogon_creds_cli_context_common(client_computer,
488 server_netbios_domain,
492 if (!NT_STATUS_IS_OK(status)) {
496 context->db.ctx = db_open_rbt(context);
497 if (context->db.ctx == NULL) {
498 talloc_free(context);
499 return NT_STATUS_NO_MEMORY;
506 char *netlogon_creds_cli_debug_string(
507 const struct netlogon_creds_cli_context *context,
510 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
511 context->db.key_name);
514 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
515 struct netlogon_creds_cli_context *context)
517 return context->client.auth_level;
520 struct netlogon_creds_cli_fetch_state {
522 struct netlogon_creds_CredentialState *creds;
523 uint32_t required_flags;
527 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
530 struct netlogon_creds_cli_fetch_state *state =
531 (struct netlogon_creds_cli_fetch_state *)private_data;
532 enum ndr_err_code ndr_err;
536 state->creds = talloc_zero(state->mem_ctx,
537 struct netlogon_creds_CredentialState);
538 if (state->creds == NULL) {
539 state->status = NT_STATUS_NO_MEMORY;
543 blob.data = data.dptr;
544 blob.length = data.dsize;
546 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
547 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
548 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
549 TALLOC_FREE(state->creds);
550 state->status = ndr_map_error2ntstatus(ndr_err);
554 tmp_flags = state->creds->negotiate_flags;
555 tmp_flags &= state->required_flags;
556 if (tmp_flags != state->required_flags) {
557 TALLOC_FREE(state->creds);
558 state->status = NT_STATUS_DOWNGRADE_DETECTED;
562 state->status = NT_STATUS_OK;
565 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
567 struct netlogon_creds_CredentialState **_creds)
570 struct netlogon_creds_cli_fetch_state fstate = {
572 .status = NT_STATUS_INTERNAL_ERROR,
573 .required_flags = context->client.required_flags,
575 static const struct netr_Credential zero_creds;
579 status = dbwrap_parse_record(context->db.ctx,
580 context->db.key_data,
581 netlogon_creds_cli_fetch_parser,
583 if (!NT_STATUS_IS_OK(status)) {
586 status = fstate.status;
587 if (!NT_STATUS_IS_OK(status)) {
592 * mark it as invalid for step operations.
594 fstate.creds->sequence = 0;
595 fstate.creds->seed = zero_creds;
596 fstate.creds->client = zero_creds;
597 fstate.creds->server = zero_creds;
599 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
600 *_creds = fstate.creds;
605 * It is really important to try SamLogonEx here,
606 * because multiple processes can talk to the same
607 * domain controller, without using the credential
610 * With a normal SamLogon call, we must keep the
611 * credentials chain updated and intact between all
612 * users of the machine account (which would imply
613 * cross-node communication for every NTLM logon).
615 * The credentials chain is not per NETLOGON pipe
616 * connection, but globally on the server/client pair
617 * by computer name, while the client is free to use
618 * any computer name. We include the cluster node number
619 * in our computer name in order to avoid cross node
620 * coordination of the credential chain.
622 * It's also important to use NetlogonValidationSamInfo4 (6),
623 * because it relies on the rpc transport encryption
624 * and avoids using the global netlogon schannel
625 * session key to en/decrypt secret information
626 * like the user_session_key for network logons.
628 * [MS-APDS] 3.1.5.2 NTLM Network Logon
629 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
630 * NETLOGON_NEG_AUTHENTICATED_RPC set together
631 * are the indication that the server supports
632 * NetlogonValidationSamInfo4 (6). And it must only
633 * be used if "SealSecureChannel" is used.
635 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
636 * check is done in netlogon_creds_cli_LogonSamLogon*().
638 context->server.cached_flags = fstate.creds->negotiate_flags;
639 context->server.try_validation6 = true;
640 context->server.try_logon_ex = true;
641 context->server.try_logon_with = true;
643 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
644 context->server.try_validation6 = false;
645 context->server.try_logon_ex = false;
647 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
648 context->server.try_validation6 = false;
651 *_creds = fstate.creds;
655 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
656 const struct netlogon_creds_CredentialState *creds1)
658 TALLOC_CTX *frame = talloc_stackframe();
659 struct netlogon_creds_CredentialState *creds2;
663 enum ndr_err_code ndr_err;
666 status = netlogon_creds_cli_get(context, frame, &creds2);
667 if (!NT_STATUS_IS_OK(status)) {
672 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
673 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
674 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
679 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
680 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
681 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
686 if (blob1.length != blob2.length) {
691 cmp = memcmp(blob1.data, blob2.data, blob1.length);
701 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
702 struct netlogon_creds_CredentialState **_creds)
704 struct netlogon_creds_CredentialState *creds = *_creds;
706 enum ndr_err_code ndr_err;
712 if (context->db.locked_state == NULL) {
714 * this was not the result of netlogon_creds_cli_lock*()
717 return NT_STATUS_INVALID_PAGE_PROTECTION;
720 if (context->db.locked_state->creds != creds) {
722 * this was not the result of netlogon_creds_cli_lock*()
725 return NT_STATUS_INVALID_PAGE_PROTECTION;
728 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
729 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
730 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
732 status = ndr_map_error2ntstatus(ndr_err);
736 data.dptr = blob.data;
737 data.dsize = blob.length;
739 status = dbwrap_store(context->db.ctx,
740 context->db.key_data,
743 if (!NT_STATUS_IS_OK(status)) {
750 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
751 struct netlogon_creds_CredentialState **_creds)
753 struct netlogon_creds_CredentialState *creds = *_creds;
758 if (context->db.locked_state == NULL) {
760 * this was not the result of netlogon_creds_cli_lock*()
763 return NT_STATUS_INVALID_PAGE_PROTECTION;
766 if (context->db.locked_state->creds != creds) {
768 * this was not the result of netlogon_creds_cli_lock*()
771 return NT_STATUS_INVALID_PAGE_PROTECTION;
774 status = dbwrap_delete(context->db.ctx,
775 context->db.key_data);
777 if (!NT_STATUS_IS_OK(status)) {
784 struct netlogon_creds_cli_lock_state {
785 struct netlogon_creds_cli_locked_state *locked_state;
786 struct netlogon_creds_CredentialState *creds;
789 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
790 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
792 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
793 struct tevent_context *ev,
794 struct netlogon_creds_cli_context *context)
796 struct tevent_req *req;
797 struct netlogon_creds_cli_lock_state *state;
798 struct netlogon_creds_cli_locked_state *locked_state;
799 struct tevent_req *subreq;
801 req = tevent_req_create(mem_ctx, &state,
802 struct netlogon_creds_cli_lock_state);
807 if (context->db.locked_state != NULL) {
808 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
809 return tevent_req_post(req, ev);
812 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
813 if (tevent_req_nomem(locked_state, req)) {
814 return tevent_req_post(req, ev);
816 talloc_set_destructor(locked_state,
817 netlogon_creds_cli_locked_state_destructor);
818 locked_state->context = context;
820 context->db.locked_state = locked_state;
821 state->locked_state = locked_state;
823 if (context->db.g_ctx == NULL) {
824 netlogon_creds_cli_lock_fetch(req);
825 if (!tevent_req_is_in_progress(req)) {
826 return tevent_req_post(req, ev);
832 subreq = g_lock_lock_send(state, ev,
834 context->db.key_name,
836 if (tevent_req_nomem(subreq, req)) {
837 return tevent_req_post(req, ev);
839 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
844 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
846 struct tevent_req *req =
847 tevent_req_callback_data(subreq,
849 struct netlogon_creds_cli_lock_state *state =
851 struct netlogon_creds_cli_lock_state);
854 status = g_lock_lock_recv(subreq);
856 if (tevent_req_nterror(req, status)) {
859 state->locked_state->is_glocked = true;
861 netlogon_creds_cli_lock_fetch(req);
864 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
866 struct netlogon_creds_cli_lock_state *state =
868 struct netlogon_creds_cli_lock_state);
869 struct netlogon_creds_cli_context *context = state->locked_state->context;
870 struct netlogon_creds_cli_fetch_state fstate = {
871 .status = NT_STATUS_INTERNAL_ERROR,
872 .required_flags = context->client.required_flags,
876 fstate.mem_ctx = state;
877 status = dbwrap_parse_record(context->db.ctx,
878 context->db.key_data,
879 netlogon_creds_cli_fetch_parser,
881 if (tevent_req_nterror(req, status)) {
884 status = fstate.status;
885 if (tevent_req_nterror(req, status)) {
889 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
890 state->creds = fstate.creds;
891 tevent_req_done(req);
895 context->server.cached_flags = fstate.creds->negotiate_flags;
896 context->server.try_validation6 = true;
897 context->server.try_logon_ex = true;
898 context->server.try_logon_with = true;
900 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
901 context->server.try_validation6 = false;
902 context->server.try_logon_ex = false;
904 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
905 context->server.try_validation6 = false;
908 state->creds = fstate.creds;
909 tevent_req_done(req);
913 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
915 struct netlogon_creds_CredentialState **creds)
917 struct netlogon_creds_cli_lock_state *state =
919 struct netlogon_creds_cli_lock_state);
922 if (tevent_req_is_nterror(req, &status)) {
923 tevent_req_received(req);
927 talloc_steal(state->creds, state->locked_state);
928 state->locked_state->creds = state->creds;
929 *creds = talloc_move(mem_ctx, &state->creds);
930 tevent_req_received(req);
934 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
936 struct netlogon_creds_CredentialState **creds)
938 TALLOC_CTX *frame = talloc_stackframe();
939 struct tevent_context *ev;
940 struct tevent_req *req;
941 NTSTATUS status = NT_STATUS_NO_MEMORY;
943 ev = samba_tevent_context_init(frame);
947 req = netlogon_creds_cli_lock_send(frame, ev, context);
951 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
954 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
960 struct netlogon_creds_cli_auth_state {
961 struct tevent_context *ev;
962 struct netlogon_creds_cli_context *context;
963 struct dcerpc_binding_handle *binding_handle;
964 uint8_t num_nt_hashes;
965 uint8_t idx_nt_hashes;
966 const struct samr_Password * const *nt_hashes;
967 const struct samr_Password *used_nt_hash;
968 char *srv_name_slash;
969 uint32_t current_flags;
970 struct netr_Credential client_challenge;
971 struct netr_Credential server_challenge;
972 struct netlogon_creds_CredentialState *creds;
973 struct netr_Credential client_credential;
974 struct netr_Credential server_credential;
979 struct netlogon_creds_cli_locked_state *locked_state;
982 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
983 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
985 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
986 struct tevent_context *ev,
987 struct netlogon_creds_cli_context *context,
988 struct dcerpc_binding_handle *b,
989 uint8_t num_nt_hashes,
990 const struct samr_Password * const *nt_hashes)
992 struct tevent_req *req;
993 struct netlogon_creds_cli_auth_state *state;
994 struct netlogon_creds_cli_locked_state *locked_state;
997 req = tevent_req_create(mem_ctx, &state,
998 struct netlogon_creds_cli_auth_state);
1004 state->context = context;
1005 state->binding_handle = b;
1006 if (num_nt_hashes < 1) {
1007 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1008 return tevent_req_post(req, ev);
1010 if (num_nt_hashes > 4) {
1011 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1012 return tevent_req_post(req, ev);
1015 state->num_nt_hashes = num_nt_hashes;
1016 state->idx_nt_hashes = 0;
1017 state->nt_hashes = nt_hashes;
1019 if (context->db.locked_state != NULL) {
1020 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
1021 return tevent_req_post(req, ev);
1024 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
1025 if (tevent_req_nomem(locked_state, req)) {
1026 return tevent_req_post(req, ev);
1028 talloc_set_destructor(locked_state,
1029 netlogon_creds_cli_locked_state_destructor);
1030 locked_state->context = context;
1032 context->db.locked_state = locked_state;
1033 state->locked_state = locked_state;
1035 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1036 context->server.computer);
1037 if (tevent_req_nomem(state->srv_name_slash, req)) {
1038 return tevent_req_post(req, ev);
1041 state->try_auth3 = true;
1042 state->try_auth2 = true;
1044 if (context->client.required_flags != 0) {
1045 state->require_auth2 = true;
1048 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1049 state->current_flags = context->client.proposed_flags;
1051 if (context->db.g_ctx != NULL) {
1052 struct tevent_req *subreq;
1054 subreq = g_lock_lock_send(state, ev,
1056 context->db.key_name,
1058 if (tevent_req_nomem(subreq, req)) {
1059 return tevent_req_post(req, ev);
1061 tevent_req_set_callback(subreq,
1062 netlogon_creds_cli_auth_locked,
1068 status = dbwrap_purge(state->context->db.ctx,
1069 state->context->db.key_data);
1070 if (tevent_req_nterror(req, status)) {
1071 return tevent_req_post(req, ev);
1074 netlogon_creds_cli_auth_challenge_start(req);
1075 if (!tevent_req_is_in_progress(req)) {
1076 return tevent_req_post(req, ev);
1082 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1084 struct tevent_req *req =
1085 tevent_req_callback_data(subreq,
1087 struct netlogon_creds_cli_auth_state *state =
1088 tevent_req_data(req,
1089 struct netlogon_creds_cli_auth_state);
1092 status = g_lock_lock_recv(subreq);
1093 TALLOC_FREE(subreq);
1094 if (tevent_req_nterror(req, status)) {
1097 state->locked_state->is_glocked = true;
1099 status = dbwrap_purge(state->context->db.ctx,
1100 state->context->db.key_data);
1101 if (tevent_req_nterror(req, status)) {
1105 netlogon_creds_cli_auth_challenge_start(req);
1108 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1110 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1112 struct netlogon_creds_cli_auth_state *state =
1113 tevent_req_data(req,
1114 struct netlogon_creds_cli_auth_state);
1115 struct tevent_req *subreq;
1117 TALLOC_FREE(state->creds);
1119 generate_random_buffer(state->client_challenge.data,
1120 sizeof(state->client_challenge.data));
1122 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1123 state->binding_handle,
1124 state->srv_name_slash,
1125 state->context->client.computer,
1126 &state->client_challenge,
1127 &state->server_challenge);
1128 if (tevent_req_nomem(subreq, req)) {
1131 tevent_req_set_callback(subreq,
1132 netlogon_creds_cli_auth_challenge_done,
1136 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1138 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1140 struct tevent_req *req =
1141 tevent_req_callback_data(subreq,
1143 struct netlogon_creds_cli_auth_state *state =
1144 tevent_req_data(req,
1145 struct netlogon_creds_cli_auth_state);
1149 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1150 TALLOC_FREE(subreq);
1151 if (tevent_req_nterror(req, status)) {
1154 if (tevent_req_nterror(req, result)) {
1158 if (!state->try_auth3 && !state->try_auth2) {
1159 state->current_flags = 0;
1162 /* Calculate the session key and client credentials */
1164 state->creds = netlogon_creds_client_init(state,
1165 state->context->client.account,
1166 state->context->client.computer,
1167 state->context->client.type,
1168 &state->client_challenge,
1169 &state->server_challenge,
1170 state->used_nt_hash,
1171 &state->client_credential,
1172 state->current_flags);
1173 if (tevent_req_nomem(state->creds, req)) {
1177 if (state->try_auth3) {
1178 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1179 state->binding_handle,
1180 state->srv_name_slash,
1181 state->context->client.account,
1182 state->context->client.type,
1183 state->context->client.computer,
1184 &state->client_credential,
1185 &state->server_credential,
1186 &state->creds->negotiate_flags,
1188 if (tevent_req_nomem(subreq, req)) {
1191 } else if (state->try_auth2) {
1194 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1195 state->binding_handle,
1196 state->srv_name_slash,
1197 state->context->client.account,
1198 state->context->client.type,
1199 state->context->client.computer,
1200 &state->client_credential,
1201 &state->server_credential,
1202 &state->creds->negotiate_flags);
1203 if (tevent_req_nomem(subreq, req)) {
1209 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1210 state->binding_handle,
1211 state->srv_name_slash,
1212 state->context->client.account,
1213 state->context->client.type,
1214 state->context->client.computer,
1215 &state->client_credential,
1216 &state->server_credential);
1217 if (tevent_req_nomem(subreq, req)) {
1221 tevent_req_set_callback(subreq,
1222 netlogon_creds_cli_auth_srvauth_done,
1226 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1228 struct tevent_req *req =
1229 tevent_req_callback_data(subreq,
1231 struct netlogon_creds_cli_auth_state *state =
1232 tevent_req_data(req,
1233 struct netlogon_creds_cli_auth_state);
1237 enum ndr_err_code ndr_err;
1242 if (state->try_auth3) {
1243 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1245 TALLOC_FREE(subreq);
1246 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1247 state->try_auth3 = false;
1248 netlogon_creds_cli_auth_challenge_start(req);
1251 if (tevent_req_nterror(req, status)) {
1254 } else if (state->try_auth2) {
1255 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1257 TALLOC_FREE(subreq);
1258 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1259 state->try_auth2 = false;
1260 if (state->require_auth2) {
1261 status = NT_STATUS_DOWNGRADE_DETECTED;
1262 tevent_req_nterror(req, status);
1265 netlogon_creds_cli_auth_challenge_start(req);
1268 if (tevent_req_nterror(req, status)) {
1272 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1274 TALLOC_FREE(subreq);
1275 if (tevent_req_nterror(req, status)) {
1280 if (!NT_STATUS_IS_OK(result) &&
1281 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1283 tevent_req_nterror(req, result);
1287 tmp_flags = state->creds->negotiate_flags;
1288 tmp_flags &= state->context->client.required_flags;
1289 if (tmp_flags != state->context->client.required_flags) {
1290 if (NT_STATUS_IS_OK(result)) {
1291 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1294 tevent_req_nterror(req, result);
1298 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1300 tmp_flags = state->context->client.proposed_flags;
1301 if ((state->current_flags == tmp_flags) &&
1302 (state->creds->negotiate_flags != tmp_flags))
1305 * lets retry with the negotiated flags
1307 state->current_flags = state->creds->negotiate_flags;
1308 netlogon_creds_cli_auth_challenge_start(req);
1312 state->idx_nt_hashes += 1;
1313 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1315 * we already retried, giving up...
1317 tevent_req_nterror(req, result);
1322 * lets retry with the old nt hash.
1324 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1325 state->current_flags = state->context->client.proposed_flags;
1326 netlogon_creds_cli_auth_challenge_start(req);
1330 ok = netlogon_creds_client_check(state->creds,
1331 &state->server_credential);
1333 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1337 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1338 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1339 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1340 status = ndr_map_error2ntstatus(ndr_err);
1341 tevent_req_nterror(req, status);
1345 data.dptr = blob.data;
1346 data.dsize = blob.length;
1348 status = dbwrap_store(state->context->db.ctx,
1349 state->context->db.key_data,
1351 TALLOC_FREE(state->locked_state);
1352 if (tevent_req_nterror(req, status)) {
1356 tevent_req_done(req);
1359 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1360 uint8_t *idx_nt_hashes)
1362 struct netlogon_creds_cli_auth_state *state =
1363 tevent_req_data(req,
1364 struct netlogon_creds_cli_auth_state);
1369 if (tevent_req_is_nterror(req, &status)) {
1370 tevent_req_received(req);
1374 *idx_nt_hashes = state->idx_nt_hashes;
1375 tevent_req_received(req);
1376 return NT_STATUS_OK;
1379 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1380 struct dcerpc_binding_handle *b,
1381 uint8_t num_nt_hashes,
1382 const struct samr_Password * const *nt_hashes,
1383 uint8_t *idx_nt_hashes)
1385 TALLOC_CTX *frame = talloc_stackframe();
1386 struct tevent_context *ev;
1387 struct tevent_req *req;
1388 NTSTATUS status = NT_STATUS_NO_MEMORY;
1392 ev = samba_tevent_context_init(frame);
1396 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1397 num_nt_hashes, nt_hashes);
1401 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1404 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1410 struct netlogon_creds_cli_check_state {
1411 struct tevent_context *ev;
1412 struct netlogon_creds_cli_context *context;
1413 struct dcerpc_binding_handle *binding_handle;
1415 char *srv_name_slash;
1417 union netr_Capabilities caps;
1419 struct netlogon_creds_CredentialState *creds;
1420 struct netlogon_creds_CredentialState tmp_creds;
1421 struct netr_Authenticator req_auth;
1422 struct netr_Authenticator rep_auth;
1425 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1427 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1429 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1430 struct tevent_context *ev,
1431 struct netlogon_creds_cli_context *context,
1432 struct dcerpc_binding_handle *b)
1434 struct tevent_req *req;
1435 struct netlogon_creds_cli_check_state *state;
1436 struct tevent_req *subreq;
1437 enum dcerpc_AuthType auth_type;
1438 enum dcerpc_AuthLevel auth_level;
1440 req = tevent_req_create(mem_ctx, &state,
1441 struct netlogon_creds_cli_check_state);
1447 state->context = context;
1448 state->binding_handle = b;
1450 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1451 context->server.computer);
1452 if (tevent_req_nomem(state->srv_name_slash, req)) {
1453 return tevent_req_post(req, ev);
1456 dcerpc_binding_handle_auth_info(state->binding_handle,
1457 &auth_type, &auth_level);
1459 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1460 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1461 return tevent_req_post(req, ev);
1464 switch (auth_level) {
1465 case DCERPC_AUTH_LEVEL_INTEGRITY:
1466 case DCERPC_AUTH_LEVEL_PRIVACY:
1469 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1470 return tevent_req_post(req, ev);
1473 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1475 if (tevent_req_nomem(subreq, req)) {
1476 return tevent_req_post(req, ev);
1479 tevent_req_set_callback(subreq,
1480 netlogon_creds_cli_check_locked,
1486 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1489 struct netlogon_creds_cli_check_state *state =
1490 tevent_req_data(req,
1491 struct netlogon_creds_cli_check_state);
1493 if (state->creds == NULL) {
1497 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1498 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1499 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1500 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1501 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1502 TALLOC_FREE(state->creds);
1506 netlogon_creds_cli_delete(state->context, &state->creds);
1509 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1511 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1513 struct tevent_req *req =
1514 tevent_req_callback_data(subreq,
1516 struct netlogon_creds_cli_check_state *state =
1517 tevent_req_data(req,
1518 struct netlogon_creds_cli_check_state);
1521 status = netlogon_creds_cli_lock_recv(subreq, state,
1523 TALLOC_FREE(subreq);
1524 if (tevent_req_nterror(req, status)) {
1529 * we defer all callbacks in order to cleanup
1530 * the database record.
1532 tevent_req_defer_callback(req, state->ev);
1534 state->tmp_creds = *state->creds;
1535 netlogon_creds_client_authenticator(&state->tmp_creds,
1537 ZERO_STRUCT(state->rep_auth);
1539 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1540 state->binding_handle,
1541 state->srv_name_slash,
1542 state->context->client.computer,
1547 if (tevent_req_nomem(subreq, req)) {
1548 status = NT_STATUS_NO_MEMORY;
1549 netlogon_creds_cli_check_cleanup(req, status);
1552 tevent_req_set_callback(subreq,
1553 netlogon_creds_cli_check_caps,
1557 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1559 struct tevent_req *req =
1560 tevent_req_callback_data(subreq,
1562 struct netlogon_creds_cli_check_state *state =
1563 tevent_req_data(req,
1564 struct netlogon_creds_cli_check_state);
1569 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1571 TALLOC_FREE(subreq);
1572 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1574 * Note that the negotiated flags are already checked
1575 * for our required flags after the ServerAuthenticate3/2 call.
1577 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1579 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1581 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1582 * already, we expect this to work!
1584 status = NT_STATUS_DOWNGRADE_DETECTED;
1585 tevent_req_nterror(req, status);
1586 netlogon_creds_cli_check_cleanup(req, status);
1590 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1592 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1593 * we expect this to work at least as far as the
1594 * NOT_SUPPORTED error handled below!
1596 * NT 4.0 and Old Samba servers are not
1597 * allowed without "require strong key = no"
1599 status = NT_STATUS_DOWNGRADE_DETECTED;
1600 tevent_req_nterror(req, status);
1601 netlogon_creds_cli_check_cleanup(req, status);
1606 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1607 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1608 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1610 * This is needed against NT 4.0 and old Samba servers.
1612 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1613 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1614 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1615 * with the next request as the sequence number processing
1618 netlogon_creds_cli_check_cleanup(req, status);
1619 tevent_req_done(req);
1622 if (tevent_req_nterror(req, status)) {
1623 netlogon_creds_cli_check_cleanup(req, status);
1627 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1629 * Note that the negotiated flags are already checked
1630 * for our required flags after the ServerAuthenticate3/2 call.
1632 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1634 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1636 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1637 * already, we expect this to work!
1639 status = NT_STATUS_DOWNGRADE_DETECTED;
1640 tevent_req_nterror(req, status);
1641 netlogon_creds_cli_check_cleanup(req, status);
1646 * This is ok, the server does not support
1647 * NETLOGON_NEG_SUPPORTS_AES.
1649 * netr_LogonGetCapabilities() was
1650 * netr_LogonDummyRoutine1() before
1651 * NETLOGON_NEG_SUPPORTS_AES was invented.
1653 netlogon_creds_cli_check_cleanup(req, result);
1654 tevent_req_done(req);
1658 ok = netlogon_creds_client_check(&state->tmp_creds,
1659 &state->rep_auth.cred);
1661 status = NT_STATUS_ACCESS_DENIED;
1662 tevent_req_nterror(req, status);
1663 netlogon_creds_cli_check_cleanup(req, status);
1667 if (tevent_req_nterror(req, result)) {
1668 netlogon_creds_cli_check_cleanup(req, result);
1672 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1673 status = NT_STATUS_DOWNGRADE_DETECTED;
1674 tevent_req_nterror(req, status);
1675 netlogon_creds_cli_check_cleanup(req, status);
1680 * This is the key check that makes this check secure. If we
1681 * get OK here (rather than NOT_SUPPORTED), then the server
1682 * did support AES. If the server only proposed STRONG_KEYS
1683 * and not AES, then it should have failed with
1684 * NOT_IMPLEMENTED. We always send AES as a client, so the
1685 * server should always have returned it.
1687 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1688 status = NT_STATUS_DOWNGRADE_DETECTED;
1689 tevent_req_nterror(req, status);
1690 netlogon_creds_cli_check_cleanup(req, status);
1694 *state->creds = state->tmp_creds;
1695 status = netlogon_creds_cli_store(state->context,
1697 netlogon_creds_cli_check_cleanup(req, status);
1698 if (tevent_req_nterror(req, status)) {
1702 tevent_req_done(req);
1705 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1709 if (tevent_req_is_nterror(req, &status)) {
1710 netlogon_creds_cli_check_cleanup(req, status);
1711 tevent_req_received(req);
1715 tevent_req_received(req);
1716 return NT_STATUS_OK;
1719 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1720 struct dcerpc_binding_handle *b)
1722 TALLOC_CTX *frame = talloc_stackframe();
1723 struct tevent_context *ev;
1724 struct tevent_req *req;
1725 NTSTATUS status = NT_STATUS_NO_MEMORY;
1727 ev = samba_tevent_context_init(frame);
1731 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1735 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1738 status = netlogon_creds_cli_check_recv(req);
1744 struct netlogon_creds_cli_ServerPasswordSet_state {
1745 struct tevent_context *ev;
1746 struct netlogon_creds_cli_context *context;
1747 struct dcerpc_binding_handle *binding_handle;
1748 uint32_t old_timeout;
1750 char *srv_name_slash;
1751 enum dcerpc_AuthType auth_type;
1752 enum dcerpc_AuthLevel auth_level;
1754 struct samr_CryptPassword samr_crypt_password;
1755 struct netr_CryptPassword netr_crypt_password;
1756 struct samr_Password samr_password;
1758 struct netlogon_creds_CredentialState *creds;
1759 struct netlogon_creds_CredentialState tmp_creds;
1760 struct netr_Authenticator req_auth;
1761 struct netr_Authenticator rep_auth;
1764 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1766 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1768 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1769 struct tevent_context *ev,
1770 struct netlogon_creds_cli_context *context,
1771 struct dcerpc_binding_handle *b,
1772 const DATA_BLOB *new_password,
1773 const uint32_t *new_version)
1775 struct tevent_req *req;
1776 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1777 struct tevent_req *subreq;
1780 req = tevent_req_create(mem_ctx, &state,
1781 struct netlogon_creds_cli_ServerPasswordSet_state);
1787 state->context = context;
1788 state->binding_handle = b;
1790 if (new_password->length < 14) {
1791 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1792 return tevent_req_post(req, ev);
1796 * netr_ServerPasswordSet
1798 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1801 * netr_ServerPasswordSet2
1803 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1806 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1807 return tevent_req_post(req, ev);
1810 if (new_version != NULL) {
1811 struct NL_PASSWORD_VERSION version;
1812 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1813 uint32_t ofs = 512 - len;
1817 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1818 return tevent_req_post(req, ev);
1822 version.ReservedField = 0;
1823 version.PasswordVersionNumber = *new_version;
1824 version.PasswordVersionPresent =
1825 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1827 p = state->samr_crypt_password.data + ofs;
1828 SIVAL(p, 0, version.ReservedField);
1829 SIVAL(p, 4, version.PasswordVersionNumber);
1830 SIVAL(p, 8, version.PasswordVersionPresent);
1833 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1834 context->server.computer);
1835 if (tevent_req_nomem(state->srv_name_slash, req)) {
1836 return tevent_req_post(req, ev);
1839 dcerpc_binding_handle_auth_info(state->binding_handle,
1841 &state->auth_level);
1843 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1845 if (tevent_req_nomem(subreq, req)) {
1846 return tevent_req_post(req, ev);
1849 tevent_req_set_callback(subreq,
1850 netlogon_creds_cli_ServerPasswordSet_locked,
1856 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1859 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1860 tevent_req_data(req,
1861 struct netlogon_creds_cli_ServerPasswordSet_state);
1863 if (state->creds == NULL) {
1867 dcerpc_binding_handle_set_timeout(state->binding_handle,
1868 state->old_timeout);
1870 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1871 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1872 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1873 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1874 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1875 TALLOC_FREE(state->creds);
1879 netlogon_creds_cli_delete(state->context, &state->creds);
1882 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1884 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1886 struct tevent_req *req =
1887 tevent_req_callback_data(subreq,
1889 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1890 tevent_req_data(req,
1891 struct netlogon_creds_cli_ServerPasswordSet_state);
1894 status = netlogon_creds_cli_lock_recv(subreq, state,
1896 TALLOC_FREE(subreq);
1897 if (tevent_req_nterror(req, status)) {
1901 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1902 switch (state->auth_level) {
1903 case DCERPC_AUTH_LEVEL_INTEGRITY:
1904 case DCERPC_AUTH_LEVEL_PRIVACY:
1907 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1911 uint32_t tmp = state->creds->negotiate_flags;
1913 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1915 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1916 * it should be used, which means
1917 * we had a chance to verify no downgrade
1920 * This relies on netlogon_creds_cli_check*
1921 * being called before, as first request after
1924 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1929 state->old_timeout = dcerpc_binding_handle_set_timeout(
1930 state->binding_handle, 600000);
1933 * we defer all callbacks in order to cleanup
1934 * the database record.
1936 tevent_req_defer_callback(req, state->ev);
1938 state->tmp_creds = *state->creds;
1939 netlogon_creds_client_authenticator(&state->tmp_creds,
1941 ZERO_STRUCT(state->rep_auth);
1943 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1945 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1946 netlogon_creds_aes_encrypt(&state->tmp_creds,
1947 state->samr_crypt_password.data,
1950 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1951 state->samr_crypt_password.data,
1955 memcpy(state->netr_crypt_password.data,
1956 state->samr_crypt_password.data, 512);
1957 state->netr_crypt_password.length =
1958 IVAL(state->samr_crypt_password.data, 512);
1960 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1961 state->binding_handle,
1962 state->srv_name_slash,
1963 state->tmp_creds.account_name,
1964 state->tmp_creds.secure_channel_type,
1965 state->tmp_creds.computer_name,
1968 &state->netr_crypt_password);
1969 if (tevent_req_nomem(subreq, req)) {
1970 status = NT_STATUS_NO_MEMORY;
1971 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1975 netlogon_creds_des_encrypt(&state->tmp_creds,
1976 &state->samr_password);
1978 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1979 state->binding_handle,
1980 state->srv_name_slash,
1981 state->tmp_creds.account_name,
1982 state->tmp_creds.secure_channel_type,
1983 state->tmp_creds.computer_name,
1986 &state->samr_password);
1987 if (tevent_req_nomem(subreq, req)) {
1988 status = NT_STATUS_NO_MEMORY;
1989 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1994 tevent_req_set_callback(subreq,
1995 netlogon_creds_cli_ServerPasswordSet_done,
1999 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2001 struct tevent_req *req =
2002 tevent_req_callback_data(subreq,
2004 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2005 tevent_req_data(req,
2006 struct netlogon_creds_cli_ServerPasswordSet_state);
2011 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2012 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2014 TALLOC_FREE(subreq);
2015 if (tevent_req_nterror(req, status)) {
2016 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2020 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2022 TALLOC_FREE(subreq);
2023 if (tevent_req_nterror(req, status)) {
2024 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2029 ok = netlogon_creds_client_check(&state->tmp_creds,
2030 &state->rep_auth.cred);
2032 status = NT_STATUS_ACCESS_DENIED;
2033 tevent_req_nterror(req, status);
2034 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2038 if (tevent_req_nterror(req, result)) {
2039 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2043 dcerpc_binding_handle_set_timeout(state->binding_handle,
2044 state->old_timeout);
2046 *state->creds = state->tmp_creds;
2047 status = netlogon_creds_cli_store(state->context,
2049 if (tevent_req_nterror(req, status)) {
2050 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2054 tevent_req_done(req);
2057 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2061 if (tevent_req_is_nterror(req, &status)) {
2062 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2063 tevent_req_received(req);
2067 tevent_req_received(req);
2068 return NT_STATUS_OK;
2071 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2072 struct netlogon_creds_cli_context *context,
2073 struct dcerpc_binding_handle *b,
2074 const DATA_BLOB *new_password,
2075 const uint32_t *new_version)
2077 TALLOC_CTX *frame = talloc_stackframe();
2078 struct tevent_context *ev;
2079 struct tevent_req *req;
2080 NTSTATUS status = NT_STATUS_NO_MEMORY;
2082 ev = samba_tevent_context_init(frame);
2086 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2092 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2095 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2101 struct netlogon_creds_cli_LogonSamLogon_state {
2102 struct tevent_context *ev;
2103 struct netlogon_creds_cli_context *context;
2104 struct dcerpc_binding_handle *binding_handle;
2106 char *srv_name_slash;
2108 enum netr_LogonInfoClass logon_level;
2109 const union netr_LogonLevel *const_logon;
2110 union netr_LogonLevel *logon;
2113 uint16_t validation_level;
2114 union netr_Validation *validation;
2115 uint8_t authoritative;
2118 * do we need encryption at the application layer?
2122 bool try_validation6;
2125 * the read only credentials before we started the operation
2126 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2128 struct netlogon_creds_CredentialState *ro_creds;
2131 * The (locked) credentials used for the credential chain
2132 * used for netr_LogonSamLogonWithFlags() or
2133 * netr_LogonSamLogonWith().
2135 struct netlogon_creds_CredentialState *lk_creds;
2138 * While we have locked the global credentials (lk_creds above)
2139 * we operate an a temporary copy, because a server
2140 * may not support netr_LogonSamLogonWithFlags() and
2141 * didn't process our netr_Authenticator, so we need to
2142 * restart from lk_creds.
2144 struct netlogon_creds_CredentialState tmp_creds;
2145 struct netr_Authenticator req_auth;
2146 struct netr_Authenticator rep_auth;
2149 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2150 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2153 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2154 struct tevent_context *ev,
2155 struct netlogon_creds_cli_context *context,
2156 struct dcerpc_binding_handle *b,
2157 enum netr_LogonInfoClass logon_level,
2158 const union netr_LogonLevel *logon,
2161 struct tevent_req *req;
2162 struct netlogon_creds_cli_LogonSamLogon_state *state;
2164 req = tevent_req_create(mem_ctx, &state,
2165 struct netlogon_creds_cli_LogonSamLogon_state);
2171 state->context = context;
2172 state->binding_handle = b;
2174 state->logon_level = logon_level;
2175 state->const_logon = logon;
2176 state->flags = flags;
2178 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2179 context->server.computer);
2180 if (tevent_req_nomem(state->srv_name_slash, req)) {
2181 return tevent_req_post(req, ev);
2184 switch (logon_level) {
2185 case NetlogonInteractiveInformation:
2186 case NetlogonInteractiveTransitiveInformation:
2187 case NetlogonServiceInformation:
2188 case NetlogonServiceTransitiveInformation:
2189 case NetlogonGenericInformation:
2190 state->user_encrypt = true;
2193 case NetlogonNetworkInformation:
2194 case NetlogonNetworkTransitiveInformation:
2198 state->validation = talloc_zero(state, union netr_Validation);
2199 if (tevent_req_nomem(state->validation, req)) {
2200 return tevent_req_post(req, ev);
2203 netlogon_creds_cli_LogonSamLogon_start(req);
2204 if (!tevent_req_is_in_progress(req)) {
2205 return tevent_req_post(req, ev);
2209 * we defer all callbacks in order to cleanup
2210 * the database record.
2212 tevent_req_defer_callback(req, state->ev);
2216 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2219 struct netlogon_creds_cli_LogonSamLogon_state *state =
2220 tevent_req_data(req,
2221 struct netlogon_creds_cli_LogonSamLogon_state);
2223 if (state->lk_creds == NULL) {
2227 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2229 * This is a hack to recover from a bug in old
2230 * Samba servers, when LogonSamLogonEx() fails:
2232 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2234 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2236 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2237 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2238 * If the sign/seal check fails.
2240 * In that case we need to cleanup the netlogon session.
2242 * It's the job of the caller to disconnect the current
2243 * connection, if netlogon_creds_cli_LogonSamLogon()
2244 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2246 if (!state->context->server.try_logon_with) {
2247 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2251 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2252 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2253 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2254 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2255 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2256 TALLOC_FREE(state->lk_creds);
2260 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2263 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2265 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2267 struct netlogon_creds_cli_LogonSamLogon_state *state =
2268 tevent_req_data(req,
2269 struct netlogon_creds_cli_LogonSamLogon_state);
2270 struct tevent_req *subreq;
2272 enum dcerpc_AuthType auth_type;
2273 enum dcerpc_AuthLevel auth_level;
2275 TALLOC_FREE(state->ro_creds);
2276 TALLOC_FREE(state->logon);
2277 ZERO_STRUCTP(state->validation);
2279 dcerpc_binding_handle_auth_info(state->binding_handle,
2280 &auth_type, &auth_level);
2282 state->try_logon_ex = state->context->server.try_logon_ex;
2283 state->try_validation6 = state->context->server.try_validation6;
2285 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2286 state->try_logon_ex = false;
2289 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2290 state->try_validation6 = false;
2293 if (state->try_logon_ex) {
2294 if (state->try_validation6) {
2295 state->validation_level = 6;
2297 state->validation_level = 3;
2298 state->user_encrypt = true;
2301 state->logon = netlogon_creds_shallow_copy_logon(state,
2303 state->const_logon);
2304 if (tevent_req_nomem(state->logon, req)) {
2305 status = NT_STATUS_NO_MEMORY;
2306 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2310 if (state->user_encrypt) {
2311 status = netlogon_creds_cli_get(state->context,
2314 if (!NT_STATUS_IS_OK(status)) {
2315 status = NT_STATUS_ACCESS_DENIED;
2316 tevent_req_nterror(req, status);
2317 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2321 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2326 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2327 state->binding_handle,
2328 state->srv_name_slash,
2329 state->context->client.computer,
2332 state->validation_level,
2334 &state->authoritative,
2336 if (tevent_req_nomem(subreq, req)) {
2337 status = NT_STATUS_NO_MEMORY;
2338 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2341 tevent_req_set_callback(subreq,
2342 netlogon_creds_cli_LogonSamLogon_done,
2347 if (state->lk_creds == NULL) {
2348 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2350 if (tevent_req_nomem(subreq, req)) {
2351 status = NT_STATUS_NO_MEMORY;
2352 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2355 tevent_req_set_callback(subreq,
2356 netlogon_creds_cli_LogonSamLogon_done,
2361 state->tmp_creds = *state->lk_creds;
2362 netlogon_creds_client_authenticator(&state->tmp_creds,
2364 ZERO_STRUCT(state->rep_auth);
2366 state->logon = netlogon_creds_shallow_copy_logon(state,
2368 state->const_logon);
2369 if (tevent_req_nomem(state->logon, req)) {
2370 status = NT_STATUS_NO_MEMORY;
2371 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2375 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2379 state->validation_level = 3;
2381 if (state->context->server.try_logon_with) {
2382 subreq = dcerpc_netr_LogonSamLogonWithFlags_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,
2394 if (tevent_req_nomem(subreq, req)) {
2395 status = NT_STATUS_NO_MEMORY;
2396 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2402 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2403 state->binding_handle,
2404 state->srv_name_slash,
2405 state->context->client.computer,
2410 state->validation_level,
2412 &state->authoritative);
2413 if (tevent_req_nomem(subreq, req)) {
2414 status = NT_STATUS_NO_MEMORY;
2415 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2420 tevent_req_set_callback(subreq,
2421 netlogon_creds_cli_LogonSamLogon_done,
2425 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2427 struct tevent_req *req =
2428 tevent_req_callback_data(subreq,
2430 struct netlogon_creds_cli_LogonSamLogon_state *state =
2431 tevent_req_data(req,
2432 struct netlogon_creds_cli_LogonSamLogon_state);
2437 if (state->try_logon_ex) {
2438 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2441 TALLOC_FREE(subreq);
2442 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2443 state->context->server.try_validation6 = false;
2444 state->context->server.try_logon_ex = false;
2445 netlogon_creds_cli_LogonSamLogon_start(req);
2448 if (tevent_req_nterror(req, status)) {
2449 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2453 if ((state->validation_level == 6) &&
2454 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2455 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2456 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2458 state->context->server.try_validation6 = false;
2459 netlogon_creds_cli_LogonSamLogon_start(req);
2463 if (tevent_req_nterror(req, result)) {
2464 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2468 if (state->ro_creds == NULL) {
2469 tevent_req_done(req);
2473 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2476 * We got a race, lets retry with on authenticator
2479 * netlogon_creds_cli_LogonSamLogon_start()
2480 * will TALLOC_FREE(state->ro_creds);
2482 state->try_logon_ex = false;
2483 netlogon_creds_cli_LogonSamLogon_start(req);
2487 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2488 state->validation_level,
2491 tevent_req_done(req);
2495 if (state->lk_creds == NULL) {
2496 status = netlogon_creds_cli_lock_recv(subreq, state,
2498 TALLOC_FREE(subreq);
2499 if (tevent_req_nterror(req, status)) {
2500 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2504 netlogon_creds_cli_LogonSamLogon_start(req);
2508 if (state->context->server.try_logon_with) {
2509 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2512 TALLOC_FREE(subreq);
2513 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2514 state->context->server.try_logon_with = false;
2515 netlogon_creds_cli_LogonSamLogon_start(req);
2518 if (tevent_req_nterror(req, status)) {
2519 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2523 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2526 TALLOC_FREE(subreq);
2527 if (tevent_req_nterror(req, status)) {
2528 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2533 ok = netlogon_creds_client_check(&state->tmp_creds,
2534 &state->rep_auth.cred);
2536 status = NT_STATUS_ACCESS_DENIED;
2537 tevent_req_nterror(req, status);
2538 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2542 *state->lk_creds = state->tmp_creds;
2543 status = netlogon_creds_cli_store(state->context,
2545 if (tevent_req_nterror(req, status)) {
2546 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2550 if (tevent_req_nterror(req, result)) {
2551 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2555 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2556 state->validation_level,
2559 tevent_req_done(req);
2562 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2563 TALLOC_CTX *mem_ctx,
2564 uint16_t *validation_level,
2565 union netr_Validation **validation,
2566 uint8_t *authoritative,
2569 struct netlogon_creds_cli_LogonSamLogon_state *state =
2570 tevent_req_data(req,
2571 struct netlogon_creds_cli_LogonSamLogon_state);
2574 /* authoritative is also returned on error */
2575 *authoritative = state->authoritative;
2577 if (tevent_req_is_nterror(req, &status)) {
2578 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2579 tevent_req_received(req);
2583 *validation_level = state->validation_level;
2584 *validation = talloc_move(mem_ctx, &state->validation);
2585 *flags = state->flags;
2587 tevent_req_received(req);
2588 return NT_STATUS_OK;
2591 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2592 struct netlogon_creds_cli_context *context,
2593 struct dcerpc_binding_handle *b,
2594 enum netr_LogonInfoClass logon_level,
2595 const union netr_LogonLevel *logon,
2596 TALLOC_CTX *mem_ctx,
2597 uint16_t *validation_level,
2598 union netr_Validation **validation,
2599 uint8_t *authoritative,
2602 TALLOC_CTX *frame = talloc_stackframe();
2603 struct tevent_context *ev;
2604 struct tevent_req *req;
2605 NTSTATUS status = NT_STATUS_NO_MEMORY;
2607 ev = samba_tevent_context_init(frame);
2611 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2617 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2620 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2630 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2631 struct tevent_context *ev;
2632 struct netlogon_creds_cli_context *context;
2633 struct dcerpc_binding_handle *binding_handle;
2635 char *srv_name_slash;
2636 enum dcerpc_AuthType auth_type;
2637 enum dcerpc_AuthLevel auth_level;
2639 const char *site_name;
2641 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2643 struct netlogon_creds_CredentialState *creds;
2644 struct netlogon_creds_CredentialState tmp_creds;
2645 struct netr_Authenticator req_auth;
2646 struct netr_Authenticator rep_auth;
2649 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2651 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2653 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2654 struct tevent_context *ev,
2655 struct netlogon_creds_cli_context *context,
2656 struct dcerpc_binding_handle *b,
2657 const char *site_name,
2659 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2661 struct tevent_req *req;
2662 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2663 struct tevent_req *subreq;
2665 req = tevent_req_create(mem_ctx, &state,
2666 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2672 state->context = context;
2673 state->binding_handle = b;
2675 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2676 context->server.computer);
2677 if (tevent_req_nomem(state->srv_name_slash, req)) {
2678 return tevent_req_post(req, ev);
2681 state->site_name = site_name;
2682 state->dns_ttl = dns_ttl;
2683 state->dns_names = dns_names;
2685 dcerpc_binding_handle_auth_info(state->binding_handle,
2687 &state->auth_level);
2689 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2691 if (tevent_req_nomem(subreq, req)) {
2692 return tevent_req_post(req, ev);
2695 tevent_req_set_callback(subreq,
2696 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2702 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2705 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2706 tevent_req_data(req,
2707 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2709 if (state->creds == NULL) {
2713 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2714 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2715 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2716 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2717 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2718 TALLOC_FREE(state->creds);
2722 netlogon_creds_cli_delete(state->context, &state->creds);
2725 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2727 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2729 struct tevent_req *req =
2730 tevent_req_callback_data(subreq,
2732 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2733 tevent_req_data(req,
2734 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2737 status = netlogon_creds_cli_lock_recv(subreq, state,
2739 TALLOC_FREE(subreq);
2740 if (tevent_req_nterror(req, status)) {
2744 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2745 switch (state->auth_level) {
2746 case DCERPC_AUTH_LEVEL_INTEGRITY:
2747 case DCERPC_AUTH_LEVEL_PRIVACY:
2750 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2754 uint32_t tmp = state->creds->negotiate_flags;
2756 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2758 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2759 * it should be used, which means
2760 * we had a chance to verify no downgrade
2763 * This relies on netlogon_creds_cli_check*
2764 * being called before, as first request after
2767 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2773 * we defer all callbacks in order to cleanup
2774 * the database record.
2776 tevent_req_defer_callback(req, state->ev);
2778 state->tmp_creds = *state->creds;
2779 netlogon_creds_client_authenticator(&state->tmp_creds,
2781 ZERO_STRUCT(state->rep_auth);
2783 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2784 state->binding_handle,
2785 state->srv_name_slash,
2786 state->tmp_creds.computer_name,
2792 if (tevent_req_nomem(subreq, req)) {
2793 status = NT_STATUS_NO_MEMORY;
2794 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2798 tevent_req_set_callback(subreq,
2799 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2803 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2805 struct tevent_req *req =
2806 tevent_req_callback_data(subreq,
2808 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2809 tevent_req_data(req,
2810 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2816 * We use state->dns_names as the memory context, as this is
2817 * the only in/out variable and it has been overwritten by the
2818 * out parameter from the server.
2820 * We need to preserve the return value until the caller can use it.
2822 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2824 TALLOC_FREE(subreq);
2825 if (tevent_req_nterror(req, status)) {
2826 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2830 ok = netlogon_creds_client_check(&state->tmp_creds,
2831 &state->rep_auth.cred);
2833 status = NT_STATUS_ACCESS_DENIED;
2834 tevent_req_nterror(req, status);
2835 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2839 *state->creds = state->tmp_creds;
2840 status = netlogon_creds_cli_store(state->context,
2843 if (tevent_req_nterror(req, status)) {
2844 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2848 if (tevent_req_nterror(req, result)) {
2849 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2853 tevent_req_done(req);
2856 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2860 if (tevent_req_is_nterror(req, &status)) {
2861 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2862 tevent_req_received(req);
2866 tevent_req_received(req);
2867 return NT_STATUS_OK;
2870 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2871 struct netlogon_creds_cli_context *context,
2872 struct dcerpc_binding_handle *b,
2873 const char *site_name,
2875 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2877 TALLOC_CTX *frame = talloc_stackframe();
2878 struct tevent_context *ev;
2879 struct tevent_req *req;
2880 NTSTATUS status = NT_STATUS_NO_MEMORY;
2882 ev = samba_tevent_context_init(frame);
2886 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2893 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2896 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2902 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2903 struct tevent_context *ev;
2904 struct netlogon_creds_cli_context *context;
2905 struct dcerpc_binding_handle *binding_handle;
2907 char *srv_name_slash;
2908 enum dcerpc_AuthType auth_type;
2909 enum dcerpc_AuthLevel auth_level;
2911 struct samr_Password new_owf_password;
2912 struct samr_Password old_owf_password;
2913 struct netr_TrustInfo *trust_info;
2915 struct netlogon_creds_CredentialState *creds;
2916 struct netlogon_creds_CredentialState tmp_creds;
2917 struct netr_Authenticator req_auth;
2918 struct netr_Authenticator rep_auth;
2921 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2923 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2925 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2926 struct tevent_context *ev,
2927 struct netlogon_creds_cli_context *context,
2928 struct dcerpc_binding_handle *b)
2930 struct tevent_req *req;
2931 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2932 struct tevent_req *subreq;
2934 req = tevent_req_create(mem_ctx, &state,
2935 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2941 state->context = context;
2942 state->binding_handle = b;
2944 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2945 context->server.computer);
2946 if (tevent_req_nomem(state->srv_name_slash, req)) {
2947 return tevent_req_post(req, ev);
2950 dcerpc_binding_handle_auth_info(state->binding_handle,
2952 &state->auth_level);
2954 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2956 if (tevent_req_nomem(subreq, req)) {
2957 return tevent_req_post(req, ev);
2960 tevent_req_set_callback(subreq,
2961 netlogon_creds_cli_ServerGetTrustInfo_locked,
2967 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2970 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2971 tevent_req_data(req,
2972 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2974 if (state->creds == NULL) {
2978 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2979 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2980 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2981 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2982 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2983 TALLOC_FREE(state->creds);
2987 netlogon_creds_cli_delete(state->context, &state->creds);
2990 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2992 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2994 struct tevent_req *req =
2995 tevent_req_callback_data(subreq,
2997 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2998 tevent_req_data(req,
2999 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3002 status = netlogon_creds_cli_lock_recv(subreq, state,
3004 TALLOC_FREE(subreq);
3005 if (tevent_req_nterror(req, status)) {
3009 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3010 switch (state->auth_level) {
3011 case DCERPC_AUTH_LEVEL_PRIVACY:
3014 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3018 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3023 * we defer all callbacks in order to cleanup
3024 * the database record.
3026 tevent_req_defer_callback(req, state->ev);
3028 state->tmp_creds = *state->creds;
3029 netlogon_creds_client_authenticator(&state->tmp_creds,
3031 ZERO_STRUCT(state->rep_auth);
3033 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3034 state->binding_handle,
3035 state->srv_name_slash,
3036 state->tmp_creds.account_name,
3037 state->tmp_creds.secure_channel_type,
3038 state->tmp_creds.computer_name,
3041 &state->new_owf_password,
3042 &state->old_owf_password,
3043 &state->trust_info);
3044 if (tevent_req_nomem(subreq, req)) {
3045 status = NT_STATUS_NO_MEMORY;
3046 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3050 tevent_req_set_callback(subreq,
3051 netlogon_creds_cli_ServerGetTrustInfo_done,
3055 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3057 struct tevent_req *req =
3058 tevent_req_callback_data(subreq,
3060 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3061 tevent_req_data(req,
3062 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3065 const struct samr_Password zero = {};
3070 * We use state->dns_names as the memory context, as this is
3071 * the only in/out variable and it has been overwritten by the
3072 * out parameter from the server.
3074 * We need to preserve the return value until the caller can use it.
3076 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3077 TALLOC_FREE(subreq);
3078 if (tevent_req_nterror(req, status)) {
3079 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3083 ok = netlogon_creds_client_check(&state->tmp_creds,
3084 &state->rep_auth.cred);
3086 status = NT_STATUS_ACCESS_DENIED;
3087 tevent_req_nterror(req, status);
3088 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3092 cmp = memcmp(state->new_owf_password.hash,
3093 zero.hash, sizeof(zero.hash));
3095 netlogon_creds_des_decrypt(&state->tmp_creds,
3096 &state->new_owf_password);
3098 cmp = memcmp(state->old_owf_password.hash,
3099 zero.hash, sizeof(zero.hash));
3101 netlogon_creds_des_decrypt(&state->tmp_creds,
3102 &state->old_owf_password);
3105 *state->creds = state->tmp_creds;
3106 status = netlogon_creds_cli_store(state->context,
3108 if (tevent_req_nterror(req, status)) {
3109 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3113 if (tevent_req_nterror(req, result)) {
3114 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3118 tevent_req_done(req);
3121 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3122 TALLOC_CTX *mem_ctx,
3123 struct samr_Password *new_owf_password,
3124 struct samr_Password *old_owf_password,
3125 struct netr_TrustInfo **trust_info)
3127 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3128 tevent_req_data(req,
3129 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3132 if (tevent_req_is_nterror(req, &status)) {
3133 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3134 tevent_req_received(req);
3138 if (new_owf_password != NULL) {
3139 *new_owf_password = state->new_owf_password;
3141 if (old_owf_password != NULL) {
3142 *old_owf_password = state->old_owf_password;
3144 if (trust_info != NULL) {
3145 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3148 tevent_req_received(req);
3149 return NT_STATUS_OK;
3152 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3153 struct netlogon_creds_cli_context *context,
3154 struct dcerpc_binding_handle *b,
3155 TALLOC_CTX *mem_ctx,
3156 struct samr_Password *new_owf_password,
3157 struct samr_Password *old_owf_password,
3158 struct netr_TrustInfo **trust_info)
3160 TALLOC_CTX *frame = talloc_stackframe();
3161 struct tevent_context *ev;
3162 struct tevent_req *req;
3163 NTSTATUS status = NT_STATUS_NO_MEMORY;
3165 ev = samba_tevent_context_init(frame);
3169 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3173 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3176 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3186 struct netlogon_creds_cli_GetForestTrustInformation_state {
3187 struct tevent_context *ev;
3188 struct netlogon_creds_cli_context *context;
3189 struct dcerpc_binding_handle *binding_handle;
3191 char *srv_name_slash;
3192 enum dcerpc_AuthType auth_type;
3193 enum dcerpc_AuthLevel auth_level;
3196 struct lsa_ForestTrustInformation *forest_trust_info;
3198 struct netlogon_creds_CredentialState *creds;
3199 struct netlogon_creds_CredentialState tmp_creds;
3200 struct netr_Authenticator req_auth;
3201 struct netr_Authenticator rep_auth;
3204 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3206 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3208 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3209 struct tevent_context *ev,
3210 struct netlogon_creds_cli_context *context,
3211 struct dcerpc_binding_handle *b)
3213 struct tevent_req *req;
3214 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3215 struct tevent_req *subreq;
3217 req = tevent_req_create(mem_ctx, &state,
3218 struct netlogon_creds_cli_GetForestTrustInformation_state);
3224 state->context = context;
3225 state->binding_handle = b;
3227 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3228 context->server.computer);
3229 if (tevent_req_nomem(state->srv_name_slash, req)) {
3230 return tevent_req_post(req, ev);
3235 dcerpc_binding_handle_auth_info(state->binding_handle,
3237 &state->auth_level);
3239 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3241 if (tevent_req_nomem(subreq, req)) {
3242 return tevent_req_post(req, ev);
3245 tevent_req_set_callback(subreq,
3246 netlogon_creds_cli_GetForestTrustInformation_locked,
3252 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3255 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3256 tevent_req_data(req,
3257 struct netlogon_creds_cli_GetForestTrustInformation_state);
3259 if (state->creds == NULL) {
3263 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3264 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3265 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3266 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3267 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3268 TALLOC_FREE(state->creds);
3272 netlogon_creds_cli_delete(state->context, &state->creds);
3275 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3277 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3279 struct tevent_req *req =
3280 tevent_req_callback_data(subreq,
3282 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3283 tevent_req_data(req,
3284 struct netlogon_creds_cli_GetForestTrustInformation_state);
3287 status = netlogon_creds_cli_lock_recv(subreq, state,
3289 TALLOC_FREE(subreq);
3290 if (tevent_req_nterror(req, status)) {
3294 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3295 switch (state->auth_level) {
3296 case DCERPC_AUTH_LEVEL_INTEGRITY:
3297 case DCERPC_AUTH_LEVEL_PRIVACY:
3300 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3304 uint32_t tmp = state->creds->negotiate_flags;
3306 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3308 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3309 * it should be used, which means
3310 * we had a chance to verify no downgrade
3313 * This relies on netlogon_creds_cli_check*
3314 * being called before, as first request after
3317 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3323 * we defer all callbacks in order to cleanup
3324 * the database record.
3326 tevent_req_defer_callback(req, state->ev);
3328 state->tmp_creds = *state->creds;
3329 netlogon_creds_client_authenticator(&state->tmp_creds,
3331 ZERO_STRUCT(state->rep_auth);
3333 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3334 state->binding_handle,
3335 state->srv_name_slash,
3336 state->tmp_creds.computer_name,
3340 &state->forest_trust_info);
3341 if (tevent_req_nomem(subreq, req)) {
3342 status = NT_STATUS_NO_MEMORY;
3343 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3347 tevent_req_set_callback(subreq,
3348 netlogon_creds_cli_GetForestTrustInformation_done,
3352 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3354 struct tevent_req *req =
3355 tevent_req_callback_data(subreq,
3357 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3358 tevent_req_data(req,
3359 struct netlogon_creds_cli_GetForestTrustInformation_state);
3365 * We use state->dns_names as the memory context, as this is
3366 * the only in/out variable and it has been overwritten by the
3367 * out parameter from the server.
3369 * We need to preserve the return value until the caller can use it.
3371 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3372 TALLOC_FREE(subreq);
3373 if (tevent_req_nterror(req, status)) {
3374 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3378 ok = netlogon_creds_client_check(&state->tmp_creds,
3379 &state->rep_auth.cred);
3381 status = NT_STATUS_ACCESS_DENIED;
3382 tevent_req_nterror(req, status);
3383 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3387 *state->creds = state->tmp_creds;
3388 status = netlogon_creds_cli_store(state->context,
3391 if (tevent_req_nterror(req, status)) {
3392 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3396 if (tevent_req_nterror(req, result)) {
3397 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3401 tevent_req_done(req);
3404 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3405 TALLOC_CTX *mem_ctx,
3406 struct lsa_ForestTrustInformation **forest_trust_info)
3408 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3409 tevent_req_data(req,
3410 struct netlogon_creds_cli_GetForestTrustInformation_state);
3413 if (tevent_req_is_nterror(req, &status)) {
3414 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3415 tevent_req_received(req);
3419 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3421 tevent_req_received(req);
3422 return NT_STATUS_OK;
3425 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3426 struct netlogon_creds_cli_context *context,
3427 struct dcerpc_binding_handle *b,
3428 TALLOC_CTX *mem_ctx,
3429 struct lsa_ForestTrustInformation **forest_trust_info)
3431 TALLOC_CTX *frame = talloc_stackframe();
3432 struct tevent_context *ev;
3433 struct tevent_req *req;
3434 NTSTATUS status = NT_STATUS_NO_MEMORY;
3436 ev = samba_tevent_context_init(frame);
3440 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3444 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3447 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3455 struct netlogon_creds_cli_SendToSam_state {
3456 struct tevent_context *ev;
3457 struct netlogon_creds_cli_context *context;
3458 struct dcerpc_binding_handle *binding_handle;
3460 char *srv_name_slash;
3461 enum dcerpc_AuthType auth_type;
3462 enum dcerpc_AuthLevel auth_level;
3466 struct netlogon_creds_CredentialState *creds;
3467 struct netlogon_creds_CredentialState tmp_creds;
3468 struct netr_Authenticator req_auth;
3469 struct netr_Authenticator rep_auth;
3472 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3474 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3476 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3477 struct tevent_context *ev,
3478 struct netlogon_creds_cli_context *context,
3479 struct dcerpc_binding_handle *b,
3480 struct netr_SendToSamBase *message)
3482 struct tevent_req *req;
3483 struct netlogon_creds_cli_SendToSam_state *state;
3484 struct tevent_req *subreq;
3485 enum ndr_err_code ndr_err;
3487 req = tevent_req_create(mem_ctx, &state,
3488 struct netlogon_creds_cli_SendToSam_state);
3494 state->context = context;
3495 state->binding_handle = b;
3497 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3498 context->server.computer);
3499 if (tevent_req_nomem(state->srv_name_slash, req)) {
3500 return tevent_req_post(req, ev);
3503 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3504 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3505 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3506 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3507 tevent_req_nterror(req, status);
3508 return tevent_req_post(req, ev);
3511 dcerpc_binding_handle_auth_info(state->binding_handle,
3513 &state->auth_level);
3515 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3517 if (tevent_req_nomem(subreq, req)) {
3518 return tevent_req_post(req, ev);
3521 tevent_req_set_callback(subreq,
3522 netlogon_creds_cli_SendToSam_locked,
3528 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3531 struct netlogon_creds_cli_SendToSam_state *state =
3532 tevent_req_data(req,
3533 struct netlogon_creds_cli_SendToSam_state);
3535 if (state->creds == NULL) {
3539 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3540 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3541 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3542 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3543 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3544 TALLOC_FREE(state->creds);
3548 netlogon_creds_cli_delete(state->context, &state->creds);
3551 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3553 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3555 struct tevent_req *req =
3556 tevent_req_callback_data(subreq,
3558 struct netlogon_creds_cli_SendToSam_state *state =
3559 tevent_req_data(req,
3560 struct netlogon_creds_cli_SendToSam_state);
3563 status = netlogon_creds_cli_lock_recv(subreq, state,
3565 TALLOC_FREE(subreq);
3566 if (tevent_req_nterror(req, status)) {
3570 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3571 switch (state->auth_level) {
3572 case DCERPC_AUTH_LEVEL_INTEGRITY:
3573 case DCERPC_AUTH_LEVEL_PRIVACY:
3576 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3580 uint32_t tmp = state->creds->negotiate_flags;
3582 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3584 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3585 * it should be used, which means
3586 * we had a chance to verify no downgrade
3589 * This relies on netlogon_creds_cli_check*
3590 * being called before, as first request after
3593 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3599 * we defer all callbacks in order to cleanup
3600 * the database record.
3602 tevent_req_defer_callback(req, state->ev);
3604 state->tmp_creds = *state->creds;
3605 netlogon_creds_client_authenticator(&state->tmp_creds,
3607 ZERO_STRUCT(state->rep_auth);
3609 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3610 netlogon_creds_aes_encrypt(&state->tmp_creds,
3612 state->opaque.length);
3614 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3616 state->opaque.length);
3619 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3620 state->binding_handle,
3621 state->srv_name_slash,
3622 state->tmp_creds.computer_name,
3626 state->opaque.length);
3627 if (tevent_req_nomem(subreq, req)) {
3628 status = NT_STATUS_NO_MEMORY;
3629 netlogon_creds_cli_SendToSam_cleanup(req, status);
3633 tevent_req_set_callback(subreq,
3634 netlogon_creds_cli_SendToSam_done,
3638 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3640 struct tevent_req *req =
3641 tevent_req_callback_data(subreq,
3643 struct netlogon_creds_cli_SendToSam_state *state =
3644 tevent_req_data(req,
3645 struct netlogon_creds_cli_SendToSam_state);
3650 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3651 TALLOC_FREE(subreq);
3652 if (tevent_req_nterror(req, status)) {
3653 netlogon_creds_cli_SendToSam_cleanup(req, status);
3657 ok = netlogon_creds_client_check(&state->tmp_creds,
3658 &state->rep_auth.cred);
3660 status = NT_STATUS_ACCESS_DENIED;
3661 tevent_req_nterror(req, status);
3662 netlogon_creds_cli_SendToSam_cleanup(req, status);
3666 *state->creds = state->tmp_creds;
3667 status = netlogon_creds_cli_store(state->context,
3670 if (tevent_req_nterror(req, status)) {
3671 netlogon_creds_cli_SendToSam_cleanup(req, status);
3676 * Creds must be stored before we send back application errors
3677 * e.g. NT_STATUS_NOT_IMPLEMENTED
3679 if (tevent_req_nterror(req, result)) {
3680 netlogon_creds_cli_SendToSam_cleanup(req, result);
3684 tevent_req_done(req);
3687 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3688 struct dcerpc_binding_handle *b,
3689 struct netr_SendToSamBase *message)
3691 TALLOC_CTX *frame = talloc_stackframe();
3692 struct tevent_context *ev;
3693 struct tevent_req *req;
3694 NTSTATUS status = NT_STATUS_OK;
3696 ev = samba_tevent_context_init(frame);
3700 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3704 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3708 /* Ignore the result */