param: Rename variable used for lp_abort_shutdown_script szAbortShutdownScript
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob88893ad7d3a69fdd82cd4b0b28f073e5da26bcc8
1 /*
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/>.
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include <tevent.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/server_id.h"
35 #include "netlogon_creds_cli.h"
36 #include "source3/include/messages.h"
37 #include "source3/include/g_lock.h"
39 struct netlogon_creds_cli_locked_state;
41 struct netlogon_creds_cli_context {
42 struct {
43 const char *computer;
44 const char *account;
45 uint32_t proposed_flags;
46 uint32_t required_flags;
47 enum netr_SchannelType type;
48 enum dcerpc_AuthLevel auth_level;
49 } client;
51 struct {
52 const char *computer;
53 const char *netbios_domain;
54 uint32_t cached_flags;
55 bool try_validation6;
56 bool try_logon_ex;
57 bool try_logon_with;
58 } server;
60 struct {
61 const char *key_name;
62 TDB_DATA key_data;
63 struct db_context *ctx;
64 struct g_lock_ctx *g_ctx;
65 struct netlogon_creds_cli_locked_state *locked_state;
66 } db;
69 struct netlogon_creds_cli_locked_state {
70 struct netlogon_creds_cli_context *context;
71 bool is_glocked;
72 struct netlogon_creds_CredentialState *creds;
75 static int netlogon_creds_cli_locked_state_destructor(
76 struct netlogon_creds_cli_locked_state *state)
78 struct netlogon_creds_cli_context *context = state->context;
80 if (context == NULL) {
81 return 0;
84 if (context->db.locked_state == state) {
85 context->db.locked_state = NULL;
88 if (state->is_glocked) {
89 g_lock_unlock(context->db.g_ctx,
90 context->db.key_name);
93 return 0;
96 static NTSTATUS netlogon_creds_cli_context_common(
97 const char *client_computer,
98 const char *client_account,
99 enum netr_SchannelType type,
100 enum dcerpc_AuthLevel auth_level,
101 uint32_t proposed_flags,
102 uint32_t required_flags,
103 const char *server_computer,
104 const char *server_netbios_domain,
105 TALLOC_CTX *mem_ctx,
106 struct netlogon_creds_cli_context **_context)
108 struct netlogon_creds_cli_context *context = NULL;
109 TALLOC_CTX *frame = talloc_stackframe();
110 char *_key_name = NULL;
111 char *server_netbios_name = NULL;
112 char *p = NULL;
114 *_context = NULL;
116 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
117 if (context == NULL) {
118 TALLOC_FREE(frame);
119 return NT_STATUS_NO_MEMORY;
122 context->client.computer = talloc_strdup(context, client_computer);
123 if (context->client.computer == NULL) {
124 TALLOC_FREE(context);
125 TALLOC_FREE(frame);
126 return NT_STATUS_NO_MEMORY;
129 context->client.account = talloc_strdup(context, client_account);
130 if (context->client.account == NULL) {
131 TALLOC_FREE(context);
132 TALLOC_FREE(frame);
133 return NT_STATUS_NO_MEMORY;
136 context->client.proposed_flags = proposed_flags;
137 context->client.required_flags = required_flags;
138 context->client.type = type;
139 context->client.auth_level = auth_level;
141 context->server.computer = talloc_strdup(context, server_computer);
142 if (context->server.computer == NULL) {
143 TALLOC_FREE(context);
144 TALLOC_FREE(frame);
145 return NT_STATUS_NO_MEMORY;
148 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
149 if (context->server.netbios_domain == NULL) {
150 TALLOC_FREE(context);
151 TALLOC_FREE(frame);
152 return NT_STATUS_NO_MEMORY;
156 * TODO:
157 * Force the callers to provide a unique
158 * value for server_computer and use this directly.
160 * For now we have to deal with
161 * "HOSTNAME" vs. "hostname.example.com".
163 server_netbios_name = talloc_strdup(frame, server_computer);
164 if (server_netbios_name == NULL) {
165 TALLOC_FREE(context);
166 TALLOC_FREE(frame);
167 return NT_STATUS_NO_MEMORY;
170 p = strchr(server_netbios_name, '.');
171 if (p != NULL) {
172 p[0] = '\0';
175 _key_name = talloc_asprintf(frame, "CLI[%s/%s]/SRV[%s/%s]",
176 client_computer,
177 client_account,
178 server_netbios_name,
179 server_netbios_domain);
180 if (_key_name == NULL) {
181 TALLOC_FREE(context);
182 TALLOC_FREE(frame);
183 return NT_STATUS_NO_MEMORY;
186 context->db.key_name = talloc_strdup_upper(context, _key_name);
187 if (context->db.key_name == NULL) {
188 TALLOC_FREE(context);
189 TALLOC_FREE(frame);
190 return NT_STATUS_NO_MEMORY;
193 context->db.key_data = string_term_tdb_data(context->db.key_name);
195 *_context = context;
196 TALLOC_FREE(frame);
197 return NT_STATUS_OK;
200 static struct db_context *netlogon_creds_cli_global_db;
202 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
204 if (netlogon_creds_cli_global_db != NULL) {
205 return NT_STATUS_INVALID_PARAMETER_MIX;
208 netlogon_creds_cli_global_db = talloc_move(talloc_autofree_context(), db);
209 return NT_STATUS_OK;
212 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
214 char *fname;
215 struct db_context *global_db;
217 if (netlogon_creds_cli_global_db != NULL) {
218 return NT_STATUS_OK;
221 fname = lpcfg_private_db_path(talloc_autofree_context(), lp_ctx, "netlogon_creds_cli");
222 if (fname == NULL) {
223 return NT_STATUS_NO_MEMORY;
226 global_db = dbwrap_local_open(talloc_autofree_context(), lp_ctx,
227 fname, 0,
228 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
229 O_RDWR|O_CREAT,
230 0600, DBWRAP_LOCK_ORDER_2);
231 if (global_db == NULL) {
232 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
233 fname, strerror(errno)));
234 talloc_free(fname);
235 return NT_STATUS_NO_MEMORY;
237 TALLOC_FREE(fname);
239 netlogon_creds_cli_global_db = global_db;
240 return NT_STATUS_OK;
243 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
244 struct messaging_context *msg_ctx,
245 const char *client_account,
246 enum netr_SchannelType type,
247 const char *server_computer,
248 const char *server_netbios_domain,
249 TALLOC_CTX *mem_ctx,
250 struct netlogon_creds_cli_context **_context)
252 TALLOC_CTX *frame = talloc_stackframe();
253 NTSTATUS status;
254 struct netlogon_creds_cli_context *context = NULL;
255 const char *client_computer;
256 uint32_t proposed_flags;
257 uint32_t required_flags = 0;
258 bool reject_md5_servers = false;
259 bool require_strong_key = false;
260 int require_sign_or_seal = true;
261 bool seal_secure_channel = true;
262 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
263 bool neutralize_nt4_emulation = false;
265 *_context = NULL;
267 client_computer = lpcfg_netbios_name(lp_ctx);
268 if (strlen(client_computer) > 15) {
269 return NT_STATUS_INVALID_PARAMETER_MIX;
273 * allow overwrite per domain
274 * reject md5 servers:<netbios_domain>
276 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
277 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
278 "reject md5 servers",
279 server_netbios_domain,
280 reject_md5_servers);
283 * allow overwrite per domain
284 * require strong key:<netbios_domain>
286 require_strong_key = lpcfg_require_strong_key(lp_ctx);
287 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
288 "require strong key",
289 server_netbios_domain,
290 require_strong_key);
293 * allow overwrite per domain
294 * client schannel:<netbios_domain>
296 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
297 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
298 "client schannel",
299 server_netbios_domain,
300 require_sign_or_seal);
303 * allow overwrite per domain
304 * winbind sealed pipes:<netbios_domain>
306 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
307 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
308 "winbind sealed pipes",
309 server_netbios_domain,
310 seal_secure_channel);
313 * allow overwrite per domain
314 * neutralize nt4 emulation:<netbios_domain>
316 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
317 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
318 "neutralize nt4 emulation",
319 server_netbios_domain,
320 neutralize_nt4_emulation);
322 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
323 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
325 switch (type) {
326 case SEC_CHAN_WKSTA:
327 if (lpcfg_security(lp_ctx) == SEC_ADS) {
329 * AD domains should be secure
331 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
332 require_sign_or_seal = true;
333 require_strong_key = true;
335 break;
337 case SEC_CHAN_DOMAIN:
338 break;
340 case SEC_CHAN_DNS_DOMAIN:
342 * AD domains should be secure
344 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
345 require_sign_or_seal = true;
346 require_strong_key = true;
347 neutralize_nt4_emulation = true;
348 break;
350 case SEC_CHAN_BDC:
351 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
352 require_sign_or_seal = true;
353 require_strong_key = true;
354 break;
356 case SEC_CHAN_RODC:
357 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
358 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
359 require_sign_or_seal = true;
360 require_strong_key = true;
361 neutralize_nt4_emulation = true;
362 break;
364 default:
365 TALLOC_FREE(frame);
366 return NT_STATUS_INVALID_PARAMETER;
369 if (neutralize_nt4_emulation) {
370 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
373 if (require_sign_or_seal == false) {
374 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
375 } else {
376 required_flags |= NETLOGON_NEG_ARCFOUR;
377 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
380 if (reject_md5_servers) {
381 required_flags |= NETLOGON_NEG_ARCFOUR;
382 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
383 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
384 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
387 if (require_strong_key) {
388 required_flags |= NETLOGON_NEG_ARCFOUR;
389 required_flags |= NETLOGON_NEG_STRONG_KEYS;
390 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
393 proposed_flags |= required_flags;
395 if (seal_secure_channel) {
396 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
397 } else {
398 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
401 status = netlogon_creds_cli_context_common(client_computer,
402 client_account,
403 type,
404 auth_level,
405 proposed_flags,
406 required_flags,
407 server_computer,
408 server_netbios_domain,
409 mem_ctx,
410 &context);
411 if (!NT_STATUS_IS_OK(status)) {
412 TALLOC_FREE(frame);
413 return status;
416 if (msg_ctx != NULL) {
417 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
418 if (context->db.g_ctx == NULL) {
419 TALLOC_FREE(context);
420 TALLOC_FREE(frame);
421 return NT_STATUS_NO_MEMORY;
425 if (netlogon_creds_cli_global_db != NULL) {
426 context->db.ctx = netlogon_creds_cli_global_db;
427 *_context = context;
428 TALLOC_FREE(frame);
429 return NT_STATUS_OK;
432 status = netlogon_creds_cli_open_global_db(lp_ctx);
433 if (!NT_STATUS_IS_OK(status)) {
434 TALLOC_FREE(context);
435 TALLOC_FREE(frame);
436 return NT_STATUS_NO_MEMORY;
439 context->db.ctx = netlogon_creds_cli_global_db;
440 *_context = context;
441 TALLOC_FREE(frame);
442 return NT_STATUS_OK;
445 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
446 const char *client_account,
447 enum netr_SchannelType type,
448 uint32_t proposed_flags,
449 uint32_t required_flags,
450 enum dcerpc_AuthLevel auth_level,
451 const char *server_computer,
452 const char *server_netbios_domain,
453 TALLOC_CTX *mem_ctx,
454 struct netlogon_creds_cli_context **_context)
456 NTSTATUS status;
457 struct netlogon_creds_cli_context *context = NULL;
459 *_context = NULL;
461 status = netlogon_creds_cli_context_common(client_computer,
462 client_account,
463 type,
464 auth_level,
465 proposed_flags,
466 required_flags,
467 server_computer,
468 server_netbios_domain,
469 mem_ctx,
470 &context);
471 if (!NT_STATUS_IS_OK(status)) {
472 return status;
475 context->db.ctx = db_open_rbt(context);
476 if (context->db.ctx == NULL) {
477 talloc_free(context);
478 return NT_STATUS_NO_MEMORY;
481 *_context = context;
482 return NT_STATUS_OK;
485 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
486 struct netlogon_creds_cli_context *context)
488 return context->client.auth_level;
491 struct netlogon_creds_cli_fetch_state {
492 TALLOC_CTX *mem_ctx;
493 struct netlogon_creds_CredentialState *creds;
494 uint32_t required_flags;
495 NTSTATUS status;
498 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
499 void *private_data)
501 struct netlogon_creds_cli_fetch_state *state =
502 (struct netlogon_creds_cli_fetch_state *)private_data;
503 enum ndr_err_code ndr_err;
504 DATA_BLOB blob;
505 uint32_t tmp_flags;
507 state->creds = talloc_zero(state->mem_ctx,
508 struct netlogon_creds_CredentialState);
509 if (state->creds == NULL) {
510 state->status = NT_STATUS_NO_MEMORY;
511 return;
514 blob.data = data.dptr;
515 blob.length = data.dsize;
517 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
518 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
519 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
520 TALLOC_FREE(state->creds);
521 state->status = ndr_map_error2ntstatus(ndr_err);
522 return;
525 tmp_flags = state->creds->negotiate_flags;
526 tmp_flags &= state->required_flags;
527 if (tmp_flags != state->required_flags) {
528 TALLOC_FREE(state->creds);
529 state->status = NT_STATUS_DOWNGRADE_DETECTED;
530 return;
533 state->status = NT_STATUS_OK;
536 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
537 TALLOC_CTX *mem_ctx,
538 struct netlogon_creds_CredentialState **_creds)
540 NTSTATUS status;
541 struct netlogon_creds_cli_fetch_state fstate = {
542 .mem_ctx = mem_ctx,
543 .status = NT_STATUS_INTERNAL_ERROR,
544 .required_flags = context->client.required_flags,
546 static const struct netr_Credential zero_creds;
548 *_creds = NULL;
550 status = dbwrap_parse_record(context->db.ctx,
551 context->db.key_data,
552 netlogon_creds_cli_fetch_parser,
553 &fstate);
554 if (!NT_STATUS_IS_OK(status)) {
555 return status;
557 status = fstate.status;
558 if (!NT_STATUS_IS_OK(status)) {
559 return status;
563 * mark it as invalid for step operations.
565 fstate.creds->sequence = 0;
566 fstate.creds->seed = zero_creds;
567 fstate.creds->client = zero_creds;
568 fstate.creds->server = zero_creds;
570 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
571 *_creds = fstate.creds;
572 return NT_STATUS_OK;
576 * It is really important to try SamLogonEx here,
577 * because multiple processes can talk to the same
578 * domain controller, without using the credential
579 * chain.
581 * With a normal SamLogon call, we must keep the
582 * credentials chain updated and intact between all
583 * users of the machine account (which would imply
584 * cross-node communication for every NTLM logon).
586 * The credentials chain is not per NETLOGON pipe
587 * connection, but globally on the server/client pair
588 * by computer name, while the client is free to use
589 * any computer name. We include the cluster node number
590 * in our computer name in order to avoid cross node
591 * coordination of the credential chain.
593 * It's also important to use NetlogonValidationSamInfo4 (6),
594 * because it relies on the rpc transport encryption
595 * and avoids using the global netlogon schannel
596 * session key to en/decrypt secret information
597 * like the user_session_key for network logons.
599 * [MS-APDS] 3.1.5.2 NTLM Network Logon
600 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
601 * NETLOGON_NEG_AUTHENTICATED_RPC set together
602 * are the indication that the server supports
603 * NetlogonValidationSamInfo4 (6). And it must only
604 * be used if "SealSecureChannel" is used.
606 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
607 * check is done in netlogon_creds_cli_LogonSamLogon*().
609 context->server.cached_flags = fstate.creds->negotiate_flags;
610 context->server.try_validation6 = true;
611 context->server.try_logon_ex = true;
612 context->server.try_logon_with = true;
614 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
615 context->server.try_validation6 = false;
616 context->server.try_logon_ex = false;
618 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
619 context->server.try_validation6 = false;
622 *_creds = fstate.creds;
623 return NT_STATUS_OK;
626 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
627 const struct netlogon_creds_CredentialState *creds1)
629 TALLOC_CTX *frame = talloc_stackframe();
630 struct netlogon_creds_CredentialState *creds2;
631 DATA_BLOB blob1;
632 DATA_BLOB blob2;
633 NTSTATUS status;
634 enum ndr_err_code ndr_err;
635 int cmp;
637 status = netlogon_creds_cli_get(context, frame, &creds2);
638 if (!NT_STATUS_IS_OK(status)) {
639 TALLOC_FREE(frame);
640 return false;
643 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
644 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
645 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
646 TALLOC_FREE(frame);
647 return false;
650 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
651 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
652 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
653 TALLOC_FREE(frame);
654 return false;
657 if (blob1.length != blob2.length) {
658 TALLOC_FREE(frame);
659 return false;
662 cmp = memcmp(blob1.data, blob2.data, blob1.length);
663 if (cmp != 0) {
664 TALLOC_FREE(frame);
665 return false;
668 TALLOC_FREE(frame);
669 return true;
672 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
673 struct netlogon_creds_CredentialState **_creds)
675 struct netlogon_creds_CredentialState *creds = *_creds;
676 NTSTATUS status;
677 enum ndr_err_code ndr_err;
678 DATA_BLOB blob;
679 TDB_DATA data;
681 *_creds = NULL;
683 if (context->db.locked_state == NULL) {
685 * this was not the result of netlogon_creds_cli_lock*()
687 TALLOC_FREE(creds);
688 return NT_STATUS_INVALID_PAGE_PROTECTION;
691 if (context->db.locked_state->creds != creds) {
693 * this was not the result of netlogon_creds_cli_lock*()
695 TALLOC_FREE(creds);
696 return NT_STATUS_INVALID_PAGE_PROTECTION;
699 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
700 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
701 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
702 TALLOC_FREE(creds);
703 status = ndr_map_error2ntstatus(ndr_err);
704 return status;
707 data.dptr = blob.data;
708 data.dsize = blob.length;
710 status = dbwrap_store(context->db.ctx,
711 context->db.key_data,
712 data, TDB_REPLACE);
713 TALLOC_FREE(creds);
714 if (!NT_STATUS_IS_OK(status)) {
715 return status;
718 return NT_STATUS_OK;
721 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
722 struct netlogon_creds_CredentialState **_creds)
724 struct netlogon_creds_CredentialState *creds = *_creds;
725 NTSTATUS status;
727 *_creds = NULL;
729 if (context->db.locked_state == NULL) {
731 * this was not the result of netlogon_creds_cli_lock*()
733 TALLOC_FREE(creds);
734 return NT_STATUS_INVALID_PAGE_PROTECTION;
737 if (context->db.locked_state->creds != creds) {
739 * this was not the result of netlogon_creds_cli_lock*()
741 TALLOC_FREE(creds);
742 return NT_STATUS_INVALID_PAGE_PROTECTION;
745 status = dbwrap_delete(context->db.ctx,
746 context->db.key_data);
747 TALLOC_FREE(creds);
748 if (!NT_STATUS_IS_OK(status)) {
749 return status;
752 return NT_STATUS_OK;
755 struct netlogon_creds_cli_lock_state {
756 struct netlogon_creds_cli_locked_state *locked_state;
757 struct netlogon_creds_CredentialState *creds;
760 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
761 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
763 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
764 struct tevent_context *ev,
765 struct netlogon_creds_cli_context *context)
767 struct tevent_req *req;
768 struct netlogon_creds_cli_lock_state *state;
769 struct netlogon_creds_cli_locked_state *locked_state;
770 struct tevent_req *subreq;
772 req = tevent_req_create(mem_ctx, &state,
773 struct netlogon_creds_cli_lock_state);
774 if (req == NULL) {
775 return NULL;
778 if (context->db.locked_state != NULL) {
779 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
780 return tevent_req_post(req, ev);
783 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
784 if (tevent_req_nomem(locked_state, req)) {
785 return tevent_req_post(req, ev);
787 talloc_set_destructor(locked_state,
788 netlogon_creds_cli_locked_state_destructor);
789 locked_state->context = context;
791 context->db.locked_state = locked_state;
792 state->locked_state = locked_state;
794 if (context->db.g_ctx == NULL) {
795 netlogon_creds_cli_lock_fetch(req);
796 if (!tevent_req_is_in_progress(req)) {
797 return tevent_req_post(req, ev);
800 return req;
803 subreq = g_lock_lock_send(state, ev,
804 context->db.g_ctx,
805 context->db.key_name,
806 G_LOCK_WRITE);
807 if (tevent_req_nomem(subreq, req)) {
808 return tevent_req_post(req, ev);
810 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
812 return req;
815 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
817 struct tevent_req *req =
818 tevent_req_callback_data(subreq,
819 struct tevent_req);
820 struct netlogon_creds_cli_lock_state *state =
821 tevent_req_data(req,
822 struct netlogon_creds_cli_lock_state);
823 NTSTATUS status;
825 status = g_lock_lock_recv(subreq);
826 TALLOC_FREE(subreq);
827 if (tevent_req_nterror(req, status)) {
828 return;
830 state->locked_state->is_glocked = true;
832 netlogon_creds_cli_lock_fetch(req);
835 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
837 struct netlogon_creds_cli_lock_state *state =
838 tevent_req_data(req,
839 struct netlogon_creds_cli_lock_state);
840 struct netlogon_creds_cli_context *context = state->locked_state->context;
841 struct netlogon_creds_cli_fetch_state fstate = {
842 .status = NT_STATUS_INTERNAL_ERROR,
843 .required_flags = context->client.required_flags,
845 NTSTATUS status;
847 fstate.mem_ctx = state;
848 status = dbwrap_parse_record(context->db.ctx,
849 context->db.key_data,
850 netlogon_creds_cli_fetch_parser,
851 &fstate);
852 if (tevent_req_nterror(req, status)) {
853 return;
855 status = fstate.status;
856 if (tevent_req_nterror(req, status)) {
857 return;
860 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
861 state->creds = fstate.creds;
862 tevent_req_done(req);
863 return;
866 context->server.cached_flags = fstate.creds->negotiate_flags;
867 context->server.try_validation6 = true;
868 context->server.try_logon_ex = true;
869 context->server.try_logon_with = true;
871 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
872 context->server.try_validation6 = false;
873 context->server.try_logon_ex = false;
875 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
876 context->server.try_validation6 = false;
879 state->creds = fstate.creds;
880 tevent_req_done(req);
881 return;
884 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
885 TALLOC_CTX *mem_ctx,
886 struct netlogon_creds_CredentialState **creds)
888 struct netlogon_creds_cli_lock_state *state =
889 tevent_req_data(req,
890 struct netlogon_creds_cli_lock_state);
891 NTSTATUS status;
893 if (tevent_req_is_nterror(req, &status)) {
894 tevent_req_received(req);
895 return status;
898 talloc_steal(state->creds, state->locked_state);
899 state->locked_state->creds = state->creds;
900 *creds = talloc_move(mem_ctx, &state->creds);
901 tevent_req_received(req);
902 return NT_STATUS_OK;
905 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
906 TALLOC_CTX *mem_ctx,
907 struct netlogon_creds_CredentialState **creds)
909 TALLOC_CTX *frame = talloc_stackframe();
910 struct tevent_context *ev;
911 struct tevent_req *req;
912 NTSTATUS status = NT_STATUS_NO_MEMORY;
914 ev = samba_tevent_context_init(frame);
915 if (ev == NULL) {
916 goto fail;
918 req = netlogon_creds_cli_lock_send(frame, ev, context);
919 if (req == NULL) {
920 goto fail;
922 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
923 goto fail;
925 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
926 fail:
927 TALLOC_FREE(frame);
928 return status;
931 struct netlogon_creds_cli_auth_state {
932 struct tevent_context *ev;
933 struct netlogon_creds_cli_context *context;
934 struct dcerpc_binding_handle *binding_handle;
935 struct samr_Password current_nt_hash;
936 struct samr_Password previous_nt_hash;
937 struct samr_Password used_nt_hash;
938 char *srv_name_slash;
939 uint32_t current_flags;
940 struct netr_Credential client_challenge;
941 struct netr_Credential server_challenge;
942 struct netlogon_creds_CredentialState *creds;
943 struct netr_Credential client_credential;
944 struct netr_Credential server_credential;
945 uint32_t rid;
946 bool try_auth3;
947 bool try_auth2;
948 bool require_auth2;
949 bool try_previous_nt_hash;
950 struct netlogon_creds_cli_locked_state *locked_state;
953 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
954 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
956 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
957 struct tevent_context *ev,
958 struct netlogon_creds_cli_context *context,
959 struct dcerpc_binding_handle *b,
960 struct samr_Password current_nt_hash,
961 const struct samr_Password *previous_nt_hash)
963 struct tevent_req *req;
964 struct netlogon_creds_cli_auth_state *state;
965 struct netlogon_creds_cli_locked_state *locked_state;
966 NTSTATUS status;
968 req = tevent_req_create(mem_ctx, &state,
969 struct netlogon_creds_cli_auth_state);
970 if (req == NULL) {
971 return NULL;
974 state->ev = ev;
975 state->context = context;
976 state->binding_handle = b;
977 state->current_nt_hash = current_nt_hash;
978 if (previous_nt_hash != NULL) {
979 state->previous_nt_hash = *previous_nt_hash;
980 state->try_previous_nt_hash = true;
983 if (context->db.locked_state != NULL) {
984 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
985 return tevent_req_post(req, ev);
988 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
989 if (tevent_req_nomem(locked_state, req)) {
990 return tevent_req_post(req, ev);
992 talloc_set_destructor(locked_state,
993 netlogon_creds_cli_locked_state_destructor);
994 locked_state->context = context;
996 context->db.locked_state = locked_state;
997 state->locked_state = locked_state;
999 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1000 context->server.computer);
1001 if (tevent_req_nomem(state->srv_name_slash, req)) {
1002 return tevent_req_post(req, ev);
1005 state->try_auth3 = true;
1006 state->try_auth2 = true;
1008 if (context->client.required_flags != 0) {
1009 state->require_auth2 = true;
1012 state->used_nt_hash = state->current_nt_hash;
1013 state->current_flags = context->client.proposed_flags;
1015 if (context->db.g_ctx != NULL) {
1016 struct tevent_req *subreq;
1018 subreq = g_lock_lock_send(state, ev,
1019 context->db.g_ctx,
1020 context->db.key_name,
1021 G_LOCK_WRITE);
1022 if (tevent_req_nomem(subreq, req)) {
1023 return tevent_req_post(req, ev);
1025 tevent_req_set_callback(subreq,
1026 netlogon_creds_cli_auth_locked,
1027 req);
1029 return req;
1032 status = dbwrap_delete(state->context->db.ctx,
1033 state->context->db.key_data);
1034 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1035 status = NT_STATUS_OK;
1037 if (tevent_req_nterror(req, status)) {
1038 return tevent_req_post(req, ev);
1041 netlogon_creds_cli_auth_challenge_start(req);
1042 if (!tevent_req_is_in_progress(req)) {
1043 return tevent_req_post(req, ev);
1046 return req;
1049 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1051 struct tevent_req *req =
1052 tevent_req_callback_data(subreq,
1053 struct tevent_req);
1054 struct netlogon_creds_cli_auth_state *state =
1055 tevent_req_data(req,
1056 struct netlogon_creds_cli_auth_state);
1057 NTSTATUS status;
1059 status = g_lock_lock_recv(subreq);
1060 TALLOC_FREE(subreq);
1061 if (tevent_req_nterror(req, status)) {
1062 return;
1064 state->locked_state->is_glocked = true;
1066 status = dbwrap_delete(state->context->db.ctx,
1067 state->context->db.key_data);
1068 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1069 status = NT_STATUS_OK;
1071 if (tevent_req_nterror(req, status)) {
1072 return;
1075 netlogon_creds_cli_auth_challenge_start(req);
1078 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1080 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1082 struct netlogon_creds_cli_auth_state *state =
1083 tevent_req_data(req,
1084 struct netlogon_creds_cli_auth_state);
1085 struct tevent_req *subreq;
1087 TALLOC_FREE(state->creds);
1089 generate_random_buffer(state->client_challenge.data,
1090 sizeof(state->client_challenge.data));
1092 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1093 state->binding_handle,
1094 state->srv_name_slash,
1095 state->context->client.computer,
1096 &state->client_challenge,
1097 &state->server_challenge);
1098 if (tevent_req_nomem(subreq, req)) {
1099 return;
1101 tevent_req_set_callback(subreq,
1102 netlogon_creds_cli_auth_challenge_done,
1103 req);
1106 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1108 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1110 struct tevent_req *req =
1111 tevent_req_callback_data(subreq,
1112 struct tevent_req);
1113 struct netlogon_creds_cli_auth_state *state =
1114 tevent_req_data(req,
1115 struct netlogon_creds_cli_auth_state);
1116 NTSTATUS status;
1117 NTSTATUS result;
1119 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1120 TALLOC_FREE(subreq);
1121 if (tevent_req_nterror(req, status)) {
1122 return;
1124 if (tevent_req_nterror(req, result)) {
1125 return;
1128 if (!state->try_auth3 && !state->try_auth2) {
1129 state->current_flags = 0;
1132 /* Calculate the session key and client credentials */
1134 state->creds = netlogon_creds_client_init(state,
1135 state->context->client.account,
1136 state->context->client.computer,
1137 state->context->client.type,
1138 &state->client_challenge,
1139 &state->server_challenge,
1140 &state->used_nt_hash,
1141 &state->client_credential,
1142 state->current_flags);
1143 if (tevent_req_nomem(state->creds, req)) {
1144 return;
1147 if (state->try_auth3) {
1148 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1149 state->binding_handle,
1150 state->srv_name_slash,
1151 state->context->client.account,
1152 state->context->client.type,
1153 state->context->client.computer,
1154 &state->client_credential,
1155 &state->server_credential,
1156 &state->creds->negotiate_flags,
1157 &state->rid);
1158 if (tevent_req_nomem(subreq, req)) {
1159 return;
1161 } else if (state->try_auth2) {
1162 state->rid = 0;
1164 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1165 state->binding_handle,
1166 state->srv_name_slash,
1167 state->context->client.account,
1168 state->context->client.type,
1169 state->context->client.computer,
1170 &state->client_credential,
1171 &state->server_credential,
1172 &state->creds->negotiate_flags);
1173 if (tevent_req_nomem(subreq, req)) {
1174 return;
1176 } else {
1177 state->rid = 0;
1179 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1180 state->binding_handle,
1181 state->srv_name_slash,
1182 state->context->client.account,
1183 state->context->client.type,
1184 state->context->client.computer,
1185 &state->client_credential,
1186 &state->server_credential);
1187 if (tevent_req_nomem(subreq, req)) {
1188 return;
1191 tevent_req_set_callback(subreq,
1192 netlogon_creds_cli_auth_srvauth_done,
1193 req);
1196 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1198 struct tevent_req *req =
1199 tevent_req_callback_data(subreq,
1200 struct tevent_req);
1201 struct netlogon_creds_cli_auth_state *state =
1202 tevent_req_data(req,
1203 struct netlogon_creds_cli_auth_state);
1204 NTSTATUS status;
1205 NTSTATUS result;
1206 bool ok;
1207 enum ndr_err_code ndr_err;
1208 DATA_BLOB blob;
1209 TDB_DATA data;
1210 uint32_t tmp_flags;
1212 if (state->try_auth3) {
1213 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1214 &result);
1215 TALLOC_FREE(subreq);
1216 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1217 state->try_auth3 = false;
1218 netlogon_creds_cli_auth_challenge_start(req);
1219 return;
1221 if (tevent_req_nterror(req, status)) {
1222 return;
1224 } else if (state->try_auth2) {
1225 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1226 &result);
1227 TALLOC_FREE(subreq);
1228 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1229 state->try_auth2 = false;
1230 if (state->require_auth2) {
1231 status = NT_STATUS_DOWNGRADE_DETECTED;
1232 tevent_req_nterror(req, status);
1233 return;
1235 netlogon_creds_cli_auth_challenge_start(req);
1236 return;
1238 if (tevent_req_nterror(req, status)) {
1239 return;
1241 } else {
1242 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1243 &result);
1244 TALLOC_FREE(subreq);
1245 if (tevent_req_nterror(req, status)) {
1246 return;
1250 if (!NT_STATUS_IS_OK(result) &&
1251 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1253 tevent_req_nterror(req, result);
1254 return;
1257 tmp_flags = state->creds->negotiate_flags;
1258 tmp_flags &= state->context->client.required_flags;
1259 if (tmp_flags != state->context->client.required_flags) {
1260 if (NT_STATUS_IS_OK(result)) {
1261 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1262 return;
1264 tevent_req_nterror(req, result);
1265 return;
1268 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1270 tmp_flags = state->context->client.proposed_flags;
1271 if ((state->current_flags == tmp_flags) &&
1272 (state->creds->negotiate_flags != tmp_flags))
1275 * lets retry with the negotiated flags
1277 state->current_flags = state->creds->negotiate_flags;
1278 netlogon_creds_cli_auth_challenge_start(req);
1279 return;
1282 if (!state->try_previous_nt_hash) {
1284 * we already retried, giving up...
1286 tevent_req_nterror(req, result);
1287 return;
1291 * lets retry with the old nt hash.
1293 state->try_previous_nt_hash = false;
1294 state->used_nt_hash = state->previous_nt_hash;
1295 state->current_flags = state->context->client.proposed_flags;
1296 netlogon_creds_cli_auth_challenge_start(req);
1297 return;
1300 ok = netlogon_creds_client_check(state->creds,
1301 &state->server_credential);
1302 if (!ok) {
1303 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1304 return;
1307 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1308 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1309 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1310 status = ndr_map_error2ntstatus(ndr_err);
1311 tevent_req_nterror(req, status);
1312 return;
1315 data.dptr = blob.data;
1316 data.dsize = blob.length;
1318 status = dbwrap_store(state->context->db.ctx,
1319 state->context->db.key_data,
1320 data, TDB_REPLACE);
1321 TALLOC_FREE(state->locked_state);
1322 if (tevent_req_nterror(req, status)) {
1323 return;
1326 tevent_req_done(req);
1329 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req)
1331 NTSTATUS status;
1333 if (tevent_req_is_nterror(req, &status)) {
1334 tevent_req_received(req);
1335 return status;
1338 tevent_req_received(req);
1339 return NT_STATUS_OK;
1342 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1343 struct dcerpc_binding_handle *b,
1344 struct samr_Password current_nt_hash,
1345 const struct samr_Password *previous_nt_hash)
1347 TALLOC_CTX *frame = talloc_stackframe();
1348 struct tevent_context *ev;
1349 struct tevent_req *req;
1350 NTSTATUS status = NT_STATUS_NO_MEMORY;
1352 ev = samba_tevent_context_init(frame);
1353 if (ev == NULL) {
1354 goto fail;
1356 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1357 current_nt_hash,
1358 previous_nt_hash);
1359 if (req == NULL) {
1360 goto fail;
1362 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1363 goto fail;
1365 status = netlogon_creds_cli_auth_recv(req);
1366 fail:
1367 TALLOC_FREE(frame);
1368 return status;
1371 struct netlogon_creds_cli_check_state {
1372 struct tevent_context *ev;
1373 struct netlogon_creds_cli_context *context;
1374 struct dcerpc_binding_handle *binding_handle;
1376 char *srv_name_slash;
1378 union netr_Capabilities caps;
1380 struct netlogon_creds_CredentialState *creds;
1381 struct netlogon_creds_CredentialState tmp_creds;
1382 struct netr_Authenticator req_auth;
1383 struct netr_Authenticator rep_auth;
1386 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1387 NTSTATUS status);
1388 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1390 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1391 struct tevent_context *ev,
1392 struct netlogon_creds_cli_context *context,
1393 struct dcerpc_binding_handle *b)
1395 struct tevent_req *req;
1396 struct netlogon_creds_cli_check_state *state;
1397 struct tevent_req *subreq;
1398 enum dcerpc_AuthType auth_type;
1399 enum dcerpc_AuthLevel auth_level;
1401 req = tevent_req_create(mem_ctx, &state,
1402 struct netlogon_creds_cli_check_state);
1403 if (req == NULL) {
1404 return NULL;
1407 state->ev = ev;
1408 state->context = context;
1409 state->binding_handle = b;
1411 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1412 context->server.computer);
1413 if (tevent_req_nomem(state->srv_name_slash, req)) {
1414 return tevent_req_post(req, ev);
1417 dcerpc_binding_handle_auth_info(state->binding_handle,
1418 &auth_type, &auth_level);
1420 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1421 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1422 return tevent_req_post(req, ev);
1425 switch (auth_level) {
1426 case DCERPC_AUTH_LEVEL_INTEGRITY:
1427 case DCERPC_AUTH_LEVEL_PRIVACY:
1428 break;
1429 default:
1430 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1431 return tevent_req_post(req, ev);
1434 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1435 state->context);
1436 if (tevent_req_nomem(subreq, req)) {
1437 return tevent_req_post(req, ev);
1440 tevent_req_set_callback(subreq,
1441 netlogon_creds_cli_check_locked,
1442 req);
1444 return req;
1447 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1448 NTSTATUS status)
1450 struct netlogon_creds_cli_check_state *state =
1451 tevent_req_data(req,
1452 struct netlogon_creds_cli_check_state);
1454 if (state->creds == NULL) {
1455 return;
1458 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1459 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1460 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1461 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1462 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1463 TALLOC_FREE(state->creds);
1464 return;
1467 netlogon_creds_cli_delete(state->context, &state->creds);
1470 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1472 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1474 struct tevent_req *req =
1475 tevent_req_callback_data(subreq,
1476 struct tevent_req);
1477 struct netlogon_creds_cli_check_state *state =
1478 tevent_req_data(req,
1479 struct netlogon_creds_cli_check_state);
1480 NTSTATUS status;
1482 status = netlogon_creds_cli_lock_recv(subreq, state,
1483 &state->creds);
1484 TALLOC_FREE(subreq);
1485 if (tevent_req_nterror(req, status)) {
1486 return;
1490 * we defer all callbacks in order to cleanup
1491 * the database record.
1493 tevent_req_defer_callback(req, state->ev);
1495 state->tmp_creds = *state->creds;
1496 netlogon_creds_client_authenticator(&state->tmp_creds,
1497 &state->req_auth);
1498 ZERO_STRUCT(state->rep_auth);
1500 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1501 state->binding_handle,
1502 state->srv_name_slash,
1503 state->context->client.computer,
1504 &state->req_auth,
1505 &state->rep_auth,
1507 &state->caps);
1508 if (tevent_req_nomem(subreq, req)) {
1509 status = NT_STATUS_NO_MEMORY;
1510 netlogon_creds_cli_check_cleanup(req, status);
1511 return;
1513 tevent_req_set_callback(subreq,
1514 netlogon_creds_cli_check_caps,
1515 req);
1518 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1520 struct tevent_req *req =
1521 tevent_req_callback_data(subreq,
1522 struct tevent_req);
1523 struct netlogon_creds_cli_check_state *state =
1524 tevent_req_data(req,
1525 struct netlogon_creds_cli_check_state);
1526 NTSTATUS status;
1527 NTSTATUS result;
1528 bool ok;
1530 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1531 &result);
1532 TALLOC_FREE(subreq);
1533 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1535 * Note that the negotiated flags are already checked
1536 * for our required flags after the ServerAuthenticate3/2 call.
1538 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1540 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1542 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1543 * already, we expect this to work!
1545 status = NT_STATUS_DOWNGRADE_DETECTED;
1546 tevent_req_nterror(req, status);
1547 netlogon_creds_cli_check_cleanup(req, status);
1548 return;
1551 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1553 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1554 * we expect this to work at least as far as the
1555 * NOT_SUPPORTED error handled below!
1557 * NT 4.0 and Old Samba servers are not
1558 * allowed without "require strong key = no"
1560 status = NT_STATUS_DOWNGRADE_DETECTED;
1561 tevent_req_nterror(req, status);
1562 netlogon_creds_cli_check_cleanup(req, status);
1563 return;
1567 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1568 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1569 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1571 * This is needed against NT 4.0 and old Samba servers.
1573 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1574 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1575 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1576 * with the next request as the sequence number processing
1577 * gets out of sync.
1579 netlogon_creds_cli_check_cleanup(req, status);
1580 tevent_req_done(req);
1581 return;
1583 if (tevent_req_nterror(req, status)) {
1584 netlogon_creds_cli_check_cleanup(req, status);
1585 return;
1588 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1590 * Note that the negotiated flags are already checked
1591 * for our required flags after the ServerAuthenticate3/2 call.
1593 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1595 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1597 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1598 * already, we expect this to work!
1600 status = NT_STATUS_DOWNGRADE_DETECTED;
1601 tevent_req_nterror(req, status);
1602 netlogon_creds_cli_check_cleanup(req, status);
1603 return;
1607 * This is ok, the server does not support
1608 * NETLOGON_NEG_SUPPORTS_AES.
1610 * netr_LogonGetCapabilities() was
1611 * netr_LogonDummyRoutine1() before
1612 * NETLOGON_NEG_SUPPORTS_AES was invented.
1614 netlogon_creds_cli_check_cleanup(req, result);
1615 tevent_req_done(req);
1616 return;
1619 ok = netlogon_creds_client_check(&state->tmp_creds,
1620 &state->rep_auth.cred);
1621 if (!ok) {
1622 status = NT_STATUS_ACCESS_DENIED;
1623 tevent_req_nterror(req, status);
1624 netlogon_creds_cli_check_cleanup(req, status);
1625 return;
1628 if (tevent_req_nterror(req, result)) {
1629 netlogon_creds_cli_check_cleanup(req, result);
1630 return;
1633 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1634 status = NT_STATUS_DOWNGRADE_DETECTED;
1635 tevent_req_nterror(req, status);
1636 netlogon_creds_cli_check_cleanup(req, status);
1637 return;
1641 * This is the key check that makes this check secure. If we
1642 * get OK here (rather than NOT_SUPPORTED), then the server
1643 * did support AES. If the server only proposed STRONG_KEYS
1644 * and not AES, then it should have failed with
1645 * NOT_IMPLEMENTED. We always send AES as a client, so the
1646 * server should always have returned it.
1648 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1649 status = NT_STATUS_DOWNGRADE_DETECTED;
1650 tevent_req_nterror(req, status);
1651 netlogon_creds_cli_check_cleanup(req, status);
1652 return;
1655 *state->creds = state->tmp_creds;
1656 status = netlogon_creds_cli_store(state->context,
1657 &state->creds);
1658 netlogon_creds_cli_check_cleanup(req, status);
1659 if (tevent_req_nterror(req, status)) {
1660 return;
1663 tevent_req_done(req);
1666 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1668 NTSTATUS status;
1670 if (tevent_req_is_nterror(req, &status)) {
1671 netlogon_creds_cli_check_cleanup(req, status);
1672 tevent_req_received(req);
1673 return status;
1676 tevent_req_received(req);
1677 return NT_STATUS_OK;
1680 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1681 struct dcerpc_binding_handle *b)
1683 TALLOC_CTX *frame = talloc_stackframe();
1684 struct tevent_context *ev;
1685 struct tevent_req *req;
1686 NTSTATUS status = NT_STATUS_NO_MEMORY;
1688 ev = samba_tevent_context_init(frame);
1689 if (ev == NULL) {
1690 goto fail;
1692 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1693 if (req == NULL) {
1694 goto fail;
1696 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1697 goto fail;
1699 status = netlogon_creds_cli_check_recv(req);
1700 fail:
1701 TALLOC_FREE(frame);
1702 return status;
1705 struct netlogon_creds_cli_ServerPasswordSet_state {
1706 struct tevent_context *ev;
1707 struct netlogon_creds_cli_context *context;
1708 struct dcerpc_binding_handle *binding_handle;
1709 uint32_t old_timeout;
1711 char *srv_name_slash;
1712 enum dcerpc_AuthType auth_type;
1713 enum dcerpc_AuthLevel auth_level;
1715 struct samr_CryptPassword samr_crypt_password;
1716 struct netr_CryptPassword netr_crypt_password;
1717 struct samr_Password samr_password;
1719 struct netlogon_creds_CredentialState *creds;
1720 struct netlogon_creds_CredentialState tmp_creds;
1721 struct netr_Authenticator req_auth;
1722 struct netr_Authenticator rep_auth;
1725 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1726 NTSTATUS status);
1727 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1729 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1730 struct tevent_context *ev,
1731 struct netlogon_creds_cli_context *context,
1732 struct dcerpc_binding_handle *b,
1733 const char *new_password,
1734 const uint32_t *new_version)
1736 struct tevent_req *req;
1737 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1738 struct tevent_req *subreq;
1739 bool ok;
1741 req = tevent_req_create(mem_ctx, &state,
1742 struct netlogon_creds_cli_ServerPasswordSet_state);
1743 if (req == NULL) {
1744 return NULL;
1747 state->ev = ev;
1748 state->context = context;
1749 state->binding_handle = b;
1752 * netr_ServerPasswordSet
1754 E_md4hash(new_password, state->samr_password.hash);
1757 * netr_ServerPasswordSet2
1759 ok = encode_pw_buffer(state->samr_crypt_password.data,
1760 new_password, STR_UNICODE);
1761 if (!ok) {
1762 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1763 return tevent_req_post(req, ev);
1766 if (new_version != NULL) {
1767 struct NL_PASSWORD_VERSION version;
1768 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1769 uint32_t ofs = 512 - len;
1770 uint8_t *p;
1772 if (ofs < 12) {
1773 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1774 return tevent_req_post(req, ev);
1776 ofs -= 12;
1778 version.ReservedField = 0;
1779 version.PasswordVersionNumber = *new_version;
1780 version.PasswordVersionPresent =
1781 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1783 p = state->samr_crypt_password.data + ofs;
1784 SIVAL(p, 0, version.ReservedField);
1785 SIVAL(p, 4, version.PasswordVersionNumber);
1786 SIVAL(p, 8, version.PasswordVersionPresent);
1789 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1790 context->server.computer);
1791 if (tevent_req_nomem(state->srv_name_slash, req)) {
1792 return tevent_req_post(req, ev);
1795 dcerpc_binding_handle_auth_info(state->binding_handle,
1796 &state->auth_type,
1797 &state->auth_level);
1799 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1800 state->context);
1801 if (tevent_req_nomem(subreq, req)) {
1802 return tevent_req_post(req, ev);
1805 tevent_req_set_callback(subreq,
1806 netlogon_creds_cli_ServerPasswordSet_locked,
1807 req);
1809 return req;
1812 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1813 NTSTATUS status)
1815 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1816 tevent_req_data(req,
1817 struct netlogon_creds_cli_ServerPasswordSet_state);
1819 if (state->creds == NULL) {
1820 return;
1823 dcerpc_binding_handle_set_timeout(state->binding_handle,
1824 state->old_timeout);
1826 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1827 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1828 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1829 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1830 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1831 TALLOC_FREE(state->creds);
1832 return;
1835 netlogon_creds_cli_delete(state->context, &state->creds);
1838 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1840 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1842 struct tevent_req *req =
1843 tevent_req_callback_data(subreq,
1844 struct tevent_req);
1845 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1846 tevent_req_data(req,
1847 struct netlogon_creds_cli_ServerPasswordSet_state);
1848 NTSTATUS status;
1850 status = netlogon_creds_cli_lock_recv(subreq, state,
1851 &state->creds);
1852 TALLOC_FREE(subreq);
1853 if (tevent_req_nterror(req, status)) {
1854 return;
1857 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1858 switch (state->auth_level) {
1859 case DCERPC_AUTH_LEVEL_INTEGRITY:
1860 case DCERPC_AUTH_LEVEL_PRIVACY:
1861 break;
1862 default:
1863 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1864 return;
1866 } else {
1867 uint32_t tmp = state->creds->negotiate_flags;
1869 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1871 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1872 * it should be used, which means
1873 * we had a chance to verify no downgrade
1874 * happened.
1876 * This relies on netlogon_creds_cli_check*
1877 * being called before, as first request after
1878 * the DCERPC bind.
1880 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1881 return;
1885 state->old_timeout = dcerpc_binding_handle_set_timeout(
1886 state->binding_handle, 600000);
1889 * we defer all callbacks in order to cleanup
1890 * the database record.
1892 tevent_req_defer_callback(req, state->ev);
1894 state->tmp_creds = *state->creds;
1895 netlogon_creds_client_authenticator(&state->tmp_creds,
1896 &state->req_auth);
1897 ZERO_STRUCT(state->rep_auth);
1899 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1901 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1902 netlogon_creds_aes_encrypt(&state->tmp_creds,
1903 state->samr_crypt_password.data,
1904 516);
1905 } else {
1906 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1907 state->samr_crypt_password.data,
1908 516);
1911 memcpy(state->netr_crypt_password.data,
1912 state->samr_crypt_password.data, 512);
1913 state->netr_crypt_password.length =
1914 IVAL(state->samr_crypt_password.data, 512);
1916 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1917 state->binding_handle,
1918 state->srv_name_slash,
1919 state->tmp_creds.account_name,
1920 state->tmp_creds.secure_channel_type,
1921 state->tmp_creds.computer_name,
1922 &state->req_auth,
1923 &state->rep_auth,
1924 &state->netr_crypt_password);
1925 if (tevent_req_nomem(subreq, req)) {
1926 status = NT_STATUS_NO_MEMORY;
1927 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1928 return;
1930 } else {
1931 netlogon_creds_des_encrypt(&state->tmp_creds,
1932 &state->samr_password);
1934 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1935 state->binding_handle,
1936 state->srv_name_slash,
1937 state->tmp_creds.account_name,
1938 state->tmp_creds.secure_channel_type,
1939 state->tmp_creds.computer_name,
1940 &state->req_auth,
1941 &state->rep_auth,
1942 &state->samr_password);
1943 if (tevent_req_nomem(subreq, req)) {
1944 status = NT_STATUS_NO_MEMORY;
1945 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1946 return;
1950 tevent_req_set_callback(subreq,
1951 netlogon_creds_cli_ServerPasswordSet_done,
1952 req);
1955 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1957 struct tevent_req *req =
1958 tevent_req_callback_data(subreq,
1959 struct tevent_req);
1960 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1961 tevent_req_data(req,
1962 struct netlogon_creds_cli_ServerPasswordSet_state);
1963 NTSTATUS status;
1964 NTSTATUS result;
1965 bool ok;
1967 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1968 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1969 &result);
1970 TALLOC_FREE(subreq);
1971 if (tevent_req_nterror(req, status)) {
1972 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1973 return;
1975 } else {
1976 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1977 &result);
1978 TALLOC_FREE(subreq);
1979 if (tevent_req_nterror(req, status)) {
1980 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1981 return;
1985 ok = netlogon_creds_client_check(&state->tmp_creds,
1986 &state->rep_auth.cred);
1987 if (!ok) {
1988 status = NT_STATUS_ACCESS_DENIED;
1989 tevent_req_nterror(req, status);
1990 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1991 return;
1994 if (tevent_req_nterror(req, result)) {
1995 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
1996 return;
1999 dcerpc_binding_handle_set_timeout(state->binding_handle,
2000 state->old_timeout);
2002 *state->creds = state->tmp_creds;
2003 status = netlogon_creds_cli_store(state->context,
2004 &state->creds);
2005 if (tevent_req_nterror(req, status)) {
2006 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2007 return;
2010 tevent_req_done(req);
2013 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2015 NTSTATUS status;
2017 if (tevent_req_is_nterror(req, &status)) {
2018 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2019 tevent_req_received(req);
2020 return status;
2023 tevent_req_received(req);
2024 return NT_STATUS_OK;
2027 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2028 struct netlogon_creds_cli_context *context,
2029 struct dcerpc_binding_handle *b,
2030 const char *new_password,
2031 const uint32_t *new_version)
2033 TALLOC_CTX *frame = talloc_stackframe();
2034 struct tevent_context *ev;
2035 struct tevent_req *req;
2036 NTSTATUS status = NT_STATUS_NO_MEMORY;
2038 ev = samba_tevent_context_init(frame);
2039 if (ev == NULL) {
2040 goto fail;
2042 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2043 new_password,
2044 new_version);
2045 if (req == NULL) {
2046 goto fail;
2048 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2049 goto fail;
2051 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2052 fail:
2053 TALLOC_FREE(frame);
2054 return status;
2057 struct netlogon_creds_cli_LogonSamLogon_state {
2058 struct tevent_context *ev;
2059 struct netlogon_creds_cli_context *context;
2060 struct dcerpc_binding_handle *binding_handle;
2062 char *srv_name_slash;
2064 enum netr_LogonInfoClass logon_level;
2065 const union netr_LogonLevel *const_logon;
2066 union netr_LogonLevel *logon;
2067 uint32_t flags;
2069 uint16_t validation_level;
2070 union netr_Validation *validation;
2071 uint8_t authoritative;
2074 * do we need encryption at the application layer?
2076 bool user_encrypt;
2077 bool try_logon_ex;
2078 bool try_validation6;
2081 * the read only credentials before we started the operation
2083 struct netlogon_creds_CredentialState *ro_creds;
2085 struct netlogon_creds_CredentialState *lk_creds;
2087 struct netlogon_creds_CredentialState tmp_creds;
2088 struct netr_Authenticator req_auth;
2089 struct netr_Authenticator rep_auth;
2092 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2093 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2094 NTSTATUS status);
2096 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2097 struct tevent_context *ev,
2098 struct netlogon_creds_cli_context *context,
2099 struct dcerpc_binding_handle *b,
2100 enum netr_LogonInfoClass logon_level,
2101 const union netr_LogonLevel *logon,
2102 uint32_t flags)
2104 struct tevent_req *req;
2105 struct netlogon_creds_cli_LogonSamLogon_state *state;
2107 req = tevent_req_create(mem_ctx, &state,
2108 struct netlogon_creds_cli_LogonSamLogon_state);
2109 if (req == NULL) {
2110 return NULL;
2113 state->ev = ev;
2114 state->context = context;
2115 state->binding_handle = b;
2117 state->logon_level = logon_level;
2118 state->const_logon = logon;
2119 state->flags = flags;
2121 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2122 context->server.computer);
2123 if (tevent_req_nomem(state->srv_name_slash, req)) {
2124 return tevent_req_post(req, ev);
2127 switch (logon_level) {
2128 case NetlogonInteractiveInformation:
2129 case NetlogonInteractiveTransitiveInformation:
2130 case NetlogonServiceInformation:
2131 case NetlogonServiceTransitiveInformation:
2132 case NetlogonGenericInformation:
2133 state->user_encrypt = true;
2134 break;
2136 case NetlogonNetworkInformation:
2137 case NetlogonNetworkTransitiveInformation:
2138 break;
2141 state->validation = talloc_zero(state, union netr_Validation);
2142 if (tevent_req_nomem(state->validation, req)) {
2143 return tevent_req_post(req, ev);
2146 netlogon_creds_cli_LogonSamLogon_start(req);
2147 if (!tevent_req_is_in_progress(req)) {
2148 return tevent_req_post(req, ev);
2152 * we defer all callbacks in order to cleanup
2153 * the database record.
2155 tevent_req_defer_callback(req, state->ev);
2156 return req;
2159 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2160 NTSTATUS status)
2162 struct netlogon_creds_cli_LogonSamLogon_state *state =
2163 tevent_req_data(req,
2164 struct netlogon_creds_cli_LogonSamLogon_state);
2166 if (state->lk_creds == NULL) {
2167 return;
2170 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2172 * This is a hack to recover from a bug in old
2173 * Samba servers, when LogonSamLogonEx() fails:
2175 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2177 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2179 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2180 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2181 * If the sign/seal check fails.
2183 * In that case we need to cleanup the netlogon session.
2185 * It's the job of the caller to disconnect the current
2186 * connection, if netlogon_creds_cli_LogonSamLogon()
2187 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2189 if (!state->context->server.try_logon_with) {
2190 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2194 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2195 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2196 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2197 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2198 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2199 TALLOC_FREE(state->lk_creds);
2200 return;
2203 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2206 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2208 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2210 struct netlogon_creds_cli_LogonSamLogon_state *state =
2211 tevent_req_data(req,
2212 struct netlogon_creds_cli_LogonSamLogon_state);
2213 struct tevent_req *subreq;
2214 NTSTATUS status;
2215 enum dcerpc_AuthType auth_type;
2216 enum dcerpc_AuthLevel auth_level;
2218 TALLOC_FREE(state->ro_creds);
2219 TALLOC_FREE(state->logon);
2220 ZERO_STRUCTP(state->validation);
2222 dcerpc_binding_handle_auth_info(state->binding_handle,
2223 &auth_type, &auth_level);
2225 state->try_logon_ex = state->context->server.try_logon_ex;
2226 state->try_validation6 = state->context->server.try_validation6;
2228 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2229 state->try_logon_ex = false;
2232 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2233 state->try_validation6 = false;
2236 if (state->try_logon_ex) {
2237 if (state->try_validation6) {
2238 state->validation_level = 6;
2239 } else {
2240 state->validation_level = 3;
2241 state->user_encrypt = true;
2244 state->logon = netlogon_creds_shallow_copy_logon(state,
2245 state->logon_level,
2246 state->const_logon);
2247 if (tevent_req_nomem(state->logon, req)) {
2248 status = NT_STATUS_NO_MEMORY;
2249 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2250 return;
2253 if (state->user_encrypt) {
2254 status = netlogon_creds_cli_get(state->context,
2255 state,
2256 &state->ro_creds);
2257 if (!NT_STATUS_IS_OK(status)) {
2258 status = NT_STATUS_ACCESS_DENIED;
2259 tevent_req_nterror(req, status);
2260 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2261 return;
2264 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2265 state->logon_level,
2266 state->logon);
2269 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2270 state->binding_handle,
2271 state->srv_name_slash,
2272 state->context->client.computer,
2273 state->logon_level,
2274 state->logon,
2275 state->validation_level,
2276 state->validation,
2277 &state->authoritative,
2278 &state->flags);
2279 if (tevent_req_nomem(subreq, req)) {
2280 status = NT_STATUS_NO_MEMORY;
2281 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2282 return;
2284 tevent_req_set_callback(subreq,
2285 netlogon_creds_cli_LogonSamLogon_done,
2286 req);
2287 return;
2290 if (state->lk_creds == NULL) {
2291 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2292 state->context);
2293 if (tevent_req_nomem(subreq, req)) {
2294 status = NT_STATUS_NO_MEMORY;
2295 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2296 return;
2298 tevent_req_set_callback(subreq,
2299 netlogon_creds_cli_LogonSamLogon_done,
2300 req);
2301 return;
2304 state->tmp_creds = *state->lk_creds;
2305 netlogon_creds_client_authenticator(&state->tmp_creds,
2306 &state->req_auth);
2307 ZERO_STRUCT(state->rep_auth);
2309 state->logon = netlogon_creds_shallow_copy_logon(state,
2310 state->logon_level,
2311 state->const_logon);
2312 if (tevent_req_nomem(state->logon, req)) {
2313 status = NT_STATUS_NO_MEMORY;
2314 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2315 return;
2318 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2319 state->logon_level,
2320 state->logon);
2322 state->validation_level = 3;
2324 if (state->context->server.try_logon_with) {
2325 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2326 state->binding_handle,
2327 state->srv_name_slash,
2328 state->context->client.computer,
2329 &state->req_auth,
2330 &state->rep_auth,
2331 state->logon_level,
2332 state->logon,
2333 state->validation_level,
2334 state->validation,
2335 &state->authoritative,
2336 &state->flags);
2337 if (tevent_req_nomem(subreq, req)) {
2338 status = NT_STATUS_NO_MEMORY;
2339 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2340 return;
2342 } else {
2343 state->flags = 0;
2345 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2346 state->binding_handle,
2347 state->srv_name_slash,
2348 state->context->client.computer,
2349 &state->req_auth,
2350 &state->rep_auth,
2351 state->logon_level,
2352 state->logon,
2353 state->validation_level,
2354 state->validation,
2355 &state->authoritative);
2356 if (tevent_req_nomem(subreq, req)) {
2357 status = NT_STATUS_NO_MEMORY;
2358 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2359 return;
2363 tevent_req_set_callback(subreq,
2364 netlogon_creds_cli_LogonSamLogon_done,
2365 req);
2368 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2370 struct tevent_req *req =
2371 tevent_req_callback_data(subreq,
2372 struct tevent_req);
2373 struct netlogon_creds_cli_LogonSamLogon_state *state =
2374 tevent_req_data(req,
2375 struct netlogon_creds_cli_LogonSamLogon_state);
2376 NTSTATUS status;
2377 NTSTATUS result;
2378 bool ok;
2380 if (state->try_logon_ex) {
2381 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2382 state->validation,
2383 &result);
2384 TALLOC_FREE(subreq);
2385 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2386 state->context->server.try_validation6 = false;
2387 state->context->server.try_logon_ex = false;
2388 netlogon_creds_cli_LogonSamLogon_start(req);
2389 return;
2391 if (tevent_req_nterror(req, status)) {
2392 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2393 return;
2396 if ((state->validation_level == 6) &&
2397 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2398 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2399 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2401 state->context->server.try_validation6 = false;
2402 netlogon_creds_cli_LogonSamLogon_start(req);
2403 return;
2406 if (tevent_req_nterror(req, result)) {
2407 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2408 return;
2411 if (state->ro_creds == NULL) {
2412 tevent_req_done(req);
2413 return;
2416 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2417 if (!ok) {
2419 * We got a race, lets retry with on authenticator
2420 * protection.
2422 TALLOC_FREE(state->ro_creds);
2423 state->try_logon_ex = false;
2424 netlogon_creds_cli_LogonSamLogon_start(req);
2425 return;
2428 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2429 state->validation_level,
2430 state->validation);
2432 tevent_req_done(req);
2433 return;
2436 if (state->lk_creds == NULL) {
2437 status = netlogon_creds_cli_lock_recv(subreq, state,
2438 &state->lk_creds);
2439 TALLOC_FREE(subreq);
2440 if (tevent_req_nterror(req, status)) {
2441 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2442 return;
2445 netlogon_creds_cli_LogonSamLogon_start(req);
2446 return;
2449 if (state->context->server.try_logon_with) {
2450 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2451 state->validation,
2452 &result);
2453 TALLOC_FREE(subreq);
2454 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2455 state->context->server.try_logon_with = false;
2456 netlogon_creds_cli_LogonSamLogon_start(req);
2457 return;
2459 if (tevent_req_nterror(req, status)) {
2460 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2461 return;
2463 } else {
2464 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2465 state->validation,
2466 &result);
2467 TALLOC_FREE(subreq);
2468 if (tevent_req_nterror(req, status)) {
2469 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2470 return;
2474 ok = netlogon_creds_client_check(&state->tmp_creds,
2475 &state->rep_auth.cred);
2476 if (!ok) {
2477 status = NT_STATUS_ACCESS_DENIED;
2478 tevent_req_nterror(req, status);
2479 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2480 return;
2483 *state->lk_creds = state->tmp_creds;
2484 status = netlogon_creds_cli_store(state->context,
2485 &state->lk_creds);
2486 if (tevent_req_nterror(req, status)) {
2487 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2488 return;
2491 if (tevent_req_nterror(req, result)) {
2492 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2493 return;
2496 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2497 state->validation_level,
2498 state->validation);
2500 tevent_req_done(req);
2503 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2504 TALLOC_CTX *mem_ctx,
2505 uint16_t *validation_level,
2506 union netr_Validation **validation,
2507 uint8_t *authoritative,
2508 uint32_t *flags)
2510 struct netlogon_creds_cli_LogonSamLogon_state *state =
2511 tevent_req_data(req,
2512 struct netlogon_creds_cli_LogonSamLogon_state);
2513 NTSTATUS status;
2515 /* authoritative is also returned on error */
2516 *authoritative = state->authoritative;
2518 if (tevent_req_is_nterror(req, &status)) {
2519 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2520 tevent_req_received(req);
2521 return status;
2524 *validation_level = state->validation_level;
2525 *validation = talloc_move(mem_ctx, &state->validation);
2526 *flags = state->flags;
2528 tevent_req_received(req);
2529 return NT_STATUS_OK;
2532 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2533 struct netlogon_creds_cli_context *context,
2534 struct dcerpc_binding_handle *b,
2535 enum netr_LogonInfoClass logon_level,
2536 const union netr_LogonLevel *logon,
2537 TALLOC_CTX *mem_ctx,
2538 uint16_t *validation_level,
2539 union netr_Validation **validation,
2540 uint8_t *authoritative,
2541 uint32_t *flags)
2543 TALLOC_CTX *frame = talloc_stackframe();
2544 struct tevent_context *ev;
2545 struct tevent_req *req;
2546 NTSTATUS status = NT_STATUS_NO_MEMORY;
2548 ev = samba_tevent_context_init(frame);
2549 if (ev == NULL) {
2550 goto fail;
2552 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2553 logon_level, logon,
2554 *flags);
2555 if (req == NULL) {
2556 goto fail;
2558 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2559 goto fail;
2561 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2562 validation_level,
2563 validation,
2564 authoritative,
2565 flags);
2566 fail:
2567 TALLOC_FREE(frame);
2568 return status;