netlogon_creds_cli: Avoid a static const struct
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob2b238b701bc71493b3d6a32db2087b805b081ebb
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/ndr_netlogon.h"
35 #include "../librpc/gen_ndr/server_id.h"
36 #include "netlogon_creds_cli.h"
37 #include "source3/include/messages.h"
38 #include "source3/include/g_lock.h"
39 #include "libds/common/roles.h"
40 #include "lib/crypto/crypto.h"
42 struct netlogon_creds_cli_locked_state;
44 struct netlogon_creds_cli_context {
45 struct {
46 const char *computer;
47 const char *account;
48 uint32_t proposed_flags;
49 uint32_t required_flags;
50 enum netr_SchannelType type;
51 enum dcerpc_AuthLevel auth_level;
52 } client;
54 struct {
55 const char *computer;
56 const char *netbios_domain;
57 const char *dns_domain;
58 uint32_t cached_flags;
59 bool try_validation6;
60 bool try_logon_ex;
61 bool try_logon_with;
62 } server;
64 struct {
65 const char *key_name;
66 TDB_DATA key_data;
67 struct db_context *ctx;
68 struct g_lock_ctx *g_ctx;
69 struct netlogon_creds_cli_locked_state *locked_state;
70 } db;
73 struct netlogon_creds_cli_locked_state {
74 struct netlogon_creds_cli_context *context;
75 bool is_glocked;
76 struct netlogon_creds_CredentialState *creds;
79 static int netlogon_creds_cli_locked_state_destructor(
80 struct netlogon_creds_cli_locked_state *state)
82 struct netlogon_creds_cli_context *context = state->context;
84 if (context == NULL) {
85 return 0;
88 if (context->db.locked_state == state) {
89 context->db.locked_state = NULL;
92 if (state->is_glocked) {
93 g_lock_unlock(context->db.g_ctx,
94 context->db.key_name);
97 return 0;
100 static NTSTATUS netlogon_creds_cli_context_common(
101 const char *client_computer,
102 const char *client_account,
103 enum netr_SchannelType type,
104 enum dcerpc_AuthLevel auth_level,
105 uint32_t proposed_flags,
106 uint32_t required_flags,
107 const char *server_computer,
108 const char *server_netbios_domain,
109 const char *server_dns_domain,
110 TALLOC_CTX *mem_ctx,
111 struct netlogon_creds_cli_context **_context)
113 struct netlogon_creds_cli_context *context = NULL;
114 TALLOC_CTX *frame = talloc_stackframe();
115 char *_key_name = NULL;
116 char *server_netbios_name = NULL;
117 char *p = NULL;
119 *_context = NULL;
121 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
122 if (context == NULL) {
123 TALLOC_FREE(frame);
124 return NT_STATUS_NO_MEMORY;
127 context->client.computer = talloc_strdup(context, client_computer);
128 if (context->client.computer == NULL) {
129 TALLOC_FREE(context);
130 TALLOC_FREE(frame);
131 return NT_STATUS_NO_MEMORY;
134 context->client.account = talloc_strdup(context, client_account);
135 if (context->client.account == NULL) {
136 TALLOC_FREE(context);
137 TALLOC_FREE(frame);
138 return NT_STATUS_NO_MEMORY;
141 context->client.proposed_flags = proposed_flags;
142 context->client.required_flags = required_flags;
143 context->client.type = type;
144 context->client.auth_level = auth_level;
146 context->server.computer = talloc_strdup(context, server_computer);
147 if (context->server.computer == NULL) {
148 TALLOC_FREE(context);
149 TALLOC_FREE(frame);
150 return NT_STATUS_NO_MEMORY;
153 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
154 if (context->server.netbios_domain == NULL) {
155 TALLOC_FREE(context);
156 TALLOC_FREE(frame);
157 return NT_STATUS_NO_MEMORY;
160 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
161 if (context->server.dns_domain == NULL) {
162 TALLOC_FREE(context);
163 TALLOC_FREE(frame);
164 return NT_STATUS_NO_MEMORY;
168 * TODO:
169 * Force the callers to provide a unique
170 * value for server_computer and use this directly.
172 * For now we have to deal with
173 * "HOSTNAME" vs. "hostname.example.com".
175 server_netbios_name = talloc_strdup(frame, server_computer);
176 if (server_netbios_name == NULL) {
177 TALLOC_FREE(context);
178 TALLOC_FREE(frame);
179 return NT_STATUS_NO_MEMORY;
182 p = strchr(server_netbios_name, '.');
183 if (p != NULL) {
184 p[0] = '\0';
187 _key_name = talloc_asprintf(frame, "CLI[%s/%s]/SRV[%s/%s]",
188 client_computer,
189 client_account,
190 server_netbios_name,
191 server_netbios_domain);
192 if (_key_name == NULL) {
193 TALLOC_FREE(context);
194 TALLOC_FREE(frame);
195 return NT_STATUS_NO_MEMORY;
198 context->db.key_name = talloc_strdup_upper(context, _key_name);
199 if (context->db.key_name == NULL) {
200 TALLOC_FREE(context);
201 TALLOC_FREE(frame);
202 return NT_STATUS_NO_MEMORY;
205 context->db.key_data = string_term_tdb_data(context->db.key_name);
207 *_context = context;
208 TALLOC_FREE(frame);
209 return NT_STATUS_OK;
212 static struct db_context *netlogon_creds_cli_global_db;
214 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
216 if (netlogon_creds_cli_global_db != NULL) {
217 return NT_STATUS_INVALID_PARAMETER_MIX;
220 netlogon_creds_cli_global_db = talloc_move(NULL, db);
221 return NT_STATUS_OK;
224 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
226 char *fname;
227 struct db_context *global_db;
229 if (netlogon_creds_cli_global_db != NULL) {
230 return NT_STATUS_OK;
233 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
234 if (fname == NULL) {
235 return NT_STATUS_NO_MEMORY;
238 global_db = dbwrap_local_open(NULL, lp_ctx,
239 fname, 0,
240 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
241 O_RDWR|O_CREAT,
242 0600, DBWRAP_LOCK_ORDER_2,
243 DBWRAP_FLAG_NONE);
244 if (global_db == NULL) {
245 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
246 fname, strerror(errno)));
247 talloc_free(fname);
248 return NT_STATUS_NO_MEMORY;
250 TALLOC_FREE(fname);
252 netlogon_creds_cli_global_db = global_db;
253 return NT_STATUS_OK;
256 void netlogon_creds_cli_close_global_db(void)
258 TALLOC_FREE(netlogon_creds_cli_global_db);
261 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
262 struct messaging_context *msg_ctx,
263 const char *client_account,
264 enum netr_SchannelType type,
265 const char *server_computer,
266 const char *server_netbios_domain,
267 const char *server_dns_domain,
268 TALLOC_CTX *mem_ctx,
269 struct netlogon_creds_cli_context **_context)
271 TALLOC_CTX *frame = talloc_stackframe();
272 NTSTATUS status;
273 struct netlogon_creds_cli_context *context = NULL;
274 const char *client_computer;
275 uint32_t proposed_flags;
276 uint32_t required_flags = 0;
277 bool reject_md5_servers = false;
278 bool require_strong_key = false;
279 int require_sign_or_seal = true;
280 bool seal_secure_channel = true;
281 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
282 bool neutralize_nt4_emulation = false;
284 *_context = NULL;
286 client_computer = lpcfg_netbios_name(lp_ctx);
287 if (strlen(client_computer) > 15) {
288 return NT_STATUS_INVALID_PARAMETER_MIX;
292 * allow overwrite per domain
293 * reject md5 servers:<netbios_domain>
295 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
296 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
297 "reject md5 servers",
298 server_netbios_domain,
299 reject_md5_servers);
302 * allow overwrite per domain
303 * require strong key:<netbios_domain>
305 require_strong_key = lpcfg_require_strong_key(lp_ctx);
306 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
307 "require strong key",
308 server_netbios_domain,
309 require_strong_key);
312 * allow overwrite per domain
313 * client schannel:<netbios_domain>
315 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
316 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
317 "client schannel",
318 server_netbios_domain,
319 require_sign_or_seal);
322 * allow overwrite per domain
323 * winbind sealed pipes:<netbios_domain>
325 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
326 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
327 "winbind sealed pipes",
328 server_netbios_domain,
329 seal_secure_channel);
332 * allow overwrite per domain
333 * neutralize nt4 emulation:<netbios_domain>
335 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
336 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
337 "neutralize nt4 emulation",
338 server_netbios_domain,
339 neutralize_nt4_emulation);
341 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
342 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
344 switch (type) {
345 case SEC_CHAN_WKSTA:
346 if (lpcfg_security(lp_ctx) == SEC_ADS) {
348 * AD domains should be secure
350 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
351 require_sign_or_seal = true;
352 require_strong_key = true;
354 break;
356 case SEC_CHAN_DOMAIN:
357 break;
359 case SEC_CHAN_DNS_DOMAIN:
361 * AD domains should be secure
363 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
364 require_sign_or_seal = true;
365 require_strong_key = true;
366 neutralize_nt4_emulation = true;
367 break;
369 case SEC_CHAN_BDC:
370 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
371 require_sign_or_seal = true;
372 require_strong_key = true;
373 break;
375 case SEC_CHAN_RODC:
376 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
377 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
378 require_sign_or_seal = true;
379 require_strong_key = true;
380 neutralize_nt4_emulation = true;
381 break;
383 default:
384 TALLOC_FREE(frame);
385 return NT_STATUS_INVALID_PARAMETER;
388 if (neutralize_nt4_emulation) {
389 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
392 if (require_sign_or_seal == false) {
393 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
394 } else {
395 required_flags |= NETLOGON_NEG_ARCFOUR;
396 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
399 if (reject_md5_servers) {
400 required_flags |= NETLOGON_NEG_ARCFOUR;
401 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
402 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
403 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
406 if (require_strong_key) {
407 required_flags |= NETLOGON_NEG_ARCFOUR;
408 required_flags |= NETLOGON_NEG_STRONG_KEYS;
409 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
412 proposed_flags |= required_flags;
414 if (seal_secure_channel) {
415 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
416 } else {
417 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
420 status = netlogon_creds_cli_context_common(client_computer,
421 client_account,
422 type,
423 auth_level,
424 proposed_flags,
425 required_flags,
426 server_computer,
427 server_netbios_domain,
429 mem_ctx,
430 &context);
431 if (!NT_STATUS_IS_OK(status)) {
432 TALLOC_FREE(frame);
433 return status;
436 if (msg_ctx != NULL) {
437 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
438 if (context->db.g_ctx == NULL) {
439 TALLOC_FREE(context);
440 TALLOC_FREE(frame);
441 return NT_STATUS_NO_MEMORY;
445 if (netlogon_creds_cli_global_db != NULL) {
446 context->db.ctx = netlogon_creds_cli_global_db;
447 *_context = context;
448 TALLOC_FREE(frame);
449 return NT_STATUS_OK;
452 status = netlogon_creds_cli_open_global_db(lp_ctx);
453 if (!NT_STATUS_IS_OK(status)) {
454 TALLOC_FREE(context);
455 TALLOC_FREE(frame);
456 return NT_STATUS_NO_MEMORY;
459 context->db.ctx = netlogon_creds_cli_global_db;
460 *_context = context;
461 TALLOC_FREE(frame);
462 return NT_STATUS_OK;
465 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
466 const char *client_account,
467 enum netr_SchannelType type,
468 uint32_t proposed_flags,
469 uint32_t required_flags,
470 enum dcerpc_AuthLevel auth_level,
471 const char *server_computer,
472 const char *server_netbios_domain,
473 TALLOC_CTX *mem_ctx,
474 struct netlogon_creds_cli_context **_context)
476 NTSTATUS status;
477 struct netlogon_creds_cli_context *context = NULL;
479 *_context = NULL;
481 status = netlogon_creds_cli_context_common(client_computer,
482 client_account,
483 type,
484 auth_level,
485 proposed_flags,
486 required_flags,
487 server_computer,
488 server_netbios_domain,
490 mem_ctx,
491 &context);
492 if (!NT_STATUS_IS_OK(status)) {
493 return status;
496 context->db.ctx = db_open_rbt(context);
497 if (context->db.ctx == NULL) {
498 talloc_free(context);
499 return NT_STATUS_NO_MEMORY;
502 *_context = context;
503 return NT_STATUS_OK;
506 char *netlogon_creds_cli_debug_string(
507 const struct netlogon_creds_cli_context *context,
508 TALLOC_CTX *mem_ctx)
510 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
511 context->db.key_name);
514 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
515 struct netlogon_creds_cli_context *context)
517 return context->client.auth_level;
520 struct netlogon_creds_cli_fetch_state {
521 TALLOC_CTX *mem_ctx;
522 struct netlogon_creds_CredentialState *creds;
523 uint32_t required_flags;
524 NTSTATUS status;
527 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
528 void *private_data)
530 struct netlogon_creds_cli_fetch_state *state =
531 (struct netlogon_creds_cli_fetch_state *)private_data;
532 enum ndr_err_code ndr_err;
533 DATA_BLOB blob;
534 uint32_t tmp_flags;
536 state->creds = talloc_zero(state->mem_ctx,
537 struct netlogon_creds_CredentialState);
538 if (state->creds == NULL) {
539 state->status = NT_STATUS_NO_MEMORY;
540 return;
543 blob.data = data.dptr;
544 blob.length = data.dsize;
546 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
547 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
548 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
549 TALLOC_FREE(state->creds);
550 state->status = ndr_map_error2ntstatus(ndr_err);
551 return;
554 tmp_flags = state->creds->negotiate_flags;
555 tmp_flags &= state->required_flags;
556 if (tmp_flags != state->required_flags) {
557 TALLOC_FREE(state->creds);
558 state->status = NT_STATUS_DOWNGRADE_DETECTED;
559 return;
562 state->status = NT_STATUS_OK;
565 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
566 TALLOC_CTX *mem_ctx,
567 struct netlogon_creds_CredentialState **_creds)
569 NTSTATUS status;
570 struct netlogon_creds_cli_fetch_state fstate = {
571 .mem_ctx = mem_ctx,
572 .status = NT_STATUS_INTERNAL_ERROR,
573 .required_flags = context->client.required_flags,
576 *_creds = NULL;
578 status = dbwrap_parse_record(context->db.ctx,
579 context->db.key_data,
580 netlogon_creds_cli_fetch_parser,
581 &fstate);
582 if (!NT_STATUS_IS_OK(status)) {
583 return status;
585 status = fstate.status;
586 if (!NT_STATUS_IS_OK(status)) {
587 return status;
591 * mark it as invalid for step operations.
593 fstate.creds->sequence = 0;
594 fstate.creds->seed = (struct netr_Credential) {{0}};
595 fstate.creds->client = (struct netr_Credential) {{0}};
596 fstate.creds->server = (struct netr_Credential) {{0}};
598 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
599 *_creds = fstate.creds;
600 return NT_STATUS_OK;
604 * It is really important to try SamLogonEx here,
605 * because multiple processes can talk to the same
606 * domain controller, without using the credential
607 * chain.
609 * With a normal SamLogon call, we must keep the
610 * credentials chain updated and intact between all
611 * users of the machine account (which would imply
612 * cross-node communication for every NTLM logon).
614 * The credentials chain is not per NETLOGON pipe
615 * connection, but globally on the server/client pair
616 * by computer name, while the client is free to use
617 * any computer name. We include the cluster node number
618 * in our computer name in order to avoid cross node
619 * coordination of the credential chain.
621 * It's also important to use NetlogonValidationSamInfo4 (6),
622 * because it relies on the rpc transport encryption
623 * and avoids using the global netlogon schannel
624 * session key to en/decrypt secret information
625 * like the user_session_key for network logons.
627 * [MS-APDS] 3.1.5.2 NTLM Network Logon
628 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
629 * NETLOGON_NEG_AUTHENTICATED_RPC set together
630 * are the indication that the server supports
631 * NetlogonValidationSamInfo4 (6). And it must only
632 * be used if "SealSecureChannel" is used.
634 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
635 * check is done in netlogon_creds_cli_LogonSamLogon*().
637 context->server.cached_flags = fstate.creds->negotiate_flags;
638 context->server.try_validation6 = true;
639 context->server.try_logon_ex = true;
640 context->server.try_logon_with = true;
642 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
643 context->server.try_validation6 = false;
644 context->server.try_logon_ex = false;
646 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
647 context->server.try_validation6 = false;
650 *_creds = fstate.creds;
651 return NT_STATUS_OK;
654 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
655 const struct netlogon_creds_CredentialState *creds1)
657 TALLOC_CTX *frame = talloc_stackframe();
658 struct netlogon_creds_CredentialState *creds2;
659 DATA_BLOB blob1;
660 DATA_BLOB blob2;
661 NTSTATUS status;
662 enum ndr_err_code ndr_err;
663 int cmp;
665 status = netlogon_creds_cli_get(context, frame, &creds2);
666 if (!NT_STATUS_IS_OK(status)) {
667 TALLOC_FREE(frame);
668 return false;
671 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
672 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
673 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
674 TALLOC_FREE(frame);
675 return false;
678 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
679 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
680 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
681 TALLOC_FREE(frame);
682 return false;
685 if (blob1.length != blob2.length) {
686 TALLOC_FREE(frame);
687 return false;
690 cmp = memcmp(blob1.data, blob2.data, blob1.length);
691 if (cmp != 0) {
692 TALLOC_FREE(frame);
693 return false;
696 TALLOC_FREE(frame);
697 return true;
700 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
701 struct netlogon_creds_CredentialState **_creds)
703 struct netlogon_creds_CredentialState *creds = *_creds;
704 NTSTATUS status;
705 enum ndr_err_code ndr_err;
706 DATA_BLOB blob;
707 TDB_DATA data;
709 *_creds = NULL;
711 if (context->db.locked_state == NULL) {
713 * this was not the result of netlogon_creds_cli_lock*()
715 TALLOC_FREE(creds);
716 return NT_STATUS_INVALID_PAGE_PROTECTION;
719 if (context->db.locked_state->creds != creds) {
721 * this was not the result of netlogon_creds_cli_lock*()
723 TALLOC_FREE(creds);
724 return NT_STATUS_INVALID_PAGE_PROTECTION;
727 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
728 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
729 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
730 TALLOC_FREE(creds);
731 status = ndr_map_error2ntstatus(ndr_err);
732 return status;
735 data.dptr = blob.data;
736 data.dsize = blob.length;
738 status = dbwrap_store(context->db.ctx,
739 context->db.key_data,
740 data, TDB_REPLACE);
741 TALLOC_FREE(creds);
742 if (!NT_STATUS_IS_OK(status)) {
743 return status;
746 return NT_STATUS_OK;
749 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
750 struct netlogon_creds_CredentialState **_creds)
752 struct netlogon_creds_CredentialState *creds = *_creds;
753 NTSTATUS status;
755 *_creds = NULL;
757 if (context->db.locked_state == NULL) {
759 * this was not the result of netlogon_creds_cli_lock*()
761 TALLOC_FREE(creds);
762 return NT_STATUS_INVALID_PAGE_PROTECTION;
765 if (context->db.locked_state->creds != creds) {
767 * this was not the result of netlogon_creds_cli_lock*()
769 TALLOC_FREE(creds);
770 return NT_STATUS_INVALID_PAGE_PROTECTION;
773 status = dbwrap_delete(context->db.ctx,
774 context->db.key_data);
775 TALLOC_FREE(creds);
776 if (!NT_STATUS_IS_OK(status)) {
777 return status;
780 return NT_STATUS_OK;
783 struct netlogon_creds_cli_lock_state {
784 struct netlogon_creds_cli_locked_state *locked_state;
785 struct netlogon_creds_CredentialState *creds;
788 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
789 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
791 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
792 struct tevent_context *ev,
793 struct netlogon_creds_cli_context *context)
795 struct tevent_req *req;
796 struct netlogon_creds_cli_lock_state *state;
797 struct netlogon_creds_cli_locked_state *locked_state;
798 struct tevent_req *subreq;
800 req = tevent_req_create(mem_ctx, &state,
801 struct netlogon_creds_cli_lock_state);
802 if (req == NULL) {
803 return NULL;
806 if (context->db.locked_state != NULL) {
807 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
808 return tevent_req_post(req, ev);
811 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
812 if (tevent_req_nomem(locked_state, req)) {
813 return tevent_req_post(req, ev);
815 talloc_set_destructor(locked_state,
816 netlogon_creds_cli_locked_state_destructor);
817 locked_state->context = context;
819 context->db.locked_state = locked_state;
820 state->locked_state = locked_state;
822 if (context->db.g_ctx == NULL) {
823 netlogon_creds_cli_lock_fetch(req);
824 if (!tevent_req_is_in_progress(req)) {
825 return tevent_req_post(req, ev);
828 return req;
831 subreq = g_lock_lock_send(state, ev,
832 context->db.g_ctx,
833 context->db.key_name,
834 G_LOCK_WRITE);
835 if (tevent_req_nomem(subreq, req)) {
836 return tevent_req_post(req, ev);
838 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
840 return req;
843 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
845 struct tevent_req *req =
846 tevent_req_callback_data(subreq,
847 struct tevent_req);
848 struct netlogon_creds_cli_lock_state *state =
849 tevent_req_data(req,
850 struct netlogon_creds_cli_lock_state);
851 NTSTATUS status;
853 status = g_lock_lock_recv(subreq);
854 TALLOC_FREE(subreq);
855 if (tevent_req_nterror(req, status)) {
856 return;
858 state->locked_state->is_glocked = true;
860 netlogon_creds_cli_lock_fetch(req);
863 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
865 struct netlogon_creds_cli_lock_state *state =
866 tevent_req_data(req,
867 struct netlogon_creds_cli_lock_state);
868 struct netlogon_creds_cli_context *context = state->locked_state->context;
869 struct netlogon_creds_cli_fetch_state fstate = {
870 .status = NT_STATUS_INTERNAL_ERROR,
871 .required_flags = context->client.required_flags,
873 NTSTATUS status;
875 fstate.mem_ctx = state;
876 status = dbwrap_parse_record(context->db.ctx,
877 context->db.key_data,
878 netlogon_creds_cli_fetch_parser,
879 &fstate);
880 if (tevent_req_nterror(req, status)) {
881 return;
883 status = fstate.status;
884 if (tevent_req_nterror(req, status)) {
885 return;
888 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
889 state->creds = fstate.creds;
890 tevent_req_done(req);
891 return;
894 context->server.cached_flags = fstate.creds->negotiate_flags;
895 context->server.try_validation6 = true;
896 context->server.try_logon_ex = true;
897 context->server.try_logon_with = true;
899 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
900 context->server.try_validation6 = false;
901 context->server.try_logon_ex = false;
903 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
904 context->server.try_validation6 = false;
907 state->creds = fstate.creds;
908 tevent_req_done(req);
909 return;
912 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
913 TALLOC_CTX *mem_ctx,
914 struct netlogon_creds_CredentialState **creds)
916 struct netlogon_creds_cli_lock_state *state =
917 tevent_req_data(req,
918 struct netlogon_creds_cli_lock_state);
919 NTSTATUS status;
921 if (tevent_req_is_nterror(req, &status)) {
922 tevent_req_received(req);
923 return status;
926 talloc_steal(state->creds, state->locked_state);
927 state->locked_state->creds = state->creds;
928 *creds = talloc_move(mem_ctx, &state->creds);
929 tevent_req_received(req);
930 return NT_STATUS_OK;
933 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
934 TALLOC_CTX *mem_ctx,
935 struct netlogon_creds_CredentialState **creds)
937 TALLOC_CTX *frame = talloc_stackframe();
938 struct tevent_context *ev;
939 struct tevent_req *req;
940 NTSTATUS status = NT_STATUS_NO_MEMORY;
942 ev = samba_tevent_context_init(frame);
943 if (ev == NULL) {
944 goto fail;
946 req = netlogon_creds_cli_lock_send(frame, ev, context);
947 if (req == NULL) {
948 goto fail;
950 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
951 goto fail;
953 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
954 fail:
955 TALLOC_FREE(frame);
956 return status;
959 struct netlogon_creds_cli_auth_state {
960 struct tevent_context *ev;
961 struct netlogon_creds_cli_context *context;
962 struct dcerpc_binding_handle *binding_handle;
963 uint8_t num_nt_hashes;
964 uint8_t idx_nt_hashes;
965 const struct samr_Password * const *nt_hashes;
966 const struct samr_Password *used_nt_hash;
967 char *srv_name_slash;
968 uint32_t current_flags;
969 struct netr_Credential client_challenge;
970 struct netr_Credential server_challenge;
971 struct netlogon_creds_CredentialState *creds;
972 struct netr_Credential client_credential;
973 struct netr_Credential server_credential;
974 uint32_t rid;
975 bool try_auth3;
976 bool try_auth2;
977 bool require_auth2;
978 struct netlogon_creds_cli_locked_state *locked_state;
981 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
982 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
984 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
985 struct tevent_context *ev,
986 struct netlogon_creds_cli_context *context,
987 struct dcerpc_binding_handle *b,
988 uint8_t num_nt_hashes,
989 const struct samr_Password * const *nt_hashes)
991 struct tevent_req *req;
992 struct netlogon_creds_cli_auth_state *state;
993 struct netlogon_creds_cli_locked_state *locked_state;
994 NTSTATUS status;
996 req = tevent_req_create(mem_ctx, &state,
997 struct netlogon_creds_cli_auth_state);
998 if (req == NULL) {
999 return NULL;
1002 state->ev = ev;
1003 state->context = context;
1004 state->binding_handle = b;
1005 if (num_nt_hashes < 1) {
1006 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1007 return tevent_req_post(req, ev);
1009 if (num_nt_hashes > 4) {
1010 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1011 return tevent_req_post(req, ev);
1014 state->num_nt_hashes = num_nt_hashes;
1015 state->idx_nt_hashes = 0;
1016 state->nt_hashes = nt_hashes;
1018 if (context->db.locked_state != NULL) {
1019 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
1020 return tevent_req_post(req, ev);
1023 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
1024 if (tevent_req_nomem(locked_state, req)) {
1025 return tevent_req_post(req, ev);
1027 talloc_set_destructor(locked_state,
1028 netlogon_creds_cli_locked_state_destructor);
1029 locked_state->context = context;
1031 context->db.locked_state = locked_state;
1032 state->locked_state = locked_state;
1034 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1035 context->server.computer);
1036 if (tevent_req_nomem(state->srv_name_slash, req)) {
1037 return tevent_req_post(req, ev);
1040 state->try_auth3 = true;
1041 state->try_auth2 = true;
1043 if (context->client.required_flags != 0) {
1044 state->require_auth2 = true;
1047 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1048 state->current_flags = context->client.proposed_flags;
1050 if (context->db.g_ctx != NULL) {
1051 struct tevent_req *subreq;
1053 subreq = g_lock_lock_send(state, ev,
1054 context->db.g_ctx,
1055 context->db.key_name,
1056 G_LOCK_WRITE);
1057 if (tevent_req_nomem(subreq, req)) {
1058 return tevent_req_post(req, ev);
1060 tevent_req_set_callback(subreq,
1061 netlogon_creds_cli_auth_locked,
1062 req);
1064 return req;
1067 status = dbwrap_purge(state->context->db.ctx,
1068 state->context->db.key_data);
1069 if (tevent_req_nterror(req, status)) {
1070 return tevent_req_post(req, ev);
1073 netlogon_creds_cli_auth_challenge_start(req);
1074 if (!tevent_req_is_in_progress(req)) {
1075 return tevent_req_post(req, ev);
1078 return req;
1081 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1083 struct tevent_req *req =
1084 tevent_req_callback_data(subreq,
1085 struct tevent_req);
1086 struct netlogon_creds_cli_auth_state *state =
1087 tevent_req_data(req,
1088 struct netlogon_creds_cli_auth_state);
1089 NTSTATUS status;
1091 status = g_lock_lock_recv(subreq);
1092 TALLOC_FREE(subreq);
1093 if (tevent_req_nterror(req, status)) {
1094 return;
1096 state->locked_state->is_glocked = true;
1098 status = dbwrap_purge(state->context->db.ctx,
1099 state->context->db.key_data);
1100 if (tevent_req_nterror(req, status)) {
1101 return;
1104 netlogon_creds_cli_auth_challenge_start(req);
1107 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1109 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1111 struct netlogon_creds_cli_auth_state *state =
1112 tevent_req_data(req,
1113 struct netlogon_creds_cli_auth_state);
1114 struct tevent_req *subreq;
1116 TALLOC_FREE(state->creds);
1118 generate_random_buffer(state->client_challenge.data,
1119 sizeof(state->client_challenge.data));
1121 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1122 state->binding_handle,
1123 state->srv_name_slash,
1124 state->context->client.computer,
1125 &state->client_challenge,
1126 &state->server_challenge);
1127 if (tevent_req_nomem(subreq, req)) {
1128 return;
1130 tevent_req_set_callback(subreq,
1131 netlogon_creds_cli_auth_challenge_done,
1132 req);
1135 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1137 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1139 struct tevent_req *req =
1140 tevent_req_callback_data(subreq,
1141 struct tevent_req);
1142 struct netlogon_creds_cli_auth_state *state =
1143 tevent_req_data(req,
1144 struct netlogon_creds_cli_auth_state);
1145 NTSTATUS status;
1146 NTSTATUS result;
1148 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1149 TALLOC_FREE(subreq);
1150 if (tevent_req_nterror(req, status)) {
1151 return;
1153 if (tevent_req_nterror(req, result)) {
1154 return;
1157 if (!state->try_auth3 && !state->try_auth2) {
1158 state->current_flags = 0;
1161 /* Calculate the session key and client credentials */
1163 state->creds = netlogon_creds_client_init(state,
1164 state->context->client.account,
1165 state->context->client.computer,
1166 state->context->client.type,
1167 &state->client_challenge,
1168 &state->server_challenge,
1169 state->used_nt_hash,
1170 &state->client_credential,
1171 state->current_flags);
1172 if (tevent_req_nomem(state->creds, req)) {
1173 return;
1176 if (state->try_auth3) {
1177 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1178 state->binding_handle,
1179 state->srv_name_slash,
1180 state->context->client.account,
1181 state->context->client.type,
1182 state->context->client.computer,
1183 &state->client_credential,
1184 &state->server_credential,
1185 &state->creds->negotiate_flags,
1186 &state->rid);
1187 if (tevent_req_nomem(subreq, req)) {
1188 return;
1190 } else if (state->try_auth2) {
1191 state->rid = 0;
1193 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1194 state->binding_handle,
1195 state->srv_name_slash,
1196 state->context->client.account,
1197 state->context->client.type,
1198 state->context->client.computer,
1199 &state->client_credential,
1200 &state->server_credential,
1201 &state->creds->negotiate_flags);
1202 if (tevent_req_nomem(subreq, req)) {
1203 return;
1205 } else {
1206 state->rid = 0;
1208 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1209 state->binding_handle,
1210 state->srv_name_slash,
1211 state->context->client.account,
1212 state->context->client.type,
1213 state->context->client.computer,
1214 &state->client_credential,
1215 &state->server_credential);
1216 if (tevent_req_nomem(subreq, req)) {
1217 return;
1220 tevent_req_set_callback(subreq,
1221 netlogon_creds_cli_auth_srvauth_done,
1222 req);
1225 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1227 struct tevent_req *req =
1228 tevent_req_callback_data(subreq,
1229 struct tevent_req);
1230 struct netlogon_creds_cli_auth_state *state =
1231 tevent_req_data(req,
1232 struct netlogon_creds_cli_auth_state);
1233 NTSTATUS status;
1234 NTSTATUS result;
1235 bool ok;
1236 enum ndr_err_code ndr_err;
1237 DATA_BLOB blob;
1238 TDB_DATA data;
1239 uint32_t tmp_flags;
1241 if (state->try_auth3) {
1242 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1243 &result);
1244 TALLOC_FREE(subreq);
1245 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1246 state->try_auth3 = false;
1247 netlogon_creds_cli_auth_challenge_start(req);
1248 return;
1250 if (tevent_req_nterror(req, status)) {
1251 return;
1253 } else if (state->try_auth2) {
1254 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1255 &result);
1256 TALLOC_FREE(subreq);
1257 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1258 state->try_auth2 = false;
1259 if (state->require_auth2) {
1260 status = NT_STATUS_DOWNGRADE_DETECTED;
1261 tevent_req_nterror(req, status);
1262 return;
1264 netlogon_creds_cli_auth_challenge_start(req);
1265 return;
1267 if (tevent_req_nterror(req, status)) {
1268 return;
1270 } else {
1271 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1272 &result);
1273 TALLOC_FREE(subreq);
1274 if (tevent_req_nterror(req, status)) {
1275 return;
1279 if (!NT_STATUS_IS_OK(result) &&
1280 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1282 tevent_req_nterror(req, result);
1283 return;
1286 tmp_flags = state->creds->negotiate_flags;
1287 tmp_flags &= state->context->client.required_flags;
1288 if (tmp_flags != state->context->client.required_flags) {
1289 if (NT_STATUS_IS_OK(result)) {
1290 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1291 return;
1293 tevent_req_nterror(req, result);
1294 return;
1297 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1299 tmp_flags = state->context->client.proposed_flags;
1300 if ((state->current_flags == tmp_flags) &&
1301 (state->creds->negotiate_flags != tmp_flags))
1304 * lets retry with the negotiated flags
1306 state->current_flags = state->creds->negotiate_flags;
1307 netlogon_creds_cli_auth_challenge_start(req);
1308 return;
1311 state->idx_nt_hashes += 1;
1312 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1314 * we already retried, giving up...
1316 tevent_req_nterror(req, result);
1317 return;
1321 * lets retry with the old nt hash.
1323 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1324 state->current_flags = state->context->client.proposed_flags;
1325 netlogon_creds_cli_auth_challenge_start(req);
1326 return;
1329 ok = netlogon_creds_client_check(state->creds,
1330 &state->server_credential);
1331 if (!ok) {
1332 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1333 return;
1336 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1337 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1338 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1339 status = ndr_map_error2ntstatus(ndr_err);
1340 tevent_req_nterror(req, status);
1341 return;
1344 data.dptr = blob.data;
1345 data.dsize = blob.length;
1347 status = dbwrap_store(state->context->db.ctx,
1348 state->context->db.key_data,
1349 data, TDB_REPLACE);
1350 TALLOC_FREE(state->locked_state);
1351 if (tevent_req_nterror(req, status)) {
1352 return;
1355 tevent_req_done(req);
1358 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1359 uint8_t *idx_nt_hashes)
1361 struct netlogon_creds_cli_auth_state *state =
1362 tevent_req_data(req,
1363 struct netlogon_creds_cli_auth_state);
1364 NTSTATUS status;
1366 *idx_nt_hashes = 0;
1368 if (tevent_req_is_nterror(req, &status)) {
1369 tevent_req_received(req);
1370 return status;
1373 *idx_nt_hashes = state->idx_nt_hashes;
1374 tevent_req_received(req);
1375 return NT_STATUS_OK;
1378 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1379 struct dcerpc_binding_handle *b,
1380 uint8_t num_nt_hashes,
1381 const struct samr_Password * const *nt_hashes,
1382 uint8_t *idx_nt_hashes)
1384 TALLOC_CTX *frame = talloc_stackframe();
1385 struct tevent_context *ev;
1386 struct tevent_req *req;
1387 NTSTATUS status = NT_STATUS_NO_MEMORY;
1389 *idx_nt_hashes = 0;
1391 ev = samba_tevent_context_init(frame);
1392 if (ev == NULL) {
1393 goto fail;
1395 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1396 num_nt_hashes, nt_hashes);
1397 if (req == NULL) {
1398 goto fail;
1400 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1401 goto fail;
1403 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1404 fail:
1405 TALLOC_FREE(frame);
1406 return status;
1409 struct netlogon_creds_cli_check_state {
1410 struct tevent_context *ev;
1411 struct netlogon_creds_cli_context *context;
1412 struct dcerpc_binding_handle *binding_handle;
1414 char *srv_name_slash;
1416 union netr_Capabilities caps;
1418 struct netlogon_creds_CredentialState *creds;
1419 struct netlogon_creds_CredentialState tmp_creds;
1420 struct netr_Authenticator req_auth;
1421 struct netr_Authenticator rep_auth;
1424 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1425 NTSTATUS status);
1426 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1428 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1429 struct tevent_context *ev,
1430 struct netlogon_creds_cli_context *context,
1431 struct dcerpc_binding_handle *b)
1433 struct tevent_req *req;
1434 struct netlogon_creds_cli_check_state *state;
1435 struct tevent_req *subreq;
1436 enum dcerpc_AuthType auth_type;
1437 enum dcerpc_AuthLevel auth_level;
1439 req = tevent_req_create(mem_ctx, &state,
1440 struct netlogon_creds_cli_check_state);
1441 if (req == NULL) {
1442 return NULL;
1445 state->ev = ev;
1446 state->context = context;
1447 state->binding_handle = b;
1449 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1450 context->server.computer);
1451 if (tevent_req_nomem(state->srv_name_slash, req)) {
1452 return tevent_req_post(req, ev);
1455 dcerpc_binding_handle_auth_info(state->binding_handle,
1456 &auth_type, &auth_level);
1458 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1459 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1460 return tevent_req_post(req, ev);
1463 switch (auth_level) {
1464 case DCERPC_AUTH_LEVEL_INTEGRITY:
1465 case DCERPC_AUTH_LEVEL_PRIVACY:
1466 break;
1467 default:
1468 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1469 return tevent_req_post(req, ev);
1472 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1473 state->context);
1474 if (tevent_req_nomem(subreq, req)) {
1475 return tevent_req_post(req, ev);
1478 tevent_req_set_callback(subreq,
1479 netlogon_creds_cli_check_locked,
1480 req);
1482 return req;
1485 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1486 NTSTATUS status)
1488 struct netlogon_creds_cli_check_state *state =
1489 tevent_req_data(req,
1490 struct netlogon_creds_cli_check_state);
1492 if (state->creds == NULL) {
1493 return;
1496 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1497 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1498 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1499 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1500 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1501 TALLOC_FREE(state->creds);
1502 return;
1505 netlogon_creds_cli_delete(state->context, &state->creds);
1508 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1510 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1512 struct tevent_req *req =
1513 tevent_req_callback_data(subreq,
1514 struct tevent_req);
1515 struct netlogon_creds_cli_check_state *state =
1516 tevent_req_data(req,
1517 struct netlogon_creds_cli_check_state);
1518 NTSTATUS status;
1520 status = netlogon_creds_cli_lock_recv(subreq, state,
1521 &state->creds);
1522 TALLOC_FREE(subreq);
1523 if (tevent_req_nterror(req, status)) {
1524 return;
1528 * we defer all callbacks in order to cleanup
1529 * the database record.
1531 tevent_req_defer_callback(req, state->ev);
1533 state->tmp_creds = *state->creds;
1534 netlogon_creds_client_authenticator(&state->tmp_creds,
1535 &state->req_auth);
1536 ZERO_STRUCT(state->rep_auth);
1538 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1539 state->binding_handle,
1540 state->srv_name_slash,
1541 state->context->client.computer,
1542 &state->req_auth,
1543 &state->rep_auth,
1545 &state->caps);
1546 if (tevent_req_nomem(subreq, req)) {
1547 status = NT_STATUS_NO_MEMORY;
1548 netlogon_creds_cli_check_cleanup(req, status);
1549 return;
1551 tevent_req_set_callback(subreq,
1552 netlogon_creds_cli_check_caps,
1553 req);
1556 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1558 struct tevent_req *req =
1559 tevent_req_callback_data(subreq,
1560 struct tevent_req);
1561 struct netlogon_creds_cli_check_state *state =
1562 tevent_req_data(req,
1563 struct netlogon_creds_cli_check_state);
1564 NTSTATUS status;
1565 NTSTATUS result;
1566 bool ok;
1568 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1569 &result);
1570 TALLOC_FREE(subreq);
1571 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1573 * Note that the negotiated flags are already checked
1574 * for our required flags after the ServerAuthenticate3/2 call.
1576 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1578 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1580 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1581 * already, we expect this to work!
1583 status = NT_STATUS_DOWNGRADE_DETECTED;
1584 tevent_req_nterror(req, status);
1585 netlogon_creds_cli_check_cleanup(req, status);
1586 return;
1589 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1591 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1592 * we expect this to work at least as far as the
1593 * NOT_SUPPORTED error handled below!
1595 * NT 4.0 and Old Samba servers are not
1596 * allowed without "require strong key = no"
1598 status = NT_STATUS_DOWNGRADE_DETECTED;
1599 tevent_req_nterror(req, status);
1600 netlogon_creds_cli_check_cleanup(req, status);
1601 return;
1605 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1606 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1607 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1609 * This is needed against NT 4.0 and old Samba servers.
1611 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1612 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1613 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1614 * with the next request as the sequence number processing
1615 * gets out of sync.
1617 netlogon_creds_cli_check_cleanup(req, status);
1618 tevent_req_done(req);
1619 return;
1621 if (tevent_req_nterror(req, status)) {
1622 netlogon_creds_cli_check_cleanup(req, status);
1623 return;
1626 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1628 * Note that the negotiated flags are already checked
1629 * for our required flags after the ServerAuthenticate3/2 call.
1631 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1633 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1635 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1636 * already, we expect this to work!
1638 status = NT_STATUS_DOWNGRADE_DETECTED;
1639 tevent_req_nterror(req, status);
1640 netlogon_creds_cli_check_cleanup(req, status);
1641 return;
1645 * This is ok, the server does not support
1646 * NETLOGON_NEG_SUPPORTS_AES.
1648 * netr_LogonGetCapabilities() was
1649 * netr_LogonDummyRoutine1() before
1650 * NETLOGON_NEG_SUPPORTS_AES was invented.
1652 netlogon_creds_cli_check_cleanup(req, result);
1653 tevent_req_done(req);
1654 return;
1657 ok = netlogon_creds_client_check(&state->tmp_creds,
1658 &state->rep_auth.cred);
1659 if (!ok) {
1660 status = NT_STATUS_ACCESS_DENIED;
1661 tevent_req_nterror(req, status);
1662 netlogon_creds_cli_check_cleanup(req, status);
1663 return;
1666 if (tevent_req_nterror(req, result)) {
1667 netlogon_creds_cli_check_cleanup(req, result);
1668 return;
1671 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1672 status = NT_STATUS_DOWNGRADE_DETECTED;
1673 tevent_req_nterror(req, status);
1674 netlogon_creds_cli_check_cleanup(req, status);
1675 return;
1679 * This is the key check that makes this check secure. If we
1680 * get OK here (rather than NOT_SUPPORTED), then the server
1681 * did support AES. If the server only proposed STRONG_KEYS
1682 * and not AES, then it should have failed with
1683 * NOT_IMPLEMENTED. We always send AES as a client, so the
1684 * server should always have returned it.
1686 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1687 status = NT_STATUS_DOWNGRADE_DETECTED;
1688 tevent_req_nterror(req, status);
1689 netlogon_creds_cli_check_cleanup(req, status);
1690 return;
1693 *state->creds = state->tmp_creds;
1694 status = netlogon_creds_cli_store(state->context,
1695 &state->creds);
1696 netlogon_creds_cli_check_cleanup(req, status);
1697 if (tevent_req_nterror(req, status)) {
1698 return;
1701 tevent_req_done(req);
1704 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1706 NTSTATUS status;
1708 if (tevent_req_is_nterror(req, &status)) {
1709 netlogon_creds_cli_check_cleanup(req, status);
1710 tevent_req_received(req);
1711 return status;
1714 tevent_req_received(req);
1715 return NT_STATUS_OK;
1718 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1719 struct dcerpc_binding_handle *b)
1721 TALLOC_CTX *frame = talloc_stackframe();
1722 struct tevent_context *ev;
1723 struct tevent_req *req;
1724 NTSTATUS status = NT_STATUS_NO_MEMORY;
1726 ev = samba_tevent_context_init(frame);
1727 if (ev == NULL) {
1728 goto fail;
1730 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1731 if (req == NULL) {
1732 goto fail;
1734 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1735 goto fail;
1737 status = netlogon_creds_cli_check_recv(req);
1738 fail:
1739 TALLOC_FREE(frame);
1740 return status;
1743 struct netlogon_creds_cli_ServerPasswordSet_state {
1744 struct tevent_context *ev;
1745 struct netlogon_creds_cli_context *context;
1746 struct dcerpc_binding_handle *binding_handle;
1747 uint32_t old_timeout;
1749 char *srv_name_slash;
1750 enum dcerpc_AuthType auth_type;
1751 enum dcerpc_AuthLevel auth_level;
1753 struct samr_CryptPassword samr_crypt_password;
1754 struct netr_CryptPassword netr_crypt_password;
1755 struct samr_Password samr_password;
1757 struct netlogon_creds_CredentialState *creds;
1758 struct netlogon_creds_CredentialState tmp_creds;
1759 struct netr_Authenticator req_auth;
1760 struct netr_Authenticator rep_auth;
1763 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1764 NTSTATUS status);
1765 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1767 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1768 struct tevent_context *ev,
1769 struct netlogon_creds_cli_context *context,
1770 struct dcerpc_binding_handle *b,
1771 const DATA_BLOB *new_password,
1772 const uint32_t *new_version)
1774 struct tevent_req *req;
1775 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1776 struct tevent_req *subreq;
1777 bool ok;
1779 req = tevent_req_create(mem_ctx, &state,
1780 struct netlogon_creds_cli_ServerPasswordSet_state);
1781 if (req == NULL) {
1782 return NULL;
1785 state->ev = ev;
1786 state->context = context;
1787 state->binding_handle = b;
1789 if (new_password->length < 14) {
1790 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1791 return tevent_req_post(req, ev);
1795 * netr_ServerPasswordSet
1797 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1800 * netr_ServerPasswordSet2
1802 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1803 new_password);
1804 if (!ok) {
1805 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1806 return tevent_req_post(req, ev);
1809 if (new_version != NULL) {
1810 struct NL_PASSWORD_VERSION version;
1811 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1812 uint32_t ofs = 512 - len;
1813 uint8_t *p;
1815 if (len > 500) {
1816 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1817 return tevent_req_post(req, ev);
1819 ofs -= 12;
1821 version.ReservedField = 0;
1822 version.PasswordVersionNumber = *new_version;
1823 version.PasswordVersionPresent =
1824 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1826 p = state->samr_crypt_password.data + ofs;
1827 SIVAL(p, 0, version.ReservedField);
1828 SIVAL(p, 4, version.PasswordVersionNumber);
1829 SIVAL(p, 8, version.PasswordVersionPresent);
1832 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1833 context->server.computer);
1834 if (tevent_req_nomem(state->srv_name_slash, req)) {
1835 return tevent_req_post(req, ev);
1838 dcerpc_binding_handle_auth_info(state->binding_handle,
1839 &state->auth_type,
1840 &state->auth_level);
1842 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1843 state->context);
1844 if (tevent_req_nomem(subreq, req)) {
1845 return tevent_req_post(req, ev);
1848 tevent_req_set_callback(subreq,
1849 netlogon_creds_cli_ServerPasswordSet_locked,
1850 req);
1852 return req;
1855 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1856 NTSTATUS status)
1858 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1859 tevent_req_data(req,
1860 struct netlogon_creds_cli_ServerPasswordSet_state);
1862 if (state->creds == NULL) {
1863 return;
1866 dcerpc_binding_handle_set_timeout(state->binding_handle,
1867 state->old_timeout);
1869 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1870 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1871 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1872 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1873 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1874 TALLOC_FREE(state->creds);
1875 return;
1878 netlogon_creds_cli_delete(state->context, &state->creds);
1881 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1883 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1885 struct tevent_req *req =
1886 tevent_req_callback_data(subreq,
1887 struct tevent_req);
1888 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1889 tevent_req_data(req,
1890 struct netlogon_creds_cli_ServerPasswordSet_state);
1891 NTSTATUS status;
1893 status = netlogon_creds_cli_lock_recv(subreq, state,
1894 &state->creds);
1895 TALLOC_FREE(subreq);
1896 if (tevent_req_nterror(req, status)) {
1897 return;
1900 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1901 switch (state->auth_level) {
1902 case DCERPC_AUTH_LEVEL_INTEGRITY:
1903 case DCERPC_AUTH_LEVEL_PRIVACY:
1904 break;
1905 default:
1906 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1907 return;
1909 } else {
1910 uint32_t tmp = state->creds->negotiate_flags;
1912 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1914 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1915 * it should be used, which means
1916 * we had a chance to verify no downgrade
1917 * happened.
1919 * This relies on netlogon_creds_cli_check*
1920 * being called before, as first request after
1921 * the DCERPC bind.
1923 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1924 return;
1928 state->old_timeout = dcerpc_binding_handle_set_timeout(
1929 state->binding_handle, 600000);
1932 * we defer all callbacks in order to cleanup
1933 * the database record.
1935 tevent_req_defer_callback(req, state->ev);
1937 state->tmp_creds = *state->creds;
1938 netlogon_creds_client_authenticator(&state->tmp_creds,
1939 &state->req_auth);
1940 ZERO_STRUCT(state->rep_auth);
1942 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1944 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1945 netlogon_creds_aes_encrypt(&state->tmp_creds,
1946 state->samr_crypt_password.data,
1947 516);
1948 } else {
1949 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1950 state->samr_crypt_password.data,
1951 516);
1954 memcpy(state->netr_crypt_password.data,
1955 state->samr_crypt_password.data, 512);
1956 state->netr_crypt_password.length =
1957 IVAL(state->samr_crypt_password.data, 512);
1959 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1960 state->binding_handle,
1961 state->srv_name_slash,
1962 state->tmp_creds.account_name,
1963 state->tmp_creds.secure_channel_type,
1964 state->tmp_creds.computer_name,
1965 &state->req_auth,
1966 &state->rep_auth,
1967 &state->netr_crypt_password);
1968 if (tevent_req_nomem(subreq, req)) {
1969 status = NT_STATUS_NO_MEMORY;
1970 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1971 return;
1973 } else {
1974 netlogon_creds_des_encrypt(&state->tmp_creds,
1975 &state->samr_password);
1977 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1978 state->binding_handle,
1979 state->srv_name_slash,
1980 state->tmp_creds.account_name,
1981 state->tmp_creds.secure_channel_type,
1982 state->tmp_creds.computer_name,
1983 &state->req_auth,
1984 &state->rep_auth,
1985 &state->samr_password);
1986 if (tevent_req_nomem(subreq, req)) {
1987 status = NT_STATUS_NO_MEMORY;
1988 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1989 return;
1993 tevent_req_set_callback(subreq,
1994 netlogon_creds_cli_ServerPasswordSet_done,
1995 req);
1998 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2000 struct tevent_req *req =
2001 tevent_req_callback_data(subreq,
2002 struct tevent_req);
2003 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2004 tevent_req_data(req,
2005 struct netlogon_creds_cli_ServerPasswordSet_state);
2006 NTSTATUS status;
2007 NTSTATUS result;
2008 bool ok;
2010 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2011 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2012 &result);
2013 TALLOC_FREE(subreq);
2014 if (tevent_req_nterror(req, status)) {
2015 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2016 return;
2018 } else {
2019 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2020 &result);
2021 TALLOC_FREE(subreq);
2022 if (tevent_req_nterror(req, status)) {
2023 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2024 return;
2028 ok = netlogon_creds_client_check(&state->tmp_creds,
2029 &state->rep_auth.cred);
2030 if (!ok) {
2031 status = NT_STATUS_ACCESS_DENIED;
2032 tevent_req_nterror(req, status);
2033 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2034 return;
2037 if (tevent_req_nterror(req, result)) {
2038 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2039 return;
2042 dcerpc_binding_handle_set_timeout(state->binding_handle,
2043 state->old_timeout);
2045 *state->creds = state->tmp_creds;
2046 status = netlogon_creds_cli_store(state->context,
2047 &state->creds);
2048 if (tevent_req_nterror(req, status)) {
2049 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2050 return;
2053 tevent_req_done(req);
2056 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2058 NTSTATUS status;
2060 if (tevent_req_is_nterror(req, &status)) {
2061 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2062 tevent_req_received(req);
2063 return status;
2066 tevent_req_received(req);
2067 return NT_STATUS_OK;
2070 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2071 struct netlogon_creds_cli_context *context,
2072 struct dcerpc_binding_handle *b,
2073 const DATA_BLOB *new_password,
2074 const uint32_t *new_version)
2076 TALLOC_CTX *frame = talloc_stackframe();
2077 struct tevent_context *ev;
2078 struct tevent_req *req;
2079 NTSTATUS status = NT_STATUS_NO_MEMORY;
2081 ev = samba_tevent_context_init(frame);
2082 if (ev == NULL) {
2083 goto fail;
2085 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2086 new_password,
2087 new_version);
2088 if (req == NULL) {
2089 goto fail;
2091 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2092 goto fail;
2094 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2095 fail:
2096 TALLOC_FREE(frame);
2097 return status;
2100 struct netlogon_creds_cli_LogonSamLogon_state {
2101 struct tevent_context *ev;
2102 struct netlogon_creds_cli_context *context;
2103 struct dcerpc_binding_handle *binding_handle;
2105 char *srv_name_slash;
2107 enum netr_LogonInfoClass logon_level;
2108 const union netr_LogonLevel *const_logon;
2109 union netr_LogonLevel *logon;
2110 uint32_t flags;
2112 uint16_t validation_level;
2113 union netr_Validation *validation;
2114 uint8_t authoritative;
2117 * do we need encryption at the application layer?
2119 bool user_encrypt;
2120 bool try_logon_ex;
2121 bool try_validation6;
2124 * the read only credentials before we started the operation
2125 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2127 struct netlogon_creds_CredentialState *ro_creds;
2130 * The (locked) credentials used for the credential chain
2131 * used for netr_LogonSamLogonWithFlags() or
2132 * netr_LogonSamLogonWith().
2134 struct netlogon_creds_CredentialState *lk_creds;
2137 * While we have locked the global credentials (lk_creds above)
2138 * we operate an a temporary copy, because a server
2139 * may not support netr_LogonSamLogonWithFlags() and
2140 * didn't process our netr_Authenticator, so we need to
2141 * restart from lk_creds.
2143 struct netlogon_creds_CredentialState tmp_creds;
2144 struct netr_Authenticator req_auth;
2145 struct netr_Authenticator rep_auth;
2148 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2149 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2150 NTSTATUS status);
2152 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2153 struct tevent_context *ev,
2154 struct netlogon_creds_cli_context *context,
2155 struct dcerpc_binding_handle *b,
2156 enum netr_LogonInfoClass logon_level,
2157 const union netr_LogonLevel *logon,
2158 uint32_t flags)
2160 struct tevent_req *req;
2161 struct netlogon_creds_cli_LogonSamLogon_state *state;
2163 req = tevent_req_create(mem_ctx, &state,
2164 struct netlogon_creds_cli_LogonSamLogon_state);
2165 if (req == NULL) {
2166 return NULL;
2169 state->ev = ev;
2170 state->context = context;
2171 state->binding_handle = b;
2173 state->logon_level = logon_level;
2174 state->const_logon = logon;
2175 state->flags = flags;
2177 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2178 context->server.computer);
2179 if (tevent_req_nomem(state->srv_name_slash, req)) {
2180 return tevent_req_post(req, ev);
2183 switch (logon_level) {
2184 case NetlogonInteractiveInformation:
2185 case NetlogonInteractiveTransitiveInformation:
2186 case NetlogonServiceInformation:
2187 case NetlogonServiceTransitiveInformation:
2188 case NetlogonGenericInformation:
2189 state->user_encrypt = true;
2190 break;
2192 case NetlogonNetworkInformation:
2193 case NetlogonNetworkTransitiveInformation:
2194 break;
2197 state->validation = talloc_zero(state, union netr_Validation);
2198 if (tevent_req_nomem(state->validation, req)) {
2199 return tevent_req_post(req, ev);
2202 netlogon_creds_cli_LogonSamLogon_start(req);
2203 if (!tevent_req_is_in_progress(req)) {
2204 return tevent_req_post(req, ev);
2208 * we defer all callbacks in order to cleanup
2209 * the database record.
2211 tevent_req_defer_callback(req, state->ev);
2212 return req;
2215 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2216 NTSTATUS status)
2218 struct netlogon_creds_cli_LogonSamLogon_state *state =
2219 tevent_req_data(req,
2220 struct netlogon_creds_cli_LogonSamLogon_state);
2222 if (state->lk_creds == NULL) {
2223 return;
2226 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2228 * This is a hack to recover from a bug in old
2229 * Samba servers, when LogonSamLogonEx() fails:
2231 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2233 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2235 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2236 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2237 * If the sign/seal check fails.
2239 * In that case we need to cleanup the netlogon session.
2241 * It's the job of the caller to disconnect the current
2242 * connection, if netlogon_creds_cli_LogonSamLogon()
2243 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2245 if (!state->context->server.try_logon_with) {
2246 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2250 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2251 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2252 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2253 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2254 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2255 TALLOC_FREE(state->lk_creds);
2256 return;
2259 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2262 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2264 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2266 struct netlogon_creds_cli_LogonSamLogon_state *state =
2267 tevent_req_data(req,
2268 struct netlogon_creds_cli_LogonSamLogon_state);
2269 struct tevent_req *subreq;
2270 NTSTATUS status;
2271 enum dcerpc_AuthType auth_type;
2272 enum dcerpc_AuthLevel auth_level;
2274 TALLOC_FREE(state->ro_creds);
2275 TALLOC_FREE(state->logon);
2276 ZERO_STRUCTP(state->validation);
2278 dcerpc_binding_handle_auth_info(state->binding_handle,
2279 &auth_type, &auth_level);
2281 state->try_logon_ex = state->context->server.try_logon_ex;
2282 state->try_validation6 = state->context->server.try_validation6;
2284 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2285 state->try_logon_ex = false;
2288 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2289 state->try_validation6 = false;
2292 if (state->try_logon_ex) {
2293 if (state->try_validation6) {
2294 state->validation_level = 6;
2295 } else {
2296 state->validation_level = 3;
2297 state->user_encrypt = true;
2300 state->logon = netlogon_creds_shallow_copy_logon(state,
2301 state->logon_level,
2302 state->const_logon);
2303 if (tevent_req_nomem(state->logon, req)) {
2304 status = NT_STATUS_NO_MEMORY;
2305 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2306 return;
2309 if (state->user_encrypt) {
2310 status = netlogon_creds_cli_get(state->context,
2311 state,
2312 &state->ro_creds);
2313 if (!NT_STATUS_IS_OK(status)) {
2314 status = NT_STATUS_ACCESS_DENIED;
2315 tevent_req_nterror(req, status);
2316 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2317 return;
2320 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2321 state->logon_level,
2322 state->logon);
2325 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2326 state->binding_handle,
2327 state->srv_name_slash,
2328 state->context->client.computer,
2329 state->logon_level,
2330 state->logon,
2331 state->validation_level,
2332 state->validation,
2333 &state->authoritative,
2334 &state->flags);
2335 if (tevent_req_nomem(subreq, req)) {
2336 status = NT_STATUS_NO_MEMORY;
2337 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2338 return;
2340 tevent_req_set_callback(subreq,
2341 netlogon_creds_cli_LogonSamLogon_done,
2342 req);
2343 return;
2346 if (state->lk_creds == NULL) {
2347 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2348 state->context);
2349 if (tevent_req_nomem(subreq, req)) {
2350 status = NT_STATUS_NO_MEMORY;
2351 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2352 return;
2354 tevent_req_set_callback(subreq,
2355 netlogon_creds_cli_LogonSamLogon_done,
2356 req);
2357 return;
2360 state->tmp_creds = *state->lk_creds;
2361 netlogon_creds_client_authenticator(&state->tmp_creds,
2362 &state->req_auth);
2363 ZERO_STRUCT(state->rep_auth);
2365 state->logon = netlogon_creds_shallow_copy_logon(state,
2366 state->logon_level,
2367 state->const_logon);
2368 if (tevent_req_nomem(state->logon, req)) {
2369 status = NT_STATUS_NO_MEMORY;
2370 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2371 return;
2374 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2375 state->logon_level,
2376 state->logon);
2378 state->validation_level = 3;
2380 if (state->context->server.try_logon_with) {
2381 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2382 state->binding_handle,
2383 state->srv_name_slash,
2384 state->context->client.computer,
2385 &state->req_auth,
2386 &state->rep_auth,
2387 state->logon_level,
2388 state->logon,
2389 state->validation_level,
2390 state->validation,
2391 &state->authoritative,
2392 &state->flags);
2393 if (tevent_req_nomem(subreq, req)) {
2394 status = NT_STATUS_NO_MEMORY;
2395 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2396 return;
2398 } else {
2399 state->flags = 0;
2401 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2402 state->binding_handle,
2403 state->srv_name_slash,
2404 state->context->client.computer,
2405 &state->req_auth,
2406 &state->rep_auth,
2407 state->logon_level,
2408 state->logon,
2409 state->validation_level,
2410 state->validation,
2411 &state->authoritative);
2412 if (tevent_req_nomem(subreq, req)) {
2413 status = NT_STATUS_NO_MEMORY;
2414 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2415 return;
2419 tevent_req_set_callback(subreq,
2420 netlogon_creds_cli_LogonSamLogon_done,
2421 req);
2424 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2426 struct tevent_req *req =
2427 tevent_req_callback_data(subreq,
2428 struct tevent_req);
2429 struct netlogon_creds_cli_LogonSamLogon_state *state =
2430 tevent_req_data(req,
2431 struct netlogon_creds_cli_LogonSamLogon_state);
2432 NTSTATUS status;
2433 NTSTATUS result;
2434 bool ok;
2436 if (state->try_logon_ex) {
2437 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2438 state->validation,
2439 &result);
2440 TALLOC_FREE(subreq);
2441 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2442 state->context->server.try_validation6 = false;
2443 state->context->server.try_logon_ex = false;
2444 netlogon_creds_cli_LogonSamLogon_start(req);
2445 return;
2447 if (tevent_req_nterror(req, status)) {
2448 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2449 return;
2452 if ((state->validation_level == 6) &&
2453 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2454 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2455 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2457 state->context->server.try_validation6 = false;
2458 netlogon_creds_cli_LogonSamLogon_start(req);
2459 return;
2462 if (tevent_req_nterror(req, result)) {
2463 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2464 return;
2467 if (state->ro_creds == NULL) {
2468 tevent_req_done(req);
2469 return;
2472 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2473 if (!ok) {
2475 * We got a race, lets retry with on authenticator
2476 * protection.
2478 * netlogon_creds_cli_LogonSamLogon_start()
2479 * will TALLOC_FREE(state->ro_creds);
2481 state->try_logon_ex = false;
2482 netlogon_creds_cli_LogonSamLogon_start(req);
2483 return;
2486 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2487 state->validation_level,
2488 state->validation);
2490 tevent_req_done(req);
2491 return;
2494 if (state->lk_creds == NULL) {
2495 status = netlogon_creds_cli_lock_recv(subreq, state,
2496 &state->lk_creds);
2497 TALLOC_FREE(subreq);
2498 if (tevent_req_nterror(req, status)) {
2499 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2500 return;
2503 netlogon_creds_cli_LogonSamLogon_start(req);
2504 return;
2507 if (state->context->server.try_logon_with) {
2508 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2509 state->validation,
2510 &result);
2511 TALLOC_FREE(subreq);
2512 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2513 state->context->server.try_logon_with = false;
2514 netlogon_creds_cli_LogonSamLogon_start(req);
2515 return;
2517 if (tevent_req_nterror(req, status)) {
2518 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2519 return;
2521 } else {
2522 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2523 state->validation,
2524 &result);
2525 TALLOC_FREE(subreq);
2526 if (tevent_req_nterror(req, status)) {
2527 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2528 return;
2532 ok = netlogon_creds_client_check(&state->tmp_creds,
2533 &state->rep_auth.cred);
2534 if (!ok) {
2535 status = NT_STATUS_ACCESS_DENIED;
2536 tevent_req_nterror(req, status);
2537 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2538 return;
2541 *state->lk_creds = state->tmp_creds;
2542 status = netlogon_creds_cli_store(state->context,
2543 &state->lk_creds);
2544 if (tevent_req_nterror(req, status)) {
2545 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2546 return;
2549 if (tevent_req_nterror(req, result)) {
2550 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2551 return;
2554 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2555 state->validation_level,
2556 state->validation);
2558 tevent_req_done(req);
2561 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2562 TALLOC_CTX *mem_ctx,
2563 uint16_t *validation_level,
2564 union netr_Validation **validation,
2565 uint8_t *authoritative,
2566 uint32_t *flags)
2568 struct netlogon_creds_cli_LogonSamLogon_state *state =
2569 tevent_req_data(req,
2570 struct netlogon_creds_cli_LogonSamLogon_state);
2571 NTSTATUS status;
2573 /* authoritative is also returned on error */
2574 *authoritative = state->authoritative;
2576 if (tevent_req_is_nterror(req, &status)) {
2577 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2578 tevent_req_received(req);
2579 return status;
2582 *validation_level = state->validation_level;
2583 *validation = talloc_move(mem_ctx, &state->validation);
2584 *flags = state->flags;
2586 tevent_req_received(req);
2587 return NT_STATUS_OK;
2590 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2591 struct netlogon_creds_cli_context *context,
2592 struct dcerpc_binding_handle *b,
2593 enum netr_LogonInfoClass logon_level,
2594 const union netr_LogonLevel *logon,
2595 TALLOC_CTX *mem_ctx,
2596 uint16_t *validation_level,
2597 union netr_Validation **validation,
2598 uint8_t *authoritative,
2599 uint32_t *flags)
2601 TALLOC_CTX *frame = talloc_stackframe();
2602 struct tevent_context *ev;
2603 struct tevent_req *req;
2604 NTSTATUS status = NT_STATUS_NO_MEMORY;
2606 ev = samba_tevent_context_init(frame);
2607 if (ev == NULL) {
2608 goto fail;
2610 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2611 logon_level, logon,
2612 *flags);
2613 if (req == NULL) {
2614 goto fail;
2616 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2617 goto fail;
2619 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2620 validation_level,
2621 validation,
2622 authoritative,
2623 flags);
2624 fail:
2625 TALLOC_FREE(frame);
2626 return status;
2629 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2630 struct tevent_context *ev;
2631 struct netlogon_creds_cli_context *context;
2632 struct dcerpc_binding_handle *binding_handle;
2634 char *srv_name_slash;
2635 enum dcerpc_AuthType auth_type;
2636 enum dcerpc_AuthLevel auth_level;
2638 const char *site_name;
2639 uint32_t dns_ttl;
2640 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2642 struct netlogon_creds_CredentialState *creds;
2643 struct netlogon_creds_CredentialState tmp_creds;
2644 struct netr_Authenticator req_auth;
2645 struct netr_Authenticator rep_auth;
2648 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2649 NTSTATUS status);
2650 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2652 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2653 struct tevent_context *ev,
2654 struct netlogon_creds_cli_context *context,
2655 struct dcerpc_binding_handle *b,
2656 const char *site_name,
2657 uint32_t dns_ttl,
2658 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2660 struct tevent_req *req;
2661 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2662 struct tevent_req *subreq;
2664 req = tevent_req_create(mem_ctx, &state,
2665 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2666 if (req == NULL) {
2667 return NULL;
2670 state->ev = ev;
2671 state->context = context;
2672 state->binding_handle = b;
2674 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2675 context->server.computer);
2676 if (tevent_req_nomem(state->srv_name_slash, req)) {
2677 return tevent_req_post(req, ev);
2680 state->site_name = site_name;
2681 state->dns_ttl = dns_ttl;
2682 state->dns_names = dns_names;
2684 dcerpc_binding_handle_auth_info(state->binding_handle,
2685 &state->auth_type,
2686 &state->auth_level);
2688 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2689 state->context);
2690 if (tevent_req_nomem(subreq, req)) {
2691 return tevent_req_post(req, ev);
2694 tevent_req_set_callback(subreq,
2695 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2696 req);
2698 return req;
2701 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2702 NTSTATUS status)
2704 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2705 tevent_req_data(req,
2706 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2708 if (state->creds == NULL) {
2709 return;
2712 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2713 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2714 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2715 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2716 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2717 TALLOC_FREE(state->creds);
2718 return;
2721 netlogon_creds_cli_delete(state->context, &state->creds);
2724 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2726 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2728 struct tevent_req *req =
2729 tevent_req_callback_data(subreq,
2730 struct tevent_req);
2731 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2732 tevent_req_data(req,
2733 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2734 NTSTATUS status;
2736 status = netlogon_creds_cli_lock_recv(subreq, state,
2737 &state->creds);
2738 TALLOC_FREE(subreq);
2739 if (tevent_req_nterror(req, status)) {
2740 return;
2743 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2744 switch (state->auth_level) {
2745 case DCERPC_AUTH_LEVEL_INTEGRITY:
2746 case DCERPC_AUTH_LEVEL_PRIVACY:
2747 break;
2748 default:
2749 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2750 return;
2752 } else {
2753 uint32_t tmp = state->creds->negotiate_flags;
2755 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2757 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2758 * it should be used, which means
2759 * we had a chance to verify no downgrade
2760 * happened.
2762 * This relies on netlogon_creds_cli_check*
2763 * being called before, as first request after
2764 * the DCERPC bind.
2766 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2767 return;
2772 * we defer all callbacks in order to cleanup
2773 * the database record.
2775 tevent_req_defer_callback(req, state->ev);
2777 state->tmp_creds = *state->creds;
2778 netlogon_creds_client_authenticator(&state->tmp_creds,
2779 &state->req_auth);
2780 ZERO_STRUCT(state->rep_auth);
2782 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2783 state->binding_handle,
2784 state->srv_name_slash,
2785 state->tmp_creds.computer_name,
2786 &state->req_auth,
2787 &state->rep_auth,
2788 state->site_name,
2789 state->dns_ttl,
2790 state->dns_names);
2791 if (tevent_req_nomem(subreq, req)) {
2792 status = NT_STATUS_NO_MEMORY;
2793 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2794 return;
2797 tevent_req_set_callback(subreq,
2798 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2799 req);
2802 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2804 struct tevent_req *req =
2805 tevent_req_callback_data(subreq,
2806 struct tevent_req);
2807 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2808 tevent_req_data(req,
2809 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2810 NTSTATUS status;
2811 NTSTATUS result;
2812 bool ok;
2815 * We use state->dns_names as the memory context, as this is
2816 * the only in/out variable and it has been overwritten by the
2817 * out parameter from the server.
2819 * We need to preserve the return value until the caller can use it.
2821 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2822 &result);
2823 TALLOC_FREE(subreq);
2824 if (tevent_req_nterror(req, status)) {
2825 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2826 return;
2829 ok = netlogon_creds_client_check(&state->tmp_creds,
2830 &state->rep_auth.cred);
2831 if (!ok) {
2832 status = NT_STATUS_ACCESS_DENIED;
2833 tevent_req_nterror(req, status);
2834 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2835 return;
2838 *state->creds = state->tmp_creds;
2839 status = netlogon_creds_cli_store(state->context,
2840 &state->creds);
2842 if (tevent_req_nterror(req, status)) {
2843 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2844 return;
2847 if (tevent_req_nterror(req, result)) {
2848 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2849 return;
2852 tevent_req_done(req);
2855 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2857 NTSTATUS status;
2859 if (tevent_req_is_nterror(req, &status)) {
2860 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2861 tevent_req_received(req);
2862 return status;
2865 tevent_req_received(req);
2866 return NT_STATUS_OK;
2869 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2870 struct netlogon_creds_cli_context *context,
2871 struct dcerpc_binding_handle *b,
2872 const char *site_name,
2873 uint32_t dns_ttl,
2874 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2876 TALLOC_CTX *frame = talloc_stackframe();
2877 struct tevent_context *ev;
2878 struct tevent_req *req;
2879 NTSTATUS status = NT_STATUS_NO_MEMORY;
2881 ev = samba_tevent_context_init(frame);
2882 if (ev == NULL) {
2883 goto fail;
2885 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2886 site_name,
2887 dns_ttl,
2888 dns_names);
2889 if (req == NULL) {
2890 goto fail;
2892 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2893 goto fail;
2895 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2896 fail:
2897 TALLOC_FREE(frame);
2898 return status;
2901 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2902 struct tevent_context *ev;
2903 struct netlogon_creds_cli_context *context;
2904 struct dcerpc_binding_handle *binding_handle;
2906 char *srv_name_slash;
2907 enum dcerpc_AuthType auth_type;
2908 enum dcerpc_AuthLevel auth_level;
2910 struct samr_Password new_owf_password;
2911 struct samr_Password old_owf_password;
2912 struct netr_TrustInfo *trust_info;
2914 struct netlogon_creds_CredentialState *creds;
2915 struct netlogon_creds_CredentialState tmp_creds;
2916 struct netr_Authenticator req_auth;
2917 struct netr_Authenticator rep_auth;
2920 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2921 NTSTATUS status);
2922 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2924 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2925 struct tevent_context *ev,
2926 struct netlogon_creds_cli_context *context,
2927 struct dcerpc_binding_handle *b)
2929 struct tevent_req *req;
2930 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2931 struct tevent_req *subreq;
2933 req = tevent_req_create(mem_ctx, &state,
2934 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2935 if (req == NULL) {
2936 return NULL;
2939 state->ev = ev;
2940 state->context = context;
2941 state->binding_handle = b;
2943 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2944 context->server.computer);
2945 if (tevent_req_nomem(state->srv_name_slash, req)) {
2946 return tevent_req_post(req, ev);
2949 dcerpc_binding_handle_auth_info(state->binding_handle,
2950 &state->auth_type,
2951 &state->auth_level);
2953 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2954 state->context);
2955 if (tevent_req_nomem(subreq, req)) {
2956 return tevent_req_post(req, ev);
2959 tevent_req_set_callback(subreq,
2960 netlogon_creds_cli_ServerGetTrustInfo_locked,
2961 req);
2963 return req;
2966 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2967 NTSTATUS status)
2969 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2970 tevent_req_data(req,
2971 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2973 if (state->creds == NULL) {
2974 return;
2977 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2978 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2979 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2980 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2981 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2982 TALLOC_FREE(state->creds);
2983 return;
2986 netlogon_creds_cli_delete(state->context, &state->creds);
2989 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2991 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2993 struct tevent_req *req =
2994 tevent_req_callback_data(subreq,
2995 struct tevent_req);
2996 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2997 tevent_req_data(req,
2998 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2999 NTSTATUS status;
3001 status = netlogon_creds_cli_lock_recv(subreq, state,
3002 &state->creds);
3003 TALLOC_FREE(subreq);
3004 if (tevent_req_nterror(req, status)) {
3005 return;
3008 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3009 switch (state->auth_level) {
3010 case DCERPC_AUTH_LEVEL_PRIVACY:
3011 break;
3012 default:
3013 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3014 return;
3016 } else {
3017 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3018 return;
3022 * we defer all callbacks in order to cleanup
3023 * the database record.
3025 tevent_req_defer_callback(req, state->ev);
3027 state->tmp_creds = *state->creds;
3028 netlogon_creds_client_authenticator(&state->tmp_creds,
3029 &state->req_auth);
3030 ZERO_STRUCT(state->rep_auth);
3032 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3033 state->binding_handle,
3034 state->srv_name_slash,
3035 state->tmp_creds.account_name,
3036 state->tmp_creds.secure_channel_type,
3037 state->tmp_creds.computer_name,
3038 &state->req_auth,
3039 &state->rep_auth,
3040 &state->new_owf_password,
3041 &state->old_owf_password,
3042 &state->trust_info);
3043 if (tevent_req_nomem(subreq, req)) {
3044 status = NT_STATUS_NO_MEMORY;
3045 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3046 return;
3049 tevent_req_set_callback(subreq,
3050 netlogon_creds_cli_ServerGetTrustInfo_done,
3051 req);
3054 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3056 struct tevent_req *req =
3057 tevent_req_callback_data(subreq,
3058 struct tevent_req);
3059 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3060 tevent_req_data(req,
3061 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3062 NTSTATUS status;
3063 NTSTATUS result;
3064 const struct samr_Password zero = {};
3065 int cmp;
3066 bool ok;
3069 * We use state->dns_names as the memory context, as this is
3070 * the only in/out variable and it has been overwritten by the
3071 * out parameter from the server.
3073 * We need to preserve the return value until the caller can use it.
3075 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3076 TALLOC_FREE(subreq);
3077 if (tevent_req_nterror(req, status)) {
3078 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3079 return;
3082 ok = netlogon_creds_client_check(&state->tmp_creds,
3083 &state->rep_auth.cred);
3084 if (!ok) {
3085 status = NT_STATUS_ACCESS_DENIED;
3086 tevent_req_nterror(req, status);
3087 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3088 return;
3091 cmp = memcmp(state->new_owf_password.hash,
3092 zero.hash, sizeof(zero.hash));
3093 if (cmp != 0) {
3094 netlogon_creds_des_decrypt(&state->tmp_creds,
3095 &state->new_owf_password);
3097 cmp = memcmp(state->old_owf_password.hash,
3098 zero.hash, sizeof(zero.hash));
3099 if (cmp != 0) {
3100 netlogon_creds_des_decrypt(&state->tmp_creds,
3101 &state->old_owf_password);
3104 *state->creds = state->tmp_creds;
3105 status = netlogon_creds_cli_store(state->context,
3106 &state->creds);
3107 if (tevent_req_nterror(req, status)) {
3108 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3109 return;
3112 if (tevent_req_nterror(req, result)) {
3113 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3114 return;
3117 tevent_req_done(req);
3120 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3121 TALLOC_CTX *mem_ctx,
3122 struct samr_Password *new_owf_password,
3123 struct samr_Password *old_owf_password,
3124 struct netr_TrustInfo **trust_info)
3126 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3127 tevent_req_data(req,
3128 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3129 NTSTATUS status;
3131 if (tevent_req_is_nterror(req, &status)) {
3132 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3133 tevent_req_received(req);
3134 return status;
3137 if (new_owf_password != NULL) {
3138 *new_owf_password = state->new_owf_password;
3140 if (old_owf_password != NULL) {
3141 *old_owf_password = state->old_owf_password;
3143 if (trust_info != NULL) {
3144 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3147 tevent_req_received(req);
3148 return NT_STATUS_OK;
3151 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3152 struct netlogon_creds_cli_context *context,
3153 struct dcerpc_binding_handle *b,
3154 TALLOC_CTX *mem_ctx,
3155 struct samr_Password *new_owf_password,
3156 struct samr_Password *old_owf_password,
3157 struct netr_TrustInfo **trust_info)
3159 TALLOC_CTX *frame = talloc_stackframe();
3160 struct tevent_context *ev;
3161 struct tevent_req *req;
3162 NTSTATUS status = NT_STATUS_NO_MEMORY;
3164 ev = samba_tevent_context_init(frame);
3165 if (ev == NULL) {
3166 goto fail;
3168 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3169 if (req == NULL) {
3170 goto fail;
3172 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3173 goto fail;
3175 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3176 mem_ctx,
3177 new_owf_password,
3178 old_owf_password,
3179 trust_info);
3180 fail:
3181 TALLOC_FREE(frame);
3182 return status;
3185 struct netlogon_creds_cli_GetForestTrustInformation_state {
3186 struct tevent_context *ev;
3187 struct netlogon_creds_cli_context *context;
3188 struct dcerpc_binding_handle *binding_handle;
3190 char *srv_name_slash;
3191 enum dcerpc_AuthType auth_type;
3192 enum dcerpc_AuthLevel auth_level;
3194 uint32_t flags;
3195 struct lsa_ForestTrustInformation *forest_trust_info;
3197 struct netlogon_creds_CredentialState *creds;
3198 struct netlogon_creds_CredentialState tmp_creds;
3199 struct netr_Authenticator req_auth;
3200 struct netr_Authenticator rep_auth;
3203 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3204 NTSTATUS status);
3205 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3207 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3208 struct tevent_context *ev,
3209 struct netlogon_creds_cli_context *context,
3210 struct dcerpc_binding_handle *b)
3212 struct tevent_req *req;
3213 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3214 struct tevent_req *subreq;
3216 req = tevent_req_create(mem_ctx, &state,
3217 struct netlogon_creds_cli_GetForestTrustInformation_state);
3218 if (req == NULL) {
3219 return NULL;
3222 state->ev = ev;
3223 state->context = context;
3224 state->binding_handle = b;
3226 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3227 context->server.computer);
3228 if (tevent_req_nomem(state->srv_name_slash, req)) {
3229 return tevent_req_post(req, ev);
3232 state->flags = 0;
3234 dcerpc_binding_handle_auth_info(state->binding_handle,
3235 &state->auth_type,
3236 &state->auth_level);
3238 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3239 state->context);
3240 if (tevent_req_nomem(subreq, req)) {
3241 return tevent_req_post(req, ev);
3244 tevent_req_set_callback(subreq,
3245 netlogon_creds_cli_GetForestTrustInformation_locked,
3246 req);
3248 return req;
3251 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3252 NTSTATUS status)
3254 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3255 tevent_req_data(req,
3256 struct netlogon_creds_cli_GetForestTrustInformation_state);
3258 if (state->creds == NULL) {
3259 return;
3262 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3263 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3264 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3265 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3266 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3267 TALLOC_FREE(state->creds);
3268 return;
3271 netlogon_creds_cli_delete(state->context, &state->creds);
3274 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3276 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3278 struct tevent_req *req =
3279 tevent_req_callback_data(subreq,
3280 struct tevent_req);
3281 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3282 tevent_req_data(req,
3283 struct netlogon_creds_cli_GetForestTrustInformation_state);
3284 NTSTATUS status;
3286 status = netlogon_creds_cli_lock_recv(subreq, state,
3287 &state->creds);
3288 TALLOC_FREE(subreq);
3289 if (tevent_req_nterror(req, status)) {
3290 return;
3293 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3294 switch (state->auth_level) {
3295 case DCERPC_AUTH_LEVEL_INTEGRITY:
3296 case DCERPC_AUTH_LEVEL_PRIVACY:
3297 break;
3298 default:
3299 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3300 return;
3302 } else {
3303 uint32_t tmp = state->creds->negotiate_flags;
3305 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3307 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3308 * it should be used, which means
3309 * we had a chance to verify no downgrade
3310 * happened.
3312 * This relies on netlogon_creds_cli_check*
3313 * being called before, as first request after
3314 * the DCERPC bind.
3316 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3317 return;
3322 * we defer all callbacks in order to cleanup
3323 * the database record.
3325 tevent_req_defer_callback(req, state->ev);
3327 state->tmp_creds = *state->creds;
3328 netlogon_creds_client_authenticator(&state->tmp_creds,
3329 &state->req_auth);
3330 ZERO_STRUCT(state->rep_auth);
3332 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3333 state->binding_handle,
3334 state->srv_name_slash,
3335 state->tmp_creds.computer_name,
3336 &state->req_auth,
3337 &state->rep_auth,
3338 state->flags,
3339 &state->forest_trust_info);
3340 if (tevent_req_nomem(subreq, req)) {
3341 status = NT_STATUS_NO_MEMORY;
3342 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3343 return;
3346 tevent_req_set_callback(subreq,
3347 netlogon_creds_cli_GetForestTrustInformation_done,
3348 req);
3351 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3353 struct tevent_req *req =
3354 tevent_req_callback_data(subreq,
3355 struct tevent_req);
3356 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3357 tevent_req_data(req,
3358 struct netlogon_creds_cli_GetForestTrustInformation_state);
3359 NTSTATUS status;
3360 NTSTATUS result;
3361 bool ok;
3364 * We use state->dns_names as the memory context, as this is
3365 * the only in/out variable and it has been overwritten by the
3366 * out parameter from the server.
3368 * We need to preserve the return value until the caller can use it.
3370 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3371 TALLOC_FREE(subreq);
3372 if (tevent_req_nterror(req, status)) {
3373 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3374 return;
3377 ok = netlogon_creds_client_check(&state->tmp_creds,
3378 &state->rep_auth.cred);
3379 if (!ok) {
3380 status = NT_STATUS_ACCESS_DENIED;
3381 tevent_req_nterror(req, status);
3382 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3383 return;
3386 *state->creds = state->tmp_creds;
3387 status = netlogon_creds_cli_store(state->context,
3388 &state->creds);
3390 if (tevent_req_nterror(req, status)) {
3391 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3392 return;
3395 if (tevent_req_nterror(req, result)) {
3396 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3397 return;
3400 tevent_req_done(req);
3403 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3404 TALLOC_CTX *mem_ctx,
3405 struct lsa_ForestTrustInformation **forest_trust_info)
3407 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3408 tevent_req_data(req,
3409 struct netlogon_creds_cli_GetForestTrustInformation_state);
3410 NTSTATUS status;
3412 if (tevent_req_is_nterror(req, &status)) {
3413 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3414 tevent_req_received(req);
3415 return status;
3418 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3420 tevent_req_received(req);
3421 return NT_STATUS_OK;
3424 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3425 struct netlogon_creds_cli_context *context,
3426 struct dcerpc_binding_handle *b,
3427 TALLOC_CTX *mem_ctx,
3428 struct lsa_ForestTrustInformation **forest_trust_info)
3430 TALLOC_CTX *frame = talloc_stackframe();
3431 struct tevent_context *ev;
3432 struct tevent_req *req;
3433 NTSTATUS status = NT_STATUS_NO_MEMORY;
3435 ev = samba_tevent_context_init(frame);
3436 if (ev == NULL) {
3437 goto fail;
3439 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3440 if (req == NULL) {
3441 goto fail;
3443 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3444 goto fail;
3446 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3447 mem_ctx,
3448 forest_trust_info);
3449 fail:
3450 TALLOC_FREE(frame);
3451 return status;
3454 struct netlogon_creds_cli_SendToSam_state {
3455 struct tevent_context *ev;
3456 struct netlogon_creds_cli_context *context;
3457 struct dcerpc_binding_handle *binding_handle;
3459 char *srv_name_slash;
3460 enum dcerpc_AuthType auth_type;
3461 enum dcerpc_AuthLevel auth_level;
3463 DATA_BLOB opaque;
3465 struct netlogon_creds_CredentialState *creds;
3466 struct netlogon_creds_CredentialState tmp_creds;
3467 struct netr_Authenticator req_auth;
3468 struct netr_Authenticator rep_auth;
3471 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3472 NTSTATUS status);
3473 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3475 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3476 struct tevent_context *ev,
3477 struct netlogon_creds_cli_context *context,
3478 struct dcerpc_binding_handle *b,
3479 struct netr_SendToSamBase *message)
3481 struct tevent_req *req;
3482 struct netlogon_creds_cli_SendToSam_state *state;
3483 struct tevent_req *subreq;
3484 enum ndr_err_code ndr_err;
3486 req = tevent_req_create(mem_ctx, &state,
3487 struct netlogon_creds_cli_SendToSam_state);
3488 if (req == NULL) {
3489 return NULL;
3492 state->ev = ev;
3493 state->context = context;
3494 state->binding_handle = b;
3496 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3497 context->server.computer);
3498 if (tevent_req_nomem(state->srv_name_slash, req)) {
3499 return tevent_req_post(req, ev);
3502 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3503 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3504 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3505 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3506 tevent_req_nterror(req, status);
3507 return tevent_req_post(req, ev);
3510 dcerpc_binding_handle_auth_info(state->binding_handle,
3511 &state->auth_type,
3512 &state->auth_level);
3514 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3515 state->context);
3516 if (tevent_req_nomem(subreq, req)) {
3517 return tevent_req_post(req, ev);
3520 tevent_req_set_callback(subreq,
3521 netlogon_creds_cli_SendToSam_locked,
3522 req);
3524 return req;
3527 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3528 NTSTATUS status)
3530 struct netlogon_creds_cli_SendToSam_state *state =
3531 tevent_req_data(req,
3532 struct netlogon_creds_cli_SendToSam_state);
3534 if (state->creds == NULL) {
3535 return;
3538 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3539 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3540 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3541 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3542 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3543 TALLOC_FREE(state->creds);
3544 return;
3547 netlogon_creds_cli_delete(state->context, &state->creds);
3550 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3552 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3554 struct tevent_req *req =
3555 tevent_req_callback_data(subreq,
3556 struct tevent_req);
3557 struct netlogon_creds_cli_SendToSam_state *state =
3558 tevent_req_data(req,
3559 struct netlogon_creds_cli_SendToSam_state);
3560 NTSTATUS status;
3562 status = netlogon_creds_cli_lock_recv(subreq, state,
3563 &state->creds);
3564 TALLOC_FREE(subreq);
3565 if (tevent_req_nterror(req, status)) {
3566 return;
3569 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3570 switch (state->auth_level) {
3571 case DCERPC_AUTH_LEVEL_INTEGRITY:
3572 case DCERPC_AUTH_LEVEL_PRIVACY:
3573 break;
3574 default:
3575 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3576 return;
3578 } else {
3579 uint32_t tmp = state->creds->negotiate_flags;
3581 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3583 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3584 * it should be used, which means
3585 * we had a chance to verify no downgrade
3586 * happened.
3588 * This relies on netlogon_creds_cli_check*
3589 * being called before, as first request after
3590 * the DCERPC bind.
3592 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3593 return;
3598 * we defer all callbacks in order to cleanup
3599 * the database record.
3601 tevent_req_defer_callback(req, state->ev);
3603 state->tmp_creds = *state->creds;
3604 netlogon_creds_client_authenticator(&state->tmp_creds,
3605 &state->req_auth);
3606 ZERO_STRUCT(state->rep_auth);
3608 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3609 netlogon_creds_aes_encrypt(&state->tmp_creds,
3610 state->opaque.data,
3611 state->opaque.length);
3612 } else {
3613 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3614 state->opaque.data,
3615 state->opaque.length);
3618 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3619 state->binding_handle,
3620 state->srv_name_slash,
3621 state->tmp_creds.computer_name,
3622 &state->req_auth,
3623 &state->rep_auth,
3624 state->opaque.data,
3625 state->opaque.length);
3626 if (tevent_req_nomem(subreq, req)) {
3627 status = NT_STATUS_NO_MEMORY;
3628 netlogon_creds_cli_SendToSam_cleanup(req, status);
3629 return;
3632 tevent_req_set_callback(subreq,
3633 netlogon_creds_cli_SendToSam_done,
3634 req);
3637 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3639 struct tevent_req *req =
3640 tevent_req_callback_data(subreq,
3641 struct tevent_req);
3642 struct netlogon_creds_cli_SendToSam_state *state =
3643 tevent_req_data(req,
3644 struct netlogon_creds_cli_SendToSam_state);
3645 NTSTATUS status;
3646 NTSTATUS result;
3647 bool ok;
3649 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3650 TALLOC_FREE(subreq);
3651 if (tevent_req_nterror(req, status)) {
3652 netlogon_creds_cli_SendToSam_cleanup(req, status);
3653 return;
3656 ok = netlogon_creds_client_check(&state->tmp_creds,
3657 &state->rep_auth.cred);
3658 if (!ok) {
3659 status = NT_STATUS_ACCESS_DENIED;
3660 tevent_req_nterror(req, status);
3661 netlogon_creds_cli_SendToSam_cleanup(req, status);
3662 return;
3665 *state->creds = state->tmp_creds;
3666 status = netlogon_creds_cli_store(state->context,
3667 &state->creds);
3669 if (tevent_req_nterror(req, status)) {
3670 netlogon_creds_cli_SendToSam_cleanup(req, status);
3671 return;
3675 * Creds must be stored before we send back application errors
3676 * e.g. NT_STATUS_NOT_IMPLEMENTED
3678 if (tevent_req_nterror(req, result)) {
3679 netlogon_creds_cli_SendToSam_cleanup(req, result);
3680 return;
3683 tevent_req_done(req);
3686 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3687 struct dcerpc_binding_handle *b,
3688 struct netr_SendToSamBase *message)
3690 TALLOC_CTX *frame = talloc_stackframe();
3691 struct tevent_context *ev;
3692 struct tevent_req *req;
3693 NTSTATUS status = NT_STATUS_OK;
3695 ev = samba_tevent_context_init(frame);
3696 if (ev == NULL) {
3697 goto fail;
3699 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3700 if (req == NULL) {
3701 goto fail;
3703 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3704 goto fail;
3707 /* Ignore the result */
3708 fail:
3709 TALLOC_FREE(frame);
3710 return status;