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,
578 status = dbwrap_parse_record(context->db.ctx,
579 context->db.key_data,
580 netlogon_creds_cli_fetch_parser,
582 if (!NT_STATUS_IS_OK(status)) {
585 status = fstate.status;
586 if (!NT_STATUS_IS_OK(status)) {
591 * mark it as invalid for step operations.
593 fstate.creds->sequence = 0;
594 fstate.creds->seed = (struct netr_Credential) {{0}};
595 fstate.creds->client = (struct netr_Credential) {{0}};
596 fstate.creds->server = (struct netr_Credential) {{0}};
598 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
599 *_creds = fstate.creds;
604 * It is really important to try SamLogonEx here,
605 * because multiple processes can talk to the same
606 * domain controller, without using the credential
609 * With a normal SamLogon call, we must keep the
610 * credentials chain updated and intact between all
611 * users of the machine account (which would imply
612 * cross-node communication for every NTLM logon).
614 * The credentials chain is not per NETLOGON pipe
615 * connection, but globally on the server/client pair
616 * by computer name, while the client is free to use
617 * any computer name. We include the cluster node number
618 * in our computer name in order to avoid cross node
619 * coordination of the credential chain.
621 * It's also important to use NetlogonValidationSamInfo4 (6),
622 * because it relies on the rpc transport encryption
623 * and avoids using the global netlogon schannel
624 * session key to en/decrypt secret information
625 * like the user_session_key for network logons.
627 * [MS-APDS] 3.1.5.2 NTLM Network Logon
628 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
629 * NETLOGON_NEG_AUTHENTICATED_RPC set together
630 * are the indication that the server supports
631 * NetlogonValidationSamInfo4 (6). And it must only
632 * be used if "SealSecureChannel" is used.
634 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
635 * check is done in netlogon_creds_cli_LogonSamLogon*().
637 context->server.cached_flags = fstate.creds->negotiate_flags;
638 context->server.try_validation6 = true;
639 context->server.try_logon_ex = true;
640 context->server.try_logon_with = true;
642 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
643 context->server.try_validation6 = false;
644 context->server.try_logon_ex = false;
646 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
647 context->server.try_validation6 = false;
650 *_creds = fstate.creds;
654 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
655 const struct netlogon_creds_CredentialState *creds1)
657 TALLOC_CTX *frame = talloc_stackframe();
658 struct netlogon_creds_CredentialState *creds2;
662 enum ndr_err_code ndr_err;
665 status = netlogon_creds_cli_get(context, frame, &creds2);
666 if (!NT_STATUS_IS_OK(status)) {
671 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
672 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
673 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
678 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
679 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
680 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
685 if (blob1.length != blob2.length) {
690 cmp = memcmp(blob1.data, blob2.data, blob1.length);
700 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
701 struct netlogon_creds_CredentialState **_creds)
703 struct netlogon_creds_CredentialState *creds = *_creds;
705 enum ndr_err_code ndr_err;
711 if (context->db.locked_state == NULL) {
713 * this was not the result of netlogon_creds_cli_lock*()
716 return NT_STATUS_INVALID_PAGE_PROTECTION;
719 if (context->db.locked_state->creds != creds) {
721 * this was not the result of netlogon_creds_cli_lock*()
724 return NT_STATUS_INVALID_PAGE_PROTECTION;
727 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
728 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
729 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
731 status = ndr_map_error2ntstatus(ndr_err);
735 data.dptr = blob.data;
736 data.dsize = blob.length;
738 status = dbwrap_store(context->db.ctx,
739 context->db.key_data,
742 if (!NT_STATUS_IS_OK(status)) {
749 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
750 struct netlogon_creds_CredentialState **_creds)
752 struct netlogon_creds_CredentialState *creds = *_creds;
757 if (context->db.locked_state == NULL) {
759 * this was not the result of netlogon_creds_cli_lock*()
762 return NT_STATUS_INVALID_PAGE_PROTECTION;
765 if (context->db.locked_state->creds != creds) {
767 * this was not the result of netlogon_creds_cli_lock*()
770 return NT_STATUS_INVALID_PAGE_PROTECTION;
773 status = dbwrap_delete(context->db.ctx,
774 context->db.key_data);
776 if (!NT_STATUS_IS_OK(status)) {
783 struct netlogon_creds_cli_lock_state {
784 struct netlogon_creds_cli_locked_state *locked_state;
785 struct netlogon_creds_CredentialState *creds;
788 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
789 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
791 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
792 struct tevent_context *ev,
793 struct netlogon_creds_cli_context *context)
795 struct tevent_req *req;
796 struct netlogon_creds_cli_lock_state *state;
797 struct netlogon_creds_cli_locked_state *locked_state;
798 struct tevent_req *subreq;
800 req = tevent_req_create(mem_ctx, &state,
801 struct netlogon_creds_cli_lock_state);
806 if (context->db.locked_state != NULL) {
807 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
808 return tevent_req_post(req, ev);
811 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
812 if (tevent_req_nomem(locked_state, req)) {
813 return tevent_req_post(req, ev);
815 talloc_set_destructor(locked_state,
816 netlogon_creds_cli_locked_state_destructor);
817 locked_state->context = context;
819 context->db.locked_state = locked_state;
820 state->locked_state = locked_state;
822 if (context->db.g_ctx == NULL) {
823 netlogon_creds_cli_lock_fetch(req);
824 if (!tevent_req_is_in_progress(req)) {
825 return tevent_req_post(req, ev);
831 subreq = g_lock_lock_send(state, ev,
833 context->db.key_name,
835 if (tevent_req_nomem(subreq, req)) {
836 return tevent_req_post(req, ev);
838 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
843 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
845 struct tevent_req *req =
846 tevent_req_callback_data(subreq,
848 struct netlogon_creds_cli_lock_state *state =
850 struct netlogon_creds_cli_lock_state);
853 status = g_lock_lock_recv(subreq);
855 if (tevent_req_nterror(req, status)) {
858 state->locked_state->is_glocked = true;
860 netlogon_creds_cli_lock_fetch(req);
863 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
865 struct netlogon_creds_cli_lock_state *state =
867 struct netlogon_creds_cli_lock_state);
868 struct netlogon_creds_cli_context *context = state->locked_state->context;
869 struct netlogon_creds_cli_fetch_state fstate = {
870 .status = NT_STATUS_INTERNAL_ERROR,
871 .required_flags = context->client.required_flags,
875 fstate.mem_ctx = state;
876 status = dbwrap_parse_record(context->db.ctx,
877 context->db.key_data,
878 netlogon_creds_cli_fetch_parser,
880 if (tevent_req_nterror(req, status)) {
883 status = fstate.status;
884 if (tevent_req_nterror(req, status)) {
888 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
889 state->creds = fstate.creds;
890 tevent_req_done(req);
894 context->server.cached_flags = fstate.creds->negotiate_flags;
895 context->server.try_validation6 = true;
896 context->server.try_logon_ex = true;
897 context->server.try_logon_with = true;
899 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
900 context->server.try_validation6 = false;
901 context->server.try_logon_ex = false;
903 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
904 context->server.try_validation6 = false;
907 state->creds = fstate.creds;
908 tevent_req_done(req);
912 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
914 struct netlogon_creds_CredentialState **creds)
916 struct netlogon_creds_cli_lock_state *state =
918 struct netlogon_creds_cli_lock_state);
921 if (tevent_req_is_nterror(req, &status)) {
922 tevent_req_received(req);
926 talloc_steal(state->creds, state->locked_state);
927 state->locked_state->creds = state->creds;
928 *creds = talloc_move(mem_ctx, &state->creds);
929 tevent_req_received(req);
933 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
935 struct netlogon_creds_CredentialState **creds)
937 TALLOC_CTX *frame = talloc_stackframe();
938 struct tevent_context *ev;
939 struct tevent_req *req;
940 NTSTATUS status = NT_STATUS_NO_MEMORY;
942 ev = samba_tevent_context_init(frame);
946 req = netlogon_creds_cli_lock_send(frame, ev, context);
950 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
953 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
959 struct netlogon_creds_cli_auth_state {
960 struct tevent_context *ev;
961 struct netlogon_creds_cli_context *context;
962 struct dcerpc_binding_handle *binding_handle;
963 uint8_t num_nt_hashes;
964 uint8_t idx_nt_hashes;
965 const struct samr_Password * const *nt_hashes;
966 const struct samr_Password *used_nt_hash;
967 char *srv_name_slash;
968 uint32_t current_flags;
969 struct netr_Credential client_challenge;
970 struct netr_Credential server_challenge;
971 struct netlogon_creds_CredentialState *creds;
972 struct netr_Credential client_credential;
973 struct netr_Credential server_credential;
978 struct netlogon_creds_cli_locked_state *locked_state;
981 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
982 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
984 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
985 struct tevent_context *ev,
986 struct netlogon_creds_cli_context *context,
987 struct dcerpc_binding_handle *b,
988 uint8_t num_nt_hashes,
989 const struct samr_Password * const *nt_hashes)
991 struct tevent_req *req;
992 struct netlogon_creds_cli_auth_state *state;
993 struct netlogon_creds_cli_locked_state *locked_state;
996 req = tevent_req_create(mem_ctx, &state,
997 struct netlogon_creds_cli_auth_state);
1003 state->context = context;
1004 state->binding_handle = b;
1005 if (num_nt_hashes < 1) {
1006 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1007 return tevent_req_post(req, ev);
1009 if (num_nt_hashes > 4) {
1010 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1011 return tevent_req_post(req, ev);
1014 state->num_nt_hashes = num_nt_hashes;
1015 state->idx_nt_hashes = 0;
1016 state->nt_hashes = nt_hashes;
1018 if (context->db.locked_state != NULL) {
1019 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
1020 return tevent_req_post(req, ev);
1023 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
1024 if (tevent_req_nomem(locked_state, req)) {
1025 return tevent_req_post(req, ev);
1027 talloc_set_destructor(locked_state,
1028 netlogon_creds_cli_locked_state_destructor);
1029 locked_state->context = context;
1031 context->db.locked_state = locked_state;
1032 state->locked_state = locked_state;
1034 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1035 context->server.computer);
1036 if (tevent_req_nomem(state->srv_name_slash, req)) {
1037 return tevent_req_post(req, ev);
1040 state->try_auth3 = true;
1041 state->try_auth2 = true;
1043 if (context->client.required_flags != 0) {
1044 state->require_auth2 = true;
1047 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1048 state->current_flags = context->client.proposed_flags;
1050 if (context->db.g_ctx != NULL) {
1051 struct tevent_req *subreq;
1053 subreq = g_lock_lock_send(state, ev,
1055 context->db.key_name,
1057 if (tevent_req_nomem(subreq, req)) {
1058 return tevent_req_post(req, ev);
1060 tevent_req_set_callback(subreq,
1061 netlogon_creds_cli_auth_locked,
1067 status = dbwrap_purge(state->context->db.ctx,
1068 state->context->db.key_data);
1069 if (tevent_req_nterror(req, status)) {
1070 return tevent_req_post(req, ev);
1073 netlogon_creds_cli_auth_challenge_start(req);
1074 if (!tevent_req_is_in_progress(req)) {
1075 return tevent_req_post(req, ev);
1081 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1083 struct tevent_req *req =
1084 tevent_req_callback_data(subreq,
1086 struct netlogon_creds_cli_auth_state *state =
1087 tevent_req_data(req,
1088 struct netlogon_creds_cli_auth_state);
1091 status = g_lock_lock_recv(subreq);
1092 TALLOC_FREE(subreq);
1093 if (tevent_req_nterror(req, status)) {
1096 state->locked_state->is_glocked = true;
1098 status = dbwrap_purge(state->context->db.ctx,
1099 state->context->db.key_data);
1100 if (tevent_req_nterror(req, status)) {
1104 netlogon_creds_cli_auth_challenge_start(req);
1107 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1109 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1111 struct netlogon_creds_cli_auth_state *state =
1112 tevent_req_data(req,
1113 struct netlogon_creds_cli_auth_state);
1114 struct tevent_req *subreq;
1116 TALLOC_FREE(state->creds);
1118 generate_random_buffer(state->client_challenge.data,
1119 sizeof(state->client_challenge.data));
1121 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1122 state->binding_handle,
1123 state->srv_name_slash,
1124 state->context->client.computer,
1125 &state->client_challenge,
1126 &state->server_challenge);
1127 if (tevent_req_nomem(subreq, req)) {
1130 tevent_req_set_callback(subreq,
1131 netlogon_creds_cli_auth_challenge_done,
1135 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1137 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1139 struct tevent_req *req =
1140 tevent_req_callback_data(subreq,
1142 struct netlogon_creds_cli_auth_state *state =
1143 tevent_req_data(req,
1144 struct netlogon_creds_cli_auth_state);
1148 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1149 TALLOC_FREE(subreq);
1150 if (tevent_req_nterror(req, status)) {
1153 if (tevent_req_nterror(req, result)) {
1157 if (!state->try_auth3 && !state->try_auth2) {
1158 state->current_flags = 0;
1161 /* Calculate the session key and client credentials */
1163 state->creds = netlogon_creds_client_init(state,
1164 state->context->client.account,
1165 state->context->client.computer,
1166 state->context->client.type,
1167 &state->client_challenge,
1168 &state->server_challenge,
1169 state->used_nt_hash,
1170 &state->client_credential,
1171 state->current_flags);
1172 if (tevent_req_nomem(state->creds, req)) {
1176 if (state->try_auth3) {
1177 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1178 state->binding_handle,
1179 state->srv_name_slash,
1180 state->context->client.account,
1181 state->context->client.type,
1182 state->context->client.computer,
1183 &state->client_credential,
1184 &state->server_credential,
1185 &state->creds->negotiate_flags,
1187 if (tevent_req_nomem(subreq, req)) {
1190 } else if (state->try_auth2) {
1193 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1194 state->binding_handle,
1195 state->srv_name_slash,
1196 state->context->client.account,
1197 state->context->client.type,
1198 state->context->client.computer,
1199 &state->client_credential,
1200 &state->server_credential,
1201 &state->creds->negotiate_flags);
1202 if (tevent_req_nomem(subreq, req)) {
1208 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1209 state->binding_handle,
1210 state->srv_name_slash,
1211 state->context->client.account,
1212 state->context->client.type,
1213 state->context->client.computer,
1214 &state->client_credential,
1215 &state->server_credential);
1216 if (tevent_req_nomem(subreq, req)) {
1220 tevent_req_set_callback(subreq,
1221 netlogon_creds_cli_auth_srvauth_done,
1225 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1227 struct tevent_req *req =
1228 tevent_req_callback_data(subreq,
1230 struct netlogon_creds_cli_auth_state *state =
1231 tevent_req_data(req,
1232 struct netlogon_creds_cli_auth_state);
1236 enum ndr_err_code ndr_err;
1241 if (state->try_auth3) {
1242 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1244 TALLOC_FREE(subreq);
1245 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1246 state->try_auth3 = false;
1247 netlogon_creds_cli_auth_challenge_start(req);
1250 if (tevent_req_nterror(req, status)) {
1253 } else if (state->try_auth2) {
1254 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1256 TALLOC_FREE(subreq);
1257 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1258 state->try_auth2 = false;
1259 if (state->require_auth2) {
1260 status = NT_STATUS_DOWNGRADE_DETECTED;
1261 tevent_req_nterror(req, status);
1264 netlogon_creds_cli_auth_challenge_start(req);
1267 if (tevent_req_nterror(req, status)) {
1271 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1273 TALLOC_FREE(subreq);
1274 if (tevent_req_nterror(req, status)) {
1279 if (!NT_STATUS_IS_OK(result) &&
1280 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1282 tevent_req_nterror(req, result);
1286 tmp_flags = state->creds->negotiate_flags;
1287 tmp_flags &= state->context->client.required_flags;
1288 if (tmp_flags != state->context->client.required_flags) {
1289 if (NT_STATUS_IS_OK(result)) {
1290 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1293 tevent_req_nterror(req, result);
1297 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1299 tmp_flags = state->context->client.proposed_flags;
1300 if ((state->current_flags == tmp_flags) &&
1301 (state->creds->negotiate_flags != tmp_flags))
1304 * lets retry with the negotiated flags
1306 state->current_flags = state->creds->negotiate_flags;
1307 netlogon_creds_cli_auth_challenge_start(req);
1311 state->idx_nt_hashes += 1;
1312 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1314 * we already retried, giving up...
1316 tevent_req_nterror(req, result);
1321 * lets retry with the old nt hash.
1323 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1324 state->current_flags = state->context->client.proposed_flags;
1325 netlogon_creds_cli_auth_challenge_start(req);
1329 ok = netlogon_creds_client_check(state->creds,
1330 &state->server_credential);
1332 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1336 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1337 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1338 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1339 status = ndr_map_error2ntstatus(ndr_err);
1340 tevent_req_nterror(req, status);
1344 data.dptr = blob.data;
1345 data.dsize = blob.length;
1347 status = dbwrap_store(state->context->db.ctx,
1348 state->context->db.key_data,
1350 TALLOC_FREE(state->locked_state);
1351 if (tevent_req_nterror(req, status)) {
1355 tevent_req_done(req);
1358 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1359 uint8_t *idx_nt_hashes)
1361 struct netlogon_creds_cli_auth_state *state =
1362 tevent_req_data(req,
1363 struct netlogon_creds_cli_auth_state);
1368 if (tevent_req_is_nterror(req, &status)) {
1369 tevent_req_received(req);
1373 *idx_nt_hashes = state->idx_nt_hashes;
1374 tevent_req_received(req);
1375 return NT_STATUS_OK;
1378 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1379 struct dcerpc_binding_handle *b,
1380 uint8_t num_nt_hashes,
1381 const struct samr_Password * const *nt_hashes,
1382 uint8_t *idx_nt_hashes)
1384 TALLOC_CTX *frame = talloc_stackframe();
1385 struct tevent_context *ev;
1386 struct tevent_req *req;
1387 NTSTATUS status = NT_STATUS_NO_MEMORY;
1391 ev = samba_tevent_context_init(frame);
1395 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1396 num_nt_hashes, nt_hashes);
1400 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1403 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1409 struct netlogon_creds_cli_check_state {
1410 struct tevent_context *ev;
1411 struct netlogon_creds_cli_context *context;
1412 struct dcerpc_binding_handle *binding_handle;
1414 char *srv_name_slash;
1416 union netr_Capabilities caps;
1418 struct netlogon_creds_CredentialState *creds;
1419 struct netlogon_creds_CredentialState tmp_creds;
1420 struct netr_Authenticator req_auth;
1421 struct netr_Authenticator rep_auth;
1424 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1426 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1428 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1429 struct tevent_context *ev,
1430 struct netlogon_creds_cli_context *context,
1431 struct dcerpc_binding_handle *b)
1433 struct tevent_req *req;
1434 struct netlogon_creds_cli_check_state *state;
1435 struct tevent_req *subreq;
1436 enum dcerpc_AuthType auth_type;
1437 enum dcerpc_AuthLevel auth_level;
1439 req = tevent_req_create(mem_ctx, &state,
1440 struct netlogon_creds_cli_check_state);
1446 state->context = context;
1447 state->binding_handle = b;
1449 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1450 context->server.computer);
1451 if (tevent_req_nomem(state->srv_name_slash, req)) {
1452 return tevent_req_post(req, ev);
1455 dcerpc_binding_handle_auth_info(state->binding_handle,
1456 &auth_type, &auth_level);
1458 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1459 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1460 return tevent_req_post(req, ev);
1463 switch (auth_level) {
1464 case DCERPC_AUTH_LEVEL_INTEGRITY:
1465 case DCERPC_AUTH_LEVEL_PRIVACY:
1468 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1469 return tevent_req_post(req, ev);
1472 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1474 if (tevent_req_nomem(subreq, req)) {
1475 return tevent_req_post(req, ev);
1478 tevent_req_set_callback(subreq,
1479 netlogon_creds_cli_check_locked,
1485 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1488 struct netlogon_creds_cli_check_state *state =
1489 tevent_req_data(req,
1490 struct netlogon_creds_cli_check_state);
1492 if (state->creds == NULL) {
1496 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1497 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1498 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1499 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1500 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1501 TALLOC_FREE(state->creds);
1505 netlogon_creds_cli_delete(state->context, &state->creds);
1508 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1510 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1512 struct tevent_req *req =
1513 tevent_req_callback_data(subreq,
1515 struct netlogon_creds_cli_check_state *state =
1516 tevent_req_data(req,
1517 struct netlogon_creds_cli_check_state);
1520 status = netlogon_creds_cli_lock_recv(subreq, state,
1522 TALLOC_FREE(subreq);
1523 if (tevent_req_nterror(req, status)) {
1528 * we defer all callbacks in order to cleanup
1529 * the database record.
1531 tevent_req_defer_callback(req, state->ev);
1533 state->tmp_creds = *state->creds;
1534 netlogon_creds_client_authenticator(&state->tmp_creds,
1536 ZERO_STRUCT(state->rep_auth);
1538 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1539 state->binding_handle,
1540 state->srv_name_slash,
1541 state->context->client.computer,
1546 if (tevent_req_nomem(subreq, req)) {
1547 status = NT_STATUS_NO_MEMORY;
1548 netlogon_creds_cli_check_cleanup(req, status);
1551 tevent_req_set_callback(subreq,
1552 netlogon_creds_cli_check_caps,
1556 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1558 struct tevent_req *req =
1559 tevent_req_callback_data(subreq,
1561 struct netlogon_creds_cli_check_state *state =
1562 tevent_req_data(req,
1563 struct netlogon_creds_cli_check_state);
1568 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1570 TALLOC_FREE(subreq);
1571 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1573 * Note that the negotiated flags are already checked
1574 * for our required flags after the ServerAuthenticate3/2 call.
1576 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1578 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1580 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1581 * already, we expect this to work!
1583 status = NT_STATUS_DOWNGRADE_DETECTED;
1584 tevent_req_nterror(req, status);
1585 netlogon_creds_cli_check_cleanup(req, status);
1589 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1591 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1592 * we expect this to work at least as far as the
1593 * NOT_SUPPORTED error handled below!
1595 * NT 4.0 and Old Samba servers are not
1596 * allowed without "require strong key = no"
1598 status = NT_STATUS_DOWNGRADE_DETECTED;
1599 tevent_req_nterror(req, status);
1600 netlogon_creds_cli_check_cleanup(req, status);
1605 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1606 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1607 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1609 * This is needed against NT 4.0 and old Samba servers.
1611 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1612 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1613 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1614 * with the next request as the sequence number processing
1617 netlogon_creds_cli_check_cleanup(req, status);
1618 tevent_req_done(req);
1621 if (tevent_req_nterror(req, status)) {
1622 netlogon_creds_cli_check_cleanup(req, status);
1626 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1628 * Note that the negotiated flags are already checked
1629 * for our required flags after the ServerAuthenticate3/2 call.
1631 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1633 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1635 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1636 * already, we expect this to work!
1638 status = NT_STATUS_DOWNGRADE_DETECTED;
1639 tevent_req_nterror(req, status);
1640 netlogon_creds_cli_check_cleanup(req, status);
1645 * This is ok, the server does not support
1646 * NETLOGON_NEG_SUPPORTS_AES.
1648 * netr_LogonGetCapabilities() was
1649 * netr_LogonDummyRoutine1() before
1650 * NETLOGON_NEG_SUPPORTS_AES was invented.
1652 netlogon_creds_cli_check_cleanup(req, result);
1653 tevent_req_done(req);
1657 ok = netlogon_creds_client_check(&state->tmp_creds,
1658 &state->rep_auth.cred);
1660 status = NT_STATUS_ACCESS_DENIED;
1661 tevent_req_nterror(req, status);
1662 netlogon_creds_cli_check_cleanup(req, status);
1666 if (tevent_req_nterror(req, result)) {
1667 netlogon_creds_cli_check_cleanup(req, result);
1671 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1672 status = NT_STATUS_DOWNGRADE_DETECTED;
1673 tevent_req_nterror(req, status);
1674 netlogon_creds_cli_check_cleanup(req, status);
1679 * This is the key check that makes this check secure. If we
1680 * get OK here (rather than NOT_SUPPORTED), then the server
1681 * did support AES. If the server only proposed STRONG_KEYS
1682 * and not AES, then it should have failed with
1683 * NOT_IMPLEMENTED. We always send AES as a client, so the
1684 * server should always have returned it.
1686 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1687 status = NT_STATUS_DOWNGRADE_DETECTED;
1688 tevent_req_nterror(req, status);
1689 netlogon_creds_cli_check_cleanup(req, status);
1693 *state->creds = state->tmp_creds;
1694 status = netlogon_creds_cli_store(state->context,
1696 netlogon_creds_cli_check_cleanup(req, status);
1697 if (tevent_req_nterror(req, status)) {
1701 tevent_req_done(req);
1704 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1708 if (tevent_req_is_nterror(req, &status)) {
1709 netlogon_creds_cli_check_cleanup(req, status);
1710 tevent_req_received(req);
1714 tevent_req_received(req);
1715 return NT_STATUS_OK;
1718 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1719 struct dcerpc_binding_handle *b)
1721 TALLOC_CTX *frame = talloc_stackframe();
1722 struct tevent_context *ev;
1723 struct tevent_req *req;
1724 NTSTATUS status = NT_STATUS_NO_MEMORY;
1726 ev = samba_tevent_context_init(frame);
1730 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1734 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1737 status = netlogon_creds_cli_check_recv(req);
1743 struct netlogon_creds_cli_ServerPasswordSet_state {
1744 struct tevent_context *ev;
1745 struct netlogon_creds_cli_context *context;
1746 struct dcerpc_binding_handle *binding_handle;
1747 uint32_t old_timeout;
1749 char *srv_name_slash;
1750 enum dcerpc_AuthType auth_type;
1751 enum dcerpc_AuthLevel auth_level;
1753 struct samr_CryptPassword samr_crypt_password;
1754 struct netr_CryptPassword netr_crypt_password;
1755 struct samr_Password samr_password;
1757 struct netlogon_creds_CredentialState *creds;
1758 struct netlogon_creds_CredentialState tmp_creds;
1759 struct netr_Authenticator req_auth;
1760 struct netr_Authenticator rep_auth;
1763 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1765 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1767 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1768 struct tevent_context *ev,
1769 struct netlogon_creds_cli_context *context,
1770 struct dcerpc_binding_handle *b,
1771 const DATA_BLOB *new_password,
1772 const uint32_t *new_version)
1774 struct tevent_req *req;
1775 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1776 struct tevent_req *subreq;
1779 req = tevent_req_create(mem_ctx, &state,
1780 struct netlogon_creds_cli_ServerPasswordSet_state);
1786 state->context = context;
1787 state->binding_handle = b;
1789 if (new_password->length < 14) {
1790 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1791 return tevent_req_post(req, ev);
1795 * netr_ServerPasswordSet
1797 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1800 * netr_ServerPasswordSet2
1802 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1805 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1806 return tevent_req_post(req, ev);
1809 if (new_version != NULL) {
1810 struct NL_PASSWORD_VERSION version;
1811 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1812 uint32_t ofs = 512 - len;
1816 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1817 return tevent_req_post(req, ev);
1821 version.ReservedField = 0;
1822 version.PasswordVersionNumber = *new_version;
1823 version.PasswordVersionPresent =
1824 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1826 p = state->samr_crypt_password.data + ofs;
1827 SIVAL(p, 0, version.ReservedField);
1828 SIVAL(p, 4, version.PasswordVersionNumber);
1829 SIVAL(p, 8, version.PasswordVersionPresent);
1832 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1833 context->server.computer);
1834 if (tevent_req_nomem(state->srv_name_slash, req)) {
1835 return tevent_req_post(req, ev);
1838 dcerpc_binding_handle_auth_info(state->binding_handle,
1840 &state->auth_level);
1842 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1844 if (tevent_req_nomem(subreq, req)) {
1845 return tevent_req_post(req, ev);
1848 tevent_req_set_callback(subreq,
1849 netlogon_creds_cli_ServerPasswordSet_locked,
1855 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1858 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1859 tevent_req_data(req,
1860 struct netlogon_creds_cli_ServerPasswordSet_state);
1862 if (state->creds == NULL) {
1866 dcerpc_binding_handle_set_timeout(state->binding_handle,
1867 state->old_timeout);
1869 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1870 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1871 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1872 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1873 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1874 TALLOC_FREE(state->creds);
1878 netlogon_creds_cli_delete(state->context, &state->creds);
1881 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1883 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1885 struct tevent_req *req =
1886 tevent_req_callback_data(subreq,
1888 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1889 tevent_req_data(req,
1890 struct netlogon_creds_cli_ServerPasswordSet_state);
1893 status = netlogon_creds_cli_lock_recv(subreq, state,
1895 TALLOC_FREE(subreq);
1896 if (tevent_req_nterror(req, status)) {
1900 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1901 switch (state->auth_level) {
1902 case DCERPC_AUTH_LEVEL_INTEGRITY:
1903 case DCERPC_AUTH_LEVEL_PRIVACY:
1906 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1910 uint32_t tmp = state->creds->negotiate_flags;
1912 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1914 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1915 * it should be used, which means
1916 * we had a chance to verify no downgrade
1919 * This relies on netlogon_creds_cli_check*
1920 * being called before, as first request after
1923 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1928 state->old_timeout = dcerpc_binding_handle_set_timeout(
1929 state->binding_handle, 600000);
1932 * we defer all callbacks in order to cleanup
1933 * the database record.
1935 tevent_req_defer_callback(req, state->ev);
1937 state->tmp_creds = *state->creds;
1938 netlogon_creds_client_authenticator(&state->tmp_creds,
1940 ZERO_STRUCT(state->rep_auth);
1942 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1944 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1945 netlogon_creds_aes_encrypt(&state->tmp_creds,
1946 state->samr_crypt_password.data,
1949 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1950 state->samr_crypt_password.data,
1954 memcpy(state->netr_crypt_password.data,
1955 state->samr_crypt_password.data, 512);
1956 state->netr_crypt_password.length =
1957 IVAL(state->samr_crypt_password.data, 512);
1959 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1960 state->binding_handle,
1961 state->srv_name_slash,
1962 state->tmp_creds.account_name,
1963 state->tmp_creds.secure_channel_type,
1964 state->tmp_creds.computer_name,
1967 &state->netr_crypt_password);
1968 if (tevent_req_nomem(subreq, req)) {
1969 status = NT_STATUS_NO_MEMORY;
1970 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1974 netlogon_creds_des_encrypt(&state->tmp_creds,
1975 &state->samr_password);
1977 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1978 state->binding_handle,
1979 state->srv_name_slash,
1980 state->tmp_creds.account_name,
1981 state->tmp_creds.secure_channel_type,
1982 state->tmp_creds.computer_name,
1985 &state->samr_password);
1986 if (tevent_req_nomem(subreq, req)) {
1987 status = NT_STATUS_NO_MEMORY;
1988 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1993 tevent_req_set_callback(subreq,
1994 netlogon_creds_cli_ServerPasswordSet_done,
1998 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2000 struct tevent_req *req =
2001 tevent_req_callback_data(subreq,
2003 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2004 tevent_req_data(req,
2005 struct netlogon_creds_cli_ServerPasswordSet_state);
2010 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2011 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2013 TALLOC_FREE(subreq);
2014 if (tevent_req_nterror(req, status)) {
2015 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2019 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2021 TALLOC_FREE(subreq);
2022 if (tevent_req_nterror(req, status)) {
2023 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2028 ok = netlogon_creds_client_check(&state->tmp_creds,
2029 &state->rep_auth.cred);
2031 status = NT_STATUS_ACCESS_DENIED;
2032 tevent_req_nterror(req, status);
2033 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2037 if (tevent_req_nterror(req, result)) {
2038 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2042 dcerpc_binding_handle_set_timeout(state->binding_handle,
2043 state->old_timeout);
2045 *state->creds = state->tmp_creds;
2046 status = netlogon_creds_cli_store(state->context,
2048 if (tevent_req_nterror(req, status)) {
2049 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2053 tevent_req_done(req);
2056 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2060 if (tevent_req_is_nterror(req, &status)) {
2061 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2062 tevent_req_received(req);
2066 tevent_req_received(req);
2067 return NT_STATUS_OK;
2070 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2071 struct netlogon_creds_cli_context *context,
2072 struct dcerpc_binding_handle *b,
2073 const DATA_BLOB *new_password,
2074 const uint32_t *new_version)
2076 TALLOC_CTX *frame = talloc_stackframe();
2077 struct tevent_context *ev;
2078 struct tevent_req *req;
2079 NTSTATUS status = NT_STATUS_NO_MEMORY;
2081 ev = samba_tevent_context_init(frame);
2085 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2091 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2094 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2100 struct netlogon_creds_cli_LogonSamLogon_state {
2101 struct tevent_context *ev;
2102 struct netlogon_creds_cli_context *context;
2103 struct dcerpc_binding_handle *binding_handle;
2105 char *srv_name_slash;
2107 enum netr_LogonInfoClass logon_level;
2108 const union netr_LogonLevel *const_logon;
2109 union netr_LogonLevel *logon;
2112 uint16_t validation_level;
2113 union netr_Validation *validation;
2114 uint8_t authoritative;
2117 * do we need encryption at the application layer?
2121 bool try_validation6;
2124 * the read only credentials before we started the operation
2125 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2127 struct netlogon_creds_CredentialState *ro_creds;
2130 * The (locked) credentials used for the credential chain
2131 * used for netr_LogonSamLogonWithFlags() or
2132 * netr_LogonSamLogonWith().
2134 struct netlogon_creds_CredentialState *lk_creds;
2137 * While we have locked the global credentials (lk_creds above)
2138 * we operate an a temporary copy, because a server
2139 * may not support netr_LogonSamLogonWithFlags() and
2140 * didn't process our netr_Authenticator, so we need to
2141 * restart from lk_creds.
2143 struct netlogon_creds_CredentialState tmp_creds;
2144 struct netr_Authenticator req_auth;
2145 struct netr_Authenticator rep_auth;
2148 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2149 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2152 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2153 struct tevent_context *ev,
2154 struct netlogon_creds_cli_context *context,
2155 struct dcerpc_binding_handle *b,
2156 enum netr_LogonInfoClass logon_level,
2157 const union netr_LogonLevel *logon,
2160 struct tevent_req *req;
2161 struct netlogon_creds_cli_LogonSamLogon_state *state;
2163 req = tevent_req_create(mem_ctx, &state,
2164 struct netlogon_creds_cli_LogonSamLogon_state);
2170 state->context = context;
2171 state->binding_handle = b;
2173 state->logon_level = logon_level;
2174 state->const_logon = logon;
2175 state->flags = flags;
2177 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2178 context->server.computer);
2179 if (tevent_req_nomem(state->srv_name_slash, req)) {
2180 return tevent_req_post(req, ev);
2183 switch (logon_level) {
2184 case NetlogonInteractiveInformation:
2185 case NetlogonInteractiveTransitiveInformation:
2186 case NetlogonServiceInformation:
2187 case NetlogonServiceTransitiveInformation:
2188 case NetlogonGenericInformation:
2189 state->user_encrypt = true;
2192 case NetlogonNetworkInformation:
2193 case NetlogonNetworkTransitiveInformation:
2197 state->validation = talloc_zero(state, union netr_Validation);
2198 if (tevent_req_nomem(state->validation, req)) {
2199 return tevent_req_post(req, ev);
2202 netlogon_creds_cli_LogonSamLogon_start(req);
2203 if (!tevent_req_is_in_progress(req)) {
2204 return tevent_req_post(req, ev);
2208 * we defer all callbacks in order to cleanup
2209 * the database record.
2211 tevent_req_defer_callback(req, state->ev);
2215 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2218 struct netlogon_creds_cli_LogonSamLogon_state *state =
2219 tevent_req_data(req,
2220 struct netlogon_creds_cli_LogonSamLogon_state);
2222 if (state->lk_creds == NULL) {
2226 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2228 * This is a hack to recover from a bug in old
2229 * Samba servers, when LogonSamLogonEx() fails:
2231 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2233 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2235 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2236 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2237 * If the sign/seal check fails.
2239 * In that case we need to cleanup the netlogon session.
2241 * It's the job of the caller to disconnect the current
2242 * connection, if netlogon_creds_cli_LogonSamLogon()
2243 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2245 if (!state->context->server.try_logon_with) {
2246 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2250 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2251 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2252 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2253 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2254 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2255 TALLOC_FREE(state->lk_creds);
2259 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2262 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2264 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2266 struct netlogon_creds_cli_LogonSamLogon_state *state =
2267 tevent_req_data(req,
2268 struct netlogon_creds_cli_LogonSamLogon_state);
2269 struct tevent_req *subreq;
2271 enum dcerpc_AuthType auth_type;
2272 enum dcerpc_AuthLevel auth_level;
2274 TALLOC_FREE(state->ro_creds);
2275 TALLOC_FREE(state->logon);
2276 ZERO_STRUCTP(state->validation);
2278 dcerpc_binding_handle_auth_info(state->binding_handle,
2279 &auth_type, &auth_level);
2281 state->try_logon_ex = state->context->server.try_logon_ex;
2282 state->try_validation6 = state->context->server.try_validation6;
2284 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2285 state->try_logon_ex = false;
2288 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2289 state->try_validation6 = false;
2292 if (state->try_logon_ex) {
2293 if (state->try_validation6) {
2294 state->validation_level = 6;
2296 state->validation_level = 3;
2297 state->user_encrypt = true;
2300 state->logon = netlogon_creds_shallow_copy_logon(state,
2302 state->const_logon);
2303 if (tevent_req_nomem(state->logon, req)) {
2304 status = NT_STATUS_NO_MEMORY;
2305 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2309 if (state->user_encrypt) {
2310 status = netlogon_creds_cli_get(state->context,
2313 if (!NT_STATUS_IS_OK(status)) {
2314 status = NT_STATUS_ACCESS_DENIED;
2315 tevent_req_nterror(req, status);
2316 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2320 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2325 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2326 state->binding_handle,
2327 state->srv_name_slash,
2328 state->context->client.computer,
2331 state->validation_level,
2333 &state->authoritative,
2335 if (tevent_req_nomem(subreq, req)) {
2336 status = NT_STATUS_NO_MEMORY;
2337 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2340 tevent_req_set_callback(subreq,
2341 netlogon_creds_cli_LogonSamLogon_done,
2346 if (state->lk_creds == NULL) {
2347 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2349 if (tevent_req_nomem(subreq, req)) {
2350 status = NT_STATUS_NO_MEMORY;
2351 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2354 tevent_req_set_callback(subreq,
2355 netlogon_creds_cli_LogonSamLogon_done,
2360 state->tmp_creds = *state->lk_creds;
2361 netlogon_creds_client_authenticator(&state->tmp_creds,
2363 ZERO_STRUCT(state->rep_auth);
2365 state->logon = netlogon_creds_shallow_copy_logon(state,
2367 state->const_logon);
2368 if (tevent_req_nomem(state->logon, req)) {
2369 status = NT_STATUS_NO_MEMORY;
2370 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2374 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2378 state->validation_level = 3;
2380 if (state->context->server.try_logon_with) {
2381 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2382 state->binding_handle,
2383 state->srv_name_slash,
2384 state->context->client.computer,
2389 state->validation_level,
2391 &state->authoritative,
2393 if (tevent_req_nomem(subreq, req)) {
2394 status = NT_STATUS_NO_MEMORY;
2395 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2401 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2402 state->binding_handle,
2403 state->srv_name_slash,
2404 state->context->client.computer,
2409 state->validation_level,
2411 &state->authoritative);
2412 if (tevent_req_nomem(subreq, req)) {
2413 status = NT_STATUS_NO_MEMORY;
2414 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2419 tevent_req_set_callback(subreq,
2420 netlogon_creds_cli_LogonSamLogon_done,
2424 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2426 struct tevent_req *req =
2427 tevent_req_callback_data(subreq,
2429 struct netlogon_creds_cli_LogonSamLogon_state *state =
2430 tevent_req_data(req,
2431 struct netlogon_creds_cli_LogonSamLogon_state);
2436 if (state->try_logon_ex) {
2437 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2440 TALLOC_FREE(subreq);
2441 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2442 state->context->server.try_validation6 = false;
2443 state->context->server.try_logon_ex = false;
2444 netlogon_creds_cli_LogonSamLogon_start(req);
2447 if (tevent_req_nterror(req, status)) {
2448 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2452 if ((state->validation_level == 6) &&
2453 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2454 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2455 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2457 state->context->server.try_validation6 = false;
2458 netlogon_creds_cli_LogonSamLogon_start(req);
2462 if (tevent_req_nterror(req, result)) {
2463 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2467 if (state->ro_creds == NULL) {
2468 tevent_req_done(req);
2472 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2475 * We got a race, lets retry with on authenticator
2478 * netlogon_creds_cli_LogonSamLogon_start()
2479 * will TALLOC_FREE(state->ro_creds);
2481 state->try_logon_ex = false;
2482 netlogon_creds_cli_LogonSamLogon_start(req);
2486 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2487 state->validation_level,
2490 tevent_req_done(req);
2494 if (state->lk_creds == NULL) {
2495 status = netlogon_creds_cli_lock_recv(subreq, state,
2497 TALLOC_FREE(subreq);
2498 if (tevent_req_nterror(req, status)) {
2499 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2503 netlogon_creds_cli_LogonSamLogon_start(req);
2507 if (state->context->server.try_logon_with) {
2508 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2511 TALLOC_FREE(subreq);
2512 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2513 state->context->server.try_logon_with = false;
2514 netlogon_creds_cli_LogonSamLogon_start(req);
2517 if (tevent_req_nterror(req, status)) {
2518 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2522 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2525 TALLOC_FREE(subreq);
2526 if (tevent_req_nterror(req, status)) {
2527 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2532 ok = netlogon_creds_client_check(&state->tmp_creds,
2533 &state->rep_auth.cred);
2535 status = NT_STATUS_ACCESS_DENIED;
2536 tevent_req_nterror(req, status);
2537 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2541 *state->lk_creds = state->tmp_creds;
2542 status = netlogon_creds_cli_store(state->context,
2544 if (tevent_req_nterror(req, status)) {
2545 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2549 if (tevent_req_nterror(req, result)) {
2550 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2554 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2555 state->validation_level,
2558 tevent_req_done(req);
2561 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2562 TALLOC_CTX *mem_ctx,
2563 uint16_t *validation_level,
2564 union netr_Validation **validation,
2565 uint8_t *authoritative,
2568 struct netlogon_creds_cli_LogonSamLogon_state *state =
2569 tevent_req_data(req,
2570 struct netlogon_creds_cli_LogonSamLogon_state);
2573 /* authoritative is also returned on error */
2574 *authoritative = state->authoritative;
2576 if (tevent_req_is_nterror(req, &status)) {
2577 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2578 tevent_req_received(req);
2582 *validation_level = state->validation_level;
2583 *validation = talloc_move(mem_ctx, &state->validation);
2584 *flags = state->flags;
2586 tevent_req_received(req);
2587 return NT_STATUS_OK;
2590 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2591 struct netlogon_creds_cli_context *context,
2592 struct dcerpc_binding_handle *b,
2593 enum netr_LogonInfoClass logon_level,
2594 const union netr_LogonLevel *logon,
2595 TALLOC_CTX *mem_ctx,
2596 uint16_t *validation_level,
2597 union netr_Validation **validation,
2598 uint8_t *authoritative,
2601 TALLOC_CTX *frame = talloc_stackframe();
2602 struct tevent_context *ev;
2603 struct tevent_req *req;
2604 NTSTATUS status = NT_STATUS_NO_MEMORY;
2606 ev = samba_tevent_context_init(frame);
2610 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2616 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2619 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2629 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2630 struct tevent_context *ev;
2631 struct netlogon_creds_cli_context *context;
2632 struct dcerpc_binding_handle *binding_handle;
2634 char *srv_name_slash;
2635 enum dcerpc_AuthType auth_type;
2636 enum dcerpc_AuthLevel auth_level;
2638 const char *site_name;
2640 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2642 struct netlogon_creds_CredentialState *creds;
2643 struct netlogon_creds_CredentialState tmp_creds;
2644 struct netr_Authenticator req_auth;
2645 struct netr_Authenticator rep_auth;
2648 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2650 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2652 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2653 struct tevent_context *ev,
2654 struct netlogon_creds_cli_context *context,
2655 struct dcerpc_binding_handle *b,
2656 const char *site_name,
2658 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2660 struct tevent_req *req;
2661 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2662 struct tevent_req *subreq;
2664 req = tevent_req_create(mem_ctx, &state,
2665 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2671 state->context = context;
2672 state->binding_handle = b;
2674 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2675 context->server.computer);
2676 if (tevent_req_nomem(state->srv_name_slash, req)) {
2677 return tevent_req_post(req, ev);
2680 state->site_name = site_name;
2681 state->dns_ttl = dns_ttl;
2682 state->dns_names = dns_names;
2684 dcerpc_binding_handle_auth_info(state->binding_handle,
2686 &state->auth_level);
2688 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2690 if (tevent_req_nomem(subreq, req)) {
2691 return tevent_req_post(req, ev);
2694 tevent_req_set_callback(subreq,
2695 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2701 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2704 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2705 tevent_req_data(req,
2706 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2708 if (state->creds == NULL) {
2712 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2713 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2714 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2715 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2716 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2717 TALLOC_FREE(state->creds);
2721 netlogon_creds_cli_delete(state->context, &state->creds);
2724 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2726 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2728 struct tevent_req *req =
2729 tevent_req_callback_data(subreq,
2731 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2732 tevent_req_data(req,
2733 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2736 status = netlogon_creds_cli_lock_recv(subreq, state,
2738 TALLOC_FREE(subreq);
2739 if (tevent_req_nterror(req, status)) {
2743 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2744 switch (state->auth_level) {
2745 case DCERPC_AUTH_LEVEL_INTEGRITY:
2746 case DCERPC_AUTH_LEVEL_PRIVACY:
2749 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2753 uint32_t tmp = state->creds->negotiate_flags;
2755 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2757 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2758 * it should be used, which means
2759 * we had a chance to verify no downgrade
2762 * This relies on netlogon_creds_cli_check*
2763 * being called before, as first request after
2766 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2772 * we defer all callbacks in order to cleanup
2773 * the database record.
2775 tevent_req_defer_callback(req, state->ev);
2777 state->tmp_creds = *state->creds;
2778 netlogon_creds_client_authenticator(&state->tmp_creds,
2780 ZERO_STRUCT(state->rep_auth);
2782 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2783 state->binding_handle,
2784 state->srv_name_slash,
2785 state->tmp_creds.computer_name,
2791 if (tevent_req_nomem(subreq, req)) {
2792 status = NT_STATUS_NO_MEMORY;
2793 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2797 tevent_req_set_callback(subreq,
2798 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2802 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2804 struct tevent_req *req =
2805 tevent_req_callback_data(subreq,
2807 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2808 tevent_req_data(req,
2809 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2815 * We use state->dns_names as the memory context, as this is
2816 * the only in/out variable and it has been overwritten by the
2817 * out parameter from the server.
2819 * We need to preserve the return value until the caller can use it.
2821 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2823 TALLOC_FREE(subreq);
2824 if (tevent_req_nterror(req, status)) {
2825 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2829 ok = netlogon_creds_client_check(&state->tmp_creds,
2830 &state->rep_auth.cred);
2832 status = NT_STATUS_ACCESS_DENIED;
2833 tevent_req_nterror(req, status);
2834 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2838 *state->creds = state->tmp_creds;
2839 status = netlogon_creds_cli_store(state->context,
2842 if (tevent_req_nterror(req, status)) {
2843 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2847 if (tevent_req_nterror(req, result)) {
2848 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2852 tevent_req_done(req);
2855 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2859 if (tevent_req_is_nterror(req, &status)) {
2860 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2861 tevent_req_received(req);
2865 tevent_req_received(req);
2866 return NT_STATUS_OK;
2869 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2870 struct netlogon_creds_cli_context *context,
2871 struct dcerpc_binding_handle *b,
2872 const char *site_name,
2874 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2876 TALLOC_CTX *frame = talloc_stackframe();
2877 struct tevent_context *ev;
2878 struct tevent_req *req;
2879 NTSTATUS status = NT_STATUS_NO_MEMORY;
2881 ev = samba_tevent_context_init(frame);
2885 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2892 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2895 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2901 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2902 struct tevent_context *ev;
2903 struct netlogon_creds_cli_context *context;
2904 struct dcerpc_binding_handle *binding_handle;
2906 char *srv_name_slash;
2907 enum dcerpc_AuthType auth_type;
2908 enum dcerpc_AuthLevel auth_level;
2910 struct samr_Password new_owf_password;
2911 struct samr_Password old_owf_password;
2912 struct netr_TrustInfo *trust_info;
2914 struct netlogon_creds_CredentialState *creds;
2915 struct netlogon_creds_CredentialState tmp_creds;
2916 struct netr_Authenticator req_auth;
2917 struct netr_Authenticator rep_auth;
2920 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2922 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2924 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2925 struct tevent_context *ev,
2926 struct netlogon_creds_cli_context *context,
2927 struct dcerpc_binding_handle *b)
2929 struct tevent_req *req;
2930 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2931 struct tevent_req *subreq;
2933 req = tevent_req_create(mem_ctx, &state,
2934 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2940 state->context = context;
2941 state->binding_handle = b;
2943 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2944 context->server.computer);
2945 if (tevent_req_nomem(state->srv_name_slash, req)) {
2946 return tevent_req_post(req, ev);
2949 dcerpc_binding_handle_auth_info(state->binding_handle,
2951 &state->auth_level);
2953 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2955 if (tevent_req_nomem(subreq, req)) {
2956 return tevent_req_post(req, ev);
2959 tevent_req_set_callback(subreq,
2960 netlogon_creds_cli_ServerGetTrustInfo_locked,
2966 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2969 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2970 tevent_req_data(req,
2971 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2973 if (state->creds == NULL) {
2977 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2978 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2979 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2980 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2981 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2982 TALLOC_FREE(state->creds);
2986 netlogon_creds_cli_delete(state->context, &state->creds);
2989 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2991 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2993 struct tevent_req *req =
2994 tevent_req_callback_data(subreq,
2996 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2997 tevent_req_data(req,
2998 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3001 status = netlogon_creds_cli_lock_recv(subreq, state,
3003 TALLOC_FREE(subreq);
3004 if (tevent_req_nterror(req, status)) {
3008 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3009 switch (state->auth_level) {
3010 case DCERPC_AUTH_LEVEL_PRIVACY:
3013 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3017 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3022 * we defer all callbacks in order to cleanup
3023 * the database record.
3025 tevent_req_defer_callback(req, state->ev);
3027 state->tmp_creds = *state->creds;
3028 netlogon_creds_client_authenticator(&state->tmp_creds,
3030 ZERO_STRUCT(state->rep_auth);
3032 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3033 state->binding_handle,
3034 state->srv_name_slash,
3035 state->tmp_creds.account_name,
3036 state->tmp_creds.secure_channel_type,
3037 state->tmp_creds.computer_name,
3040 &state->new_owf_password,
3041 &state->old_owf_password,
3042 &state->trust_info);
3043 if (tevent_req_nomem(subreq, req)) {
3044 status = NT_STATUS_NO_MEMORY;
3045 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3049 tevent_req_set_callback(subreq,
3050 netlogon_creds_cli_ServerGetTrustInfo_done,
3054 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3056 struct tevent_req *req =
3057 tevent_req_callback_data(subreq,
3059 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3060 tevent_req_data(req,
3061 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3064 const struct samr_Password zero = {};
3069 * We use state->dns_names as the memory context, as this is
3070 * the only in/out variable and it has been overwritten by the
3071 * out parameter from the server.
3073 * We need to preserve the return value until the caller can use it.
3075 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3076 TALLOC_FREE(subreq);
3077 if (tevent_req_nterror(req, status)) {
3078 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3082 ok = netlogon_creds_client_check(&state->tmp_creds,
3083 &state->rep_auth.cred);
3085 status = NT_STATUS_ACCESS_DENIED;
3086 tevent_req_nterror(req, status);
3087 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3091 cmp = memcmp(state->new_owf_password.hash,
3092 zero.hash, sizeof(zero.hash));
3094 netlogon_creds_des_decrypt(&state->tmp_creds,
3095 &state->new_owf_password);
3097 cmp = memcmp(state->old_owf_password.hash,
3098 zero.hash, sizeof(zero.hash));
3100 netlogon_creds_des_decrypt(&state->tmp_creds,
3101 &state->old_owf_password);
3104 *state->creds = state->tmp_creds;
3105 status = netlogon_creds_cli_store(state->context,
3107 if (tevent_req_nterror(req, status)) {
3108 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3112 if (tevent_req_nterror(req, result)) {
3113 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3117 tevent_req_done(req);
3120 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3121 TALLOC_CTX *mem_ctx,
3122 struct samr_Password *new_owf_password,
3123 struct samr_Password *old_owf_password,
3124 struct netr_TrustInfo **trust_info)
3126 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3127 tevent_req_data(req,
3128 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3131 if (tevent_req_is_nterror(req, &status)) {
3132 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3133 tevent_req_received(req);
3137 if (new_owf_password != NULL) {
3138 *new_owf_password = state->new_owf_password;
3140 if (old_owf_password != NULL) {
3141 *old_owf_password = state->old_owf_password;
3143 if (trust_info != NULL) {
3144 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3147 tevent_req_received(req);
3148 return NT_STATUS_OK;
3151 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3152 struct netlogon_creds_cli_context *context,
3153 struct dcerpc_binding_handle *b,