libcli/auth: remove unused netlogon_creds_cli_context_copy()
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob17240640ca83578f45a2936e468f332c7ba8df56
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_open_global_db(struct loadparm_context *lp_ctx)
204 char *fname;
205 struct db_context *global_db;
207 if (netlogon_creds_cli_global_db != NULL) {
208 return NT_STATUS_OK;
211 fname = lpcfg_private_db_path(talloc_autofree_context(), lp_ctx, "netlogon_creds_cli");
212 if (fname == NULL) {
213 return NT_STATUS_NO_MEMORY;
216 global_db = dbwrap_local_open(talloc_autofree_context(), lp_ctx,
217 fname, 0,
218 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
219 O_RDWR|O_CREAT,
220 0600, DBWRAP_LOCK_ORDER_2);
221 if (global_db == NULL) {
222 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
223 fname, strerror(errno)));
224 talloc_free(fname);
225 return NT_STATUS_NO_MEMORY;
227 TALLOC_FREE(fname);
229 netlogon_creds_cli_global_db = global_db;
230 return NT_STATUS_OK;
233 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
234 struct messaging_context *msg_ctx,
235 const char *client_account,
236 enum netr_SchannelType type,
237 const char *server_computer,
238 const char *server_netbios_domain,
239 TALLOC_CTX *mem_ctx,
240 struct netlogon_creds_cli_context **_context)
242 TALLOC_CTX *frame = talloc_stackframe();
243 NTSTATUS status;
244 struct netlogon_creds_cli_context *context = NULL;
245 const char *client_computer;
246 uint32_t proposed_flags;
247 uint32_t required_flags = 0;
248 bool reject_md5_servers = false;
249 bool require_strong_key = false;
250 int require_sign_or_seal = true;
251 bool seal_secure_channel = true;
252 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
253 bool neutralize_nt4_emulation = false;
254 struct server_id self = {
255 .vnn = NONCLUSTER_VNN,
256 .unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY,
259 if (msg_ctx != NULL) {
260 self = messaging_server_id(msg_ctx);
263 *_context = NULL;
265 if (self.vnn != NONCLUSTER_VNN) {
266 client_computer = talloc_asprintf(frame,
267 "%s_cluster_vnn_%u",
268 lpcfg_netbios_name(lp_ctx),
269 (unsigned)self.vnn);
270 if (client_computer == NULL) {
271 TALLOC_FREE(frame);
272 return NT_STATUS_NO_MEMORY;
274 } else {
275 client_computer = lpcfg_netbios_name(lp_ctx);
279 * allow overwrite per domain
280 * reject md5 servers:<netbios_domain>
282 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
283 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
284 "reject md5 servers",
285 server_netbios_domain,
286 reject_md5_servers);
289 * allow overwrite per domain
290 * require strong key:<netbios_domain>
292 require_strong_key = lpcfg_require_strong_key(lp_ctx);
293 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
294 "require strong key",
295 server_netbios_domain,
296 require_strong_key);
299 * allow overwrite per domain
300 * client schannel:<netbios_domain>
302 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
303 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
304 "client schannel",
305 server_netbios_domain,
306 require_sign_or_seal);
309 * allow overwrite per domain
310 * winbind sealed pipes:<netbios_domain>
312 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
313 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
314 "winbind sealed pipes",
315 server_netbios_domain,
316 seal_secure_channel);
319 * allow overwrite per domain
320 * neutralize nt4 emulation:<netbios_domain>
322 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
323 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
324 "neutralize nt4 emulation",
325 server_netbios_domain,
326 neutralize_nt4_emulation);
328 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
329 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
331 switch (type) {
332 case SEC_CHAN_WKSTA:
333 if (lpcfg_security(lp_ctx) == SEC_ADS) {
335 * AD domains should be secure
337 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
338 require_sign_or_seal = true;
339 require_strong_key = true;
341 break;
343 case SEC_CHAN_DOMAIN:
344 break;
346 case SEC_CHAN_DNS_DOMAIN:
348 * AD domains should be secure
350 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
351 require_sign_or_seal = true;
352 require_strong_key = true;
353 neutralize_nt4_emulation = true;
354 break;
356 case SEC_CHAN_BDC:
357 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
358 require_sign_or_seal = true;
359 require_strong_key = true;
360 break;
362 case SEC_CHAN_RODC:
363 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
364 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
365 require_sign_or_seal = true;
366 require_strong_key = true;
367 neutralize_nt4_emulation = true;
368 break;
370 default:
371 TALLOC_FREE(frame);
372 return NT_STATUS_INVALID_PARAMETER;
375 if (neutralize_nt4_emulation) {
376 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
379 if (require_sign_or_seal == false) {
380 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
381 } else {
382 required_flags |= NETLOGON_NEG_ARCFOUR;
383 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
386 if (reject_md5_servers) {
387 required_flags |= NETLOGON_NEG_ARCFOUR;
388 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
389 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
390 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
393 if (require_strong_key) {
394 required_flags |= NETLOGON_NEG_ARCFOUR;
395 required_flags |= NETLOGON_NEG_STRONG_KEYS;
396 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
399 proposed_flags |= required_flags;
401 if (seal_secure_channel) {
402 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
403 } else {
404 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
407 status = netlogon_creds_cli_context_common(client_computer,
408 client_account,
409 type,
410 auth_level,
411 proposed_flags,
412 required_flags,
413 server_computer,
414 server_netbios_domain,
415 mem_ctx,
416 &context);
417 if (!NT_STATUS_IS_OK(status)) {
418 TALLOC_FREE(frame);
419 return status;
422 if (msg_ctx != NULL) {
423 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
424 if (context->db.g_ctx == NULL) {
425 TALLOC_FREE(context);
426 TALLOC_FREE(frame);
427 return NT_STATUS_NO_MEMORY;
431 if (netlogon_creds_cli_global_db != NULL) {
432 context->db.ctx = netlogon_creds_cli_global_db;
433 *_context = context;
434 TALLOC_FREE(frame);
435 return NT_STATUS_OK;
438 status = netlogon_creds_cli_open_global_db(lp_ctx);
439 if (!NT_STATUS_IS_OK(status)) {
440 TALLOC_FREE(context);
441 TALLOC_FREE(frame);
442 return NT_STATUS_NO_MEMORY;
445 context->db.ctx = netlogon_creds_cli_global_db;
446 *_context = context;
447 TALLOC_FREE(frame);
448 return NT_STATUS_OK;
451 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
452 const char *client_account,
453 enum netr_SchannelType type,
454 uint32_t proposed_flags,
455 uint32_t required_flags,
456 enum dcerpc_AuthLevel auth_level,
457 const char *server_computer,
458 const char *server_netbios_domain,
459 TALLOC_CTX *mem_ctx,
460 struct netlogon_creds_cli_context **_context)
462 NTSTATUS status;
463 struct netlogon_creds_cli_context *context = NULL;
465 *_context = NULL;
467 status = netlogon_creds_cli_context_common(client_computer,
468 client_account,
469 type,
470 auth_level,
471 proposed_flags,
472 required_flags,
473 server_computer,
474 server_netbios_domain,
475 mem_ctx,
476 &context);
477 if (!NT_STATUS_IS_OK(status)) {
478 return status;
481 context->db.ctx = db_open_rbt(context);
482 if (context->db.ctx == NULL) {
483 talloc_free(context);
484 return NT_STATUS_NO_MEMORY;
487 *_context = context;
488 return NT_STATUS_OK;
491 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
492 struct netlogon_creds_cli_context *context)
494 return context->client.auth_level;
497 struct netlogon_creds_cli_fetch_state {
498 TALLOC_CTX *mem_ctx;
499 struct netlogon_creds_CredentialState *creds;
500 uint32_t required_flags;
501 NTSTATUS status;
504 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
505 void *private_data)
507 struct netlogon_creds_cli_fetch_state *state =
508 (struct netlogon_creds_cli_fetch_state *)private_data;
509 enum ndr_err_code ndr_err;
510 DATA_BLOB blob;
511 uint32_t tmp_flags;
513 state->creds = talloc_zero(state->mem_ctx,
514 struct netlogon_creds_CredentialState);
515 if (state->creds == NULL) {
516 state->status = NT_STATUS_NO_MEMORY;
517 return;
520 blob.data = data.dptr;
521 blob.length = data.dsize;
523 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
524 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
525 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
526 TALLOC_FREE(state->creds);
527 state->status = ndr_map_error2ntstatus(ndr_err);
528 return;
531 tmp_flags = state->creds->negotiate_flags;
532 tmp_flags &= state->required_flags;
533 if (tmp_flags != state->required_flags) {
534 TALLOC_FREE(state->creds);
535 state->status = NT_STATUS_DOWNGRADE_DETECTED;
536 return;
539 state->status = NT_STATUS_OK;
542 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
543 TALLOC_CTX *mem_ctx,
544 struct netlogon_creds_CredentialState **_creds)
546 NTSTATUS status;
547 struct netlogon_creds_cli_fetch_state fstate = {
548 .mem_ctx = mem_ctx,
549 .status = NT_STATUS_INTERNAL_ERROR,
550 .required_flags = context->client.required_flags,
552 static const struct netr_Credential zero_creds;
554 *_creds = NULL;
556 status = dbwrap_parse_record(context->db.ctx,
557 context->db.key_data,
558 netlogon_creds_cli_fetch_parser,
559 &fstate);
560 if (!NT_STATUS_IS_OK(status)) {
561 return status;
563 status = fstate.status;
564 if (!NT_STATUS_IS_OK(status)) {
565 return status;
569 * mark it as invalid for step operations.
571 fstate.creds->sequence = 0;
572 fstate.creds->seed = zero_creds;
573 fstate.creds->client = zero_creds;
574 fstate.creds->server = zero_creds;
576 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
577 *_creds = fstate.creds;
578 return NT_STATUS_OK;
582 * It is really important to try SamLogonEx here,
583 * because multiple processes can talk to the same
584 * domain controller, without using the credential
585 * chain.
587 * With a normal SamLogon call, we must keep the
588 * credentials chain updated and intact between all
589 * users of the machine account (which would imply
590 * cross-node communication for every NTLM logon).
592 * The credentials chain is not per NETLOGON pipe
593 * connection, but globally on the server/client pair
594 * by computer name, while the client is free to use
595 * any computer name. We include the cluster node number
596 * in our computer name in order to avoid cross node
597 * coordination of the credential chain.
599 * It's also important to use NetlogonValidationSamInfo4 (6),
600 * because it relies on the rpc transport encryption
601 * and avoids using the global netlogon schannel
602 * session key to en/decrypt secret information
603 * like the user_session_key for network logons.
605 * [MS-APDS] 3.1.5.2 NTLM Network Logon
606 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
607 * NETLOGON_NEG_AUTHENTICATED_RPC set together
608 * are the indication that the server supports
609 * NetlogonValidationSamInfo4 (6). And it must only
610 * be used if "SealSecureChannel" is used.
612 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
613 * check is done in netlogon_creds_cli_LogonSamLogon*().
615 context->server.cached_flags = fstate.creds->negotiate_flags;
616 context->server.try_validation6 = true;
617 context->server.try_logon_ex = true;
618 context->server.try_logon_with = true;
620 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
621 context->server.try_validation6 = false;
622 context->server.try_logon_ex = false;
624 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
625 context->server.try_validation6 = false;
628 *_creds = fstate.creds;
629 return NT_STATUS_OK;
632 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
633 const struct netlogon_creds_CredentialState *creds1)
635 TALLOC_CTX *frame = talloc_stackframe();
636 struct netlogon_creds_CredentialState *creds2;
637 DATA_BLOB blob1;
638 DATA_BLOB blob2;
639 NTSTATUS status;
640 enum ndr_err_code ndr_err;
641 int cmp;
643 status = netlogon_creds_cli_get(context, frame, &creds2);
644 if (!NT_STATUS_IS_OK(status)) {
645 TALLOC_FREE(frame);
646 return false;
649 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
650 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
651 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
652 TALLOC_FREE(frame);
653 return false;
656 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
657 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
658 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
659 TALLOC_FREE(frame);
660 return false;
663 if (blob1.length != blob2.length) {
664 TALLOC_FREE(frame);
665 return false;
668 cmp = memcmp(blob1.data, blob2.data, blob1.length);
669 if (cmp != 0) {
670 TALLOC_FREE(frame);
671 return false;
674 TALLOC_FREE(frame);
675 return true;
678 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
679 struct netlogon_creds_CredentialState **_creds)
681 struct netlogon_creds_CredentialState *creds = *_creds;
682 NTSTATUS status;
683 enum ndr_err_code ndr_err;
684 DATA_BLOB blob;
685 TDB_DATA data;
687 *_creds = NULL;
689 if (context->db.locked_state == NULL) {
691 * this was not the result of netlogon_creds_cli_lock*()
693 TALLOC_FREE(creds);
694 return NT_STATUS_INVALID_PAGE_PROTECTION;
697 if (context->db.locked_state->creds != creds) {
699 * this was not the result of netlogon_creds_cli_lock*()
701 TALLOC_FREE(creds);
702 return NT_STATUS_INVALID_PAGE_PROTECTION;
705 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
706 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
707 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
708 TALLOC_FREE(creds);
709 status = ndr_map_error2ntstatus(ndr_err);
710 return status;
713 data.dptr = blob.data;
714 data.dsize = blob.length;
716 status = dbwrap_store(context->db.ctx,
717 context->db.key_data,
718 data, TDB_REPLACE);
719 TALLOC_FREE(creds);
720 if (!NT_STATUS_IS_OK(status)) {
721 return status;
724 return NT_STATUS_OK;
727 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
728 struct netlogon_creds_CredentialState **_creds)
730 struct netlogon_creds_CredentialState *creds = *_creds;
731 NTSTATUS status;
733 *_creds = NULL;
735 if (context->db.locked_state == NULL) {
737 * this was not the result of netlogon_creds_cli_lock*()
739 TALLOC_FREE(creds);
740 return NT_STATUS_INVALID_PAGE_PROTECTION;
743 if (context->db.locked_state->creds != creds) {
745 * this was not the result of netlogon_creds_cli_lock*()
747 TALLOC_FREE(creds);
748 return NT_STATUS_INVALID_PAGE_PROTECTION;
751 status = dbwrap_delete(context->db.ctx,
752 context->db.key_data);
753 TALLOC_FREE(creds);
754 if (!NT_STATUS_IS_OK(status)) {
755 return status;
758 return NT_STATUS_OK;
761 struct netlogon_creds_cli_lock_state {
762 struct netlogon_creds_cli_locked_state *locked_state;
763 struct netlogon_creds_CredentialState *creds;
766 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
767 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
769 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
770 struct tevent_context *ev,
771 struct netlogon_creds_cli_context *context)
773 struct tevent_req *req;
774 struct netlogon_creds_cli_lock_state *state;
775 struct netlogon_creds_cli_locked_state *locked_state;
776 struct tevent_req *subreq;
778 req = tevent_req_create(mem_ctx, &state,
779 struct netlogon_creds_cli_lock_state);
780 if (req == NULL) {
781 return NULL;
784 if (context->db.locked_state != NULL) {
785 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
786 return tevent_req_post(req, ev);
789 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
790 if (tevent_req_nomem(locked_state, req)) {
791 return tevent_req_post(req, ev);
793 talloc_set_destructor(locked_state,
794 netlogon_creds_cli_locked_state_destructor);
795 locked_state->context = context;
797 context->db.locked_state = locked_state;
798 state->locked_state = locked_state;
800 if (context->db.g_ctx == NULL) {
801 netlogon_creds_cli_lock_fetch(req);
802 if (!tevent_req_is_in_progress(req)) {
803 return tevent_req_post(req, ev);
806 return req;
809 subreq = g_lock_lock_send(state, ev,
810 context->db.g_ctx,
811 context->db.key_name,
812 G_LOCK_WRITE);
813 if (tevent_req_nomem(subreq, req)) {
814 return tevent_req_post(req, ev);
816 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
818 return req;
821 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
823 struct tevent_req *req =
824 tevent_req_callback_data(subreq,
825 struct tevent_req);
826 struct netlogon_creds_cli_lock_state *state =
827 tevent_req_data(req,
828 struct netlogon_creds_cli_lock_state);
829 NTSTATUS status;
831 status = g_lock_lock_recv(subreq);
832 TALLOC_FREE(subreq);
833 if (tevent_req_nterror(req, status)) {
834 return;
836 state->locked_state->is_glocked = true;
838 netlogon_creds_cli_lock_fetch(req);
841 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
843 struct netlogon_creds_cli_lock_state *state =
844 tevent_req_data(req,
845 struct netlogon_creds_cli_lock_state);
846 struct netlogon_creds_cli_context *context = state->locked_state->context;
847 struct netlogon_creds_cli_fetch_state fstate = {
848 .status = NT_STATUS_INTERNAL_ERROR,
849 .required_flags = context->client.required_flags,
851 NTSTATUS status;
853 fstate.mem_ctx = state;
854 status = dbwrap_parse_record(context->db.ctx,
855 context->db.key_data,
856 netlogon_creds_cli_fetch_parser,
857 &fstate);
858 if (tevent_req_nterror(req, status)) {
859 return;
861 status = fstate.status;
862 if (tevent_req_nterror(req, status)) {
863 return;
866 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
867 state->creds = fstate.creds;
868 tevent_req_done(req);
869 return;
872 context->server.cached_flags = fstate.creds->negotiate_flags;
873 context->server.try_validation6 = true;
874 context->server.try_logon_ex = true;
875 context->server.try_logon_with = true;
877 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
878 context->server.try_validation6 = false;
879 context->server.try_logon_ex = false;
881 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
882 context->server.try_validation6 = false;
885 state->creds = fstate.creds;
886 tevent_req_done(req);
887 return;
890 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
891 TALLOC_CTX *mem_ctx,
892 struct netlogon_creds_CredentialState **creds)
894 struct netlogon_creds_cli_lock_state *state =
895 tevent_req_data(req,
896 struct netlogon_creds_cli_lock_state);
897 NTSTATUS status;
899 if (tevent_req_is_nterror(req, &status)) {
900 tevent_req_received(req);
901 return status;
904 talloc_steal(state->creds, state->locked_state);
905 state->locked_state->creds = state->creds;
906 *creds = talloc_move(mem_ctx, &state->creds);
907 tevent_req_received(req);
908 return NT_STATUS_OK;
911 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
912 TALLOC_CTX *mem_ctx,
913 struct netlogon_creds_CredentialState **creds)
915 TALLOC_CTX *frame = talloc_stackframe();
916 struct tevent_context *ev;
917 struct tevent_req *req;
918 NTSTATUS status = NT_STATUS_NO_MEMORY;
920 ev = samba_tevent_context_init(frame);
921 if (ev == NULL) {
922 goto fail;
924 req = netlogon_creds_cli_lock_send(frame, ev, context);
925 if (req == NULL) {
926 goto fail;
928 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
929 goto fail;
931 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
932 fail:
933 TALLOC_FREE(frame);
934 return status;
937 struct netlogon_creds_cli_auth_state {
938 struct tevent_context *ev;
939 struct netlogon_creds_cli_context *context;
940 struct dcerpc_binding_handle *binding_handle;
941 struct samr_Password current_nt_hash;
942 struct samr_Password previous_nt_hash;
943 struct samr_Password used_nt_hash;
944 char *srv_name_slash;
945 uint32_t current_flags;
946 struct netr_Credential client_challenge;
947 struct netr_Credential server_challenge;
948 struct netlogon_creds_CredentialState *creds;
949 struct netr_Credential client_credential;
950 struct netr_Credential server_credential;
951 uint32_t rid;
952 bool try_auth3;
953 bool try_auth2;
954 bool require_auth2;
955 bool try_previous_nt_hash;
956 struct netlogon_creds_cli_locked_state *locked_state;
959 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
960 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
962 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
963 struct tevent_context *ev,
964 struct netlogon_creds_cli_context *context,
965 struct dcerpc_binding_handle *b,
966 struct samr_Password current_nt_hash,
967 const struct samr_Password *previous_nt_hash)
969 struct tevent_req *req;
970 struct netlogon_creds_cli_auth_state *state;
971 struct netlogon_creds_cli_locked_state *locked_state;
972 NTSTATUS status;
974 req = tevent_req_create(mem_ctx, &state,
975 struct netlogon_creds_cli_auth_state);
976 if (req == NULL) {
977 return NULL;
980 state->ev = ev;
981 state->context = context;
982 state->binding_handle = b;
983 state->current_nt_hash = current_nt_hash;
984 if (previous_nt_hash != NULL) {
985 state->previous_nt_hash = *previous_nt_hash;
986 state->try_previous_nt_hash = true;
989 if (context->db.locked_state != NULL) {
990 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
991 return tevent_req_post(req, ev);
994 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
995 if (tevent_req_nomem(locked_state, req)) {
996 return tevent_req_post(req, ev);
998 talloc_set_destructor(locked_state,
999 netlogon_creds_cli_locked_state_destructor);
1000 locked_state->context = context;
1002 context->db.locked_state = locked_state;
1003 state->locked_state = locked_state;
1005 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1006 context->server.computer);
1007 if (tevent_req_nomem(state->srv_name_slash, req)) {
1008 return tevent_req_post(req, ev);
1011 state->try_auth3 = true;
1012 state->try_auth2 = true;
1014 if (context->client.required_flags != 0) {
1015 state->require_auth2 = true;
1018 state->used_nt_hash = state->current_nt_hash;
1019 state->current_flags = context->client.proposed_flags;
1021 if (context->db.g_ctx != NULL) {
1022 struct tevent_req *subreq;
1024 subreq = g_lock_lock_send(state, ev,
1025 context->db.g_ctx,
1026 context->db.key_name,
1027 G_LOCK_WRITE);
1028 if (tevent_req_nomem(subreq, req)) {
1029 return tevent_req_post(req, ev);
1031 tevent_req_set_callback(subreq,
1032 netlogon_creds_cli_auth_locked,
1033 req);
1035 return req;
1038 status = dbwrap_delete(state->context->db.ctx,
1039 state->context->db.key_data);
1040 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1041 status = NT_STATUS_OK;
1043 if (tevent_req_nterror(req, status)) {
1044 return tevent_req_post(req, ev);
1047 netlogon_creds_cli_auth_challenge_start(req);
1048 if (!tevent_req_is_in_progress(req)) {
1049 return tevent_req_post(req, ev);
1052 return req;
1055 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1057 struct tevent_req *req =
1058 tevent_req_callback_data(subreq,
1059 struct tevent_req);
1060 struct netlogon_creds_cli_auth_state *state =
1061 tevent_req_data(req,
1062 struct netlogon_creds_cli_auth_state);
1063 NTSTATUS status;
1065 status = g_lock_lock_recv(subreq);
1066 TALLOC_FREE(subreq);
1067 if (tevent_req_nterror(req, status)) {
1068 return;
1070 state->locked_state->is_glocked = true;
1072 status = dbwrap_delete(state->context->db.ctx,
1073 state->context->db.key_data);
1074 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1075 status = NT_STATUS_OK;
1077 if (tevent_req_nterror(req, status)) {
1078 return;
1081 netlogon_creds_cli_auth_challenge_start(req);
1084 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1086 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1088 struct netlogon_creds_cli_auth_state *state =
1089 tevent_req_data(req,
1090 struct netlogon_creds_cli_auth_state);
1091 struct tevent_req *subreq;
1093 TALLOC_FREE(state->creds);
1095 generate_random_buffer(state->client_challenge.data,
1096 sizeof(state->client_challenge.data));
1098 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1099 state->binding_handle,
1100 state->srv_name_slash,
1101 state->context->client.computer,
1102 &state->client_challenge,
1103 &state->server_challenge);
1104 if (tevent_req_nomem(subreq, req)) {
1105 return;
1107 tevent_req_set_callback(subreq,
1108 netlogon_creds_cli_auth_challenge_done,
1109 req);
1112 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1114 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1116 struct tevent_req *req =
1117 tevent_req_callback_data(subreq,
1118 struct tevent_req);
1119 struct netlogon_creds_cli_auth_state *state =
1120 tevent_req_data(req,
1121 struct netlogon_creds_cli_auth_state);
1122 NTSTATUS status;
1123 NTSTATUS result;
1125 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1126 TALLOC_FREE(subreq);
1127 if (tevent_req_nterror(req, status)) {
1128 return;
1130 if (tevent_req_nterror(req, result)) {
1131 return;
1134 if (!state->try_auth3 && !state->try_auth2) {
1135 state->current_flags = 0;
1138 /* Calculate the session key and client credentials */
1140 state->creds = netlogon_creds_client_init(state,
1141 state->context->client.account,
1142 state->context->client.computer,
1143 state->context->client.type,
1144 &state->client_challenge,
1145 &state->server_challenge,
1146 &state->used_nt_hash,
1147 &state->client_credential,
1148 state->current_flags);
1149 if (tevent_req_nomem(state->creds, req)) {
1150 return;
1153 if (state->try_auth3) {
1154 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1155 state->binding_handle,
1156 state->srv_name_slash,
1157 state->context->client.account,
1158 state->context->client.type,
1159 state->context->client.computer,
1160 &state->client_credential,
1161 &state->server_credential,
1162 &state->creds->negotiate_flags,
1163 &state->rid);
1164 if (tevent_req_nomem(subreq, req)) {
1165 return;
1167 } else if (state->try_auth2) {
1168 state->rid = 0;
1170 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1171 state->binding_handle,
1172 state->srv_name_slash,
1173 state->context->client.account,
1174 state->context->client.type,
1175 state->context->client.computer,
1176 &state->client_credential,
1177 &state->server_credential,
1178 &state->creds->negotiate_flags);
1179 if (tevent_req_nomem(subreq, req)) {
1180 return;
1182 } else {
1183 state->rid = 0;
1185 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1186 state->binding_handle,
1187 state->srv_name_slash,
1188 state->context->client.account,
1189 state->context->client.type,
1190 state->context->client.computer,
1191 &state->client_credential,
1192 &state->server_credential);
1193 if (tevent_req_nomem(subreq, req)) {
1194 return;
1197 tevent_req_set_callback(subreq,
1198 netlogon_creds_cli_auth_srvauth_done,
1199 req);
1202 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1204 struct tevent_req *req =
1205 tevent_req_callback_data(subreq,
1206 struct tevent_req);
1207 struct netlogon_creds_cli_auth_state *state =
1208 tevent_req_data(req,
1209 struct netlogon_creds_cli_auth_state);
1210 NTSTATUS status;
1211 NTSTATUS result;
1212 bool ok;
1213 enum ndr_err_code ndr_err;
1214 DATA_BLOB blob;
1215 TDB_DATA data;
1216 uint32_t tmp_flags;
1218 if (state->try_auth3) {
1219 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1220 &result);
1221 TALLOC_FREE(subreq);
1222 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1223 state->try_auth3 = false;
1224 netlogon_creds_cli_auth_challenge_start(req);
1225 return;
1227 if (tevent_req_nterror(req, status)) {
1228 return;
1230 } else if (state->try_auth2) {
1231 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1232 &result);
1233 TALLOC_FREE(subreq);
1234 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1235 state->try_auth2 = false;
1236 if (state->require_auth2) {
1237 status = NT_STATUS_DOWNGRADE_DETECTED;
1238 tevent_req_nterror(req, status);
1239 return;
1241 netlogon_creds_cli_auth_challenge_start(req);
1242 return;
1244 if (tevent_req_nterror(req, status)) {
1245 return;
1247 } else {
1248 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1249 &result);
1250 TALLOC_FREE(subreq);
1251 if (tevent_req_nterror(req, status)) {
1252 return;
1256 if (!NT_STATUS_IS_OK(result) &&
1257 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1259 tevent_req_nterror(req, result);
1260 return;
1263 tmp_flags = state->creds->negotiate_flags;
1264 tmp_flags &= state->context->client.required_flags;
1265 if (tmp_flags != state->context->client.required_flags) {
1266 if (NT_STATUS_IS_OK(result)) {
1267 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1268 return;
1270 tevent_req_nterror(req, result);
1271 return;
1274 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1276 tmp_flags = state->context->client.proposed_flags;
1277 if ((state->current_flags == tmp_flags) &&
1278 (state->creds->negotiate_flags != tmp_flags))
1281 * lets retry with the negotiated flags
1283 state->current_flags = state->creds->negotiate_flags;
1284 netlogon_creds_cli_auth_challenge_start(req);
1285 return;
1288 if (!state->try_previous_nt_hash) {
1290 * we already retried, giving up...
1292 tevent_req_nterror(req, result);
1293 return;
1297 * lets retry with the old nt hash.
1299 state->try_previous_nt_hash = false;
1300 state->used_nt_hash = state->previous_nt_hash;
1301 state->current_flags = state->context->client.proposed_flags;
1302 netlogon_creds_cli_auth_challenge_start(req);
1303 return;
1306 ok = netlogon_creds_client_check(state->creds,
1307 &state->server_credential);
1308 if (!ok) {
1309 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1310 return;
1313 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1314 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1315 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1316 status = ndr_map_error2ntstatus(ndr_err);
1317 tevent_req_nterror(req, status);
1318 return;
1321 data.dptr = blob.data;
1322 data.dsize = blob.length;
1324 status = dbwrap_store(state->context->db.ctx,
1325 state->context->db.key_data,
1326 data, TDB_REPLACE);
1327 TALLOC_FREE(state->locked_state);
1328 if (tevent_req_nterror(req, status)) {
1329 return;
1332 tevent_req_done(req);
1335 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req)
1337 NTSTATUS status;
1339 if (tevent_req_is_nterror(req, &status)) {
1340 tevent_req_received(req);
1341 return status;
1344 tevent_req_received(req);
1345 return NT_STATUS_OK;
1348 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1349 struct dcerpc_binding_handle *b,
1350 struct samr_Password current_nt_hash,
1351 const struct samr_Password *previous_nt_hash)
1353 TALLOC_CTX *frame = talloc_stackframe();
1354 struct tevent_context *ev;
1355 struct tevent_req *req;
1356 NTSTATUS status = NT_STATUS_NO_MEMORY;
1358 ev = samba_tevent_context_init(frame);
1359 if (ev == NULL) {
1360 goto fail;
1362 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1363 current_nt_hash,
1364 previous_nt_hash);
1365 if (req == NULL) {
1366 goto fail;
1368 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1369 goto fail;
1371 status = netlogon_creds_cli_auth_recv(req);
1372 fail:
1373 TALLOC_FREE(frame);
1374 return status;
1377 struct netlogon_creds_cli_check_state {
1378 struct tevent_context *ev;
1379 struct netlogon_creds_cli_context *context;
1380 struct dcerpc_binding_handle *binding_handle;
1382 char *srv_name_slash;
1384 union netr_Capabilities caps;
1386 struct netlogon_creds_CredentialState *creds;
1387 struct netlogon_creds_CredentialState tmp_creds;
1388 struct netr_Authenticator req_auth;
1389 struct netr_Authenticator rep_auth;
1392 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1393 NTSTATUS status);
1394 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1396 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1397 struct tevent_context *ev,
1398 struct netlogon_creds_cli_context *context,
1399 struct dcerpc_binding_handle *b)
1401 struct tevent_req *req;
1402 struct netlogon_creds_cli_check_state *state;
1403 struct tevent_req *subreq;
1404 enum dcerpc_AuthType auth_type;
1405 enum dcerpc_AuthLevel auth_level;
1407 req = tevent_req_create(mem_ctx, &state,
1408 struct netlogon_creds_cli_check_state);
1409 if (req == NULL) {
1410 return NULL;
1413 state->ev = ev;
1414 state->context = context;
1415 state->binding_handle = b;
1417 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1418 context->server.computer);
1419 if (tevent_req_nomem(state->srv_name_slash, req)) {
1420 return tevent_req_post(req, ev);
1423 dcerpc_binding_handle_auth_info(state->binding_handle,
1424 &auth_type, &auth_level);
1426 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1427 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1428 return tevent_req_post(req, ev);
1431 switch (auth_level) {
1432 case DCERPC_AUTH_LEVEL_INTEGRITY:
1433 case DCERPC_AUTH_LEVEL_PRIVACY:
1434 break;
1435 default:
1436 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1437 return tevent_req_post(req, ev);
1440 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1441 state->context);
1442 if (tevent_req_nomem(subreq, req)) {
1443 return tevent_req_post(req, ev);
1446 tevent_req_set_callback(subreq,
1447 netlogon_creds_cli_check_locked,
1448 req);
1450 return req;
1453 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1454 NTSTATUS status)
1456 struct netlogon_creds_cli_check_state *state =
1457 tevent_req_data(req,
1458 struct netlogon_creds_cli_check_state);
1460 if (state->creds == NULL) {
1461 return;
1464 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1465 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1466 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1467 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1468 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1469 TALLOC_FREE(state->creds);
1470 return;
1473 netlogon_creds_cli_delete(state->context, &state->creds);
1476 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1478 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1480 struct tevent_req *req =
1481 tevent_req_callback_data(subreq,
1482 struct tevent_req);
1483 struct netlogon_creds_cli_check_state *state =
1484 tevent_req_data(req,
1485 struct netlogon_creds_cli_check_state);
1486 NTSTATUS status;
1488 status = netlogon_creds_cli_lock_recv(subreq, state,
1489 &state->creds);
1490 TALLOC_FREE(subreq);
1491 if (tevent_req_nterror(req, status)) {
1492 return;
1496 * we defer all callbacks in order to cleanup
1497 * the database record.
1499 tevent_req_defer_callback(req, state->ev);
1501 state->tmp_creds = *state->creds;
1502 netlogon_creds_client_authenticator(&state->tmp_creds,
1503 &state->req_auth);
1504 ZERO_STRUCT(state->rep_auth);
1506 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1507 state->binding_handle,
1508 state->srv_name_slash,
1509 state->context->client.computer,
1510 &state->req_auth,
1511 &state->rep_auth,
1513 &state->caps);
1514 if (tevent_req_nomem(subreq, req)) {
1515 status = NT_STATUS_NO_MEMORY;
1516 netlogon_creds_cli_check_cleanup(req, status);
1517 return;
1519 tevent_req_set_callback(subreq,
1520 netlogon_creds_cli_check_caps,
1521 req);
1524 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1526 struct tevent_req *req =
1527 tevent_req_callback_data(subreq,
1528 struct tevent_req);
1529 struct netlogon_creds_cli_check_state *state =
1530 tevent_req_data(req,
1531 struct netlogon_creds_cli_check_state);
1532 NTSTATUS status;
1533 NTSTATUS result;
1534 bool ok;
1536 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1537 &result);
1538 TALLOC_FREE(subreq);
1539 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1541 * Note that the negotiated flags are already checked
1542 * for our required flags after the ServerAuthenticate3/2 call.
1544 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1546 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1548 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1549 * already, we expect this to work!
1551 status = NT_STATUS_DOWNGRADE_DETECTED;
1552 tevent_req_nterror(req, status);
1553 netlogon_creds_cli_check_cleanup(req, status);
1554 return;
1557 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1559 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1560 * we expect this to work at least as far as the
1561 * NOT_SUPPORTED error handled below!
1563 * NT 4.0 and Old Samba servers are not
1564 * allowed without "require strong key = no"
1566 status = NT_STATUS_DOWNGRADE_DETECTED;
1567 tevent_req_nterror(req, status);
1568 netlogon_creds_cli_check_cleanup(req, status);
1569 return;
1573 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1574 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1575 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1577 * This is needed against NT 4.0 and old Samba servers.
1579 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1580 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1581 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1582 * with the next request as the sequence number processing
1583 * gets out of sync.
1585 netlogon_creds_cli_check_cleanup(req, result);
1586 tevent_req_done(req);
1587 return;
1589 if (tevent_req_nterror(req, status)) {
1590 netlogon_creds_cli_check_cleanup(req, status);
1591 return;
1594 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1596 * Note that the negotiated flags are already checked
1597 * for our required flags after the ServerAuthenticate3/2 call.
1599 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1601 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1603 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1604 * already, we expect this to work!
1606 status = NT_STATUS_DOWNGRADE_DETECTED;
1607 tevent_req_nterror(req, status);
1608 netlogon_creds_cli_check_cleanup(req, status);
1609 return;
1613 * This is ok, the server does not support
1614 * NETLOGON_NEG_SUPPORTS_AES.
1616 * netr_LogonGetCapabilities() was
1617 * netr_LogonDummyRoutine1() before
1618 * NETLOGON_NEG_SUPPORTS_AES was invented.
1620 netlogon_creds_cli_check_cleanup(req, result);
1621 tevent_req_done(req);
1622 return;
1625 ok = netlogon_creds_client_check(&state->tmp_creds,
1626 &state->rep_auth.cred);
1627 if (!ok) {
1628 status = NT_STATUS_ACCESS_DENIED;
1629 tevent_req_nterror(req, status);
1630 netlogon_creds_cli_check_cleanup(req, status);
1631 return;
1634 if (tevent_req_nterror(req, result)) {
1635 netlogon_creds_cli_check_cleanup(req, result);
1636 return;
1639 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1640 status = NT_STATUS_DOWNGRADE_DETECTED;
1641 tevent_req_nterror(req, status);
1642 netlogon_creds_cli_check_cleanup(req, status);
1643 return;
1647 * This is the key check that makes this check secure. If we
1648 * get OK here (rather than NOT_SUPPORTED), then the server
1649 * did support AES. If the server only proposed STRONG_KEYS
1650 * and not AES, then it should have failed with
1651 * NOT_IMPLEMENTED. We always send AES as a client, so the
1652 * server should always have returned it.
1654 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1655 status = NT_STATUS_DOWNGRADE_DETECTED;
1656 tevent_req_nterror(req, status);
1657 netlogon_creds_cli_check_cleanup(req, status);
1658 return;
1661 *state->creds = state->tmp_creds;
1662 status = netlogon_creds_cli_store(state->context,
1663 &state->creds);
1664 netlogon_creds_cli_check_cleanup(req, status);
1665 if (tevent_req_nterror(req, status)) {
1666 return;
1669 tevent_req_done(req);
1672 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1674 NTSTATUS status;
1676 if (tevent_req_is_nterror(req, &status)) {
1677 netlogon_creds_cli_check_cleanup(req, status);
1678 tevent_req_received(req);
1679 return status;
1682 tevent_req_received(req);
1683 return NT_STATUS_OK;
1686 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1687 struct dcerpc_binding_handle *b)
1689 TALLOC_CTX *frame = talloc_stackframe();
1690 struct tevent_context *ev;
1691 struct tevent_req *req;
1692 NTSTATUS status = NT_STATUS_NO_MEMORY;
1694 ev = samba_tevent_context_init(frame);
1695 if (ev == NULL) {
1696 goto fail;
1698 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1699 if (req == NULL) {
1700 goto fail;
1702 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1703 goto fail;
1705 status = netlogon_creds_cli_check_recv(req);
1706 fail:
1707 TALLOC_FREE(frame);
1708 return status;
1711 struct netlogon_creds_cli_ServerPasswordSet_state {
1712 struct tevent_context *ev;
1713 struct netlogon_creds_cli_context *context;
1714 struct dcerpc_binding_handle *binding_handle;
1715 uint32_t old_timeout;
1717 char *srv_name_slash;
1718 enum dcerpc_AuthType auth_type;
1719 enum dcerpc_AuthLevel auth_level;
1721 struct samr_CryptPassword samr_crypt_password;
1722 struct netr_CryptPassword netr_crypt_password;
1723 struct samr_Password samr_password;
1725 struct netlogon_creds_CredentialState *creds;
1726 struct netlogon_creds_CredentialState tmp_creds;
1727 struct netr_Authenticator req_auth;
1728 struct netr_Authenticator rep_auth;
1731 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1732 NTSTATUS status);
1733 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1735 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1736 struct tevent_context *ev,
1737 struct netlogon_creds_cli_context *context,
1738 struct dcerpc_binding_handle *b,
1739 const char *new_password,
1740 const uint32_t *new_version)
1742 struct tevent_req *req;
1743 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1744 struct tevent_req *subreq;
1745 bool ok;
1747 req = tevent_req_create(mem_ctx, &state,
1748 struct netlogon_creds_cli_ServerPasswordSet_state);
1749 if (req == NULL) {
1750 return NULL;
1753 state->ev = ev;
1754 state->context = context;
1755 state->binding_handle = b;
1758 * netr_ServerPasswordSet
1760 E_md4hash(new_password, state->samr_password.hash);
1763 * netr_ServerPasswordSet2
1765 ok = encode_pw_buffer(state->samr_crypt_password.data,
1766 new_password, STR_UNICODE);
1767 if (!ok) {
1768 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1769 return tevent_req_post(req, ev);
1772 if (new_version != NULL) {
1773 struct NL_PASSWORD_VERSION version;
1774 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1775 uint32_t ofs = 512 - len;
1776 uint8_t *p;
1778 if (ofs < 12) {
1779 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1780 return tevent_req_post(req, ev);
1782 ofs -= 12;
1784 version.ReservedField = 0;
1785 version.PasswordVersionNumber = *new_version;
1786 version.PasswordVersionPresent =
1787 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1789 p = state->samr_crypt_password.data + ofs;
1790 SIVAL(p, 0, version.ReservedField);
1791 SIVAL(p, 4, version.PasswordVersionNumber);
1792 SIVAL(p, 8, version.PasswordVersionPresent);
1795 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1796 context->server.computer);
1797 if (tevent_req_nomem(state->srv_name_slash, req)) {
1798 return tevent_req_post(req, ev);
1801 dcerpc_binding_handle_auth_info(state->binding_handle,
1802 &state->auth_type,
1803 &state->auth_level);
1805 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1806 state->context);
1807 if (tevent_req_nomem(subreq, req)) {
1808 return tevent_req_post(req, ev);
1811 tevent_req_set_callback(subreq,
1812 netlogon_creds_cli_ServerPasswordSet_locked,
1813 req);
1815 return req;
1818 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1819 NTSTATUS status)
1821 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1822 tevent_req_data(req,
1823 struct netlogon_creds_cli_ServerPasswordSet_state);
1825 if (state->creds == NULL) {
1826 return;
1829 dcerpc_binding_handle_set_timeout(state->binding_handle,
1830 state->old_timeout);
1832 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1833 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1834 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1835 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1836 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1837 TALLOC_FREE(state->creds);
1838 return;
1841 netlogon_creds_cli_delete(state->context, &state->creds);
1844 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1846 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1848 struct tevent_req *req =
1849 tevent_req_callback_data(subreq,
1850 struct tevent_req);
1851 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1852 tevent_req_data(req,
1853 struct netlogon_creds_cli_ServerPasswordSet_state);
1854 NTSTATUS status;
1856 status = netlogon_creds_cli_lock_recv(subreq, state,
1857 &state->creds);
1858 TALLOC_FREE(subreq);
1859 if (tevent_req_nterror(req, status)) {
1860 return;
1863 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1864 switch (state->auth_level) {
1865 case DCERPC_AUTH_LEVEL_INTEGRITY:
1866 case DCERPC_AUTH_LEVEL_PRIVACY:
1867 break;
1868 default:
1869 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1870 return;
1872 } else {
1873 uint32_t tmp = state->creds->negotiate_flags;
1875 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1877 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1878 * it should be used, which means
1879 * we had a chance to verify no downgrade
1880 * happened.
1882 * This relies on netlogon_creds_cli_check*
1883 * being called before, as first request after
1884 * the DCERPC bind.
1886 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1887 return;
1891 state->old_timeout = dcerpc_binding_handle_set_timeout(
1892 state->binding_handle, 600000);
1895 * we defer all callbacks in order to cleanup
1896 * the database record.
1898 tevent_req_defer_callback(req, state->ev);
1900 state->tmp_creds = *state->creds;
1901 netlogon_creds_client_authenticator(&state->tmp_creds,
1902 &state->req_auth);
1903 ZERO_STRUCT(state->rep_auth);
1905 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1907 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1908 netlogon_creds_aes_encrypt(&state->tmp_creds,
1909 state->samr_crypt_password.data,
1910 516);
1911 } else {
1912 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1913 state->samr_crypt_password.data,
1914 516);
1917 memcpy(state->netr_crypt_password.data,
1918 state->samr_crypt_password.data, 512);
1919 state->netr_crypt_password.length =
1920 IVAL(state->samr_crypt_password.data, 512);
1922 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1923 state->binding_handle,
1924 state->srv_name_slash,
1925 state->tmp_creds.account_name,
1926 state->tmp_creds.secure_channel_type,
1927 state->tmp_creds.computer_name,
1928 &state->req_auth,
1929 &state->rep_auth,
1930 &state->netr_crypt_password);
1931 if (tevent_req_nomem(subreq, req)) {
1932 status = NT_STATUS_NO_MEMORY;
1933 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1934 return;
1936 } else {
1937 netlogon_creds_des_encrypt(&state->tmp_creds,
1938 &state->samr_password);
1940 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1941 state->binding_handle,
1942 state->srv_name_slash,
1943 state->tmp_creds.account_name,
1944 state->tmp_creds.secure_channel_type,
1945 state->tmp_creds.computer_name,
1946 &state->req_auth,
1947 &state->rep_auth,
1948 &state->samr_password);
1949 if (tevent_req_nomem(subreq, req)) {
1950 status = NT_STATUS_NO_MEMORY;
1951 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1952 return;
1956 tevent_req_set_callback(subreq,
1957 netlogon_creds_cli_ServerPasswordSet_done,
1958 req);
1961 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1963 struct tevent_req *req =
1964 tevent_req_callback_data(subreq,
1965 struct tevent_req);
1966 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1967 tevent_req_data(req,
1968 struct netlogon_creds_cli_ServerPasswordSet_state);
1969 NTSTATUS status;
1970 NTSTATUS result;
1971 bool ok;
1973 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1974 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1975 &result);
1976 TALLOC_FREE(subreq);
1977 if (tevent_req_nterror(req, status)) {
1978 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1979 return;
1981 } else {
1982 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1983 &result);
1984 TALLOC_FREE(subreq);
1985 if (tevent_req_nterror(req, status)) {
1986 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1987 return;
1991 ok = netlogon_creds_client_check(&state->tmp_creds,
1992 &state->rep_auth.cred);
1993 if (!ok) {
1994 status = NT_STATUS_ACCESS_DENIED;
1995 tevent_req_nterror(req, status);
1996 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1997 return;
2000 if (tevent_req_nterror(req, result)) {
2001 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2002 return;
2005 dcerpc_binding_handle_set_timeout(state->binding_handle,
2006 state->old_timeout);
2008 *state->creds = state->tmp_creds;
2009 status = netlogon_creds_cli_store(state->context,
2010 &state->creds);
2011 if (tevent_req_nterror(req, status)) {
2012 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2013 return;
2016 tevent_req_done(req);
2019 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2021 NTSTATUS status;
2023 if (tevent_req_is_nterror(req, &status)) {
2024 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2025 tevent_req_received(req);
2026 return status;
2029 tevent_req_received(req);
2030 return NT_STATUS_OK;
2033 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2034 struct netlogon_creds_cli_context *context,
2035 struct dcerpc_binding_handle *b,
2036 const char *new_password,
2037 const uint32_t *new_version)
2039 TALLOC_CTX *frame = talloc_stackframe();
2040 struct tevent_context *ev;
2041 struct tevent_req *req;
2042 NTSTATUS status = NT_STATUS_NO_MEMORY;
2044 ev = samba_tevent_context_init(frame);
2045 if (ev == NULL) {
2046 goto fail;
2048 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2049 new_password,
2050 new_version);
2051 if (req == NULL) {
2052 goto fail;
2054 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2055 goto fail;
2057 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2058 fail:
2059 TALLOC_FREE(frame);
2060 return status;
2063 struct netlogon_creds_cli_LogonSamLogon_state {
2064 struct tevent_context *ev;
2065 struct netlogon_creds_cli_context *context;
2066 struct dcerpc_binding_handle *binding_handle;
2068 char *srv_name_slash;
2070 enum netr_LogonInfoClass logon_level;
2071 const union netr_LogonLevel *const_logon;
2072 union netr_LogonLevel *logon;
2073 uint32_t flags;
2075 uint16_t validation_level;
2076 union netr_Validation *validation;
2077 uint8_t authoritative;
2080 * do we need encryption at the application layer?
2082 bool user_encrypt;
2083 bool try_logon_ex;
2084 bool try_validation6;
2087 * the read only credentials before we started the operation
2089 struct netlogon_creds_CredentialState *ro_creds;
2091 struct netlogon_creds_CredentialState *lk_creds;
2093 struct netlogon_creds_CredentialState tmp_creds;
2094 struct netr_Authenticator req_auth;
2095 struct netr_Authenticator rep_auth;
2098 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2099 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2100 NTSTATUS status);
2102 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2103 struct tevent_context *ev,
2104 struct netlogon_creds_cli_context *context,
2105 struct dcerpc_binding_handle *b,
2106 enum netr_LogonInfoClass logon_level,
2107 const union netr_LogonLevel *logon,
2108 uint32_t flags)
2110 struct tevent_req *req;
2111 struct netlogon_creds_cli_LogonSamLogon_state *state;
2113 req = tevent_req_create(mem_ctx, &state,
2114 struct netlogon_creds_cli_LogonSamLogon_state);
2115 if (req == NULL) {
2116 return NULL;
2119 state->ev = ev;
2120 state->context = context;
2121 state->binding_handle = b;
2123 state->logon_level = logon_level;
2124 state->const_logon = logon;
2125 state->flags = flags;
2127 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2128 context->server.computer);
2129 if (tevent_req_nomem(state->srv_name_slash, req)) {
2130 return tevent_req_post(req, ev);
2133 switch (logon_level) {
2134 case NetlogonInteractiveInformation:
2135 case NetlogonInteractiveTransitiveInformation:
2136 case NetlogonServiceInformation:
2137 case NetlogonServiceTransitiveInformation:
2138 case NetlogonGenericInformation:
2139 state->user_encrypt = true;
2140 break;
2142 case NetlogonNetworkInformation:
2143 case NetlogonNetworkTransitiveInformation:
2144 break;
2147 state->validation = talloc_zero(state, union netr_Validation);
2148 if (tevent_req_nomem(state->validation, req)) {
2149 return tevent_req_post(req, ev);
2152 netlogon_creds_cli_LogonSamLogon_start(req);
2153 if (!tevent_req_is_in_progress(req)) {
2154 return tevent_req_post(req, ev);
2158 * we defer all callbacks in order to cleanup
2159 * the database record.
2161 tevent_req_defer_callback(req, state->ev);
2162 return req;
2165 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2166 NTSTATUS status)
2168 struct netlogon_creds_cli_LogonSamLogon_state *state =
2169 tevent_req_data(req,
2170 struct netlogon_creds_cli_LogonSamLogon_state);
2172 if (state->lk_creds == NULL) {
2173 return;
2176 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2178 * This is a hack to recover from a bug in old
2179 * Samba servers, when LogonSamLogonEx() fails:
2181 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2183 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2185 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2186 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2187 * If the sign/seal check fails.
2189 * In that case we need to cleanup the netlogon session.
2191 * It's the job of the caller to disconnect the current
2192 * connection, if netlogon_creds_cli_LogonSamLogon()
2193 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2195 if (!state->context->server.try_logon_with) {
2196 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2200 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2201 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2202 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2203 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2204 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2205 TALLOC_FREE(state->lk_creds);
2206 return;
2209 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2212 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2214 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2216 struct netlogon_creds_cli_LogonSamLogon_state *state =
2217 tevent_req_data(req,
2218 struct netlogon_creds_cli_LogonSamLogon_state);
2219 struct tevent_req *subreq;
2220 NTSTATUS status;
2221 enum dcerpc_AuthType auth_type;
2222 enum dcerpc_AuthLevel auth_level;
2224 TALLOC_FREE(state->ro_creds);
2225 TALLOC_FREE(state->logon);
2226 ZERO_STRUCTP(state->validation);
2228 dcerpc_binding_handle_auth_info(state->binding_handle,
2229 &auth_type, &auth_level);
2231 state->try_logon_ex = state->context->server.try_logon_ex;
2232 state->try_validation6 = state->context->server.try_validation6;
2234 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2235 state->try_logon_ex = false;
2238 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2239 state->try_validation6 = false;
2242 if (state->try_logon_ex) {
2243 if (state->try_validation6) {
2244 state->validation_level = 6;
2245 } else {
2246 state->validation_level = 3;
2247 state->user_encrypt = true;
2250 state->logon = netlogon_creds_shallow_copy_logon(state,
2251 state->logon_level,
2252 state->const_logon);
2253 if (tevent_req_nomem(state->logon, req)) {
2254 status = NT_STATUS_NO_MEMORY;
2255 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2256 return;
2259 if (state->user_encrypt) {
2260 status = netlogon_creds_cli_get(state->context,
2261 state,
2262 &state->ro_creds);
2263 if (!NT_STATUS_IS_OK(status)) {
2264 status = NT_STATUS_ACCESS_DENIED;
2265 tevent_req_nterror(req, status);
2266 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2267 return;
2270 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2271 state->logon_level,
2272 state->logon);
2275 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2276 state->binding_handle,
2277 state->srv_name_slash,
2278 state->context->client.computer,
2279 state->logon_level,
2280 state->logon,
2281 state->validation_level,
2282 state->validation,
2283 &state->authoritative,
2284 &state->flags);
2285 if (tevent_req_nomem(subreq, req)) {
2286 status = NT_STATUS_NO_MEMORY;
2287 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2288 return;
2290 tevent_req_set_callback(subreq,
2291 netlogon_creds_cli_LogonSamLogon_done,
2292 req);
2293 return;
2296 if (state->lk_creds == NULL) {
2297 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2298 state->context);
2299 if (tevent_req_nomem(subreq, req)) {
2300 status = NT_STATUS_NO_MEMORY;
2301 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2302 return;
2304 tevent_req_set_callback(subreq,
2305 netlogon_creds_cli_LogonSamLogon_done,
2306 req);
2307 return;
2310 state->tmp_creds = *state->lk_creds;
2311 netlogon_creds_client_authenticator(&state->tmp_creds,
2312 &state->req_auth);
2313 ZERO_STRUCT(state->rep_auth);
2315 state->logon = netlogon_creds_shallow_copy_logon(state,
2316 state->logon_level,
2317 state->const_logon);
2318 if (tevent_req_nomem(state->logon, req)) {
2319 status = NT_STATUS_NO_MEMORY;
2320 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2321 return;
2324 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2325 state->logon_level,
2326 state->logon);
2328 state->validation_level = 3;
2330 if (state->context->server.try_logon_with) {
2331 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2332 state->binding_handle,
2333 state->srv_name_slash,
2334 state->context->client.computer,
2335 &state->req_auth,
2336 &state->rep_auth,
2337 state->logon_level,
2338 state->logon,
2339 state->validation_level,
2340 state->validation,
2341 &state->authoritative,
2342 &state->flags);
2343 if (tevent_req_nomem(subreq, req)) {
2344 status = NT_STATUS_NO_MEMORY;
2345 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2346 return;
2348 } else {
2349 state->flags = 0;
2351 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2352 state->binding_handle,
2353 state->srv_name_slash,
2354 state->context->client.computer,
2355 &state->req_auth,
2356 &state->rep_auth,
2357 state->logon_level,
2358 state->logon,
2359 state->validation_level,
2360 state->validation,
2361 &state->authoritative);
2362 if (tevent_req_nomem(subreq, req)) {
2363 status = NT_STATUS_NO_MEMORY;
2364 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2365 return;
2369 tevent_req_set_callback(subreq,
2370 netlogon_creds_cli_LogonSamLogon_done,
2371 req);
2374 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2376 struct tevent_req *req =
2377 tevent_req_callback_data(subreq,
2378 struct tevent_req);
2379 struct netlogon_creds_cli_LogonSamLogon_state *state =
2380 tevent_req_data(req,
2381 struct netlogon_creds_cli_LogonSamLogon_state);
2382 NTSTATUS status;
2383 NTSTATUS result;
2384 bool ok;
2386 if (state->try_logon_ex) {
2387 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2388 state->validation,
2389 &result);
2390 TALLOC_FREE(subreq);
2391 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2392 state->context->server.try_validation6 = false;
2393 state->context->server.try_logon_ex = false;
2394 netlogon_creds_cli_LogonSamLogon_start(req);
2395 return;
2397 if (tevent_req_nterror(req, status)) {
2398 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2399 return;
2402 if ((state->validation_level == 6) &&
2403 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2404 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2405 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2407 state->context->server.try_validation6 = false;
2408 netlogon_creds_cli_LogonSamLogon_start(req);
2409 return;
2412 if (tevent_req_nterror(req, result)) {
2413 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2414 return;
2417 if (state->ro_creds == NULL) {
2418 tevent_req_done(req);
2419 return;
2422 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2423 if (!ok) {
2425 * We got a race, lets retry with on authenticator
2426 * protection.
2428 TALLOC_FREE(state->ro_creds);
2429 state->try_logon_ex = false;
2430 netlogon_creds_cli_LogonSamLogon_start(req);
2431 return;
2434 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2435 state->validation_level,
2436 state->validation);
2438 tevent_req_done(req);
2439 return;
2442 if (state->lk_creds == NULL) {
2443 status = netlogon_creds_cli_lock_recv(subreq, state,
2444 &state->lk_creds);
2445 TALLOC_FREE(subreq);
2446 if (tevent_req_nterror(req, status)) {
2447 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2448 return;
2451 netlogon_creds_cli_LogonSamLogon_start(req);
2452 return;
2455 if (state->context->server.try_logon_with) {
2456 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2457 state->validation,
2458 &result);
2459 TALLOC_FREE(subreq);
2460 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2461 state->context->server.try_logon_with = false;
2462 netlogon_creds_cli_LogonSamLogon_start(req);
2463 return;
2465 if (tevent_req_nterror(req, status)) {
2466 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2467 return;
2469 } else {
2470 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2471 state->validation,
2472 &result);
2473 TALLOC_FREE(subreq);
2474 if (tevent_req_nterror(req, status)) {
2475 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2476 return;
2480 ok = netlogon_creds_client_check(&state->tmp_creds,
2481 &state->rep_auth.cred);
2482 if (!ok) {
2483 status = NT_STATUS_ACCESS_DENIED;
2484 tevent_req_nterror(req, status);
2485 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2486 return;
2489 *state->lk_creds = state->tmp_creds;
2490 status = netlogon_creds_cli_store(state->context,
2491 &state->lk_creds);
2492 if (tevent_req_nterror(req, status)) {
2493 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2494 return;
2497 if (tevent_req_nterror(req, result)) {
2498 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2499 return;
2502 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2503 state->validation_level,
2504 state->validation);
2506 tevent_req_done(req);
2509 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2510 TALLOC_CTX *mem_ctx,
2511 uint16_t *validation_level,
2512 union netr_Validation **validation,
2513 uint8_t *authoritative,
2514 uint32_t *flags)
2516 struct netlogon_creds_cli_LogonSamLogon_state *state =
2517 tevent_req_data(req,
2518 struct netlogon_creds_cli_LogonSamLogon_state);
2519 NTSTATUS status;
2521 /* authoritative is also returned on error */
2522 *authoritative = state->authoritative;
2524 if (tevent_req_is_nterror(req, &status)) {
2525 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2526 tevent_req_received(req);
2527 return status;
2530 *validation_level = state->validation_level;
2531 *validation = talloc_move(mem_ctx, &state->validation);
2532 *flags = state->flags;
2534 tevent_req_received(req);
2535 return NT_STATUS_OK;
2538 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2539 struct netlogon_creds_cli_context *context,
2540 struct dcerpc_binding_handle *b,
2541 enum netr_LogonInfoClass logon_level,
2542 const union netr_LogonLevel *logon,
2543 TALLOC_CTX *mem_ctx,
2544 uint16_t *validation_level,
2545 union netr_Validation **validation,
2546 uint8_t *authoritative,
2547 uint32_t *flags)
2549 TALLOC_CTX *frame = talloc_stackframe();
2550 struct tevent_context *ev;
2551 struct tevent_req *req;
2552 NTSTATUS status = NT_STATUS_NO_MEMORY;
2554 ev = samba_tevent_context_init(frame);
2555 if (ev == NULL) {
2556 goto fail;
2558 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2559 logon_level, logon,
2560 *flags);
2561 if (req == NULL) {
2562 goto fail;
2564 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2565 goto fail;
2567 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2568 validation_level,
2569 validation,
2570 authoritative,
2571 flags);
2572 fail:
2573 TALLOC_FREE(frame);
2574 return status;