rpc_client3: Avoid "cli_credentials" in cli_rpc_pipe_open_schannel_with_creds
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob3209f6cf871a6c385a4d048372ccb1fffd2e1dcd
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"
41 #include "auth/credentials/credentials.h"
43 struct netlogon_creds_cli_locked_state;
45 struct netlogon_creds_cli_context {
46 struct {
47 const char *computer;
48 const char *account;
49 uint32_t proposed_flags;
50 uint32_t required_flags;
51 enum netr_SchannelType type;
52 enum dcerpc_AuthLevel auth_level;
53 } client;
55 struct {
56 const char *computer;
57 const char *netbios_domain;
58 const char *dns_domain;
59 uint32_t cached_flags;
60 bool try_validation6;
61 bool try_logon_ex;
62 bool try_logon_with;
63 } server;
65 struct {
66 const char *key_name;
67 TDB_DATA key_data;
68 struct db_context *ctx;
69 struct g_lock_ctx *g_ctx;
70 struct netlogon_creds_cli_locked_state *locked_state;
71 } db;
74 struct netlogon_creds_cli_locked_state {
75 struct netlogon_creds_cli_context *context;
76 bool is_glocked;
77 struct netlogon_creds_CredentialState *creds;
80 static int netlogon_creds_cli_locked_state_destructor(
81 struct netlogon_creds_cli_locked_state *state)
83 struct netlogon_creds_cli_context *context = state->context;
85 if (context == NULL) {
86 return 0;
89 if (context->db.locked_state == state) {
90 context->db.locked_state = NULL;
93 if (state->is_glocked) {
94 g_lock_unlock(context->db.g_ctx,
95 context->db.key_name);
98 return 0;
101 static NTSTATUS netlogon_creds_cli_context_common(
102 const char *client_computer,
103 const char *client_account,
104 enum netr_SchannelType type,
105 enum dcerpc_AuthLevel auth_level,
106 uint32_t proposed_flags,
107 uint32_t required_flags,
108 const char *server_computer,
109 const char *server_netbios_domain,
110 const char *server_dns_domain,
111 TALLOC_CTX *mem_ctx,
112 struct netlogon_creds_cli_context **_context)
114 struct netlogon_creds_cli_context *context = NULL;
115 char *_key_name = NULL;
116 size_t server_netbios_name_len;
117 char *p = NULL;
119 *_context = NULL;
121 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
122 if (context == NULL) {
123 return NT_STATUS_NO_MEMORY;
126 context->client.computer = talloc_strdup(context, client_computer);
127 if (context->client.computer == NULL) {
128 TALLOC_FREE(context);
129 return NT_STATUS_NO_MEMORY;
132 context->client.account = talloc_strdup(context, client_account);
133 if (context->client.account == NULL) {
134 TALLOC_FREE(context);
135 return NT_STATUS_NO_MEMORY;
138 context->client.proposed_flags = proposed_flags;
139 context->client.required_flags = required_flags;
140 context->client.type = type;
141 context->client.auth_level = auth_level;
143 context->server.computer = talloc_strdup(context, server_computer);
144 if (context->server.computer == NULL) {
145 TALLOC_FREE(context);
146 return NT_STATUS_NO_MEMORY;
149 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
150 if (context->server.netbios_domain == NULL) {
151 TALLOC_FREE(context);
152 return NT_STATUS_NO_MEMORY;
155 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
156 if (context->server.dns_domain == NULL) {
157 TALLOC_FREE(context);
158 return NT_STATUS_NO_MEMORY;
162 * TODO:
163 * Force the callers to provide a unique
164 * value for server_computer and use this directly.
166 * For now we have to deal with
167 * "HOSTNAME" vs. "hostname.example.com".
170 p = strchr(server_computer, '.');
171 if (p != NULL) {
172 server_netbios_name_len = p-server_computer;
173 } else {
174 server_netbios_name_len = strlen(server_computer);
177 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
178 client_computer,
179 client_account,
180 (int)server_netbios_name_len,
181 server_computer,
182 server_netbios_domain);
183 if (_key_name == NULL) {
184 TALLOC_FREE(context);
185 return NT_STATUS_NO_MEMORY;
188 context->db.key_name = talloc_strdup_upper(context, _key_name);
189 TALLOC_FREE(_key_name);
190 if (context->db.key_name == NULL) {
191 TALLOC_FREE(context);
192 return NT_STATUS_NO_MEMORY;
195 context->db.key_data = string_term_tdb_data(context->db.key_name);
197 *_context = context;
198 return NT_STATUS_OK;
201 static struct db_context *netlogon_creds_cli_global_db;
203 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
205 if (netlogon_creds_cli_global_db != NULL) {
206 return NT_STATUS_INVALID_PARAMETER_MIX;
209 netlogon_creds_cli_global_db = talloc_move(NULL, db);
210 return NT_STATUS_OK;
213 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
215 char *fname;
216 struct db_context *global_db;
218 if (netlogon_creds_cli_global_db != NULL) {
219 return NT_STATUS_OK;
222 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
223 if (fname == NULL) {
224 return NT_STATUS_NO_MEMORY;
227 global_db = dbwrap_local_open(NULL, lp_ctx,
228 fname, 0,
229 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
230 O_RDWR|O_CREAT,
231 0600, DBWRAP_LOCK_ORDER_2,
232 DBWRAP_FLAG_NONE);
233 if (global_db == NULL) {
234 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
235 fname, strerror(errno)));
236 talloc_free(fname);
237 return NT_STATUS_NO_MEMORY;
239 TALLOC_FREE(fname);
241 netlogon_creds_cli_global_db = global_db;
242 return NT_STATUS_OK;
245 void netlogon_creds_cli_close_global_db(void)
247 TALLOC_FREE(netlogon_creds_cli_global_db);
250 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
251 struct messaging_context *msg_ctx,
252 const char *client_account,
253 enum netr_SchannelType type,
254 const char *server_computer,
255 const char *server_netbios_domain,
256 const char *server_dns_domain,
257 TALLOC_CTX *mem_ctx,
258 struct netlogon_creds_cli_context **_context)
260 TALLOC_CTX *frame = talloc_stackframe();
261 NTSTATUS status;
262 struct netlogon_creds_cli_context *context = NULL;
263 const char *client_computer;
264 uint32_t proposed_flags;
265 uint32_t required_flags = 0;
266 bool reject_md5_servers = false;
267 bool require_strong_key = false;
268 int require_sign_or_seal = true;
269 bool seal_secure_channel = true;
270 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
271 bool neutralize_nt4_emulation = false;
273 *_context = NULL;
275 if (msg_ctx == NULL) {
276 TALLOC_FREE(frame);
277 return NT_STATUS_INVALID_PARAMETER_MIX;
280 client_computer = lpcfg_netbios_name(lp_ctx);
281 if (strlen(client_computer) > 15) {
282 TALLOC_FREE(frame);
283 return NT_STATUS_INVALID_PARAMETER_MIX;
287 * allow overwrite per domain
288 * reject md5 servers:<netbios_domain>
290 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
291 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
292 "reject md5 servers",
293 server_netbios_domain,
294 reject_md5_servers);
297 * allow overwrite per domain
298 * require strong key:<netbios_domain>
300 require_strong_key = lpcfg_require_strong_key(lp_ctx);
301 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
302 "require strong key",
303 server_netbios_domain,
304 require_strong_key);
307 * allow overwrite per domain
308 * client schannel:<netbios_domain>
310 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
311 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
312 "client schannel",
313 server_netbios_domain,
314 require_sign_or_seal);
317 * allow overwrite per domain
318 * winbind sealed pipes:<netbios_domain>
320 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
321 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
322 "winbind sealed pipes",
323 server_netbios_domain,
324 seal_secure_channel);
327 * allow overwrite per domain
328 * neutralize nt4 emulation:<netbios_domain>
330 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
331 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
332 "neutralize nt4 emulation",
333 server_netbios_domain,
334 neutralize_nt4_emulation);
336 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
337 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
339 switch (type) {
340 case SEC_CHAN_WKSTA:
341 if (lpcfg_security(lp_ctx) == SEC_ADS) {
343 * AD domains should be secure
345 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
346 require_sign_or_seal = true;
347 require_strong_key = true;
349 break;
351 case SEC_CHAN_DOMAIN:
352 break;
354 case SEC_CHAN_DNS_DOMAIN:
356 * AD domains should be secure
358 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
359 require_sign_or_seal = true;
360 require_strong_key = true;
361 neutralize_nt4_emulation = true;
362 break;
364 case SEC_CHAN_BDC:
365 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
366 require_sign_or_seal = true;
367 require_strong_key = true;
368 break;
370 case SEC_CHAN_RODC:
371 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
372 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
373 require_sign_or_seal = true;
374 require_strong_key = true;
375 neutralize_nt4_emulation = true;
376 break;
378 default:
379 TALLOC_FREE(frame);
380 return NT_STATUS_INVALID_PARAMETER;
383 if (neutralize_nt4_emulation) {
384 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
387 if (require_sign_or_seal) {
388 required_flags |= NETLOGON_NEG_ARCFOUR;
389 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
390 } else {
391 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
394 if (reject_md5_servers) {
395 required_flags |= NETLOGON_NEG_ARCFOUR;
396 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
397 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
398 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
401 if (require_strong_key) {
402 required_flags |= NETLOGON_NEG_ARCFOUR;
403 required_flags |= NETLOGON_NEG_STRONG_KEYS;
404 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
407 proposed_flags |= required_flags;
409 if (seal_secure_channel) {
410 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
411 } else {
412 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
415 status = netlogon_creds_cli_context_common(client_computer,
416 client_account,
417 type,
418 auth_level,
419 proposed_flags,
420 required_flags,
421 server_computer,
422 server_netbios_domain,
424 mem_ctx,
425 &context);
426 if (!NT_STATUS_IS_OK(status)) {
427 TALLOC_FREE(frame);
428 return status;
431 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
432 if (context->db.g_ctx == NULL) {
433 TALLOC_FREE(context);
434 TALLOC_FREE(frame);
435 return NT_STATUS_NO_MEMORY;
438 status = netlogon_creds_cli_open_global_db(lp_ctx);
439 if (!NT_STATUS_IS_OK(status)) {
440 TALLOC_FREE(context);
441 TALLOC_FREE(frame);
442 return NT_STATUS_NO_MEMORY;
445 context->db.ctx = netlogon_creds_cli_global_db;
446 *_context = context;
447 TALLOC_FREE(frame);
448 return NT_STATUS_OK;
451 NTSTATUS netlogon_creds_bind_cli_credentials(
452 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
453 struct cli_credentials **pcli_creds)
455 struct cli_credentials *cli_creds;
456 struct netlogon_creds_CredentialState *ncreds;
457 NTSTATUS status;
459 cli_creds = cli_credentials_init(mem_ctx);
460 if (cli_creds == NULL) {
461 return NT_STATUS_NO_MEMORY;
463 cli_credentials_set_secure_channel_type(cli_creds,
464 context->client.type);
465 cli_credentials_set_username(cli_creds, context->client.account,
466 CRED_SPECIFIED);
467 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
468 CRED_SPECIFIED);
469 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
470 CRED_SPECIFIED);
472 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
473 if (!NT_STATUS_IS_OK(status)) {
474 TALLOC_FREE(cli_creds);
475 return status;
477 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
479 *pcli_creds = cli_creds;
480 return NT_STATUS_OK;
483 char *netlogon_creds_cli_debug_string(
484 const struct netlogon_creds_cli_context *context,
485 TALLOC_CTX *mem_ctx)
487 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
488 context->db.key_name);
491 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
492 struct netlogon_creds_cli_context *context)
494 return context->client.auth_level;
497 struct netlogon_creds_cli_fetch_state {
498 TALLOC_CTX *mem_ctx;
499 struct netlogon_creds_CredentialState *creds;
500 uint32_t required_flags;
501 NTSTATUS status;
504 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
505 void *private_data)
507 struct netlogon_creds_cli_fetch_state *state =
508 (struct netlogon_creds_cli_fetch_state *)private_data;
509 enum ndr_err_code ndr_err;
510 DATA_BLOB blob;
511 uint32_t tmp_flags;
513 state->creds = talloc_zero(state->mem_ctx,
514 struct netlogon_creds_CredentialState);
515 if (state->creds == NULL) {
516 state->status = NT_STATUS_NO_MEMORY;
517 return;
520 blob.data = data.dptr;
521 blob.length = data.dsize;
523 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
524 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
525 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
526 TALLOC_FREE(state->creds);
527 state->status = ndr_map_error2ntstatus(ndr_err);
528 return;
531 if (DEBUGLEVEL >= 10) {
532 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
535 tmp_flags = state->creds->negotiate_flags;
536 tmp_flags &= state->required_flags;
537 if (tmp_flags != state->required_flags) {
538 TALLOC_FREE(state->creds);
539 state->status = NT_STATUS_DOWNGRADE_DETECTED;
540 return;
543 state->status = NT_STATUS_OK;
546 static NTSTATUS netlogon_creds_cli_get_internal(
547 struct netlogon_creds_cli_context *context,
548 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
550 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
551 TALLOC_CTX *mem_ctx,
552 struct netlogon_creds_CredentialState **_creds)
554 NTSTATUS status;
555 struct netlogon_creds_CredentialState *creds;
557 *_creds = NULL;
559 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
560 if (!NT_STATUS_IS_OK(status)) {
561 return status;
565 * mark it as invalid for step operations.
567 creds->sequence = 0;
568 creds->seed = (struct netr_Credential) {{0}};
569 creds->client = (struct netr_Credential) {{0}};
570 creds->server = (struct netr_Credential) {{0}};
572 *_creds = creds;
573 return NT_STATUS_OK;
576 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
577 const struct netlogon_creds_CredentialState *creds1)
579 TALLOC_CTX *frame = talloc_stackframe();
580 struct netlogon_creds_CredentialState *creds2;
581 DATA_BLOB blob1;
582 DATA_BLOB blob2;
583 NTSTATUS status;
584 enum ndr_err_code ndr_err;
585 int cmp;
587 status = netlogon_creds_cli_get(context, frame, &creds2);
588 if (!NT_STATUS_IS_OK(status)) {
589 TALLOC_FREE(frame);
590 return false;
593 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
594 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
595 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
596 TALLOC_FREE(frame);
597 return false;
600 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
601 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
602 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
603 TALLOC_FREE(frame);
604 return false;
607 cmp = data_blob_cmp(&blob1, &blob2);
609 TALLOC_FREE(frame);
611 return (cmp == 0);
614 static NTSTATUS netlogon_creds_cli_store_internal(
615 struct netlogon_creds_cli_context *context,
616 struct netlogon_creds_CredentialState *creds)
618 NTSTATUS status;
619 enum ndr_err_code ndr_err;
620 DATA_BLOB blob;
621 TDB_DATA data;
623 if (DEBUGLEVEL >= 10) {
624 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
627 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
628 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
629 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
630 status = ndr_map_error2ntstatus(ndr_err);
631 return status;
634 data.dptr = blob.data;
635 data.dsize = blob.length;
637 status = dbwrap_store(context->db.ctx,
638 context->db.key_data,
639 data, TDB_REPLACE);
640 TALLOC_FREE(data.dptr);
641 if (!NT_STATUS_IS_OK(status)) {
642 return status;
645 return NT_STATUS_OK;
648 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
649 struct netlogon_creds_CredentialState *creds)
651 NTSTATUS status;
653 if (context->db.locked_state == NULL) {
655 * this was not the result of netlogon_creds_cli_lock*()
657 return NT_STATUS_INVALID_PAGE_PROTECTION;
660 if (context->db.locked_state->creds != creds) {
662 * this was not the result of netlogon_creds_cli_lock*()
664 return NT_STATUS_INVALID_PAGE_PROTECTION;
667 status = netlogon_creds_cli_store_internal(context, creds);
668 return status;
671 static NTSTATUS netlogon_creds_cli_delete_internal(
672 struct netlogon_creds_cli_context *context)
674 NTSTATUS status;
675 status = dbwrap_delete(context->db.ctx, context->db.key_data);
676 return status;
679 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
680 struct netlogon_creds_CredentialState *creds)
682 NTSTATUS status;
684 if (context->db.locked_state == NULL) {
686 * this was not the result of netlogon_creds_cli_lock*()
688 return NT_STATUS_INVALID_PAGE_PROTECTION;
691 if (context->db.locked_state->creds != creds) {
693 * this was not the result of netlogon_creds_cli_lock*()
695 return NT_STATUS_INVALID_PAGE_PROTECTION;
698 status = netlogon_creds_cli_delete_internal(context);
699 return status;
702 struct netlogon_creds_cli_lock_state {
703 struct netlogon_creds_cli_locked_state *locked_state;
704 struct netlogon_creds_CredentialState *creds;
707 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
709 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
710 struct tevent_context *ev,
711 struct netlogon_creds_cli_context *context)
713 struct tevent_req *req;
714 struct netlogon_creds_cli_lock_state *state;
715 struct netlogon_creds_cli_locked_state *locked_state;
716 struct tevent_req *subreq;
718 req = tevent_req_create(mem_ctx, &state,
719 struct netlogon_creds_cli_lock_state);
720 if (req == NULL) {
721 return NULL;
724 if (context->db.locked_state != NULL) {
725 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
726 return tevent_req_post(req, ev);
729 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
730 if (tevent_req_nomem(locked_state, req)) {
731 return tevent_req_post(req, ev);
733 talloc_set_destructor(locked_state,
734 netlogon_creds_cli_locked_state_destructor);
735 locked_state->context = context;
737 context->db.locked_state = locked_state;
738 state->locked_state = locked_state;
740 if (context->db.g_ctx == NULL) {
741 NTSTATUS status;
743 status = netlogon_creds_cli_get_internal(
744 context, state, &state->creds);
745 if (tevent_req_nterror(req, status)) {
746 return tevent_req_post(req, ev);
749 return req;
752 subreq = g_lock_lock_send(state, ev,
753 context->db.g_ctx,
754 context->db.key_name,
755 G_LOCK_WRITE);
756 if (tevent_req_nomem(subreq, req)) {
757 return tevent_req_post(req, ev);
759 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
761 return req;
764 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
766 struct tevent_req *req =
767 tevent_req_callback_data(subreq,
768 struct tevent_req);
769 struct netlogon_creds_cli_lock_state *state =
770 tevent_req_data(req,
771 struct netlogon_creds_cli_lock_state);
772 NTSTATUS status;
774 status = g_lock_lock_recv(subreq);
775 TALLOC_FREE(subreq);
776 if (tevent_req_nterror(req, status)) {
777 return;
779 state->locked_state->is_glocked = true;
781 status = netlogon_creds_cli_get_internal(state->locked_state->context,
782 state, &state->creds);
783 if (tevent_req_nterror(req, status)) {
784 return;
786 tevent_req_done(req);
789 static NTSTATUS netlogon_creds_cli_get_internal(
790 struct netlogon_creds_cli_context *context,
791 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
793 struct netlogon_creds_cli_fetch_state fstate = {
794 .status = NT_STATUS_INTERNAL_ERROR,
795 .required_flags = context->client.required_flags,
797 NTSTATUS status;
799 fstate.mem_ctx = mem_ctx;
800 status = dbwrap_parse_record(context->db.ctx,
801 context->db.key_data,
802 netlogon_creds_cli_fetch_parser,
803 &fstate);
804 if (!NT_STATUS_IS_OK(status)) {
805 return status;
807 if (!NT_STATUS_IS_OK(fstate.status)) {
808 return fstate.status;
811 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
812 *pcreds = fstate.creds;
813 return NT_STATUS_OK;
817 * It is really important to try SamLogonEx here,
818 * because multiple processes can talk to the same
819 * domain controller, without using the credential
820 * chain.
822 * With a normal SamLogon call, we must keep the
823 * credentials chain updated and intact between all
824 * users of the machine account (which would imply
825 * cross-node communication for every NTLM logon).
827 * The credentials chain is not per NETLOGON pipe
828 * connection, but globally on the server/client pair
829 * by computer name.
831 * It's also important to use NetlogonValidationSamInfo4 (6),
832 * because it relies on the rpc transport encryption
833 * and avoids using the global netlogon schannel
834 * session key to en/decrypt secret information
835 * like the user_session_key for network logons.
837 * [MS-APDS] 3.1.5.2 NTLM Network Logon
838 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
839 * NETLOGON_NEG_AUTHENTICATED_RPC set together
840 * are the indication that the server supports
841 * NetlogonValidationSamInfo4 (6). And it must only
842 * be used if "SealSecureChannel" is used.
844 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
845 * check is done in netlogon_creds_cli_LogonSamLogon*().
848 context->server.cached_flags = fstate.creds->negotiate_flags;
849 context->server.try_validation6 = true;
850 context->server.try_logon_ex = true;
851 context->server.try_logon_with = true;
853 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
854 context->server.try_validation6 = false;
855 context->server.try_logon_ex = false;
857 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
858 context->server.try_validation6 = false;
861 *pcreds = fstate.creds;
862 return NT_STATUS_OK;
865 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
866 TALLOC_CTX *mem_ctx,
867 struct netlogon_creds_CredentialState **creds)
869 struct netlogon_creds_cli_lock_state *state =
870 tevent_req_data(req,
871 struct netlogon_creds_cli_lock_state);
872 NTSTATUS status;
874 if (tevent_req_is_nterror(req, &status)) {
875 tevent_req_received(req);
876 return status;
879 talloc_steal(state->creds, state->locked_state);
880 state->locked_state->creds = state->creds;
881 *creds = talloc_move(mem_ctx, &state->creds);
882 tevent_req_received(req);
883 return NT_STATUS_OK;
886 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
887 TALLOC_CTX *mem_ctx,
888 struct netlogon_creds_CredentialState **creds)
890 TALLOC_CTX *frame = talloc_stackframe();
891 struct tevent_context *ev;
892 struct tevent_req *req;
893 NTSTATUS status = NT_STATUS_NO_MEMORY;
895 ev = samba_tevent_context_init(frame);
896 if (ev == NULL) {
897 goto fail;
899 req = netlogon_creds_cli_lock_send(frame, ev, context);
900 if (req == NULL) {
901 goto fail;
903 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
904 goto fail;
906 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
907 fail:
908 TALLOC_FREE(frame);
909 return status;
912 struct netlogon_creds_cli_auth_state {
913 struct tevent_context *ev;
914 struct netlogon_creds_cli_context *context;
915 struct dcerpc_binding_handle *binding_handle;
916 uint8_t num_nt_hashes;
917 uint8_t idx_nt_hashes;
918 const struct samr_Password * const *nt_hashes;
919 const struct samr_Password *used_nt_hash;
920 char *srv_name_slash;
921 uint32_t current_flags;
922 struct netr_Credential client_challenge;
923 struct netr_Credential server_challenge;
924 struct netlogon_creds_CredentialState *creds;
925 struct netr_Credential client_credential;
926 struct netr_Credential server_credential;
927 uint32_t rid;
928 bool try_auth3;
929 bool try_auth2;
930 bool require_auth2;
931 struct netlogon_creds_cli_locked_state *locked_state;
934 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
935 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
937 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
938 struct tevent_context *ev,
939 struct netlogon_creds_cli_context *context,
940 struct dcerpc_binding_handle *b,
941 uint8_t num_nt_hashes,
942 const struct samr_Password * const *nt_hashes)
944 struct tevent_req *req;
945 struct netlogon_creds_cli_auth_state *state;
946 struct netlogon_creds_cli_locked_state *locked_state;
947 NTSTATUS status;
949 req = tevent_req_create(mem_ctx, &state,
950 struct netlogon_creds_cli_auth_state);
951 if (req == NULL) {
952 return NULL;
955 state->ev = ev;
956 state->context = context;
957 state->binding_handle = b;
958 if (num_nt_hashes < 1) {
959 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
960 return tevent_req_post(req, ev);
962 if (num_nt_hashes > 4) {
963 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
964 return tevent_req_post(req, ev);
967 state->num_nt_hashes = num_nt_hashes;
968 state->idx_nt_hashes = 0;
969 state->nt_hashes = nt_hashes;
971 if (context->db.locked_state != NULL) {
972 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
973 return tevent_req_post(req, ev);
976 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
977 if (tevent_req_nomem(locked_state, req)) {
978 return tevent_req_post(req, ev);
980 talloc_set_destructor(locked_state,
981 netlogon_creds_cli_locked_state_destructor);
982 locked_state->context = context;
984 context->db.locked_state = locked_state;
985 state->locked_state = locked_state;
987 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
988 context->server.computer);
989 if (tevent_req_nomem(state->srv_name_slash, req)) {
990 return tevent_req_post(req, ev);
993 state->try_auth3 = true;
994 state->try_auth2 = true;
996 if (context->client.required_flags != 0) {
997 state->require_auth2 = true;
1000 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1001 state->current_flags = context->client.proposed_flags;
1003 if (context->db.g_ctx != NULL) {
1004 struct tevent_req *subreq;
1006 subreq = g_lock_lock_send(state, ev,
1007 context->db.g_ctx,
1008 context->db.key_name,
1009 G_LOCK_WRITE);
1010 if (tevent_req_nomem(subreq, req)) {
1011 return tevent_req_post(req, ev);
1013 tevent_req_set_callback(subreq,
1014 netlogon_creds_cli_auth_locked,
1015 req);
1017 return req;
1020 status = dbwrap_purge(state->context->db.ctx,
1021 state->context->db.key_data);
1022 if (tevent_req_nterror(req, status)) {
1023 return tevent_req_post(req, ev);
1026 netlogon_creds_cli_auth_challenge_start(req);
1027 if (!tevent_req_is_in_progress(req)) {
1028 return tevent_req_post(req, ev);
1031 return req;
1034 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1036 struct tevent_req *req =
1037 tevent_req_callback_data(subreq,
1038 struct tevent_req);
1039 struct netlogon_creds_cli_auth_state *state =
1040 tevent_req_data(req,
1041 struct netlogon_creds_cli_auth_state);
1042 NTSTATUS status;
1044 status = g_lock_lock_recv(subreq);
1045 TALLOC_FREE(subreq);
1046 if (tevent_req_nterror(req, status)) {
1047 return;
1049 state->locked_state->is_glocked = true;
1051 status = dbwrap_purge(state->context->db.ctx,
1052 state->context->db.key_data);
1053 if (tevent_req_nterror(req, status)) {
1054 return;
1057 netlogon_creds_cli_auth_challenge_start(req);
1060 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1062 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1064 struct netlogon_creds_cli_auth_state *state =
1065 tevent_req_data(req,
1066 struct netlogon_creds_cli_auth_state);
1067 struct tevent_req *subreq;
1069 TALLOC_FREE(state->creds);
1071 generate_random_buffer(state->client_challenge.data,
1072 sizeof(state->client_challenge.data));
1074 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1075 state->binding_handle,
1076 state->srv_name_slash,
1077 state->context->client.computer,
1078 &state->client_challenge,
1079 &state->server_challenge);
1080 if (tevent_req_nomem(subreq, req)) {
1081 return;
1083 tevent_req_set_callback(subreq,
1084 netlogon_creds_cli_auth_challenge_done,
1085 req);
1088 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1090 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1092 struct tevent_req *req =
1093 tevent_req_callback_data(subreq,
1094 struct tevent_req);
1095 struct netlogon_creds_cli_auth_state *state =
1096 tevent_req_data(req,
1097 struct netlogon_creds_cli_auth_state);
1098 NTSTATUS status;
1099 NTSTATUS result;
1101 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1102 TALLOC_FREE(subreq);
1103 if (tevent_req_nterror(req, status)) {
1104 return;
1106 if (tevent_req_nterror(req, result)) {
1107 return;
1110 if (!state->try_auth3 && !state->try_auth2) {
1111 state->current_flags = 0;
1114 /* Calculate the session key and client credentials */
1116 state->creds = netlogon_creds_client_init(state,
1117 state->context->client.account,
1118 state->context->client.computer,
1119 state->context->client.type,
1120 &state->client_challenge,
1121 &state->server_challenge,
1122 state->used_nt_hash,
1123 &state->client_credential,
1124 state->current_flags);
1125 if (tevent_req_nomem(state->creds, req)) {
1126 return;
1129 if (state->try_auth3) {
1130 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1131 state->binding_handle,
1132 state->srv_name_slash,
1133 state->context->client.account,
1134 state->context->client.type,
1135 state->context->client.computer,
1136 &state->client_credential,
1137 &state->server_credential,
1138 &state->creds->negotiate_flags,
1139 &state->rid);
1140 if (tevent_req_nomem(subreq, req)) {
1141 return;
1143 } else if (state->try_auth2) {
1144 state->rid = 0;
1146 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1147 state->binding_handle,
1148 state->srv_name_slash,
1149 state->context->client.account,
1150 state->context->client.type,
1151 state->context->client.computer,
1152 &state->client_credential,
1153 &state->server_credential,
1154 &state->creds->negotiate_flags);
1155 if (tevent_req_nomem(subreq, req)) {
1156 return;
1158 } else {
1159 state->rid = 0;
1161 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1162 state->binding_handle,
1163 state->srv_name_slash,
1164 state->context->client.account,
1165 state->context->client.type,
1166 state->context->client.computer,
1167 &state->client_credential,
1168 &state->server_credential);
1169 if (tevent_req_nomem(subreq, req)) {
1170 return;
1173 tevent_req_set_callback(subreq,
1174 netlogon_creds_cli_auth_srvauth_done,
1175 req);
1178 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1180 struct tevent_req *req =
1181 tevent_req_callback_data(subreq,
1182 struct tevent_req);
1183 struct netlogon_creds_cli_auth_state *state =
1184 tevent_req_data(req,
1185 struct netlogon_creds_cli_auth_state);
1186 NTSTATUS status;
1187 NTSTATUS result;
1188 bool ok;
1189 enum ndr_err_code ndr_err;
1190 DATA_BLOB blob;
1191 TDB_DATA data;
1192 uint32_t tmp_flags;
1194 if (state->try_auth3) {
1195 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1196 &result);
1197 TALLOC_FREE(subreq);
1198 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1199 state->try_auth3 = false;
1200 netlogon_creds_cli_auth_challenge_start(req);
1201 return;
1203 if (tevent_req_nterror(req, status)) {
1204 return;
1206 } else if (state->try_auth2) {
1207 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1208 &result);
1209 TALLOC_FREE(subreq);
1210 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1211 state->try_auth2 = false;
1212 if (state->require_auth2) {
1213 status = NT_STATUS_DOWNGRADE_DETECTED;
1214 tevent_req_nterror(req, status);
1215 return;
1217 netlogon_creds_cli_auth_challenge_start(req);
1218 return;
1220 if (tevent_req_nterror(req, status)) {
1221 return;
1223 } else {
1224 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1225 &result);
1226 TALLOC_FREE(subreq);
1227 if (tevent_req_nterror(req, status)) {
1228 return;
1232 if (!NT_STATUS_IS_OK(result) &&
1233 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1235 tevent_req_nterror(req, result);
1236 return;
1239 tmp_flags = state->creds->negotiate_flags;
1240 tmp_flags &= state->context->client.required_flags;
1241 if (tmp_flags != state->context->client.required_flags) {
1242 if (NT_STATUS_IS_OK(result)) {
1243 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1244 return;
1246 tevent_req_nterror(req, result);
1247 return;
1250 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1252 tmp_flags = state->context->client.proposed_flags;
1253 if ((state->current_flags == tmp_flags) &&
1254 (state->creds->negotiate_flags != tmp_flags))
1257 * lets retry with the negotiated flags
1259 state->current_flags = state->creds->negotiate_flags;
1260 netlogon_creds_cli_auth_challenge_start(req);
1261 return;
1264 state->idx_nt_hashes += 1;
1265 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1267 * we already retried, giving up...
1269 tevent_req_nterror(req, result);
1270 return;
1274 * lets retry with the old nt hash.
1276 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1277 state->current_flags = state->context->client.proposed_flags;
1278 netlogon_creds_cli_auth_challenge_start(req);
1279 return;
1282 ok = netlogon_creds_client_check(state->creds,
1283 &state->server_credential);
1284 if (!ok) {
1285 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1286 return;
1289 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1290 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1291 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1292 status = ndr_map_error2ntstatus(ndr_err);
1293 tevent_req_nterror(req, status);
1294 return;
1297 data.dptr = blob.data;
1298 data.dsize = blob.length;
1300 status = dbwrap_store(state->context->db.ctx,
1301 state->context->db.key_data,
1302 data, TDB_REPLACE);
1303 TALLOC_FREE(state->locked_state);
1304 if (tevent_req_nterror(req, status)) {
1305 return;
1308 tevent_req_done(req);
1311 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1312 uint8_t *idx_nt_hashes)
1314 struct netlogon_creds_cli_auth_state *state =
1315 tevent_req_data(req,
1316 struct netlogon_creds_cli_auth_state);
1317 NTSTATUS status;
1319 *idx_nt_hashes = 0;
1321 if (tevent_req_is_nterror(req, &status)) {
1322 tevent_req_received(req);
1323 return status;
1326 *idx_nt_hashes = state->idx_nt_hashes;
1327 tevent_req_received(req);
1328 return NT_STATUS_OK;
1331 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1332 struct dcerpc_binding_handle *b,
1333 uint8_t num_nt_hashes,
1334 const struct samr_Password * const *nt_hashes,
1335 uint8_t *idx_nt_hashes)
1337 TALLOC_CTX *frame = talloc_stackframe();
1338 struct tevent_context *ev;
1339 struct tevent_req *req;
1340 NTSTATUS status = NT_STATUS_NO_MEMORY;
1342 *idx_nt_hashes = 0;
1344 ev = samba_tevent_context_init(frame);
1345 if (ev == NULL) {
1346 goto fail;
1348 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1349 num_nt_hashes, nt_hashes);
1350 if (req == NULL) {
1351 goto fail;
1353 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1354 goto fail;
1356 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1357 fail:
1358 TALLOC_FREE(frame);
1359 return status;
1362 struct netlogon_creds_cli_check_state {
1363 struct tevent_context *ev;
1364 struct netlogon_creds_cli_context *context;
1365 struct dcerpc_binding_handle *binding_handle;
1367 char *srv_name_slash;
1369 union netr_Capabilities caps;
1371 struct netlogon_creds_CredentialState *creds;
1372 struct netlogon_creds_CredentialState tmp_creds;
1373 struct netr_Authenticator req_auth;
1374 struct netr_Authenticator rep_auth;
1377 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1378 NTSTATUS status);
1379 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1381 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1382 struct tevent_context *ev,
1383 struct netlogon_creds_cli_context *context,
1384 struct dcerpc_binding_handle *b)
1386 struct tevent_req *req;
1387 struct netlogon_creds_cli_check_state *state;
1388 struct tevent_req *subreq;
1389 enum dcerpc_AuthType auth_type;
1390 enum dcerpc_AuthLevel auth_level;
1392 req = tevent_req_create(mem_ctx, &state,
1393 struct netlogon_creds_cli_check_state);
1394 if (req == NULL) {
1395 return NULL;
1398 state->ev = ev;
1399 state->context = context;
1400 state->binding_handle = b;
1402 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1403 context->server.computer);
1404 if (tevent_req_nomem(state->srv_name_slash, req)) {
1405 return tevent_req_post(req, ev);
1408 dcerpc_binding_handle_auth_info(state->binding_handle,
1409 &auth_type, &auth_level);
1411 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1412 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1413 return tevent_req_post(req, ev);
1416 switch (auth_level) {
1417 case DCERPC_AUTH_LEVEL_INTEGRITY:
1418 case DCERPC_AUTH_LEVEL_PRIVACY:
1419 break;
1420 default:
1421 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1422 return tevent_req_post(req, ev);
1425 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1426 state->context);
1427 if (tevent_req_nomem(subreq, req)) {
1428 return tevent_req_post(req, ev);
1431 tevent_req_set_callback(subreq,
1432 netlogon_creds_cli_check_locked,
1433 req);
1435 return req;
1438 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1439 NTSTATUS status)
1441 struct netlogon_creds_cli_check_state *state =
1442 tevent_req_data(req,
1443 struct netlogon_creds_cli_check_state);
1445 if (state->creds == NULL) {
1446 return;
1449 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1450 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1451 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1452 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1453 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1454 TALLOC_FREE(state->creds);
1455 return;
1458 netlogon_creds_cli_delete(state->context, state->creds);
1459 TALLOC_FREE(state->creds);
1462 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1464 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1466 struct tevent_req *req =
1467 tevent_req_callback_data(subreq,
1468 struct tevent_req);
1469 struct netlogon_creds_cli_check_state *state =
1470 tevent_req_data(req,
1471 struct netlogon_creds_cli_check_state);
1472 NTSTATUS status;
1474 status = netlogon_creds_cli_lock_recv(subreq, state,
1475 &state->creds);
1476 TALLOC_FREE(subreq);
1477 if (tevent_req_nterror(req, status)) {
1478 return;
1482 * we defer all callbacks in order to cleanup
1483 * the database record.
1485 tevent_req_defer_callback(req, state->ev);
1487 state->tmp_creds = *state->creds;
1488 netlogon_creds_client_authenticator(&state->tmp_creds,
1489 &state->req_auth);
1490 ZERO_STRUCT(state->rep_auth);
1492 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1493 state->binding_handle,
1494 state->srv_name_slash,
1495 state->context->client.computer,
1496 &state->req_auth,
1497 &state->rep_auth,
1499 &state->caps);
1500 if (tevent_req_nomem(subreq, req)) {
1501 status = NT_STATUS_NO_MEMORY;
1502 netlogon_creds_cli_check_cleanup(req, status);
1503 return;
1505 tevent_req_set_callback(subreq,
1506 netlogon_creds_cli_check_caps,
1507 req);
1510 static void netlogon_creds_cli_check_caps(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;
1519 NTSTATUS result;
1520 bool ok;
1522 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1523 &result);
1524 TALLOC_FREE(subreq);
1525 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1527 * Note that the negotiated flags are already checked
1528 * for our required flags after the ServerAuthenticate3/2 call.
1530 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1532 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1534 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1535 * already, we expect this to work!
1537 status = NT_STATUS_DOWNGRADE_DETECTED;
1538 tevent_req_nterror(req, status);
1539 netlogon_creds_cli_check_cleanup(req, status);
1540 return;
1543 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1545 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1546 * we expect this to work at least as far as the
1547 * NOT_SUPPORTED error handled below!
1549 * NT 4.0 and Old Samba servers are not
1550 * allowed without "require strong key = no"
1552 status = NT_STATUS_DOWNGRADE_DETECTED;
1553 tevent_req_nterror(req, status);
1554 netlogon_creds_cli_check_cleanup(req, status);
1555 return;
1559 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1560 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1561 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1563 * This is needed against NT 4.0 and old Samba servers.
1565 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1566 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1567 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1568 * with the next request as the sequence number processing
1569 * gets out of sync.
1571 netlogon_creds_cli_check_cleanup(req, status);
1572 tevent_req_done(req);
1573 return;
1575 if (tevent_req_nterror(req, status)) {
1576 netlogon_creds_cli_check_cleanup(req, status);
1577 return;
1580 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1582 * Note that the negotiated flags are already checked
1583 * for our required flags after the ServerAuthenticate3/2 call.
1585 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1587 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1589 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1590 * already, we expect this to work!
1592 status = NT_STATUS_DOWNGRADE_DETECTED;
1593 tevent_req_nterror(req, status);
1594 netlogon_creds_cli_check_cleanup(req, status);
1595 return;
1599 * This is ok, the server does not support
1600 * NETLOGON_NEG_SUPPORTS_AES.
1602 * netr_LogonGetCapabilities() was
1603 * netr_LogonDummyRoutine1() before
1604 * NETLOGON_NEG_SUPPORTS_AES was invented.
1606 netlogon_creds_cli_check_cleanup(req, result);
1607 tevent_req_done(req);
1608 return;
1611 ok = netlogon_creds_client_check(&state->tmp_creds,
1612 &state->rep_auth.cred);
1613 if (!ok) {
1614 status = NT_STATUS_ACCESS_DENIED;
1615 tevent_req_nterror(req, status);
1616 netlogon_creds_cli_check_cleanup(req, status);
1617 return;
1620 if (tevent_req_nterror(req, result)) {
1621 netlogon_creds_cli_check_cleanup(req, result);
1622 return;
1625 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1626 status = NT_STATUS_DOWNGRADE_DETECTED;
1627 tevent_req_nterror(req, status);
1628 netlogon_creds_cli_check_cleanup(req, status);
1629 return;
1633 * This is the key check that makes this check secure. If we
1634 * get OK here (rather than NOT_SUPPORTED), then the server
1635 * did support AES. If the server only proposed STRONG_KEYS
1636 * and not AES, then it should have failed with
1637 * NOT_IMPLEMENTED. We always send AES as a client, so the
1638 * server should always have returned it.
1640 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1641 status = NT_STATUS_DOWNGRADE_DETECTED;
1642 tevent_req_nterror(req, status);
1643 netlogon_creds_cli_check_cleanup(req, status);
1644 return;
1647 *state->creds = state->tmp_creds;
1648 status = netlogon_creds_cli_store(state->context,
1649 state->creds);
1650 TALLOC_FREE(state->creds);
1651 if (tevent_req_nterror(req, status)) {
1652 return;
1655 tevent_req_done(req);
1658 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1660 NTSTATUS status;
1662 if (tevent_req_is_nterror(req, &status)) {
1663 netlogon_creds_cli_check_cleanup(req, status);
1664 tevent_req_received(req);
1665 return status;
1668 tevent_req_received(req);
1669 return NT_STATUS_OK;
1672 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1673 struct dcerpc_binding_handle *b)
1675 TALLOC_CTX *frame = talloc_stackframe();
1676 struct tevent_context *ev;
1677 struct tevent_req *req;
1678 NTSTATUS status = NT_STATUS_NO_MEMORY;
1680 ev = samba_tevent_context_init(frame);
1681 if (ev == NULL) {
1682 goto fail;
1684 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1685 if (req == NULL) {
1686 goto fail;
1688 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1689 goto fail;
1691 status = netlogon_creds_cli_check_recv(req);
1692 fail:
1693 TALLOC_FREE(frame);
1694 return status;
1697 struct netlogon_creds_cli_ServerPasswordSet_state {
1698 struct tevent_context *ev;
1699 struct netlogon_creds_cli_context *context;
1700 struct dcerpc_binding_handle *binding_handle;
1701 uint32_t old_timeout;
1703 char *srv_name_slash;
1704 enum dcerpc_AuthType auth_type;
1705 enum dcerpc_AuthLevel auth_level;
1707 struct samr_CryptPassword samr_crypt_password;
1708 struct netr_CryptPassword netr_crypt_password;
1709 struct samr_Password samr_password;
1711 struct netlogon_creds_CredentialState *creds;
1712 struct netlogon_creds_CredentialState tmp_creds;
1713 struct netr_Authenticator req_auth;
1714 struct netr_Authenticator rep_auth;
1717 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1718 NTSTATUS status);
1719 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1721 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1722 struct tevent_context *ev,
1723 struct netlogon_creds_cli_context *context,
1724 struct dcerpc_binding_handle *b,
1725 const DATA_BLOB *new_password,
1726 const uint32_t *new_version)
1728 struct tevent_req *req;
1729 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1730 struct tevent_req *subreq;
1731 bool ok;
1733 req = tevent_req_create(mem_ctx, &state,
1734 struct netlogon_creds_cli_ServerPasswordSet_state);
1735 if (req == NULL) {
1736 return NULL;
1739 state->ev = ev;
1740 state->context = context;
1741 state->binding_handle = b;
1743 if (new_password->length < 14) {
1744 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1745 return tevent_req_post(req, ev);
1749 * netr_ServerPasswordSet
1751 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1754 * netr_ServerPasswordSet2
1756 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1757 new_password);
1758 if (!ok) {
1759 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1760 return tevent_req_post(req, ev);
1763 if (new_version != NULL) {
1764 struct NL_PASSWORD_VERSION version;
1765 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1766 uint32_t ofs = 512 - len;
1767 uint8_t *p;
1769 if (len > 500) {
1770 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1771 return tevent_req_post(req, ev);
1773 ofs -= 12;
1775 version.ReservedField = 0;
1776 version.PasswordVersionNumber = *new_version;
1777 version.PasswordVersionPresent =
1778 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1780 p = state->samr_crypt_password.data + ofs;
1781 SIVAL(p, 0, version.ReservedField);
1782 SIVAL(p, 4, version.PasswordVersionNumber);
1783 SIVAL(p, 8, version.PasswordVersionPresent);
1786 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1787 context->server.computer);
1788 if (tevent_req_nomem(state->srv_name_slash, req)) {
1789 return tevent_req_post(req, ev);
1792 dcerpc_binding_handle_auth_info(state->binding_handle,
1793 &state->auth_type,
1794 &state->auth_level);
1796 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1797 state->context);
1798 if (tevent_req_nomem(subreq, req)) {
1799 return tevent_req_post(req, ev);
1802 tevent_req_set_callback(subreq,
1803 netlogon_creds_cli_ServerPasswordSet_locked,
1804 req);
1806 return req;
1809 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1810 NTSTATUS status)
1812 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1813 tevent_req_data(req,
1814 struct netlogon_creds_cli_ServerPasswordSet_state);
1816 if (state->creds == NULL) {
1817 return;
1820 dcerpc_binding_handle_set_timeout(state->binding_handle,
1821 state->old_timeout);
1823 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1824 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1825 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1826 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1827 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1828 TALLOC_FREE(state->creds);
1829 return;
1832 netlogon_creds_cli_delete(state->context, state->creds);
1833 TALLOC_FREE(state->creds);
1836 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1838 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1840 struct tevent_req *req =
1841 tevent_req_callback_data(subreq,
1842 struct tevent_req);
1843 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1844 tevent_req_data(req,
1845 struct netlogon_creds_cli_ServerPasswordSet_state);
1846 NTSTATUS status;
1848 status = netlogon_creds_cli_lock_recv(subreq, state,
1849 &state->creds);
1850 TALLOC_FREE(subreq);
1851 if (tevent_req_nterror(req, status)) {
1852 return;
1855 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1856 switch (state->auth_level) {
1857 case DCERPC_AUTH_LEVEL_INTEGRITY:
1858 case DCERPC_AUTH_LEVEL_PRIVACY:
1859 break;
1860 default:
1861 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1862 return;
1864 } else {
1865 uint32_t tmp = state->creds->negotiate_flags;
1867 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1869 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1870 * it should be used, which means
1871 * we had a chance to verify no downgrade
1872 * happened.
1874 * This relies on netlogon_creds_cli_check*
1875 * being called before, as first request after
1876 * the DCERPC bind.
1878 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1879 return;
1883 state->old_timeout = dcerpc_binding_handle_set_timeout(
1884 state->binding_handle, 600000);
1887 * we defer all callbacks in order to cleanup
1888 * the database record.
1890 tevent_req_defer_callback(req, state->ev);
1892 state->tmp_creds = *state->creds;
1893 netlogon_creds_client_authenticator(&state->tmp_creds,
1894 &state->req_auth);
1895 ZERO_STRUCT(state->rep_auth);
1897 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1899 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1900 netlogon_creds_aes_encrypt(&state->tmp_creds,
1901 state->samr_crypt_password.data,
1902 516);
1903 } else {
1904 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1905 state->samr_crypt_password.data,
1906 516);
1909 memcpy(state->netr_crypt_password.data,
1910 state->samr_crypt_password.data, 512);
1911 state->netr_crypt_password.length =
1912 IVAL(state->samr_crypt_password.data, 512);
1914 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1915 state->binding_handle,
1916 state->srv_name_slash,
1917 state->tmp_creds.account_name,
1918 state->tmp_creds.secure_channel_type,
1919 state->tmp_creds.computer_name,
1920 &state->req_auth,
1921 &state->rep_auth,
1922 &state->netr_crypt_password);
1923 if (tevent_req_nomem(subreq, req)) {
1924 status = NT_STATUS_NO_MEMORY;
1925 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1926 return;
1928 } else {
1929 netlogon_creds_des_encrypt(&state->tmp_creds,
1930 &state->samr_password);
1932 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1933 state->binding_handle,
1934 state->srv_name_slash,
1935 state->tmp_creds.account_name,
1936 state->tmp_creds.secure_channel_type,
1937 state->tmp_creds.computer_name,
1938 &state->req_auth,
1939 &state->rep_auth,
1940 &state->samr_password);
1941 if (tevent_req_nomem(subreq, req)) {
1942 status = NT_STATUS_NO_MEMORY;
1943 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1944 return;
1948 tevent_req_set_callback(subreq,
1949 netlogon_creds_cli_ServerPasswordSet_done,
1950 req);
1953 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1955 struct tevent_req *req =
1956 tevent_req_callback_data(subreq,
1957 struct tevent_req);
1958 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1959 tevent_req_data(req,
1960 struct netlogon_creds_cli_ServerPasswordSet_state);
1961 NTSTATUS status;
1962 NTSTATUS result;
1963 bool ok;
1965 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1966 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1967 &result);
1968 TALLOC_FREE(subreq);
1969 if (tevent_req_nterror(req, status)) {
1970 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1971 return;
1973 } else {
1974 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1975 &result);
1976 TALLOC_FREE(subreq);
1977 if (tevent_req_nterror(req, status)) {
1978 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1979 return;
1983 ok = netlogon_creds_client_check(&state->tmp_creds,
1984 &state->rep_auth.cred);
1985 if (!ok) {
1986 status = NT_STATUS_ACCESS_DENIED;
1987 tevent_req_nterror(req, status);
1988 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1989 return;
1992 if (tevent_req_nterror(req, result)) {
1993 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
1994 return;
1997 dcerpc_binding_handle_set_timeout(state->binding_handle,
1998 state->old_timeout);
2000 *state->creds = state->tmp_creds;
2001 status = netlogon_creds_cli_store(state->context,
2002 state->creds);
2003 TALLOC_FREE(state->creds);
2004 if (tevent_req_nterror(req, status)) {
2005 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2006 return;
2009 tevent_req_done(req);
2012 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2014 NTSTATUS status;
2016 if (tevent_req_is_nterror(req, &status)) {
2017 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2018 tevent_req_received(req);
2019 return status;
2022 tevent_req_received(req);
2023 return NT_STATUS_OK;
2026 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2027 struct netlogon_creds_cli_context *context,
2028 struct dcerpc_binding_handle *b,
2029 const DATA_BLOB *new_password,
2030 const uint32_t *new_version)
2032 TALLOC_CTX *frame = talloc_stackframe();
2033 struct tevent_context *ev;
2034 struct tevent_req *req;
2035 NTSTATUS status = NT_STATUS_NO_MEMORY;
2037 ev = samba_tevent_context_init(frame);
2038 if (ev == NULL) {
2039 goto fail;
2041 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2042 new_password,
2043 new_version);
2044 if (req == NULL) {
2045 goto fail;
2047 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2048 goto fail;
2050 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2051 fail:
2052 TALLOC_FREE(frame);
2053 return status;
2056 struct netlogon_creds_cli_LogonSamLogon_state {
2057 struct tevent_context *ev;
2058 struct netlogon_creds_cli_context *context;
2059 struct dcerpc_binding_handle *binding_handle;
2061 char *srv_name_slash;
2063 enum netr_LogonInfoClass logon_level;
2064 const union netr_LogonLevel *const_logon;
2065 union netr_LogonLevel *logon;
2066 uint32_t flags;
2068 uint16_t validation_level;
2069 union netr_Validation *validation;
2070 uint8_t authoritative;
2073 * do we need encryption at the application layer?
2075 bool user_encrypt;
2076 bool try_logon_ex;
2077 bool try_validation6;
2080 * the read only credentials before we started the operation
2081 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2083 struct netlogon_creds_CredentialState *ro_creds;
2086 * The (locked) credentials used for the credential chain
2087 * used for netr_LogonSamLogonWithFlags() or
2088 * netr_LogonSamLogonWith().
2090 struct netlogon_creds_CredentialState *lk_creds;
2093 * While we have locked the global credentials (lk_creds above)
2094 * we operate an a temporary copy, because a server
2095 * may not support netr_LogonSamLogonWithFlags() and
2096 * didn't process our netr_Authenticator, so we need to
2097 * restart from lk_creds.
2099 struct netlogon_creds_CredentialState tmp_creds;
2100 struct netr_Authenticator req_auth;
2101 struct netr_Authenticator rep_auth;
2104 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2105 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2106 NTSTATUS status);
2108 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2109 struct tevent_context *ev,
2110 struct netlogon_creds_cli_context *context,
2111 struct dcerpc_binding_handle *b,
2112 enum netr_LogonInfoClass logon_level,
2113 const union netr_LogonLevel *logon,
2114 uint32_t flags)
2116 struct tevent_req *req;
2117 struct netlogon_creds_cli_LogonSamLogon_state *state;
2119 req = tevent_req_create(mem_ctx, &state,
2120 struct netlogon_creds_cli_LogonSamLogon_state);
2121 if (req == NULL) {
2122 return NULL;
2125 state->ev = ev;
2126 state->context = context;
2127 state->binding_handle = b;
2129 state->logon_level = logon_level;
2130 state->const_logon = logon;
2131 state->flags = flags;
2133 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2134 context->server.computer);
2135 if (tevent_req_nomem(state->srv_name_slash, req)) {
2136 return tevent_req_post(req, ev);
2139 switch (logon_level) {
2140 case NetlogonInteractiveInformation:
2141 case NetlogonInteractiveTransitiveInformation:
2142 case NetlogonServiceInformation:
2143 case NetlogonServiceTransitiveInformation:
2144 case NetlogonGenericInformation:
2145 state->user_encrypt = true;
2146 break;
2148 case NetlogonNetworkInformation:
2149 case NetlogonNetworkTransitiveInformation:
2150 break;
2153 state->validation = talloc_zero(state, union netr_Validation);
2154 if (tevent_req_nomem(state->validation, req)) {
2155 return tevent_req_post(req, ev);
2158 netlogon_creds_cli_LogonSamLogon_start(req);
2159 if (!tevent_req_is_in_progress(req)) {
2160 return tevent_req_post(req, ev);
2164 * we defer all callbacks in order to cleanup
2165 * the database record.
2167 tevent_req_defer_callback(req, state->ev);
2168 return req;
2171 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2172 NTSTATUS status)
2174 struct netlogon_creds_cli_LogonSamLogon_state *state =
2175 tevent_req_data(req,
2176 struct netlogon_creds_cli_LogonSamLogon_state);
2178 if (state->lk_creds == NULL) {
2179 return;
2182 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2184 * This is a hack to recover from a bug in old
2185 * Samba servers, when LogonSamLogonEx() fails:
2187 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2189 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2191 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2192 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2193 * If the sign/seal check fails.
2195 * In that case we need to cleanup the netlogon session.
2197 * It's the job of the caller to disconnect the current
2198 * connection, if netlogon_creds_cli_LogonSamLogon()
2199 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2201 if (!state->context->server.try_logon_with) {
2202 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2206 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2207 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2208 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2209 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2210 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2211 TALLOC_FREE(state->lk_creds);
2212 return;
2215 netlogon_creds_cli_delete(state->context, state->lk_creds);
2216 TALLOC_FREE(state->lk_creds);
2219 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2221 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2223 struct netlogon_creds_cli_LogonSamLogon_state *state =
2224 tevent_req_data(req,
2225 struct netlogon_creds_cli_LogonSamLogon_state);
2226 struct tevent_req *subreq;
2227 NTSTATUS status;
2228 enum dcerpc_AuthType auth_type;
2229 enum dcerpc_AuthLevel auth_level;
2231 TALLOC_FREE(state->ro_creds);
2232 TALLOC_FREE(state->logon);
2233 ZERO_STRUCTP(state->validation);
2235 dcerpc_binding_handle_auth_info(state->binding_handle,
2236 &auth_type, &auth_level);
2238 state->try_logon_ex = state->context->server.try_logon_ex;
2239 state->try_validation6 = state->context->server.try_validation6;
2241 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2242 state->try_logon_ex = false;
2245 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2246 state->try_validation6 = false;
2249 if (state->try_logon_ex) {
2250 if (state->try_validation6) {
2251 state->validation_level = 6;
2252 } else {
2253 state->validation_level = 3;
2254 state->user_encrypt = true;
2257 state->logon = netlogon_creds_shallow_copy_logon(state,
2258 state->logon_level,
2259 state->const_logon);
2260 if (tevent_req_nomem(state->logon, req)) {
2261 status = NT_STATUS_NO_MEMORY;
2262 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2263 return;
2266 if (state->user_encrypt) {
2267 status = netlogon_creds_cli_get(state->context,
2268 state,
2269 &state->ro_creds);
2270 if (!NT_STATUS_IS_OK(status)) {
2271 status = NT_STATUS_ACCESS_DENIED;
2272 tevent_req_nterror(req, status);
2273 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2274 return;
2277 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2278 state->logon_level,
2279 state->logon);
2282 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2283 state->binding_handle,
2284 state->srv_name_slash,
2285 state->context->client.computer,
2286 state->logon_level,
2287 state->logon,
2288 state->validation_level,
2289 state->validation,
2290 &state->authoritative,
2291 &state->flags);
2292 if (tevent_req_nomem(subreq, req)) {
2293 status = NT_STATUS_NO_MEMORY;
2294 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2295 return;
2297 tevent_req_set_callback(subreq,
2298 netlogon_creds_cli_LogonSamLogon_done,
2299 req);
2300 return;
2303 if (state->lk_creds == NULL) {
2304 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2305 state->context);
2306 if (tevent_req_nomem(subreq, req)) {
2307 status = NT_STATUS_NO_MEMORY;
2308 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2309 return;
2311 tevent_req_set_callback(subreq,
2312 netlogon_creds_cli_LogonSamLogon_done,
2313 req);
2314 return;
2317 state->tmp_creds = *state->lk_creds;
2318 netlogon_creds_client_authenticator(&state->tmp_creds,
2319 &state->req_auth);
2320 ZERO_STRUCT(state->rep_auth);
2322 state->logon = netlogon_creds_shallow_copy_logon(state,
2323 state->logon_level,
2324 state->const_logon);
2325 if (tevent_req_nomem(state->logon, req)) {
2326 status = NT_STATUS_NO_MEMORY;
2327 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2328 return;
2331 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2332 state->logon_level,
2333 state->logon);
2335 state->validation_level = 3;
2337 if (state->context->server.try_logon_with) {
2338 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2339 state->binding_handle,
2340 state->srv_name_slash,
2341 state->context->client.computer,
2342 &state->req_auth,
2343 &state->rep_auth,
2344 state->logon_level,
2345 state->logon,
2346 state->validation_level,
2347 state->validation,
2348 &state->authoritative,
2349 &state->flags);
2350 if (tevent_req_nomem(subreq, req)) {
2351 status = NT_STATUS_NO_MEMORY;
2352 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2353 return;
2355 } else {
2356 state->flags = 0;
2358 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2359 state->binding_handle,
2360 state->srv_name_slash,
2361 state->context->client.computer,
2362 &state->req_auth,
2363 &state->rep_auth,
2364 state->logon_level,
2365 state->logon,
2366 state->validation_level,
2367 state->validation,
2368 &state->authoritative);
2369 if (tevent_req_nomem(subreq, req)) {
2370 status = NT_STATUS_NO_MEMORY;
2371 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2372 return;
2376 tevent_req_set_callback(subreq,
2377 netlogon_creds_cli_LogonSamLogon_done,
2378 req);
2381 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2383 struct tevent_req *req =
2384 tevent_req_callback_data(subreq,
2385 struct tevent_req);
2386 struct netlogon_creds_cli_LogonSamLogon_state *state =
2387 tevent_req_data(req,
2388 struct netlogon_creds_cli_LogonSamLogon_state);
2389 NTSTATUS status;
2390 NTSTATUS result;
2391 bool ok;
2393 if (state->try_logon_ex) {
2394 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2395 state->validation,
2396 &result);
2397 TALLOC_FREE(subreq);
2398 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2399 state->context->server.try_validation6 = false;
2400 state->context->server.try_logon_ex = false;
2401 netlogon_creds_cli_LogonSamLogon_start(req);
2402 return;
2404 if (tevent_req_nterror(req, status)) {
2405 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2406 return;
2409 if ((state->validation_level == 6) &&
2410 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2411 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2412 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2414 state->context->server.try_validation6 = false;
2415 netlogon_creds_cli_LogonSamLogon_start(req);
2416 return;
2419 if (tevent_req_nterror(req, result)) {
2420 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2421 return;
2424 if (state->ro_creds == NULL) {
2425 tevent_req_done(req);
2426 return;
2429 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2430 if (!ok) {
2432 * We got a race, lets retry with on authenticator
2433 * protection.
2435 * netlogon_creds_cli_LogonSamLogon_start()
2436 * will TALLOC_FREE(state->ro_creds);
2438 state->try_logon_ex = false;
2439 netlogon_creds_cli_LogonSamLogon_start(req);
2440 return;
2443 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2444 state->validation_level,
2445 state->validation);
2447 tevent_req_done(req);
2448 return;
2451 if (state->lk_creds == NULL) {
2452 status = netlogon_creds_cli_lock_recv(subreq, state,
2453 &state->lk_creds);
2454 TALLOC_FREE(subreq);
2455 if (tevent_req_nterror(req, status)) {
2456 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2457 return;
2460 netlogon_creds_cli_LogonSamLogon_start(req);
2461 return;
2464 if (state->context->server.try_logon_with) {
2465 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2466 state->validation,
2467 &result);
2468 TALLOC_FREE(subreq);
2469 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2470 state->context->server.try_logon_with = false;
2471 netlogon_creds_cli_LogonSamLogon_start(req);
2472 return;
2474 if (tevent_req_nterror(req, status)) {
2475 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2476 return;
2478 } else {
2479 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2480 state->validation,
2481 &result);
2482 TALLOC_FREE(subreq);
2483 if (tevent_req_nterror(req, status)) {
2484 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2485 return;
2489 ok = netlogon_creds_client_check(&state->tmp_creds,
2490 &state->rep_auth.cred);
2491 if (!ok) {
2492 status = NT_STATUS_ACCESS_DENIED;
2493 tevent_req_nterror(req, status);
2494 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2495 return;
2498 *state->lk_creds = state->tmp_creds;
2499 status = netlogon_creds_cli_store(state->context,
2500 state->lk_creds);
2501 TALLOC_FREE(state->lk_creds);
2503 if (tevent_req_nterror(req, status)) {
2504 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2505 return;
2508 if (tevent_req_nterror(req, result)) {
2509 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2510 return;
2513 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2514 state->validation_level,
2515 state->validation);
2517 tevent_req_done(req);
2520 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2521 TALLOC_CTX *mem_ctx,
2522 uint16_t *validation_level,
2523 union netr_Validation **validation,
2524 uint8_t *authoritative,
2525 uint32_t *flags)
2527 struct netlogon_creds_cli_LogonSamLogon_state *state =
2528 tevent_req_data(req,
2529 struct netlogon_creds_cli_LogonSamLogon_state);
2530 NTSTATUS status;
2532 /* authoritative is also returned on error */
2533 *authoritative = state->authoritative;
2535 if (tevent_req_is_nterror(req, &status)) {
2536 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2537 tevent_req_received(req);
2538 return status;
2541 *validation_level = state->validation_level;
2542 *validation = talloc_move(mem_ctx, &state->validation);
2543 *flags = state->flags;
2545 tevent_req_received(req);
2546 return NT_STATUS_OK;
2549 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2550 struct netlogon_creds_cli_context *context,
2551 struct dcerpc_binding_handle *b,
2552 enum netr_LogonInfoClass logon_level,
2553 const union netr_LogonLevel *logon,
2554 TALLOC_CTX *mem_ctx,
2555 uint16_t *validation_level,
2556 union netr_Validation **validation,
2557 uint8_t *authoritative,
2558 uint32_t *flags)
2560 TALLOC_CTX *frame = talloc_stackframe();
2561 struct tevent_context *ev;
2562 struct tevent_req *req;
2563 NTSTATUS status = NT_STATUS_NO_MEMORY;
2565 ev = samba_tevent_context_init(frame);
2566 if (ev == NULL) {
2567 goto fail;
2569 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2570 logon_level, logon,
2571 *flags);
2572 if (req == NULL) {
2573 goto fail;
2575 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2576 goto fail;
2578 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2579 validation_level,
2580 validation,
2581 authoritative,
2582 flags);
2583 fail:
2584 TALLOC_FREE(frame);
2585 return status;
2588 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2589 struct tevent_context *ev;
2590 struct netlogon_creds_cli_context *context;
2591 struct dcerpc_binding_handle *binding_handle;
2593 char *srv_name_slash;
2594 enum dcerpc_AuthType auth_type;
2595 enum dcerpc_AuthLevel auth_level;
2597 const char *site_name;
2598 uint32_t dns_ttl;
2599 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2601 struct netlogon_creds_CredentialState *creds;
2602 struct netlogon_creds_CredentialState tmp_creds;
2603 struct netr_Authenticator req_auth;
2604 struct netr_Authenticator rep_auth;
2607 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2608 NTSTATUS status);
2609 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2611 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2612 struct tevent_context *ev,
2613 struct netlogon_creds_cli_context *context,
2614 struct dcerpc_binding_handle *b,
2615 const char *site_name,
2616 uint32_t dns_ttl,
2617 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2619 struct tevent_req *req;
2620 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2621 struct tevent_req *subreq;
2623 req = tevent_req_create(mem_ctx, &state,
2624 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2625 if (req == NULL) {
2626 return NULL;
2629 state->ev = ev;
2630 state->context = context;
2631 state->binding_handle = b;
2633 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2634 context->server.computer);
2635 if (tevent_req_nomem(state->srv_name_slash, req)) {
2636 return tevent_req_post(req, ev);
2639 state->site_name = site_name;
2640 state->dns_ttl = dns_ttl;
2641 state->dns_names = dns_names;
2643 dcerpc_binding_handle_auth_info(state->binding_handle,
2644 &state->auth_type,
2645 &state->auth_level);
2647 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2648 state->context);
2649 if (tevent_req_nomem(subreq, req)) {
2650 return tevent_req_post(req, ev);
2653 tevent_req_set_callback(subreq,
2654 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2655 req);
2657 return req;
2660 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2661 NTSTATUS status)
2663 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2664 tevent_req_data(req,
2665 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2667 if (state->creds == NULL) {
2668 return;
2671 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2672 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2673 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2674 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2675 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2676 TALLOC_FREE(state->creds);
2677 return;
2680 netlogon_creds_cli_delete(state->context, state->creds);
2681 TALLOC_FREE(state->creds);
2684 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2686 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2688 struct tevent_req *req =
2689 tevent_req_callback_data(subreq,
2690 struct tevent_req);
2691 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2692 tevent_req_data(req,
2693 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2694 NTSTATUS status;
2696 status = netlogon_creds_cli_lock_recv(subreq, state,
2697 &state->creds);
2698 TALLOC_FREE(subreq);
2699 if (tevent_req_nterror(req, status)) {
2700 return;
2703 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2704 switch (state->auth_level) {
2705 case DCERPC_AUTH_LEVEL_INTEGRITY:
2706 case DCERPC_AUTH_LEVEL_PRIVACY:
2707 break;
2708 default:
2709 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2710 return;
2712 } else {
2713 uint32_t tmp = state->creds->negotiate_flags;
2715 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2717 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2718 * it should be used, which means
2719 * we had a chance to verify no downgrade
2720 * happened.
2722 * This relies on netlogon_creds_cli_check*
2723 * being called before, as first request after
2724 * the DCERPC bind.
2726 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2727 return;
2732 * we defer all callbacks in order to cleanup
2733 * the database record.
2735 tevent_req_defer_callback(req, state->ev);
2737 state->tmp_creds = *state->creds;
2738 netlogon_creds_client_authenticator(&state->tmp_creds,
2739 &state->req_auth);
2740 ZERO_STRUCT(state->rep_auth);
2742 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2743 state->binding_handle,
2744 state->srv_name_slash,
2745 state->tmp_creds.computer_name,
2746 &state->req_auth,
2747 &state->rep_auth,
2748 state->site_name,
2749 state->dns_ttl,
2750 state->dns_names);
2751 if (tevent_req_nomem(subreq, req)) {
2752 status = NT_STATUS_NO_MEMORY;
2753 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2754 return;
2757 tevent_req_set_callback(subreq,
2758 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2759 req);
2762 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2764 struct tevent_req *req =
2765 tevent_req_callback_data(subreq,
2766 struct tevent_req);
2767 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2768 tevent_req_data(req,
2769 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2770 NTSTATUS status;
2771 NTSTATUS result;
2772 bool ok;
2775 * We use state->dns_names as the memory context, as this is
2776 * the only in/out variable and it has been overwritten by the
2777 * out parameter from the server.
2779 * We need to preserve the return value until the caller can use it.
2781 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2782 &result);
2783 TALLOC_FREE(subreq);
2784 if (tevent_req_nterror(req, status)) {
2785 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2786 return;
2789 ok = netlogon_creds_client_check(&state->tmp_creds,
2790 &state->rep_auth.cred);
2791 if (!ok) {
2792 status = NT_STATUS_ACCESS_DENIED;
2793 tevent_req_nterror(req, status);
2794 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2795 return;
2798 *state->creds = state->tmp_creds;
2799 status = netlogon_creds_cli_store(state->context,
2800 state->creds);
2801 TALLOC_FREE(state->creds);
2803 if (tevent_req_nterror(req, status)) {
2804 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2805 return;
2808 if (tevent_req_nterror(req, result)) {
2809 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2810 return;
2813 tevent_req_done(req);
2816 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2818 NTSTATUS status;
2820 if (tevent_req_is_nterror(req, &status)) {
2821 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2822 tevent_req_received(req);
2823 return status;
2826 tevent_req_received(req);
2827 return NT_STATUS_OK;
2830 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2831 struct netlogon_creds_cli_context *context,
2832 struct dcerpc_binding_handle *b,
2833 const char *site_name,
2834 uint32_t dns_ttl,
2835 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2837 TALLOC_CTX *frame = talloc_stackframe();
2838 struct tevent_context *ev;
2839 struct tevent_req *req;
2840 NTSTATUS status = NT_STATUS_NO_MEMORY;
2842 ev = samba_tevent_context_init(frame);
2843 if (ev == NULL) {
2844 goto fail;
2846 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2847 site_name,
2848 dns_ttl,
2849 dns_names);
2850 if (req == NULL) {
2851 goto fail;
2853 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2854 goto fail;
2856 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2857 fail:
2858 TALLOC_FREE(frame);
2859 return status;
2862 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2863 struct tevent_context *ev;
2864 struct netlogon_creds_cli_context *context;
2865 struct dcerpc_binding_handle *binding_handle;
2867 char *srv_name_slash;
2868 enum dcerpc_AuthType auth_type;
2869 enum dcerpc_AuthLevel auth_level;
2871 struct samr_Password new_owf_password;
2872 struct samr_Password old_owf_password;
2873 struct netr_TrustInfo *trust_info;
2875 struct netlogon_creds_CredentialState *creds;
2876 struct netlogon_creds_CredentialState tmp_creds;
2877 struct netr_Authenticator req_auth;
2878 struct netr_Authenticator rep_auth;
2881 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2882 NTSTATUS status);
2883 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2885 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2886 struct tevent_context *ev,
2887 struct netlogon_creds_cli_context *context,
2888 struct dcerpc_binding_handle *b)
2890 struct tevent_req *req;
2891 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2892 struct tevent_req *subreq;
2894 req = tevent_req_create(mem_ctx, &state,
2895 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2896 if (req == NULL) {
2897 return NULL;
2900 state->ev = ev;
2901 state->context = context;
2902 state->binding_handle = b;
2904 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2905 context->server.computer);
2906 if (tevent_req_nomem(state->srv_name_slash, req)) {
2907 return tevent_req_post(req, ev);
2910 dcerpc_binding_handle_auth_info(state->binding_handle,
2911 &state->auth_type,
2912 &state->auth_level);
2914 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2915 state->context);
2916 if (tevent_req_nomem(subreq, req)) {
2917 return tevent_req_post(req, ev);
2920 tevent_req_set_callback(subreq,
2921 netlogon_creds_cli_ServerGetTrustInfo_locked,
2922 req);
2924 return req;
2927 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2928 NTSTATUS status)
2930 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2931 tevent_req_data(req,
2932 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2934 if (state->creds == NULL) {
2935 return;
2938 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2939 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2940 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2941 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2942 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2943 TALLOC_FREE(state->creds);
2944 return;
2947 netlogon_creds_cli_delete(state->context, state->creds);
2948 TALLOC_FREE(state->creds);
2951 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2953 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2955 struct tevent_req *req =
2956 tevent_req_callback_data(subreq,
2957 struct tevent_req);
2958 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2959 tevent_req_data(req,
2960 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2961 NTSTATUS status;
2963 status = netlogon_creds_cli_lock_recv(subreq, state,
2964 &state->creds);
2965 TALLOC_FREE(subreq);
2966 if (tevent_req_nterror(req, status)) {
2967 return;
2970 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2971 switch (state->auth_level) {
2972 case DCERPC_AUTH_LEVEL_PRIVACY:
2973 break;
2974 default:
2975 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2976 return;
2978 } else {
2979 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2980 return;
2984 * we defer all callbacks in order to cleanup
2985 * the database record.
2987 tevent_req_defer_callback(req, state->ev);
2989 state->tmp_creds = *state->creds;
2990 netlogon_creds_client_authenticator(&state->tmp_creds,
2991 &state->req_auth);
2992 ZERO_STRUCT(state->rep_auth);
2994 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
2995 state->binding_handle,
2996 state->srv_name_slash,
2997 state->tmp_creds.account_name,
2998 state->tmp_creds.secure_channel_type,
2999 state->tmp_creds.computer_name,
3000 &state->req_auth,
3001 &state->rep_auth,
3002 &state->new_owf_password,
3003 &state->old_owf_password,
3004 &state->trust_info);
3005 if (tevent_req_nomem(subreq, req)) {
3006 status = NT_STATUS_NO_MEMORY;
3007 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3008 return;
3011 tevent_req_set_callback(subreq,
3012 netlogon_creds_cli_ServerGetTrustInfo_done,
3013 req);
3016 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3018 struct tevent_req *req =
3019 tevent_req_callback_data(subreq,
3020 struct tevent_req);
3021 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3022 tevent_req_data(req,
3023 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3024 NTSTATUS status;
3025 NTSTATUS result;
3026 const struct samr_Password zero = {};
3027 int cmp;
3028 bool ok;
3031 * We use state->dns_names as the memory context, as this is
3032 * the only in/out variable and it has been overwritten by the
3033 * out parameter from the server.
3035 * We need to preserve the return value until the caller can use it.
3037 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3038 TALLOC_FREE(subreq);
3039 if (tevent_req_nterror(req, status)) {
3040 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3041 return;
3044 ok = netlogon_creds_client_check(&state->tmp_creds,
3045 &state->rep_auth.cred);
3046 if (!ok) {
3047 status = NT_STATUS_ACCESS_DENIED;
3048 tevent_req_nterror(req, status);
3049 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3050 return;
3053 cmp = memcmp(state->new_owf_password.hash,
3054 zero.hash, sizeof(zero.hash));
3055 if (cmp != 0) {
3056 netlogon_creds_des_decrypt(&state->tmp_creds,
3057 &state->new_owf_password);
3059 cmp = memcmp(state->old_owf_password.hash,
3060 zero.hash, sizeof(zero.hash));
3061 if (cmp != 0) {
3062 netlogon_creds_des_decrypt(&state->tmp_creds,
3063 &state->old_owf_password);
3066 *state->creds = state->tmp_creds;
3067 status = netlogon_creds_cli_store(state->context,
3068 state->creds);
3069 TALLOC_FREE(state->creds);
3070 if (tevent_req_nterror(req, status)) {
3071 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3072 return;
3075 if (tevent_req_nterror(req, result)) {
3076 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3077 return;
3080 tevent_req_done(req);
3083 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3084 TALLOC_CTX *mem_ctx,
3085 struct samr_Password *new_owf_password,
3086 struct samr_Password *old_owf_password,
3087 struct netr_TrustInfo **trust_info)
3089 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3090 tevent_req_data(req,
3091 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3092 NTSTATUS status;
3094 if (tevent_req_is_nterror(req, &status)) {
3095 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3096 tevent_req_received(req);
3097 return status;
3100 if (new_owf_password != NULL) {
3101 *new_owf_password = state->new_owf_password;
3103 if (old_owf_password != NULL) {
3104 *old_owf_password = state->old_owf_password;
3106 if (trust_info != NULL) {
3107 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3110 tevent_req_received(req);
3111 return NT_STATUS_OK;
3114 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3115 struct netlogon_creds_cli_context *context,
3116 struct dcerpc_binding_handle *b,
3117 TALLOC_CTX *mem_ctx,
3118 struct samr_Password *new_owf_password,
3119 struct samr_Password *old_owf_password,
3120 struct netr_TrustInfo **trust_info)
3122 TALLOC_CTX *frame = talloc_stackframe();
3123 struct tevent_context *ev;
3124 struct tevent_req *req;
3125 NTSTATUS status = NT_STATUS_NO_MEMORY;
3127 ev = samba_tevent_context_init(frame);
3128 if (ev == NULL) {
3129 goto fail;
3131 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3132 if (req == NULL) {
3133 goto fail;
3135 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3136 goto fail;
3138 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3139 mem_ctx,
3140 new_owf_password,
3141 old_owf_password,
3142 trust_info);
3143 fail:
3144 TALLOC_FREE(frame);
3145 return status;
3148 struct netlogon_creds_cli_GetForestTrustInformation_state {
3149 struct tevent_context *ev;
3150 struct netlogon_creds_cli_context *context;
3151 struct dcerpc_binding_handle *binding_handle;
3153 char *srv_name_slash;
3154 enum dcerpc_AuthType auth_type;
3155 enum dcerpc_AuthLevel auth_level;
3157 uint32_t flags;
3158 struct lsa_ForestTrustInformation *forest_trust_info;
3160 struct netlogon_creds_CredentialState *creds;
3161 struct netlogon_creds_CredentialState tmp_creds;
3162 struct netr_Authenticator req_auth;
3163 struct netr_Authenticator rep_auth;
3166 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3167 NTSTATUS status);
3168 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3170 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3171 struct tevent_context *ev,
3172 struct netlogon_creds_cli_context *context,
3173 struct dcerpc_binding_handle *b)
3175 struct tevent_req *req;
3176 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3177 struct tevent_req *subreq;
3179 req = tevent_req_create(mem_ctx, &state,
3180 struct netlogon_creds_cli_GetForestTrustInformation_state);
3181 if (req == NULL) {
3182 return NULL;
3185 state->ev = ev;
3186 state->context = context;
3187 state->binding_handle = b;
3189 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3190 context->server.computer);
3191 if (tevent_req_nomem(state->srv_name_slash, req)) {
3192 return tevent_req_post(req, ev);
3195 state->flags = 0;
3197 dcerpc_binding_handle_auth_info(state->binding_handle,
3198 &state->auth_type,
3199 &state->auth_level);
3201 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3202 state->context);
3203 if (tevent_req_nomem(subreq, req)) {
3204 return tevent_req_post(req, ev);
3207 tevent_req_set_callback(subreq,
3208 netlogon_creds_cli_GetForestTrustInformation_locked,
3209 req);
3211 return req;
3214 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3215 NTSTATUS status)
3217 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3218 tevent_req_data(req,
3219 struct netlogon_creds_cli_GetForestTrustInformation_state);
3221 if (state->creds == NULL) {
3222 return;
3225 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3226 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3227 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3228 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3229 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3230 TALLOC_FREE(state->creds);
3231 return;
3234 netlogon_creds_cli_delete(state->context, state->creds);
3235 TALLOC_FREE(state->creds);
3238 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3240 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3242 struct tevent_req *req =
3243 tevent_req_callback_data(subreq,
3244 struct tevent_req);
3245 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3246 tevent_req_data(req,
3247 struct netlogon_creds_cli_GetForestTrustInformation_state);
3248 NTSTATUS status;
3250 status = netlogon_creds_cli_lock_recv(subreq, state,
3251 &state->creds);
3252 TALLOC_FREE(subreq);
3253 if (tevent_req_nterror(req, status)) {
3254 return;
3257 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3258 switch (state->auth_level) {
3259 case DCERPC_AUTH_LEVEL_INTEGRITY:
3260 case DCERPC_AUTH_LEVEL_PRIVACY:
3261 break;
3262 default:
3263 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3264 return;
3266 } else {
3267 uint32_t tmp = state->creds->negotiate_flags;
3269 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3271 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3272 * it should be used, which means
3273 * we had a chance to verify no downgrade
3274 * happened.
3276 * This relies on netlogon_creds_cli_check*
3277 * being called before, as first request after
3278 * the DCERPC bind.
3280 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3281 return;
3286 * we defer all callbacks in order to cleanup
3287 * the database record.
3289 tevent_req_defer_callback(req, state->ev);
3291 state->tmp_creds = *state->creds;
3292 netlogon_creds_client_authenticator(&state->tmp_creds,
3293 &state->req_auth);
3294 ZERO_STRUCT(state->rep_auth);
3296 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3297 state->binding_handle,
3298 state->srv_name_slash,
3299 state->tmp_creds.computer_name,
3300 &state->req_auth,
3301 &state->rep_auth,
3302 state->flags,
3303 &state->forest_trust_info);
3304 if (tevent_req_nomem(subreq, req)) {
3305 status = NT_STATUS_NO_MEMORY;
3306 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3307 return;
3310 tevent_req_set_callback(subreq,
3311 netlogon_creds_cli_GetForestTrustInformation_done,
3312 req);
3315 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3317 struct tevent_req *req =
3318 tevent_req_callback_data(subreq,
3319 struct tevent_req);
3320 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3321 tevent_req_data(req,
3322 struct netlogon_creds_cli_GetForestTrustInformation_state);
3323 NTSTATUS status;
3324 NTSTATUS result;
3325 bool ok;
3328 * We use state->dns_names as the memory context, as this is
3329 * the only in/out variable and it has been overwritten by the
3330 * out parameter from the server.
3332 * We need to preserve the return value until the caller can use it.
3334 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3335 TALLOC_FREE(subreq);
3336 if (tevent_req_nterror(req, status)) {
3337 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3338 return;
3341 ok = netlogon_creds_client_check(&state->tmp_creds,
3342 &state->rep_auth.cred);
3343 if (!ok) {
3344 status = NT_STATUS_ACCESS_DENIED;
3345 tevent_req_nterror(req, status);
3346 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3347 return;
3350 *state->creds = state->tmp_creds;
3351 status = netlogon_creds_cli_store(state->context,
3352 state->creds);
3353 TALLOC_FREE(state->creds);
3355 if (tevent_req_nterror(req, status)) {
3356 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3357 return;
3360 if (tevent_req_nterror(req, result)) {
3361 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3362 return;
3365 tevent_req_done(req);
3368 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3369 TALLOC_CTX *mem_ctx,
3370 struct lsa_ForestTrustInformation **forest_trust_info)
3372 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3373 tevent_req_data(req,
3374 struct netlogon_creds_cli_GetForestTrustInformation_state);
3375 NTSTATUS status;
3377 if (tevent_req_is_nterror(req, &status)) {
3378 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3379 tevent_req_received(req);
3380 return status;
3383 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3385 tevent_req_received(req);
3386 return NT_STATUS_OK;
3389 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3390 struct netlogon_creds_cli_context *context,
3391 struct dcerpc_binding_handle *b,
3392 TALLOC_CTX *mem_ctx,
3393 struct lsa_ForestTrustInformation **forest_trust_info)
3395 TALLOC_CTX *frame = talloc_stackframe();
3396 struct tevent_context *ev;
3397 struct tevent_req *req;
3398 NTSTATUS status = NT_STATUS_NO_MEMORY;
3400 ev = samba_tevent_context_init(frame);
3401 if (ev == NULL) {
3402 goto fail;
3404 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3405 if (req == NULL) {
3406 goto fail;
3408 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3409 goto fail;
3411 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3412 mem_ctx,
3413 forest_trust_info);
3414 fail:
3415 TALLOC_FREE(frame);
3416 return status;
3419 struct netlogon_creds_cli_SendToSam_state {
3420 struct tevent_context *ev;
3421 struct netlogon_creds_cli_context *context;
3422 struct dcerpc_binding_handle *binding_handle;
3424 char *srv_name_slash;
3425 enum dcerpc_AuthType auth_type;
3426 enum dcerpc_AuthLevel auth_level;
3428 DATA_BLOB opaque;
3430 struct netlogon_creds_CredentialState *creds;
3431 struct netlogon_creds_CredentialState tmp_creds;
3432 struct netr_Authenticator req_auth;
3433 struct netr_Authenticator rep_auth;
3436 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3437 NTSTATUS status);
3438 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3440 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3441 struct tevent_context *ev,
3442 struct netlogon_creds_cli_context *context,
3443 struct dcerpc_binding_handle *b,
3444 struct netr_SendToSamBase *message)
3446 struct tevent_req *req;
3447 struct netlogon_creds_cli_SendToSam_state *state;
3448 struct tevent_req *subreq;
3449 enum ndr_err_code ndr_err;
3451 req = tevent_req_create(mem_ctx, &state,
3452 struct netlogon_creds_cli_SendToSam_state);
3453 if (req == NULL) {
3454 return NULL;
3457 state->ev = ev;
3458 state->context = context;
3459 state->binding_handle = b;
3461 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3462 context->server.computer);
3463 if (tevent_req_nomem(state->srv_name_slash, req)) {
3464 return tevent_req_post(req, ev);
3467 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3468 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3469 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3470 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3471 tevent_req_nterror(req, status);
3472 return tevent_req_post(req, ev);
3475 dcerpc_binding_handle_auth_info(state->binding_handle,
3476 &state->auth_type,
3477 &state->auth_level);
3479 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3480 state->context);
3481 if (tevent_req_nomem(subreq, req)) {
3482 return tevent_req_post(req, ev);
3485 tevent_req_set_callback(subreq,
3486 netlogon_creds_cli_SendToSam_locked,
3487 req);
3489 return req;
3492 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3493 NTSTATUS status)
3495 struct netlogon_creds_cli_SendToSam_state *state =
3496 tevent_req_data(req,
3497 struct netlogon_creds_cli_SendToSam_state);
3499 if (state->creds == NULL) {
3500 return;
3503 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3504 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3505 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3506 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3507 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3508 TALLOC_FREE(state->creds);
3509 return;
3512 netlogon_creds_cli_delete(state->context, state->creds);
3513 TALLOC_FREE(state->creds);
3516 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3518 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3520 struct tevent_req *req =
3521 tevent_req_callback_data(subreq,
3522 struct tevent_req);
3523 struct netlogon_creds_cli_SendToSam_state *state =
3524 tevent_req_data(req,
3525 struct netlogon_creds_cli_SendToSam_state);
3526 NTSTATUS status;
3528 status = netlogon_creds_cli_lock_recv(subreq, state,
3529 &state->creds);
3530 TALLOC_FREE(subreq);
3531 if (tevent_req_nterror(req, status)) {
3532 return;
3535 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3536 switch (state->auth_level) {
3537 case DCERPC_AUTH_LEVEL_INTEGRITY:
3538 case DCERPC_AUTH_LEVEL_PRIVACY:
3539 break;
3540 default:
3541 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3542 return;
3544 } else {
3545 uint32_t tmp = state->creds->negotiate_flags;
3547 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3549 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3550 * it should be used, which means
3551 * we had a chance to verify no downgrade
3552 * happened.
3554 * This relies on netlogon_creds_cli_check*
3555 * being called before, as first request after
3556 * the DCERPC bind.
3558 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3559 return;
3564 * we defer all callbacks in order to cleanup
3565 * the database record.
3567 tevent_req_defer_callback(req, state->ev);
3569 state->tmp_creds = *state->creds;
3570 netlogon_creds_client_authenticator(&state->tmp_creds,
3571 &state->req_auth);
3572 ZERO_STRUCT(state->rep_auth);
3574 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3575 netlogon_creds_aes_encrypt(&state->tmp_creds,
3576 state->opaque.data,
3577 state->opaque.length);
3578 } else {
3579 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3580 state->opaque.data,
3581 state->opaque.length);
3584 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3585 state->binding_handle,
3586 state->srv_name_slash,
3587 state->tmp_creds.computer_name,
3588 &state->req_auth,
3589 &state->rep_auth,
3590 state->opaque.data,
3591 state->opaque.length);
3592 if (tevent_req_nomem(subreq, req)) {
3593 status = NT_STATUS_NO_MEMORY;
3594 netlogon_creds_cli_SendToSam_cleanup(req, status);
3595 return;
3598 tevent_req_set_callback(subreq,
3599 netlogon_creds_cli_SendToSam_done,
3600 req);
3603 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3605 struct tevent_req *req =
3606 tevent_req_callback_data(subreq,
3607 struct tevent_req);
3608 struct netlogon_creds_cli_SendToSam_state *state =
3609 tevent_req_data(req,
3610 struct netlogon_creds_cli_SendToSam_state);
3611 NTSTATUS status;
3612 NTSTATUS result;
3613 bool ok;
3615 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3616 TALLOC_FREE(subreq);
3617 if (tevent_req_nterror(req, status)) {
3618 netlogon_creds_cli_SendToSam_cleanup(req, status);
3619 return;
3622 ok = netlogon_creds_client_check(&state->tmp_creds,
3623 &state->rep_auth.cred);
3624 if (!ok) {
3625 status = NT_STATUS_ACCESS_DENIED;
3626 tevent_req_nterror(req, status);
3627 netlogon_creds_cli_SendToSam_cleanup(req, status);
3628 return;
3631 *state->creds = state->tmp_creds;
3632 status = netlogon_creds_cli_store(state->context,
3633 state->creds);
3634 TALLOC_FREE(state->creds);
3636 if (tevent_req_nterror(req, status)) {
3637 netlogon_creds_cli_SendToSam_cleanup(req, status);
3638 return;
3642 * Creds must be stored before we send back application errors
3643 * e.g. NT_STATUS_NOT_IMPLEMENTED
3645 if (tevent_req_nterror(req, result)) {
3646 netlogon_creds_cli_SendToSam_cleanup(req, result);
3647 return;
3650 tevent_req_done(req);
3653 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3654 struct dcerpc_binding_handle *b,
3655 struct netr_SendToSamBase *message)
3657 TALLOC_CTX *frame = talloc_stackframe();
3658 struct tevent_context *ev;
3659 struct tevent_req *req;
3660 NTSTATUS status = NT_STATUS_OK;
3662 ev = samba_tevent_context_init(frame);
3663 if (ev == NULL) {
3664 goto fail;
3666 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3667 if (req == NULL) {
3668 goto fail;
3670 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3671 goto fail;
3674 /* Ignore the result */
3675 fail:
3676 TALLOC_FREE(frame);
3677 return status;