Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : module to store/fetch session keys for the schannel client
5 :
6 : Copyright (C) Stefan Metzmacher 2013
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
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/md4.h"
41 : #include "auth/credentials/credentials.h"
42 : #include "lib/param/loadparm.h"
43 :
44 : struct netlogon_creds_cli_locked_state;
45 :
46 : struct netlogon_creds_cli_context {
47 : struct {
48 : const char *computer;
49 : const char *account;
50 : uint32_t proposed_flags;
51 : uint32_t required_flags;
52 : enum netr_SchannelType type;
53 : enum dcerpc_AuthLevel auth_level;
54 : } client;
55 :
56 : struct {
57 : const char *computer;
58 : const char *netbios_domain;
59 : const char *dns_domain;
60 : uint32_t cached_flags;
61 : bool try_validation6;
62 : bool try_logon_ex;
63 : bool try_logon_with;
64 : } server;
65 :
66 : struct {
67 : const char *key_name;
68 : TDB_DATA key_data;
69 : struct db_context *ctx;
70 : struct g_lock_ctx *g_ctx;
71 : struct netlogon_creds_cli_locked_state *locked_state;
72 : enum netlogon_creds_cli_lck_type lock;
73 : } db;
74 : };
75 :
76 : struct netlogon_creds_cli_locked_state {
77 : struct netlogon_creds_cli_context *context;
78 : bool is_glocked;
79 : struct netlogon_creds_CredentialState *creds;
80 : };
81 :
82 26 : static int netlogon_creds_cli_locked_state_destructor(
83 : struct netlogon_creds_cli_locked_state *state)
84 : {
85 26 : struct netlogon_creds_cli_context *context = state->context;
86 :
87 26 : if (context == NULL) {
88 0 : return 0;
89 : }
90 :
91 26 : if (context->db.locked_state == state) {
92 26 : context->db.locked_state = NULL;
93 : }
94 :
95 26 : if (state->is_glocked) {
96 26 : g_lock_unlock(context->db.g_ctx,
97 : string_term_tdb_data(context->db.key_name));
98 : }
99 :
100 26 : return 0;
101 : }
102 :
103 132 : static NTSTATUS netlogon_creds_cli_context_common(
104 : const char *client_computer,
105 : const char *client_account,
106 : enum netr_SchannelType type,
107 : enum dcerpc_AuthLevel auth_level,
108 : uint32_t proposed_flags,
109 : uint32_t required_flags,
110 : const char *server_computer,
111 : const char *server_netbios_domain,
112 : const char *server_dns_domain,
113 : TALLOC_CTX *mem_ctx,
114 : struct netlogon_creds_cli_context **_context)
115 : {
116 132 : struct netlogon_creds_cli_context *context = NULL;
117 132 : char *_key_name = NULL;
118 0 : size_t server_netbios_name_len;
119 132 : char *p = NULL;
120 :
121 132 : *_context = NULL;
122 :
123 132 : context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
124 132 : if (context == NULL) {
125 0 : return NT_STATUS_NO_MEMORY;
126 : }
127 :
128 132 : context->client.computer = talloc_strdup(context, client_computer);
129 132 : if (context->client.computer == NULL) {
130 0 : TALLOC_FREE(context);
131 0 : return NT_STATUS_NO_MEMORY;
132 : }
133 :
134 132 : context->client.account = talloc_strdup(context, client_account);
135 132 : if (context->client.account == NULL) {
136 0 : TALLOC_FREE(context);
137 0 : return NT_STATUS_NO_MEMORY;
138 : }
139 :
140 132 : context->client.proposed_flags = proposed_flags;
141 132 : context->client.required_flags = required_flags;
142 132 : context->client.type = type;
143 132 : context->client.auth_level = auth_level;
144 :
145 132 : context->server.computer = talloc_strdup(context, server_computer);
146 132 : if (context->server.computer == NULL) {
147 0 : TALLOC_FREE(context);
148 0 : return NT_STATUS_NO_MEMORY;
149 : }
150 :
151 132 : context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
152 132 : if (context->server.netbios_domain == NULL) {
153 0 : TALLOC_FREE(context);
154 0 : return NT_STATUS_NO_MEMORY;
155 : }
156 :
157 132 : context->server.dns_domain = talloc_strdup(context, server_dns_domain);
158 132 : if (context->server.dns_domain == NULL) {
159 0 : TALLOC_FREE(context);
160 0 : return NT_STATUS_NO_MEMORY;
161 : }
162 :
163 : /*
164 : * TODO:
165 : * Force the callers to provide a unique
166 : * value for server_computer and use this directly.
167 : *
168 : * For now we have to deal with
169 : * "HOSTNAME" vs. "hostname.example.com".
170 : */
171 :
172 132 : p = strchr(server_computer, '.');
173 132 : if (p != NULL) {
174 52 : server_netbios_name_len = p-server_computer;
175 : } else {
176 80 : server_netbios_name_len = strlen(server_computer);
177 : }
178 :
179 132 : _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
180 : client_computer,
181 : client_account,
182 : (int)server_netbios_name_len,
183 : server_computer,
184 : server_netbios_domain);
185 132 : if (_key_name == NULL) {
186 0 : TALLOC_FREE(context);
187 0 : return NT_STATUS_NO_MEMORY;
188 : }
189 :
190 132 : context->db.key_name = talloc_strdup_upper(context, _key_name);
191 132 : TALLOC_FREE(_key_name);
192 132 : if (context->db.key_name == NULL) {
193 0 : TALLOC_FREE(context);
194 0 : return NT_STATUS_NO_MEMORY;
195 : }
196 :
197 132 : context->db.key_data = string_term_tdb_data(context->db.key_name);
198 :
199 132 : *_context = context;
200 132 : return NT_STATUS_OK;
201 : }
202 :
203 : static struct db_context *netlogon_creds_cli_global_db;
204 :
205 168 : NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx,
206 : struct db_context **db)
207 : {
208 168 : netlogon_creds_cli_warn_options(lp_ctx);
209 :
210 168 : if (netlogon_creds_cli_global_db != NULL) {
211 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
212 : }
213 :
214 168 : netlogon_creds_cli_global_db = talloc_move(NULL, db);
215 168 : return NT_STATUS_OK;
216 : }
217 :
218 132 : NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
219 : {
220 0 : char *fname;
221 0 : struct db_context *global_db;
222 0 : int hash_size, tdb_flags;
223 :
224 132 : netlogon_creds_cli_warn_options(lp_ctx);
225 :
226 132 : if (netlogon_creds_cli_global_db != NULL) {
227 132 : return NT_STATUS_OK;
228 : }
229 :
230 0 : fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
231 0 : if (fname == NULL) {
232 0 : return NT_STATUS_NO_MEMORY;
233 : }
234 :
235 0 : hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
236 0 : tdb_flags = lpcfg_tdb_flags(
237 : lp_ctx,
238 : TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
239 :
240 0 : global_db = dbwrap_local_open(
241 : NULL,
242 : fname,
243 : hash_size,
244 : tdb_flags,
245 : O_RDWR|O_CREAT,
246 : 0600,
247 : DBWRAP_LOCK_ORDER_2,
248 : DBWRAP_FLAG_NONE);
249 0 : if (global_db == NULL) {
250 0 : DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
251 : fname, strerror(errno)));
252 0 : talloc_free(fname);
253 0 : return NT_STATUS_NO_MEMORY;
254 : }
255 0 : TALLOC_FREE(fname);
256 :
257 0 : netlogon_creds_cli_global_db = global_db;
258 0 : return NT_STATUS_OK;
259 : }
260 :
261 33708 : void netlogon_creds_cli_close_global_db(void)
262 : {
263 33708 : TALLOC_FREE(netlogon_creds_cli_global_db);
264 33708 : }
265 :
266 538 : void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx)
267 : {
268 538 : bool global_reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
269 538 : bool global_require_strong_key = lpcfg_require_strong_key(lp_ctx);
270 538 : int global_client_schannel = lpcfg_client_schannel(lp_ctx);
271 538 : bool global_seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
272 538 : int global_kerberos_enctypes = lpcfg_kerberos_encryption_types(lp_ctx);
273 0 : static bool warned_global_reject_md5_servers = false;
274 0 : static bool warned_global_require_strong_key = false;
275 0 : static bool warned_global_client_schannel = false;
276 0 : static bool warned_global_seal_secure_channel = false;
277 0 : static bool warned_global_kerberos_encryption_types = false;
278 0 : static int warned_global_pid = 0;
279 538 : int current_pid = tevent_cached_getpid();
280 :
281 538 : if (warned_global_pid != current_pid) {
282 269 : warned_global_reject_md5_servers = false;
283 269 : warned_global_require_strong_key = false;
284 269 : warned_global_client_schannel = false;
285 269 : warned_global_seal_secure_channel = false;
286 269 : warned_global_kerberos_encryption_types = false;
287 269 : warned_global_pid = current_pid;
288 : }
289 :
290 538 : if (!global_reject_md5_servers && !warned_global_reject_md5_servers) {
291 : /*
292 : * We want admins to notice their misconfiguration!
293 : */
294 0 : DBG_ERR("CVE-2022-38023 (and others): "
295 : "Please configure 'reject md5 servers = yes' (the default), "
296 : "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
297 0 : warned_global_reject_md5_servers = true;
298 : }
299 :
300 538 : if (!global_require_strong_key && !warned_global_require_strong_key) {
301 : /*
302 : * We want admins to notice their misconfiguration!
303 : */
304 0 : DBG_ERR("CVE-2022-38023 (and others): "
305 : "Please configure 'require strong key = yes' (the default), "
306 : "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
307 0 : warned_global_require_strong_key = true;
308 : }
309 :
310 538 : if (global_client_schannel != true && !warned_global_client_schannel) {
311 : /*
312 : * We want admins to notice their misconfiguration!
313 : */
314 0 : DBG_ERR("CVE-2022-38023 (and others): "
315 : "Please configure 'client schannel = yes' (the default), "
316 : "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
317 0 : warned_global_client_schannel = true;
318 : }
319 :
320 538 : if (!global_seal_secure_channel && !warned_global_seal_secure_channel) {
321 : /*
322 : * We want admins to notice their misconfiguration!
323 : */
324 0 : DBG_ERR("CVE-2022-38023 (and others): "
325 : "Please configure 'winbind sealed pipes = yes' (the default), "
326 : "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
327 0 : warned_global_seal_secure_channel = true;
328 : }
329 :
330 538 : if (global_kerberos_enctypes == KERBEROS_ETYPES_LEGACY &&
331 0 : !warned_global_kerberos_encryption_types)
332 : {
333 : /*
334 : * We want admins to notice their misconfiguration!
335 : */
336 0 : DBG_ERR("CVE-2022-37966: "
337 : "Please void 'kerberos encryption types = legacy', "
338 : "See https://bugzilla.samba.org/show_bug.cgi?id=15237\n");
339 0 : warned_global_kerberos_encryption_types = true;
340 : }
341 538 : }
342 :
343 132 : NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
344 : struct messaging_context *msg_ctx,
345 : const char *client_account,
346 : enum netr_SchannelType type,
347 : const char *server_computer,
348 : const char *server_netbios_domain,
349 : const char *server_dns_domain,
350 : TALLOC_CTX *mem_ctx,
351 : struct netlogon_creds_cli_context **_context)
352 : {
353 132 : TALLOC_CTX *frame = talloc_stackframe();
354 0 : NTSTATUS status;
355 132 : struct netlogon_creds_cli_context *context = NULL;
356 0 : const char *client_computer;
357 0 : uint32_t proposed_flags;
358 132 : uint32_t required_flags = 0;
359 132 : bool reject_md5_servers = true;
360 132 : bool require_strong_key = true;
361 132 : int require_sign_or_seal = true;
362 132 : bool seal_secure_channel = true;
363 132 : enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
364 132 : bool neutralize_nt4_emulation = false;
365 :
366 132 : *_context = NULL;
367 :
368 132 : if (msg_ctx == NULL) {
369 0 : TALLOC_FREE(frame);
370 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
371 : }
372 :
373 132 : client_computer = lpcfg_netbios_name(lp_ctx);
374 132 : if (strlen(client_computer) > 15) {
375 0 : TALLOC_FREE(frame);
376 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
377 : }
378 :
379 : /*
380 : * allow overwrite per domain
381 : * reject md5 servers:<netbios_domain>
382 : */
383 132 : reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
384 132 : reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
385 : "reject md5 servers",
386 : server_netbios_domain,
387 : reject_md5_servers);
388 :
389 : /*
390 : * allow overwrite per domain
391 : * require strong key:<netbios_domain>
392 : */
393 132 : require_strong_key = lpcfg_require_strong_key(lp_ctx);
394 132 : require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
395 : "require strong key",
396 : server_netbios_domain,
397 : require_strong_key);
398 :
399 : /*
400 : * allow overwrite per domain
401 : * client schannel:<netbios_domain>
402 : */
403 132 : require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
404 132 : require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
405 : "client schannel",
406 : server_netbios_domain,
407 : require_sign_or_seal);
408 :
409 : /*
410 : * allow overwrite per domain
411 : * winbind sealed pipes:<netbios_domain>
412 : */
413 132 : seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
414 132 : seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
415 : "winbind sealed pipes",
416 : server_netbios_domain,
417 : seal_secure_channel);
418 :
419 : /*
420 : * allow overwrite per domain
421 : * neutralize nt4 emulation:<netbios_domain>
422 : */
423 132 : neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
424 132 : neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
425 : "neutralize nt4 emulation",
426 : server_netbios_domain,
427 : neutralize_nt4_emulation);
428 :
429 132 : proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
430 132 : proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
431 :
432 132 : switch (type) {
433 84 : case SEC_CHAN_WKSTA:
434 84 : if (lpcfg_security(lp_ctx) == SEC_ADS) {
435 : /*
436 : * AD domains should be secure
437 : */
438 62 : required_flags |= NETLOGON_NEG_PASSWORD_SET2;
439 62 : require_sign_or_seal = true;
440 62 : require_strong_key = true;
441 : }
442 84 : break;
443 :
444 0 : case SEC_CHAN_DOMAIN:
445 0 : break;
446 :
447 0 : case SEC_CHAN_DNS_DOMAIN:
448 : /*
449 : * AD domains should be secure
450 : */
451 0 : required_flags |= NETLOGON_NEG_PASSWORD_SET2;
452 0 : require_sign_or_seal = true;
453 0 : require_strong_key = true;
454 0 : neutralize_nt4_emulation = true;
455 0 : break;
456 :
457 42 : case SEC_CHAN_BDC:
458 42 : required_flags |= NETLOGON_NEG_PASSWORD_SET2;
459 42 : require_sign_or_seal = true;
460 42 : require_strong_key = true;
461 42 : break;
462 :
463 6 : case SEC_CHAN_RODC:
464 6 : required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
465 6 : required_flags |= NETLOGON_NEG_PASSWORD_SET2;
466 6 : require_sign_or_seal = true;
467 6 : require_strong_key = true;
468 6 : neutralize_nt4_emulation = true;
469 6 : break;
470 :
471 0 : default:
472 0 : TALLOC_FREE(frame);
473 0 : return NT_STATUS_INVALID_PARAMETER;
474 : }
475 :
476 132 : if (neutralize_nt4_emulation) {
477 6 : proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
478 : }
479 :
480 132 : if (require_sign_or_seal) {
481 132 : required_flags |= NETLOGON_NEG_ARCFOUR;
482 132 : required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
483 : } else {
484 0 : proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
485 : }
486 :
487 132 : if (reject_md5_servers) {
488 132 : required_flags |= NETLOGON_NEG_ARCFOUR;
489 132 : required_flags |= NETLOGON_NEG_PASSWORD_SET2;
490 132 : required_flags |= NETLOGON_NEG_SUPPORTS_AES;
491 132 : required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
492 : }
493 :
494 132 : if (require_strong_key) {
495 132 : required_flags |= NETLOGON_NEG_ARCFOUR;
496 132 : required_flags |= NETLOGON_NEG_STRONG_KEYS;
497 132 : required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
498 : }
499 :
500 : /*
501 : * If weak crypto is disabled, do not announce that we support RC4 and
502 : * require AES.
503 : */
504 132 : if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
505 0 : required_flags &= ~NETLOGON_NEG_ARCFOUR;
506 0 : required_flags |= NETLOGON_NEG_SUPPORTS_AES;
507 0 : proposed_flags &= ~NETLOGON_NEG_ARCFOUR;
508 0 : proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
509 : }
510 :
511 132 : proposed_flags |= required_flags;
512 :
513 132 : if (seal_secure_channel) {
514 132 : auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
515 : } else {
516 0 : auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
517 : }
518 :
519 132 : status = netlogon_creds_cli_context_common(client_computer,
520 : client_account,
521 : type,
522 : auth_level,
523 : proposed_flags,
524 : required_flags,
525 : server_computer,
526 : server_netbios_domain,
527 : "",
528 : mem_ctx,
529 : &context);
530 132 : if (!NT_STATUS_IS_OK(status)) {
531 0 : TALLOC_FREE(frame);
532 0 : return status;
533 : }
534 :
535 132 : context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
536 132 : if (context->db.g_ctx == NULL) {
537 0 : TALLOC_FREE(context);
538 0 : TALLOC_FREE(frame);
539 0 : return NT_STATUS_NO_MEMORY;
540 : }
541 :
542 132 : status = netlogon_creds_cli_open_global_db(lp_ctx);
543 132 : if (!NT_STATUS_IS_OK(status)) {
544 0 : TALLOC_FREE(context);
545 0 : TALLOC_FREE(frame);
546 0 : return NT_STATUS_NO_MEMORY;
547 : }
548 :
549 132 : context->db.ctx = netlogon_creds_cli_global_db;
550 132 : *_context = context;
551 132 : TALLOC_FREE(frame);
552 132 : return NT_STATUS_OK;
553 : }
554 :
555 107 : NTSTATUS netlogon_creds_bind_cli_credentials(
556 : struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
557 : struct cli_credentials **pcli_creds)
558 : {
559 0 : struct cli_credentials *cli_creds;
560 0 : struct netlogon_creds_CredentialState *ncreds;
561 0 : NTSTATUS status;
562 :
563 107 : cli_creds = cli_credentials_init(mem_ctx);
564 107 : if (cli_creds == NULL) {
565 0 : return NT_STATUS_NO_MEMORY;
566 : }
567 107 : cli_credentials_set_secure_channel_type(cli_creds,
568 : context->client.type);
569 107 : cli_credentials_set_username(cli_creds, context->client.account,
570 : CRED_SPECIFIED);
571 107 : cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
572 : CRED_SPECIFIED);
573 107 : cli_credentials_set_realm(cli_creds, context->server.dns_domain,
574 : CRED_SPECIFIED);
575 :
576 107 : status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
577 107 : if (!NT_STATUS_IS_OK(status)) {
578 0 : TALLOC_FREE(cli_creds);
579 0 : return status;
580 : }
581 107 : cli_credentials_set_netlogon_creds(cli_creds, ncreds);
582 :
583 107 : *pcli_creds = cli_creds;
584 107 : return NT_STATUS_OK;
585 : }
586 :
587 6 : char *netlogon_creds_cli_debug_string(
588 : const struct netlogon_creds_cli_context *context,
589 : TALLOC_CTX *mem_ctx)
590 : {
591 12 : return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
592 6 : context->db.key_name);
593 : }
594 :
595 107 : enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
596 : struct netlogon_creds_cli_context *context)
597 : {
598 107 : return context->client.auth_level;
599 : }
600 :
601 602 : static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags,
602 : uint32_t proposed_flags,
603 : uint32_t required_flags)
604 : {
605 602 : uint32_t req_flags = required_flags;
606 0 : uint32_t tmp_flags;
607 :
608 602 : req_flags = required_flags;
609 602 : if ((negotiated_flags & NETLOGON_NEG_SUPPORTS_AES) &&
610 602 : (proposed_flags & NETLOGON_NEG_SUPPORTS_AES))
611 : {
612 602 : req_flags &= ~NETLOGON_NEG_ARCFOUR|NETLOGON_NEG_STRONG_KEYS;
613 : }
614 :
615 602 : tmp_flags = negotiated_flags;
616 602 : tmp_flags &= req_flags;
617 602 : if (tmp_flags != req_flags) {
618 0 : return true;
619 : }
620 :
621 602 : return false;
622 : }
623 :
624 : struct netlogon_creds_cli_fetch_state {
625 : TALLOC_CTX *mem_ctx;
626 : struct netlogon_creds_CredentialState *creds;
627 : uint32_t proposed_flags;
628 : uint32_t required_flags;
629 : NTSTATUS status;
630 : };
631 :
632 484 : static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
633 : void *private_data)
634 : {
635 484 : struct netlogon_creds_cli_fetch_state *state =
636 : (struct netlogon_creds_cli_fetch_state *)private_data;
637 0 : enum ndr_err_code ndr_err;
638 0 : DATA_BLOB blob;
639 0 : bool downgraded;
640 :
641 484 : state->creds = talloc_zero(state->mem_ctx,
642 : struct netlogon_creds_CredentialState);
643 484 : if (state->creds == NULL) {
644 0 : state->status = NT_STATUS_NO_MEMORY;
645 0 : return;
646 : }
647 :
648 484 : blob.data = data.dptr;
649 484 : blob.length = data.dsize;
650 :
651 484 : ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
652 : (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
653 484 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
654 0 : TALLOC_FREE(state->creds);
655 0 : state->status = ndr_map_error2ntstatus(ndr_err);
656 0 : return;
657 : }
658 :
659 484 : if (DEBUGLEVEL >= 10) {
660 0 : NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
661 : }
662 :
663 484 : downgraded = netlogon_creds_cli_downgraded(
664 484 : state->creds->negotiate_flags,
665 : state->proposed_flags,
666 : state->required_flags);
667 484 : if (downgraded) {
668 0 : TALLOC_FREE(state->creds);
669 0 : state->status = NT_STATUS_DOWNGRADE_DETECTED;
670 0 : return;
671 : }
672 :
673 484 : state->status = NT_STATUS_OK;
674 : }
675 :
676 : static NTSTATUS netlogon_creds_cli_get_internal(
677 : struct netlogon_creds_cli_context *context,
678 : TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
679 :
680 438 : NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
681 : TALLOC_CTX *mem_ctx,
682 : struct netlogon_creds_CredentialState **_creds)
683 : {
684 0 : NTSTATUS status;
685 0 : struct netlogon_creds_CredentialState *creds;
686 :
687 438 : *_creds = NULL;
688 :
689 438 : status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
690 438 : if (!NT_STATUS_IS_OK(status)) {
691 83 : return status;
692 : }
693 :
694 : /*
695 : * mark it as invalid for step operations.
696 : */
697 355 : creds->sequence = 0;
698 355 : creds->seed = (struct netr_Credential) {{0}};
699 355 : creds->client = (struct netr_Credential) {{0}};
700 355 : creds->server = (struct netr_Credential) {{0}};
701 :
702 355 : *_creds = creds;
703 355 : return NT_STATUS_OK;
704 : }
705 :
706 0 : bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
707 : const struct netlogon_creds_CredentialState *creds1)
708 : {
709 0 : TALLOC_CTX *frame = talloc_stackframe();
710 0 : struct netlogon_creds_CredentialState *creds2;
711 0 : DATA_BLOB blob1;
712 0 : DATA_BLOB blob2;
713 0 : NTSTATUS status;
714 0 : enum ndr_err_code ndr_err;
715 0 : bool equal;
716 :
717 0 : status = netlogon_creds_cli_get(context, frame, &creds2);
718 0 : if (!NT_STATUS_IS_OK(status)) {
719 0 : TALLOC_FREE(frame);
720 0 : return false;
721 : }
722 :
723 0 : ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
724 : (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
725 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
726 0 : TALLOC_FREE(frame);
727 0 : return false;
728 : }
729 :
730 0 : ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
731 : (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
732 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
733 0 : TALLOC_FREE(frame);
734 0 : return false;
735 : }
736 :
737 0 : equal = data_blob_equal_const_time(&blob1, &blob2);
738 :
739 0 : TALLOC_FREE(frame);
740 :
741 0 : return equal;
742 : }
743 :
744 129 : static NTSTATUS netlogon_creds_cli_store_internal(
745 : struct netlogon_creds_cli_context *context,
746 : struct netlogon_creds_CredentialState *creds)
747 : {
748 0 : NTSTATUS status;
749 0 : enum ndr_err_code ndr_err;
750 0 : DATA_BLOB blob;
751 0 : TDB_DATA data;
752 :
753 129 : if (DEBUGLEVEL >= 10) {
754 0 : NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
755 : }
756 :
757 129 : ndr_err = ndr_push_struct_blob(&blob, creds, creds,
758 : (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
759 129 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
760 0 : status = ndr_map_error2ntstatus(ndr_err);
761 0 : return status;
762 : }
763 :
764 129 : data.dptr = blob.data;
765 129 : data.dsize = blob.length;
766 :
767 129 : status = dbwrap_store(context->db.ctx,
768 : context->db.key_data,
769 : data, TDB_REPLACE);
770 129 : TALLOC_FREE(data.dptr);
771 129 : if (!NT_STATUS_IS_OK(status)) {
772 0 : return status;
773 : }
774 :
775 129 : return NT_STATUS_OK;
776 : }
777 :
778 26 : NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
779 : struct netlogon_creds_CredentialState *creds)
780 : {
781 0 : NTSTATUS status;
782 :
783 26 : if (context->db.locked_state == NULL) {
784 : /*
785 : * this was not the result of netlogon_creds_cli_lock*()
786 : */
787 0 : return NT_STATUS_INVALID_PAGE_PROTECTION;
788 : }
789 :
790 26 : if (context->db.locked_state->creds != creds) {
791 : /*
792 : * this was not the result of netlogon_creds_cli_lock*()
793 : */
794 0 : return NT_STATUS_INVALID_PAGE_PROTECTION;
795 : }
796 :
797 26 : status = netlogon_creds_cli_store_internal(context, creds);
798 26 : return status;
799 : }
800 :
801 0 : static NTSTATUS netlogon_creds_cli_delete_internal(
802 : struct netlogon_creds_cli_context *context)
803 : {
804 0 : NTSTATUS status;
805 0 : status = dbwrap_delete(context->db.ctx, context->db.key_data);
806 0 : return status;
807 : }
808 :
809 0 : NTSTATUS netlogon_creds_cli_delete_lck(
810 : struct netlogon_creds_cli_context *context)
811 : {
812 0 : NTSTATUS status;
813 :
814 0 : if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
815 0 : return NT_STATUS_NOT_LOCKED;
816 : }
817 :
818 0 : status = netlogon_creds_cli_delete_internal(context);
819 0 : return status;
820 : }
821 :
822 0 : NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
823 : struct netlogon_creds_CredentialState *creds)
824 : {
825 0 : NTSTATUS status;
826 :
827 0 : if (context->db.locked_state == NULL) {
828 : /*
829 : * this was not the result of netlogon_creds_cli_lock*()
830 : */
831 0 : return NT_STATUS_INVALID_PAGE_PROTECTION;
832 : }
833 :
834 0 : if (context->db.locked_state->creds != creds) {
835 : /*
836 : * this was not the result of netlogon_creds_cli_lock*()
837 : */
838 0 : return NT_STATUS_INVALID_PAGE_PROTECTION;
839 : }
840 :
841 0 : status = netlogon_creds_cli_delete_internal(context);
842 0 : return status;
843 : }
844 :
845 : struct netlogon_creds_cli_lock_state {
846 : struct netlogon_creds_cli_locked_state *locked_state;
847 : struct netlogon_creds_CredentialState *creds;
848 : };
849 :
850 : static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
851 :
852 26 : struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
853 : struct tevent_context *ev,
854 : struct netlogon_creds_cli_context *context)
855 : {
856 0 : struct tevent_req *req;
857 0 : struct netlogon_creds_cli_lock_state *state;
858 0 : struct netlogon_creds_cli_locked_state *locked_state;
859 0 : struct tevent_req *subreq;
860 :
861 26 : req = tevent_req_create(mem_ctx, &state,
862 : struct netlogon_creds_cli_lock_state);
863 26 : if (req == NULL) {
864 0 : return NULL;
865 : }
866 :
867 26 : if (context->db.locked_state != NULL) {
868 0 : tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
869 0 : return tevent_req_post(req, ev);
870 : }
871 :
872 26 : locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
873 26 : if (tevent_req_nomem(locked_state, req)) {
874 0 : return tevent_req_post(req, ev);
875 : }
876 26 : talloc_set_destructor(locked_state,
877 : netlogon_creds_cli_locked_state_destructor);
878 26 : locked_state->context = context;
879 :
880 26 : context->db.locked_state = locked_state;
881 26 : state->locked_state = locked_state;
882 :
883 26 : if (context->db.g_ctx == NULL) {
884 0 : NTSTATUS status;
885 :
886 0 : status = netlogon_creds_cli_get_internal(
887 0 : context, state, &state->creds);
888 0 : if (tevent_req_nterror(req, status)) {
889 0 : return tevent_req_post(req, ev);
890 : }
891 :
892 0 : return req;
893 : }
894 :
895 26 : subreq = g_lock_lock_send(state, ev,
896 : context->db.g_ctx,
897 : string_term_tdb_data(context->db.key_name),
898 : G_LOCK_WRITE,
899 : NULL, NULL);
900 26 : if (tevent_req_nomem(subreq, req)) {
901 0 : return tevent_req_post(req, ev);
902 : }
903 26 : tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
904 :
905 26 : return req;
906 : }
907 :
908 26 : static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
909 : {
910 0 : struct tevent_req *req =
911 26 : tevent_req_callback_data(subreq,
912 : struct tevent_req);
913 0 : struct netlogon_creds_cli_lock_state *state =
914 26 : tevent_req_data(req,
915 : struct netlogon_creds_cli_lock_state);
916 0 : NTSTATUS status;
917 :
918 26 : status = g_lock_lock_recv(subreq);
919 26 : TALLOC_FREE(subreq);
920 26 : if (tevent_req_nterror(req, status)) {
921 0 : return;
922 : }
923 26 : state->locked_state->is_glocked = true;
924 :
925 26 : status = netlogon_creds_cli_get_internal(state->locked_state->context,
926 : state, &state->creds);
927 26 : if (tevent_req_nterror(req, status)) {
928 0 : return;
929 : }
930 26 : tevent_req_done(req);
931 : }
932 :
933 567 : static NTSTATUS netlogon_creds_cli_get_internal(
934 : struct netlogon_creds_cli_context *context,
935 : TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
936 : {
937 567 : struct netlogon_creds_cli_fetch_state fstate = {
938 : .status = NT_STATUS_INTERNAL_ERROR,
939 567 : .proposed_flags = context->client.proposed_flags,
940 567 : .required_flags = context->client.required_flags,
941 : };
942 0 : NTSTATUS status;
943 :
944 567 : fstate.mem_ctx = mem_ctx;
945 567 : status = dbwrap_parse_record(context->db.ctx,
946 : context->db.key_data,
947 : netlogon_creds_cli_fetch_parser,
948 : &fstate);
949 567 : if (!NT_STATUS_IS_OK(status)) {
950 83 : return status;
951 : }
952 484 : if (!NT_STATUS_IS_OK(fstate.status)) {
953 0 : return fstate.status;
954 : }
955 :
956 484 : if (context->server.cached_flags == fstate.creds->negotiate_flags) {
957 359 : *pcreds = fstate.creds;
958 359 : return NT_STATUS_OK;
959 : }
960 :
961 : /*
962 : * It is really important to try SamLogonEx here,
963 : * because multiple processes can talk to the same
964 : * domain controller, without using the credential
965 : * chain.
966 : *
967 : * With a normal SamLogon call, we must keep the
968 : * credentials chain updated and intact between all
969 : * users of the machine account (which would imply
970 : * cross-node communication for every NTLM logon).
971 : *
972 : * The credentials chain is not per NETLOGON pipe
973 : * connection, but globally on the server/client pair
974 : * by computer name.
975 : *
976 : * It's also important to use NetlogonValidationSamInfo4 (6),
977 : * because it relies on the rpc transport encryption
978 : * and avoids using the global netlogon schannel
979 : * session key to en/decrypt secret information
980 : * like the user_session_key for network logons.
981 : *
982 : * [MS-APDS] 3.1.5.2 NTLM Network Logon
983 : * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
984 : * NETLOGON_NEG_AUTHENTICATED_RPC set together
985 : * are the indication that the server supports
986 : * NetlogonValidationSamInfo4 (6). And it must only
987 : * be used if "SealSecureChannel" is used.
988 : *
989 : * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
990 : * check is done in netlogon_creds_cli_LogonSamLogon*().
991 : */
992 :
993 125 : context->server.cached_flags = fstate.creds->negotiate_flags;
994 125 : context->server.try_validation6 = true;
995 125 : context->server.try_logon_ex = true;
996 125 : context->server.try_logon_with = true;
997 :
998 125 : if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
999 0 : context->server.try_validation6 = false;
1000 0 : context->server.try_logon_ex = false;
1001 : }
1002 125 : if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1003 35 : context->server.try_validation6 = false;
1004 : }
1005 :
1006 125 : *pcreds = fstate.creds;
1007 125 : return NT_STATUS_OK;
1008 : }
1009 :
1010 26 : NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
1011 : TALLOC_CTX *mem_ctx,
1012 : struct netlogon_creds_CredentialState **creds)
1013 : {
1014 0 : struct netlogon_creds_cli_lock_state *state =
1015 26 : tevent_req_data(req,
1016 : struct netlogon_creds_cli_lock_state);
1017 0 : NTSTATUS status;
1018 :
1019 26 : if (tevent_req_is_nterror(req, &status)) {
1020 0 : tevent_req_received(req);
1021 0 : return status;
1022 : }
1023 :
1024 26 : talloc_steal(state->creds, state->locked_state);
1025 26 : state->locked_state->creds = state->creds;
1026 26 : *creds = talloc_move(mem_ctx, &state->creds);
1027 26 : tevent_req_received(req);
1028 26 : return NT_STATUS_OK;
1029 : }
1030 :
1031 0 : NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
1032 : TALLOC_CTX *mem_ctx,
1033 : struct netlogon_creds_CredentialState **creds)
1034 : {
1035 0 : TALLOC_CTX *frame = talloc_stackframe();
1036 0 : struct tevent_context *ev;
1037 0 : struct tevent_req *req;
1038 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1039 :
1040 0 : ev = samba_tevent_context_init(frame);
1041 0 : if (ev == NULL) {
1042 0 : goto fail;
1043 : }
1044 0 : req = netlogon_creds_cli_lock_send(frame, ev, context);
1045 0 : if (req == NULL) {
1046 0 : goto fail;
1047 : }
1048 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1049 0 : goto fail;
1050 : }
1051 0 : status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
1052 0 : fail:
1053 0 : TALLOC_FREE(frame);
1054 0 : return status;
1055 : }
1056 :
1057 : struct netlogon_creds_cli_lck {
1058 : struct netlogon_creds_cli_context *context;
1059 : };
1060 :
1061 : struct netlogon_creds_cli_lck_state {
1062 : struct netlogon_creds_cli_lck *lck;
1063 : enum netlogon_creds_cli_lck_type type;
1064 : };
1065 :
1066 : static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
1067 : static int netlogon_creds_cli_lck_destructor(
1068 : struct netlogon_creds_cli_lck *lck);
1069 :
1070 251 : struct tevent_req *netlogon_creds_cli_lck_send(
1071 : TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1072 : struct netlogon_creds_cli_context *context,
1073 : enum netlogon_creds_cli_lck_type type)
1074 : {
1075 0 : struct tevent_req *req, *subreq;
1076 0 : struct netlogon_creds_cli_lck_state *state;
1077 0 : enum g_lock_type gtype;
1078 :
1079 251 : req = tevent_req_create(mem_ctx, &state,
1080 : struct netlogon_creds_cli_lck_state);
1081 251 : if (req == NULL) {
1082 0 : return NULL;
1083 : }
1084 :
1085 251 : if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
1086 0 : DBG_DEBUG("context already locked\n");
1087 0 : tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
1088 0 : return tevent_req_post(req, ev);
1089 : }
1090 :
1091 251 : switch (type) {
1092 0 : case NETLOGON_CREDS_CLI_LCK_SHARED:
1093 0 : gtype = G_LOCK_READ;
1094 0 : break;
1095 251 : case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
1096 251 : gtype = G_LOCK_WRITE;
1097 251 : break;
1098 0 : default:
1099 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1100 0 : return tevent_req_post(req, ev);
1101 : }
1102 :
1103 251 : state->lck = talloc(state, struct netlogon_creds_cli_lck);
1104 251 : if (tevent_req_nomem(state->lck, req)) {
1105 0 : return tevent_req_post(req, ev);
1106 : }
1107 251 : state->lck->context = context;
1108 251 : state->type = type;
1109 :
1110 251 : subreq = g_lock_lock_send(state, ev,
1111 : context->db.g_ctx,
1112 : string_term_tdb_data(context->db.key_name),
1113 : gtype,
1114 : NULL, NULL);
1115 251 : if (tevent_req_nomem(subreq, req)) {
1116 0 : return tevent_req_post(req, ev);
1117 : }
1118 251 : tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
1119 :
1120 251 : return req;
1121 : }
1122 :
1123 251 : static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
1124 : {
1125 251 : struct tevent_req *req = tevent_req_callback_data(
1126 : subreq, struct tevent_req);
1127 251 : struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1128 : req, struct netlogon_creds_cli_lck_state);
1129 0 : NTSTATUS status;
1130 :
1131 251 : status = g_lock_lock_recv(subreq);
1132 251 : TALLOC_FREE(subreq);
1133 251 : if (tevent_req_nterror(req, status)) {
1134 0 : return;
1135 : }
1136 :
1137 251 : state->lck->context->db.lock = state->type;
1138 251 : talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1139 :
1140 251 : tevent_req_done(req);
1141 : }
1142 :
1143 251 : static int netlogon_creds_cli_lck_destructor(
1144 : struct netlogon_creds_cli_lck *lck)
1145 : {
1146 251 : struct netlogon_creds_cli_context *ctx = lck->context;
1147 0 : NTSTATUS status;
1148 :
1149 251 : status = g_lock_unlock(ctx->db.g_ctx,
1150 : string_term_tdb_data(ctx->db.key_name));
1151 251 : if (!NT_STATUS_IS_OK(status)) {
1152 0 : DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1153 0 : smb_panic("g_lock_unlock failed");
1154 : }
1155 251 : ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1156 251 : return 0;
1157 : }
1158 :
1159 251 : NTSTATUS netlogon_creds_cli_lck_recv(
1160 : struct tevent_req *req, TALLOC_CTX *mem_ctx,
1161 : struct netlogon_creds_cli_lck **lck)
1162 : {
1163 251 : struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1164 : req, struct netlogon_creds_cli_lck_state);
1165 0 : NTSTATUS status;
1166 :
1167 251 : if (tevent_req_is_nterror(req, &status)) {
1168 0 : return status;
1169 : }
1170 251 : *lck = talloc_move(mem_ctx, &state->lck);
1171 251 : return NT_STATUS_OK;
1172 : }
1173 :
1174 251 : NTSTATUS netlogon_creds_cli_lck(
1175 : struct netlogon_creds_cli_context *context,
1176 : enum netlogon_creds_cli_lck_type type,
1177 : TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1178 : {
1179 251 : TALLOC_CTX *frame = talloc_stackframe();
1180 0 : struct tevent_context *ev;
1181 0 : struct tevent_req *req;
1182 251 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1183 :
1184 251 : ev = samba_tevent_context_init(frame);
1185 251 : if (ev == NULL) {
1186 0 : goto fail;
1187 : }
1188 251 : req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1189 251 : if (req == NULL) {
1190 0 : goto fail;
1191 : }
1192 251 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1193 0 : goto fail;
1194 : }
1195 251 : status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1196 251 : fail:
1197 251 : TALLOC_FREE(frame);
1198 251 : return status;
1199 : }
1200 :
1201 : struct netlogon_creds_cli_auth_state {
1202 : struct tevent_context *ev;
1203 : struct netlogon_creds_cli_context *context;
1204 : struct dcerpc_binding_handle *binding_handle;
1205 : uint8_t num_nt_hashes;
1206 : uint8_t idx_nt_hashes;
1207 : const struct samr_Password * const *nt_hashes;
1208 : const struct samr_Password *used_nt_hash;
1209 : char *srv_name_slash;
1210 : uint32_t current_flags;
1211 : struct netr_Credential client_challenge;
1212 : struct netr_Credential server_challenge;
1213 : struct netlogon_creds_CredentialState *creds;
1214 : struct netr_Credential client_credential;
1215 : struct netr_Credential server_credential;
1216 : uint32_t rid;
1217 : bool try_auth3;
1218 : bool try_auth2;
1219 : bool require_auth2;
1220 : };
1221 :
1222 : static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1223 :
1224 111 : struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1225 : struct tevent_context *ev,
1226 : struct netlogon_creds_cli_context *context,
1227 : struct dcerpc_binding_handle *b,
1228 : uint8_t num_nt_hashes,
1229 : const struct samr_Password * const *nt_hashes)
1230 : {
1231 0 : struct tevent_req *req;
1232 0 : struct netlogon_creds_cli_auth_state *state;
1233 0 : NTSTATUS status;
1234 :
1235 111 : req = tevent_req_create(mem_ctx, &state,
1236 : struct netlogon_creds_cli_auth_state);
1237 111 : if (req == NULL) {
1238 0 : return NULL;
1239 : }
1240 :
1241 111 : state->ev = ev;
1242 111 : state->context = context;
1243 111 : state->binding_handle = b;
1244 111 : if (num_nt_hashes < 1) {
1245 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1246 0 : return tevent_req_post(req, ev);
1247 : }
1248 111 : if (num_nt_hashes > 4) {
1249 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1250 0 : return tevent_req_post(req, ev);
1251 : }
1252 :
1253 111 : state->num_nt_hashes = num_nt_hashes;
1254 111 : state->idx_nt_hashes = 0;
1255 111 : state->nt_hashes = nt_hashes;
1256 :
1257 111 : if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1258 0 : tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1259 0 : return tevent_req_post(req, ev);
1260 : }
1261 :
1262 111 : state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1263 : context->server.computer);
1264 111 : if (tevent_req_nomem(state->srv_name_slash, req)) {
1265 0 : return tevent_req_post(req, ev);
1266 : }
1267 :
1268 111 : state->try_auth3 = true;
1269 111 : state->try_auth2 = true;
1270 :
1271 111 : if (context->client.required_flags != 0) {
1272 111 : state->require_auth2 = true;
1273 : }
1274 :
1275 111 : state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1276 111 : state->current_flags = context->client.proposed_flags;
1277 :
1278 111 : status = dbwrap_purge(state->context->db.ctx,
1279 111 : state->context->db.key_data);
1280 111 : if (tevent_req_nterror(req, status)) {
1281 0 : return tevent_req_post(req, ev);
1282 : }
1283 :
1284 111 : netlogon_creds_cli_auth_challenge_start(req);
1285 111 : if (!tevent_req_is_in_progress(req)) {
1286 0 : return tevent_req_post(req, ev);
1287 : }
1288 :
1289 111 : return req;
1290 : }
1291 :
1292 : static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1293 :
1294 118 : static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1295 : {
1296 0 : struct netlogon_creds_cli_auth_state *state =
1297 118 : tevent_req_data(req,
1298 : struct netlogon_creds_cli_auth_state);
1299 0 : struct tevent_req *subreq;
1300 :
1301 118 : TALLOC_FREE(state->creds);
1302 :
1303 118 : netlogon_creds_random_challenge(&state->client_challenge);
1304 :
1305 118 : subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1306 : state->binding_handle,
1307 118 : state->srv_name_slash,
1308 118 : state->context->client.computer,
1309 : &state->client_challenge,
1310 : &state->server_challenge);
1311 118 : if (tevent_req_nomem(subreq, req)) {
1312 0 : return;
1313 : }
1314 118 : tevent_req_set_callback(subreq,
1315 : netlogon_creds_cli_auth_challenge_done,
1316 : req);
1317 : }
1318 :
1319 : static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1320 :
1321 118 : static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1322 : {
1323 0 : struct tevent_req *req =
1324 118 : tevent_req_callback_data(subreq,
1325 : struct tevent_req);
1326 0 : struct netlogon_creds_cli_auth_state *state =
1327 118 : tevent_req_data(req,
1328 : struct netlogon_creds_cli_auth_state);
1329 0 : NTSTATUS status;
1330 0 : NTSTATUS result;
1331 :
1332 118 : status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1333 118 : TALLOC_FREE(subreq);
1334 118 : if (tevent_req_nterror(req, status)) {
1335 0 : return;
1336 : }
1337 118 : if (tevent_req_nterror(req, result)) {
1338 0 : return;
1339 : }
1340 :
1341 118 : if (!state->try_auth3 && !state->try_auth2) {
1342 0 : state->current_flags = 0;
1343 : }
1344 :
1345 : /* Calculate the session key and client credentials */
1346 :
1347 236 : state->creds = netlogon_creds_client_init(state,
1348 118 : state->context->client.account,
1349 118 : state->context->client.computer,
1350 118 : state->context->client.type,
1351 118 : &state->client_challenge,
1352 118 : &state->server_challenge,
1353 : state->used_nt_hash,
1354 : &state->client_credential,
1355 : state->current_flags);
1356 118 : if (tevent_req_nomem(state->creds, req)) {
1357 0 : return;
1358 : }
1359 :
1360 118 : if (state->try_auth3) {
1361 118 : subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1362 : state->binding_handle,
1363 118 : state->srv_name_slash,
1364 118 : state->context->client.account,
1365 118 : state->context->client.type,
1366 118 : state->context->client.computer,
1367 : &state->client_credential,
1368 : &state->server_credential,
1369 118 : &state->creds->negotiate_flags,
1370 : &state->rid);
1371 118 : if (tevent_req_nomem(subreq, req)) {
1372 0 : return;
1373 : }
1374 0 : } else if (state->try_auth2) {
1375 0 : state->rid = 0;
1376 :
1377 0 : subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1378 : state->binding_handle,
1379 0 : state->srv_name_slash,
1380 0 : state->context->client.account,
1381 0 : state->context->client.type,
1382 0 : state->context->client.computer,
1383 : &state->client_credential,
1384 : &state->server_credential,
1385 0 : &state->creds->negotiate_flags);
1386 0 : if (tevent_req_nomem(subreq, req)) {
1387 0 : return;
1388 : }
1389 : } else {
1390 0 : state->rid = 0;
1391 :
1392 0 : subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1393 : state->binding_handle,
1394 0 : state->srv_name_slash,
1395 0 : state->context->client.account,
1396 0 : state->context->client.type,
1397 0 : state->context->client.computer,
1398 : &state->client_credential,
1399 : &state->server_credential);
1400 0 : if (tevent_req_nomem(subreq, req)) {
1401 0 : return;
1402 : }
1403 : }
1404 118 : tevent_req_set_callback(subreq,
1405 : netlogon_creds_cli_auth_srvauth_done,
1406 : req);
1407 : }
1408 :
1409 118 : static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1410 : {
1411 0 : struct tevent_req *req =
1412 118 : tevent_req_callback_data(subreq,
1413 : struct tevent_req);
1414 0 : struct netlogon_creds_cli_auth_state *state =
1415 118 : tevent_req_data(req,
1416 : struct netlogon_creds_cli_auth_state);
1417 0 : NTSTATUS status;
1418 0 : NTSTATUS result;
1419 0 : bool ok;
1420 0 : enum ndr_err_code ndr_err;
1421 0 : DATA_BLOB blob;
1422 0 : TDB_DATA data;
1423 0 : bool downgraded;
1424 :
1425 118 : if (state->try_auth3) {
1426 118 : status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1427 : &result);
1428 118 : TALLOC_FREE(subreq);
1429 118 : if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1430 0 : state->try_auth3 = false;
1431 0 : netlogon_creds_cli_auth_challenge_start(req);
1432 0 : return;
1433 : }
1434 118 : if (tevent_req_nterror(req, status)) {
1435 0 : return;
1436 : }
1437 0 : } else if (state->try_auth2) {
1438 0 : status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1439 : &result);
1440 0 : TALLOC_FREE(subreq);
1441 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1442 0 : state->try_auth2 = false;
1443 0 : if (state->require_auth2) {
1444 0 : status = NT_STATUS_DOWNGRADE_DETECTED;
1445 0 : tevent_req_nterror(req, status);
1446 0 : return;
1447 : }
1448 0 : netlogon_creds_cli_auth_challenge_start(req);
1449 0 : return;
1450 : }
1451 0 : if (tevent_req_nterror(req, status)) {
1452 0 : return;
1453 : }
1454 : } else {
1455 0 : status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1456 : &result);
1457 0 : TALLOC_FREE(subreq);
1458 0 : if (tevent_req_nterror(req, status)) {
1459 0 : return;
1460 : }
1461 : }
1462 :
1463 118 : if (!NT_STATUS_IS_OK(result) &&
1464 14 : !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1465 : {
1466 0 : tevent_req_nterror(req, result);
1467 0 : return;
1468 : }
1469 :
1470 118 : downgraded = netlogon_creds_cli_downgraded(
1471 118 : state->creds->negotiate_flags,
1472 118 : state->context->client.proposed_flags,
1473 118 : state->context->client.required_flags);
1474 118 : if (downgraded) {
1475 0 : if (NT_STATUS_IS_OK(result)) {
1476 0 : tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1477 0 : return;
1478 : }
1479 0 : tevent_req_nterror(req, result);
1480 0 : return;
1481 : }
1482 :
1483 118 : if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1484 14 : uint32_t tmp_flags = state->context->client.proposed_flags;
1485 14 : if ((state->current_flags == tmp_flags) &&
1486 7 : (state->creds->negotiate_flags != tmp_flags))
1487 : {
1488 : /*
1489 : * lets retry with the negotiated flags
1490 : */
1491 7 : state->current_flags = state->creds->negotiate_flags;
1492 7 : netlogon_creds_cli_auth_challenge_start(req);
1493 14 : return;
1494 : }
1495 :
1496 7 : state->idx_nt_hashes += 1;
1497 7 : if (state->idx_nt_hashes >= state->num_nt_hashes) {
1498 : /*
1499 : * we already retried, giving up...
1500 : */
1501 7 : tevent_req_nterror(req, result);
1502 7 : return;
1503 : }
1504 :
1505 : /*
1506 : * lets retry with the old nt hash.
1507 : */
1508 0 : state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1509 0 : state->current_flags = state->context->client.proposed_flags;
1510 0 : netlogon_creds_cli_auth_challenge_start(req);
1511 0 : return;
1512 : }
1513 :
1514 104 : ok = netlogon_creds_client_check(state->creds,
1515 104 : &state->server_credential);
1516 104 : if (!ok) {
1517 0 : tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1518 0 : return;
1519 : }
1520 :
1521 104 : ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1522 : (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1523 104 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1524 0 : status = ndr_map_error2ntstatus(ndr_err);
1525 0 : tevent_req_nterror(req, status);
1526 0 : return;
1527 : }
1528 :
1529 104 : data.dptr = blob.data;
1530 104 : data.dsize = blob.length;
1531 :
1532 104 : status = dbwrap_store(state->context->db.ctx,
1533 104 : state->context->db.key_data,
1534 : data, TDB_REPLACE);
1535 104 : if (tevent_req_nterror(req, status)) {
1536 0 : return;
1537 : }
1538 :
1539 104 : tevent_req_done(req);
1540 : }
1541 :
1542 111 : NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1543 : uint8_t *idx_nt_hashes)
1544 : {
1545 0 : struct netlogon_creds_cli_auth_state *state =
1546 111 : tevent_req_data(req,
1547 : struct netlogon_creds_cli_auth_state);
1548 0 : NTSTATUS status;
1549 :
1550 111 : *idx_nt_hashes = 0;
1551 :
1552 111 : if (tevent_req_is_nterror(req, &status)) {
1553 7 : tevent_req_received(req);
1554 7 : return status;
1555 : }
1556 :
1557 104 : *idx_nt_hashes = state->idx_nt_hashes;
1558 104 : tevent_req_received(req);
1559 104 : return NT_STATUS_OK;
1560 : }
1561 :
1562 111 : NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1563 : struct dcerpc_binding_handle *b,
1564 : uint8_t num_nt_hashes,
1565 : const struct samr_Password * const *nt_hashes,
1566 : uint8_t *idx_nt_hashes)
1567 : {
1568 111 : TALLOC_CTX *frame = talloc_stackframe();
1569 0 : struct tevent_context *ev;
1570 0 : struct tevent_req *req;
1571 111 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1572 :
1573 111 : *idx_nt_hashes = 0;
1574 :
1575 111 : ev = samba_tevent_context_init(frame);
1576 111 : if (ev == NULL) {
1577 0 : goto fail;
1578 : }
1579 111 : req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1580 : num_nt_hashes, nt_hashes);
1581 111 : if (req == NULL) {
1582 0 : goto fail;
1583 : }
1584 111 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1585 0 : goto fail;
1586 : }
1587 111 : status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1588 111 : fail:
1589 111 : TALLOC_FREE(frame);
1590 111 : return status;
1591 : }
1592 :
1593 : struct netlogon_creds_cli_check_state {
1594 : struct tevent_context *ev;
1595 : struct netlogon_creds_cli_context *context;
1596 : struct dcerpc_binding_handle *binding_handle;
1597 :
1598 : char *srv_name_slash;
1599 :
1600 : union netr_Capabilities caps;
1601 :
1602 : struct netlogon_creds_CredentialState *creds;
1603 : struct netr_Authenticator req_auth;
1604 : struct netr_Authenticator rep_auth;
1605 : };
1606 :
1607 : static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1608 : NTSTATUS status);
1609 : static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1610 :
1611 103 : struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1612 : struct tevent_context *ev,
1613 : struct netlogon_creds_cli_context *context,
1614 : struct dcerpc_binding_handle *b)
1615 : {
1616 0 : struct tevent_req *req;
1617 0 : struct netlogon_creds_cli_check_state *state;
1618 0 : struct tevent_req *subreq;
1619 0 : enum dcerpc_AuthType auth_type;
1620 0 : enum dcerpc_AuthLevel auth_level;
1621 0 : NTSTATUS status;
1622 :
1623 103 : req = tevent_req_create(mem_ctx, &state,
1624 : struct netlogon_creds_cli_check_state);
1625 103 : if (req == NULL) {
1626 0 : return NULL;
1627 : }
1628 :
1629 103 : state->ev = ev;
1630 103 : state->context = context;
1631 103 : state->binding_handle = b;
1632 :
1633 103 : if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1634 0 : tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1635 0 : return tevent_req_post(req, ev);
1636 : }
1637 :
1638 103 : status = netlogon_creds_cli_get_internal(context, state,
1639 103 : &state->creds);
1640 103 : if (tevent_req_nterror(req, status)) {
1641 0 : return tevent_req_post(req, ev);
1642 : }
1643 :
1644 103 : state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1645 : context->server.computer);
1646 103 : if (tevent_req_nomem(state->srv_name_slash, req)) {
1647 0 : return tevent_req_post(req, ev);
1648 : }
1649 :
1650 103 : dcerpc_binding_handle_auth_info(state->binding_handle,
1651 : &auth_type, &auth_level);
1652 :
1653 103 : if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1654 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1655 0 : return tevent_req_post(req, ev);
1656 : }
1657 :
1658 103 : switch (auth_level) {
1659 103 : case DCERPC_AUTH_LEVEL_INTEGRITY:
1660 : case DCERPC_AUTH_LEVEL_PRIVACY:
1661 103 : break;
1662 0 : default:
1663 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1664 0 : return tevent_req_post(req, ev);
1665 : }
1666 :
1667 : /*
1668 : * we defer all callbacks in order to cleanup
1669 : * the database record.
1670 : */
1671 103 : tevent_req_defer_callback(req, state->ev);
1672 :
1673 103 : status = netlogon_creds_client_authenticator(state->creds,
1674 103 : &state->req_auth);
1675 103 : if (tevent_req_nterror(req, status)) {
1676 0 : return tevent_req_post(req, ev);
1677 : }
1678 103 : ZERO_STRUCT(state->rep_auth);
1679 :
1680 103 : subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1681 103 : state->binding_handle,
1682 103 : state->srv_name_slash,
1683 103 : state->context->client.computer,
1684 103 : &state->req_auth,
1685 103 : &state->rep_auth,
1686 : 1,
1687 103 : &state->caps);
1688 103 : if (tevent_req_nomem(subreq, req)) {
1689 0 : return tevent_req_post(req, ev);
1690 : }
1691 :
1692 103 : tevent_req_set_callback(subreq,
1693 : netlogon_creds_cli_check_caps,
1694 : req);
1695 :
1696 103 : return req;
1697 : }
1698 :
1699 0 : static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1700 : NTSTATUS status)
1701 : {
1702 0 : struct netlogon_creds_cli_check_state *state =
1703 0 : tevent_req_data(req,
1704 : struct netlogon_creds_cli_check_state);
1705 :
1706 0 : if (state->creds == NULL) {
1707 0 : return;
1708 : }
1709 :
1710 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1711 0 : !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1712 0 : !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1713 0 : !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1714 0 : !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1715 0 : TALLOC_FREE(state->creds);
1716 0 : return;
1717 : }
1718 :
1719 0 : netlogon_creds_cli_delete_lck(state->context);
1720 0 : TALLOC_FREE(state->creds);
1721 : }
1722 :
1723 103 : static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1724 : {
1725 0 : struct tevent_req *req =
1726 103 : tevent_req_callback_data(subreq,
1727 : struct tevent_req);
1728 0 : struct netlogon_creds_cli_check_state *state =
1729 103 : tevent_req_data(req,
1730 : struct netlogon_creds_cli_check_state);
1731 0 : NTSTATUS status;
1732 0 : NTSTATUS result;
1733 0 : bool ok;
1734 :
1735 103 : status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1736 : &result);
1737 103 : TALLOC_FREE(subreq);
1738 103 : if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1739 : /*
1740 : * Note that the negotiated flags are already checked
1741 : * for our required flags after the ServerAuthenticate3/2 call.
1742 : */
1743 0 : uint32_t negotiated = state->creds->negotiate_flags;
1744 :
1745 0 : if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1746 : /*
1747 : * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1748 : * already, we expect this to work!
1749 : */
1750 0 : status = NT_STATUS_DOWNGRADE_DETECTED;
1751 0 : tevent_req_nterror(req, status);
1752 0 : netlogon_creds_cli_check_cleanup(req, status);
1753 0 : return;
1754 : }
1755 :
1756 0 : if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1757 : /*
1758 : * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1759 : * we expect this to work at least as far as the
1760 : * NOT_SUPPORTED error handled below!
1761 : *
1762 : * NT 4.0 and Old Samba servers are not
1763 : * allowed without "require strong key = no"
1764 : */
1765 0 : status = NT_STATUS_DOWNGRADE_DETECTED;
1766 0 : tevent_req_nterror(req, status);
1767 0 : netlogon_creds_cli_check_cleanup(req, status);
1768 0 : return;
1769 : }
1770 :
1771 : /*
1772 : * If we not require NETLOGON_NEG_SUPPORTS_AES or
1773 : * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1774 : * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1775 : *
1776 : * This is needed against NT 4.0 and old Samba servers.
1777 : *
1778 : * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1779 : * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1780 : * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1781 : * with the next request as the sequence number processing
1782 : * gets out of sync.
1783 : */
1784 0 : netlogon_creds_cli_check_cleanup(req, status);
1785 0 : tevent_req_done(req);
1786 0 : return;
1787 : }
1788 103 : if (tevent_req_nterror(req, status)) {
1789 0 : netlogon_creds_cli_check_cleanup(req, status);
1790 0 : return;
1791 : }
1792 :
1793 103 : if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1794 : /*
1795 : * Note that the negotiated flags are already checked
1796 : * for our required flags after the ServerAuthenticate3/2 call.
1797 : */
1798 0 : uint32_t negotiated = state->creds->negotiate_flags;
1799 :
1800 0 : if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1801 : /*
1802 : * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1803 : * already, we expect this to work!
1804 : */
1805 0 : status = NT_STATUS_DOWNGRADE_DETECTED;
1806 0 : tevent_req_nterror(req, status);
1807 0 : netlogon_creds_cli_check_cleanup(req, status);
1808 0 : return;
1809 : }
1810 :
1811 : /*
1812 : * This is ok, the server does not support
1813 : * NETLOGON_NEG_SUPPORTS_AES.
1814 : *
1815 : * netr_LogonGetCapabilities() was
1816 : * netr_LogonDummyRoutine1() before
1817 : * NETLOGON_NEG_SUPPORTS_AES was invented.
1818 : */
1819 0 : netlogon_creds_cli_check_cleanup(req, result);
1820 0 : tevent_req_done(req);
1821 0 : return;
1822 : }
1823 :
1824 103 : ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1825 103 : if (!ok) {
1826 0 : status = NT_STATUS_ACCESS_DENIED;
1827 0 : tevent_req_nterror(req, status);
1828 0 : netlogon_creds_cli_check_cleanup(req, status);
1829 0 : return;
1830 : }
1831 :
1832 103 : if (tevent_req_nterror(req, result)) {
1833 0 : netlogon_creds_cli_check_cleanup(req, result);
1834 0 : return;
1835 : }
1836 :
1837 103 : if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1838 0 : status = NT_STATUS_DOWNGRADE_DETECTED;
1839 0 : tevent_req_nterror(req, status);
1840 0 : netlogon_creds_cli_check_cleanup(req, status);
1841 0 : return;
1842 : }
1843 :
1844 : /*
1845 : * This is the key check that makes this check secure. If we
1846 : * get OK here (rather than NOT_SUPPORTED), then the server
1847 : * did support AES. If the server only proposed STRONG_KEYS
1848 : * and not AES, then it should have failed with
1849 : * NOT_IMPLEMENTED. We always send AES as a client, so the
1850 : * server should always have returned it.
1851 : */
1852 103 : if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1853 0 : status = NT_STATUS_DOWNGRADE_DETECTED;
1854 0 : tevent_req_nterror(req, status);
1855 0 : netlogon_creds_cli_check_cleanup(req, status);
1856 0 : return;
1857 : }
1858 :
1859 103 : status = netlogon_creds_cli_store_internal(state->context,
1860 : state->creds);
1861 103 : if (tevent_req_nterror(req, status)) {
1862 0 : return;
1863 : }
1864 :
1865 103 : tevent_req_done(req);
1866 : }
1867 :
1868 103 : NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1869 : union netr_Capabilities *capabilities)
1870 : {
1871 103 : struct netlogon_creds_cli_check_state *state = tevent_req_data(
1872 : req, struct netlogon_creds_cli_check_state);
1873 0 : NTSTATUS status;
1874 :
1875 103 : if (tevent_req_is_nterror(req, &status)) {
1876 0 : netlogon_creds_cli_check_cleanup(req, status);
1877 0 : tevent_req_received(req);
1878 0 : return status;
1879 : }
1880 :
1881 103 : if (capabilities != NULL) {
1882 0 : *capabilities = state->caps;
1883 : }
1884 :
1885 103 : tevent_req_received(req);
1886 103 : return NT_STATUS_OK;
1887 : }
1888 :
1889 103 : NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1890 : struct dcerpc_binding_handle *b,
1891 : union netr_Capabilities *capabilities)
1892 : {
1893 103 : TALLOC_CTX *frame = talloc_stackframe();
1894 0 : struct tevent_context *ev;
1895 0 : struct tevent_req *req;
1896 103 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1897 :
1898 103 : ev = samba_tevent_context_init(frame);
1899 103 : if (ev == NULL) {
1900 0 : goto fail;
1901 : }
1902 103 : req = netlogon_creds_cli_check_send(frame, ev, context, b);
1903 103 : if (req == NULL) {
1904 0 : goto fail;
1905 : }
1906 103 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1907 0 : goto fail;
1908 : }
1909 103 : status = netlogon_creds_cli_check_recv(req, capabilities);
1910 103 : fail:
1911 103 : TALLOC_FREE(frame);
1912 103 : return status;
1913 : }
1914 :
1915 : struct netlogon_creds_cli_ServerPasswordSet_state {
1916 : struct tevent_context *ev;
1917 : struct netlogon_creds_cli_context *context;
1918 : struct dcerpc_binding_handle *binding_handle;
1919 : uint32_t old_timeout;
1920 :
1921 : char *srv_name_slash;
1922 : enum dcerpc_AuthType auth_type;
1923 : enum dcerpc_AuthLevel auth_level;
1924 :
1925 : struct samr_CryptPassword samr_crypt_password;
1926 : struct netr_CryptPassword netr_crypt_password;
1927 : struct samr_Password samr_password;
1928 :
1929 : struct netlogon_creds_CredentialState *creds;
1930 : struct netlogon_creds_CredentialState tmp_creds;
1931 : struct netr_Authenticator req_auth;
1932 : struct netr_Authenticator rep_auth;
1933 : };
1934 :
1935 : static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1936 : NTSTATUS status);
1937 : static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1938 :
1939 8 : struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1940 : struct tevent_context *ev,
1941 : struct netlogon_creds_cli_context *context,
1942 : struct dcerpc_binding_handle *b,
1943 : const DATA_BLOB *new_password,
1944 : const uint32_t *new_version)
1945 : {
1946 0 : struct tevent_req *req;
1947 0 : struct netlogon_creds_cli_ServerPasswordSet_state *state;
1948 0 : struct tevent_req *subreq;
1949 0 : bool ok;
1950 :
1951 8 : req = tevent_req_create(mem_ctx, &state,
1952 : struct netlogon_creds_cli_ServerPasswordSet_state);
1953 8 : if (req == NULL) {
1954 0 : return NULL;
1955 : }
1956 :
1957 8 : state->ev = ev;
1958 8 : state->context = context;
1959 8 : state->binding_handle = b;
1960 :
1961 8 : if (new_password->length < 14) {
1962 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1963 0 : return tevent_req_post(req, ev);
1964 : }
1965 :
1966 : /*
1967 : * netr_ServerPasswordSet
1968 : */
1969 8 : mdfour(state->samr_password.hash, new_password->data, new_password->length);
1970 :
1971 : /*
1972 : * netr_ServerPasswordSet2
1973 : */
1974 8 : ok = set_pw_in_buffer(state->samr_crypt_password.data,
1975 : new_password);
1976 8 : if (!ok) {
1977 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1978 0 : return tevent_req_post(req, ev);
1979 : }
1980 :
1981 8 : if (new_version != NULL) {
1982 0 : struct NL_PASSWORD_VERSION version;
1983 0 : uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1984 0 : uint32_t ofs = 512 - len;
1985 0 : uint8_t *p;
1986 :
1987 0 : if (len > 500) {
1988 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1989 0 : return tevent_req_post(req, ev);
1990 : }
1991 0 : ofs -= 12;
1992 :
1993 0 : version.ReservedField = 0;
1994 0 : version.PasswordVersionNumber = *new_version;
1995 0 : version.PasswordVersionPresent =
1996 : NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1997 :
1998 0 : p = state->samr_crypt_password.data + ofs;
1999 0 : SIVAL(p, 0, version.ReservedField);
2000 0 : SIVAL(p, 4, version.PasswordVersionNumber);
2001 0 : SIVAL(p, 8, version.PasswordVersionPresent);
2002 : }
2003 :
2004 8 : state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2005 : context->server.computer);
2006 8 : if (tevent_req_nomem(state->srv_name_slash, req)) {
2007 0 : return tevent_req_post(req, ev);
2008 : }
2009 :
2010 8 : dcerpc_binding_handle_auth_info(state->binding_handle,
2011 8 : &state->auth_type,
2012 8 : &state->auth_level);
2013 :
2014 8 : subreq = netlogon_creds_cli_lock_send(state, state->ev,
2015 8 : state->context);
2016 8 : if (tevent_req_nomem(subreq, req)) {
2017 0 : return tevent_req_post(req, ev);
2018 : }
2019 :
2020 8 : tevent_req_set_callback(subreq,
2021 : netlogon_creds_cli_ServerPasswordSet_locked,
2022 : req);
2023 :
2024 8 : return req;
2025 : }
2026 :
2027 0 : static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
2028 : NTSTATUS status)
2029 : {
2030 0 : struct netlogon_creds_cli_ServerPasswordSet_state *state =
2031 0 : tevent_req_data(req,
2032 : struct netlogon_creds_cli_ServerPasswordSet_state);
2033 :
2034 0 : if (state->creds == NULL) {
2035 0 : return;
2036 : }
2037 :
2038 0 : dcerpc_binding_handle_set_timeout(state->binding_handle,
2039 : state->old_timeout);
2040 :
2041 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2042 0 : !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2043 0 : !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2044 0 : !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2045 0 : !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2046 0 : TALLOC_FREE(state->creds);
2047 0 : return;
2048 : }
2049 :
2050 0 : netlogon_creds_cli_delete(state->context, state->creds);
2051 0 : TALLOC_FREE(state->creds);
2052 : }
2053 :
2054 : static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
2055 :
2056 8 : static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
2057 : {
2058 0 : struct tevent_req *req =
2059 8 : tevent_req_callback_data(subreq,
2060 : struct tevent_req);
2061 0 : struct netlogon_creds_cli_ServerPasswordSet_state *state =
2062 8 : tevent_req_data(req,
2063 : struct netlogon_creds_cli_ServerPasswordSet_state);
2064 0 : NTSTATUS status;
2065 :
2066 8 : status = netlogon_creds_cli_lock_recv(subreq, state,
2067 : &state->creds);
2068 8 : TALLOC_FREE(subreq);
2069 8 : if (tevent_req_nterror(req, status)) {
2070 0 : return;
2071 : }
2072 :
2073 8 : if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2074 8 : switch (state->auth_level) {
2075 8 : case DCERPC_AUTH_LEVEL_INTEGRITY:
2076 : case DCERPC_AUTH_LEVEL_PRIVACY:
2077 8 : break;
2078 0 : default:
2079 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2080 0 : return;
2081 : }
2082 : } else {
2083 0 : uint32_t tmp = state->creds->negotiate_flags;
2084 :
2085 0 : if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2086 : /*
2087 : * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2088 : * it should be used, which means
2089 : * we had a chance to verify no downgrade
2090 : * happened.
2091 : *
2092 : * This relies on netlogon_creds_cli_check*
2093 : * being called before, as first request after
2094 : * the DCERPC bind.
2095 : */
2096 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2097 0 : return;
2098 : }
2099 : }
2100 :
2101 8 : state->old_timeout = dcerpc_binding_handle_set_timeout(
2102 : state->binding_handle, 600000);
2103 :
2104 : /*
2105 : * we defer all callbacks in order to cleanup
2106 : * the database record.
2107 : */
2108 8 : tevent_req_defer_callback(req, state->ev);
2109 :
2110 8 : state->tmp_creds = *state->creds;
2111 8 : status = netlogon_creds_client_authenticator(&state->tmp_creds,
2112 : &state->req_auth);
2113 8 : if (tevent_req_nterror(req, status)) {
2114 0 : return;
2115 : }
2116 8 : ZERO_STRUCT(state->rep_auth);
2117 :
2118 8 : if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2119 :
2120 8 : if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
2121 8 : status = netlogon_creds_aes_encrypt(&state->tmp_creds,
2122 8 : state->samr_crypt_password.data,
2123 : 516);
2124 8 : if (tevent_req_nterror(req, status)) {
2125 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2126 0 : return;
2127 : }
2128 : } else {
2129 0 : status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
2130 0 : state->samr_crypt_password.data,
2131 : 516);
2132 0 : if (tevent_req_nterror(req, status)) {
2133 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2134 0 : return;
2135 : }
2136 : }
2137 :
2138 8 : memcpy(state->netr_crypt_password.data,
2139 8 : state->samr_crypt_password.data, 512);
2140 8 : state->netr_crypt_password.length =
2141 8 : IVAL(state->samr_crypt_password.data, 512);
2142 :
2143 8 : subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2144 : state->binding_handle,
2145 8 : state->srv_name_slash,
2146 : state->tmp_creds.account_name,
2147 : state->tmp_creds.secure_channel_type,
2148 : state->tmp_creds.computer_name,
2149 : &state->req_auth,
2150 : &state->rep_auth,
2151 : &state->netr_crypt_password);
2152 8 : if (tevent_req_nomem(subreq, req)) {
2153 0 : status = NT_STATUS_NO_MEMORY;
2154 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2155 0 : return;
2156 : }
2157 : } else {
2158 0 : status = netlogon_creds_des_encrypt(&state->tmp_creds,
2159 : &state->samr_password);
2160 0 : if (tevent_req_nterror(req, status)) {
2161 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2162 0 : return;
2163 : }
2164 :
2165 0 : subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2166 : state->binding_handle,
2167 0 : state->srv_name_slash,
2168 : state->tmp_creds.account_name,
2169 : state->tmp_creds.secure_channel_type,
2170 : state->tmp_creds.computer_name,
2171 : &state->req_auth,
2172 : &state->rep_auth,
2173 : &state->samr_password);
2174 0 : if (tevent_req_nomem(subreq, req)) {
2175 0 : status = NT_STATUS_NO_MEMORY;
2176 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2177 0 : return;
2178 : }
2179 : }
2180 :
2181 8 : tevent_req_set_callback(subreq,
2182 : netlogon_creds_cli_ServerPasswordSet_done,
2183 : req);
2184 : }
2185 :
2186 8 : static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2187 : {
2188 0 : struct tevent_req *req =
2189 8 : tevent_req_callback_data(subreq,
2190 : struct tevent_req);
2191 0 : struct netlogon_creds_cli_ServerPasswordSet_state *state =
2192 8 : tevent_req_data(req,
2193 : struct netlogon_creds_cli_ServerPasswordSet_state);
2194 0 : NTSTATUS status;
2195 0 : NTSTATUS result;
2196 0 : bool ok;
2197 :
2198 8 : if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2199 8 : status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2200 : &result);
2201 8 : TALLOC_FREE(subreq);
2202 8 : if (tevent_req_nterror(req, status)) {
2203 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2204 0 : return;
2205 : }
2206 : } else {
2207 0 : status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2208 : &result);
2209 0 : TALLOC_FREE(subreq);
2210 0 : if (tevent_req_nterror(req, status)) {
2211 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2212 0 : return;
2213 : }
2214 : }
2215 :
2216 8 : ok = netlogon_creds_client_check(&state->tmp_creds,
2217 8 : &state->rep_auth.cred);
2218 8 : if (!ok) {
2219 0 : status = NT_STATUS_ACCESS_DENIED;
2220 0 : tevent_req_nterror(req, status);
2221 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2222 0 : return;
2223 : }
2224 :
2225 8 : if (tevent_req_nterror(req, result)) {
2226 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2227 0 : return;
2228 : }
2229 :
2230 8 : dcerpc_binding_handle_set_timeout(state->binding_handle,
2231 : state->old_timeout);
2232 :
2233 8 : *state->creds = state->tmp_creds;
2234 8 : status = netlogon_creds_cli_store(state->context,
2235 : state->creds);
2236 8 : TALLOC_FREE(state->creds);
2237 8 : if (tevent_req_nterror(req, status)) {
2238 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2239 0 : return;
2240 : }
2241 :
2242 8 : tevent_req_done(req);
2243 : }
2244 :
2245 8 : NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2246 : {
2247 0 : NTSTATUS status;
2248 :
2249 8 : if (tevent_req_is_nterror(req, &status)) {
2250 0 : netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2251 0 : tevent_req_received(req);
2252 0 : return status;
2253 : }
2254 :
2255 8 : tevent_req_received(req);
2256 8 : return NT_STATUS_OK;
2257 : }
2258 :
2259 8 : NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2260 : struct netlogon_creds_cli_context *context,
2261 : struct dcerpc_binding_handle *b,
2262 : const DATA_BLOB *new_password,
2263 : const uint32_t *new_version)
2264 : {
2265 8 : TALLOC_CTX *frame = talloc_stackframe();
2266 0 : struct tevent_context *ev;
2267 0 : struct tevent_req *req;
2268 8 : NTSTATUS status = NT_STATUS_NO_MEMORY;
2269 :
2270 8 : ev = samba_tevent_context_init(frame);
2271 8 : if (ev == NULL) {
2272 0 : goto fail;
2273 : }
2274 8 : req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2275 : new_password,
2276 : new_version);
2277 8 : if (req == NULL) {
2278 0 : goto fail;
2279 : }
2280 8 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2281 0 : goto fail;
2282 : }
2283 8 : status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2284 8 : fail:
2285 8 : TALLOC_FREE(frame);
2286 8 : return status;
2287 : }
2288 :
2289 : struct netlogon_creds_cli_LogonSamLogon_state {
2290 : struct tevent_context *ev;
2291 : struct netlogon_creds_cli_context *context;
2292 : struct dcerpc_binding_handle *binding_handle;
2293 :
2294 : char *srv_name_slash;
2295 :
2296 : enum netr_LogonInfoClass logon_level;
2297 : const union netr_LogonLevel *const_logon;
2298 : union netr_LogonLevel *logon;
2299 : uint32_t flags;
2300 :
2301 : uint16_t validation_level;
2302 : union netr_Validation *validation;
2303 : uint8_t authoritative;
2304 :
2305 : /*
2306 : * do we need encryption at the application layer?
2307 : */
2308 : bool user_encrypt;
2309 : bool try_logon_ex;
2310 : bool try_validation6;
2311 :
2312 : /*
2313 : * the read only credentials before we started the operation
2314 : * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2315 : */
2316 : struct netlogon_creds_CredentialState *ro_creds;
2317 :
2318 : /*
2319 : * The (locked) credentials used for the credential chain
2320 : * used for netr_LogonSamLogonWithFlags() or
2321 : * netr_LogonSamLogonWith().
2322 : */
2323 : struct netlogon_creds_CredentialState *lk_creds;
2324 :
2325 : /*
2326 : * While we have locked the global credentials (lk_creds above)
2327 : * we operate an a temporary copy, because a server
2328 : * may not support netr_LogonSamLogonWithFlags() and
2329 : * didn't process our netr_Authenticator, so we need to
2330 : * restart from lk_creds.
2331 : */
2332 : struct netlogon_creds_CredentialState tmp_creds;
2333 : struct netr_Authenticator req_auth;
2334 : struct netr_Authenticator rep_auth;
2335 : };
2336 :
2337 : static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2338 : static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2339 : NTSTATUS status);
2340 :
2341 42 : struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2342 : struct tevent_context *ev,
2343 : struct netlogon_creds_cli_context *context,
2344 : struct dcerpc_binding_handle *b,
2345 : enum netr_LogonInfoClass logon_level,
2346 : const union netr_LogonLevel *logon,
2347 : uint32_t flags)
2348 : {
2349 0 : struct tevent_req *req;
2350 0 : struct netlogon_creds_cli_LogonSamLogon_state *state;
2351 :
2352 42 : req = tevent_req_create(mem_ctx, &state,
2353 : struct netlogon_creds_cli_LogonSamLogon_state);
2354 42 : if (req == NULL) {
2355 0 : return NULL;
2356 : }
2357 :
2358 42 : state->ev = ev;
2359 42 : state->context = context;
2360 42 : state->binding_handle = b;
2361 :
2362 42 : state->logon_level = logon_level;
2363 42 : state->const_logon = logon;
2364 42 : state->flags = flags;
2365 :
2366 42 : state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2367 : context->server.computer);
2368 42 : if (tevent_req_nomem(state->srv_name_slash, req)) {
2369 0 : return tevent_req_post(req, ev);
2370 : }
2371 :
2372 42 : switch (logon_level) {
2373 6 : case NetlogonInteractiveInformation:
2374 : case NetlogonInteractiveTransitiveInformation:
2375 : case NetlogonServiceInformation:
2376 : case NetlogonServiceTransitiveInformation:
2377 : case NetlogonGenericInformation:
2378 6 : state->user_encrypt = true;
2379 6 : break;
2380 :
2381 36 : case NetlogonNetworkInformation:
2382 : case NetlogonNetworkTransitiveInformation:
2383 36 : break;
2384 : }
2385 :
2386 42 : state->validation = talloc_zero(state, union netr_Validation);
2387 42 : if (tevent_req_nomem(state->validation, req)) {
2388 0 : return tevent_req_post(req, ev);
2389 : }
2390 :
2391 42 : netlogon_creds_cli_LogonSamLogon_start(req);
2392 42 : if (!tevent_req_is_in_progress(req)) {
2393 0 : return tevent_req_post(req, ev);
2394 : }
2395 :
2396 : /*
2397 : * we defer all callbacks in order to cleanup
2398 : * the database record.
2399 : */
2400 42 : tevent_req_defer_callback(req, state->ev);
2401 42 : return req;
2402 : }
2403 :
2404 24 : static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2405 : NTSTATUS status)
2406 : {
2407 0 : struct netlogon_creds_cli_LogonSamLogon_state *state =
2408 24 : tevent_req_data(req,
2409 : struct netlogon_creds_cli_LogonSamLogon_state);
2410 :
2411 24 : if (state->lk_creds == NULL) {
2412 24 : return;
2413 : }
2414 :
2415 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2416 : /*
2417 : * This is a hack to recover from a bug in old
2418 : * Samba servers, when LogonSamLogonEx() fails:
2419 : *
2420 : * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2421 : *
2422 : * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2423 : *
2424 : * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2425 : * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2426 : * If the sign/seal check fails.
2427 : *
2428 : * In that case we need to cleanup the netlogon session.
2429 : *
2430 : * It's the job of the caller to disconnect the current
2431 : * connection, if netlogon_creds_cli_LogonSamLogon()
2432 : * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2433 : */
2434 0 : if (!state->context->server.try_logon_with) {
2435 0 : status = NT_STATUS_NETWORK_ACCESS_DENIED;
2436 : }
2437 : }
2438 :
2439 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2440 0 : !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2441 0 : !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2442 0 : !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2443 0 : !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2444 0 : TALLOC_FREE(state->lk_creds);
2445 0 : return;
2446 : }
2447 :
2448 0 : netlogon_creds_cli_delete(state->context, state->lk_creds);
2449 0 : TALLOC_FREE(state->lk_creds);
2450 : }
2451 :
2452 : static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2453 :
2454 60 : static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2455 : {
2456 0 : struct netlogon_creds_cli_LogonSamLogon_state *state =
2457 60 : tevent_req_data(req,
2458 : struct netlogon_creds_cli_LogonSamLogon_state);
2459 0 : struct tevent_req *subreq;
2460 0 : NTSTATUS status;
2461 0 : enum dcerpc_AuthType auth_type;
2462 0 : enum dcerpc_AuthLevel auth_level;
2463 :
2464 60 : TALLOC_FREE(state->ro_creds);
2465 60 : TALLOC_FREE(state->logon);
2466 60 : ZERO_STRUCTP(state->validation);
2467 :
2468 60 : dcerpc_binding_handle_auth_info(state->binding_handle,
2469 : &auth_type, &auth_level);
2470 :
2471 60 : state->try_logon_ex = state->context->server.try_logon_ex;
2472 60 : state->try_validation6 = state->context->server.try_validation6;
2473 :
2474 60 : if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2475 36 : state->try_logon_ex = false;
2476 : }
2477 :
2478 60 : if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2479 36 : state->try_validation6 = false;
2480 : }
2481 :
2482 60 : if (state->try_logon_ex) {
2483 24 : if (state->try_validation6) {
2484 24 : state->validation_level = 6;
2485 : } else {
2486 0 : state->validation_level = 3;
2487 0 : state->user_encrypt = true;
2488 : }
2489 :
2490 24 : state->logon = netlogon_creds_shallow_copy_logon(state,
2491 : state->logon_level,
2492 : state->const_logon);
2493 24 : if (tevent_req_nomem(state->logon, req)) {
2494 0 : status = NT_STATUS_NO_MEMORY;
2495 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2496 0 : return;
2497 : }
2498 :
2499 24 : if (state->user_encrypt) {
2500 0 : status = netlogon_creds_cli_get(state->context,
2501 : state,
2502 : &state->ro_creds);
2503 0 : if (!NT_STATUS_IS_OK(status)) {
2504 0 : status = NT_STATUS_ACCESS_DENIED;
2505 0 : tevent_req_nterror(req, status);
2506 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2507 0 : return;
2508 : }
2509 :
2510 0 : status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2511 : state->logon_level,
2512 : state->logon);
2513 0 : if (!NT_STATUS_IS_OK(status)) {
2514 0 : status = NT_STATUS_ACCESS_DENIED;
2515 0 : tevent_req_nterror(req, status);
2516 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2517 0 : return;
2518 : }
2519 : }
2520 :
2521 24 : subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2522 : state->binding_handle,
2523 24 : state->srv_name_slash,
2524 24 : state->context->client.computer,
2525 : state->logon_level,
2526 : state->logon,
2527 24 : state->validation_level,
2528 : state->validation,
2529 : &state->authoritative,
2530 : &state->flags);
2531 24 : if (tevent_req_nomem(subreq, req)) {
2532 0 : status = NT_STATUS_NO_MEMORY;
2533 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2534 0 : return;
2535 : }
2536 24 : tevent_req_set_callback(subreq,
2537 : netlogon_creds_cli_LogonSamLogon_done,
2538 : req);
2539 24 : return;
2540 : }
2541 :
2542 36 : if (state->lk_creds == NULL) {
2543 18 : subreq = netlogon_creds_cli_lock_send(state, state->ev,
2544 : state->context);
2545 18 : if (tevent_req_nomem(subreq, req)) {
2546 0 : status = NT_STATUS_NO_MEMORY;
2547 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2548 0 : return;
2549 : }
2550 18 : tevent_req_set_callback(subreq,
2551 : netlogon_creds_cli_LogonSamLogon_done,
2552 : req);
2553 18 : return;
2554 : }
2555 :
2556 18 : state->tmp_creds = *state->lk_creds;
2557 18 : status = netlogon_creds_client_authenticator(&state->tmp_creds,
2558 : &state->req_auth);
2559 18 : if (tevent_req_nterror(req, status)) {
2560 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2561 0 : return;
2562 : }
2563 18 : ZERO_STRUCT(state->rep_auth);
2564 :
2565 18 : state->logon = netlogon_creds_shallow_copy_logon(state,
2566 : state->logon_level,
2567 : state->const_logon);
2568 18 : if (tevent_req_nomem(state->logon, req)) {
2569 0 : status = NT_STATUS_NO_MEMORY;
2570 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2571 0 : return;
2572 : }
2573 :
2574 18 : status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2575 : state->logon_level,
2576 : state->logon);
2577 18 : if (tevent_req_nterror(req, status)) {
2578 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2579 0 : return;
2580 : }
2581 :
2582 18 : state->validation_level = 3;
2583 :
2584 18 : if (state->context->server.try_logon_with) {
2585 18 : subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2586 : state->binding_handle,
2587 18 : state->srv_name_slash,
2588 18 : state->context->client.computer,
2589 : &state->req_auth,
2590 : &state->rep_auth,
2591 : state->logon_level,
2592 : state->logon,
2593 18 : state->validation_level,
2594 : state->validation,
2595 : &state->authoritative,
2596 : &state->flags);
2597 18 : if (tevent_req_nomem(subreq, req)) {
2598 0 : status = NT_STATUS_NO_MEMORY;
2599 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2600 0 : return;
2601 : }
2602 : } else {
2603 0 : state->flags = 0;
2604 :
2605 0 : subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2606 : state->binding_handle,
2607 0 : state->srv_name_slash,
2608 0 : state->context->client.computer,
2609 : &state->req_auth,
2610 : &state->rep_auth,
2611 : state->logon_level,
2612 : state->logon,
2613 0 : state->validation_level,
2614 : state->validation,
2615 : &state->authoritative);
2616 0 : if (tevent_req_nomem(subreq, req)) {
2617 0 : status = NT_STATUS_NO_MEMORY;
2618 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2619 0 : return;
2620 : }
2621 : }
2622 :
2623 18 : tevent_req_set_callback(subreq,
2624 : netlogon_creds_cli_LogonSamLogon_done,
2625 : req);
2626 : }
2627 :
2628 60 : static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2629 : {
2630 0 : struct tevent_req *req =
2631 60 : tevent_req_callback_data(subreq,
2632 : struct tevent_req);
2633 0 : struct netlogon_creds_cli_LogonSamLogon_state *state =
2634 60 : tevent_req_data(req,
2635 : struct netlogon_creds_cli_LogonSamLogon_state);
2636 0 : NTSTATUS status;
2637 0 : NTSTATUS result;
2638 0 : bool ok;
2639 :
2640 60 : if (state->try_logon_ex) {
2641 24 : status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2642 24 : state->validation,
2643 : &result);
2644 24 : TALLOC_FREE(subreq);
2645 24 : if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2646 0 : state->context->server.try_validation6 = false;
2647 0 : state->context->server.try_logon_ex = false;
2648 0 : netlogon_creds_cli_LogonSamLogon_start(req);
2649 0 : return;
2650 : }
2651 24 : if (tevent_req_nterror(req, status)) {
2652 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2653 0 : return;
2654 : }
2655 :
2656 24 : if ((state->validation_level == 6) &&
2657 24 : (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2658 24 : NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2659 24 : NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2660 : {
2661 0 : state->context->server.try_validation6 = false;
2662 0 : netlogon_creds_cli_LogonSamLogon_start(req);
2663 0 : return;
2664 : }
2665 :
2666 24 : if (tevent_req_nterror(req, result)) {
2667 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2668 0 : return;
2669 : }
2670 :
2671 24 : if (state->ro_creds == NULL) {
2672 24 : tevent_req_done(req);
2673 24 : return;
2674 : }
2675 :
2676 0 : ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2677 0 : if (!ok) {
2678 : /*
2679 : * We got a race, lets retry with on authenticator
2680 : * protection.
2681 : *
2682 : * netlogon_creds_cli_LogonSamLogon_start()
2683 : * will TALLOC_FREE(state->ro_creds);
2684 : */
2685 0 : state->try_logon_ex = false;
2686 0 : netlogon_creds_cli_LogonSamLogon_start(req);
2687 0 : return;
2688 : }
2689 :
2690 0 : status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2691 0 : state->validation_level,
2692 : state->validation);
2693 0 : if (tevent_req_nterror(req, status)) {
2694 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2695 0 : return;
2696 : }
2697 :
2698 0 : tevent_req_done(req);
2699 0 : return;
2700 : }
2701 :
2702 36 : if (state->lk_creds == NULL) {
2703 18 : status = netlogon_creds_cli_lock_recv(subreq, state,
2704 : &state->lk_creds);
2705 18 : TALLOC_FREE(subreq);
2706 18 : if (tevent_req_nterror(req, status)) {
2707 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2708 0 : return;
2709 : }
2710 :
2711 18 : netlogon_creds_cli_LogonSamLogon_start(req);
2712 18 : return;
2713 : }
2714 :
2715 18 : if (state->context->server.try_logon_with) {
2716 18 : status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2717 18 : state->validation,
2718 : &result);
2719 18 : TALLOC_FREE(subreq);
2720 18 : if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2721 0 : state->context->server.try_logon_with = false;
2722 0 : netlogon_creds_cli_LogonSamLogon_start(req);
2723 0 : return;
2724 : }
2725 18 : if (tevent_req_nterror(req, status)) {
2726 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2727 0 : return;
2728 : }
2729 : } else {
2730 0 : status = dcerpc_netr_LogonSamLogon_recv(subreq,
2731 0 : state->validation,
2732 : &result);
2733 0 : TALLOC_FREE(subreq);
2734 0 : if (tevent_req_nterror(req, status)) {
2735 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2736 0 : return;
2737 : }
2738 : }
2739 :
2740 18 : ok = netlogon_creds_client_check(&state->tmp_creds,
2741 18 : &state->rep_auth.cred);
2742 18 : if (!ok) {
2743 0 : status = NT_STATUS_ACCESS_DENIED;
2744 0 : tevent_req_nterror(req, status);
2745 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2746 0 : return;
2747 : }
2748 :
2749 18 : *state->lk_creds = state->tmp_creds;
2750 18 : status = netlogon_creds_cli_store(state->context,
2751 : state->lk_creds);
2752 18 : TALLOC_FREE(state->lk_creds);
2753 :
2754 18 : if (tevent_req_nterror(req, status)) {
2755 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2756 0 : return;
2757 : }
2758 :
2759 18 : if (tevent_req_nterror(req, result)) {
2760 12 : netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2761 12 : return;
2762 : }
2763 :
2764 6 : status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2765 6 : state->validation_level,
2766 : state->validation);
2767 6 : if (tevent_req_nterror(req, status)) {
2768 0 : netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2769 0 : return;
2770 : }
2771 :
2772 6 : tevent_req_done(req);
2773 : }
2774 :
2775 42 : NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2776 : TALLOC_CTX *mem_ctx,
2777 : uint16_t *validation_level,
2778 : union netr_Validation **validation,
2779 : uint8_t *authoritative,
2780 : uint32_t *flags)
2781 : {
2782 0 : struct netlogon_creds_cli_LogonSamLogon_state *state =
2783 42 : tevent_req_data(req,
2784 : struct netlogon_creds_cli_LogonSamLogon_state);
2785 0 : NTSTATUS status;
2786 :
2787 : /* authoritative is also returned on error */
2788 42 : *authoritative = state->authoritative;
2789 :
2790 42 : if (tevent_req_is_nterror(req, &status)) {
2791 12 : netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2792 12 : tevent_req_received(req);
2793 12 : return status;
2794 : }
2795 :
2796 30 : *validation_level = state->validation_level;
2797 30 : *validation = talloc_move(mem_ctx, &state->validation);
2798 30 : *flags = state->flags;
2799 :
2800 30 : tevent_req_received(req);
2801 30 : return NT_STATUS_OK;
2802 : }
2803 :
2804 42 : NTSTATUS netlogon_creds_cli_LogonSamLogon(
2805 : struct netlogon_creds_cli_context *context,
2806 : struct dcerpc_binding_handle *b,
2807 : enum netr_LogonInfoClass logon_level,
2808 : const union netr_LogonLevel *logon,
2809 : TALLOC_CTX *mem_ctx,
2810 : uint16_t *validation_level,
2811 : union netr_Validation **validation,
2812 : uint8_t *authoritative,
2813 : uint32_t *flags)
2814 : {
2815 42 : TALLOC_CTX *frame = talloc_stackframe();
2816 0 : struct tevent_context *ev;
2817 0 : struct tevent_req *req;
2818 42 : NTSTATUS status = NT_STATUS_NO_MEMORY;
2819 :
2820 42 : ev = samba_tevent_context_init(frame);
2821 42 : if (ev == NULL) {
2822 0 : goto fail;
2823 : }
2824 42 : req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2825 : logon_level, logon,
2826 : *flags);
2827 42 : if (req == NULL) {
2828 0 : goto fail;
2829 : }
2830 42 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2831 0 : goto fail;
2832 : }
2833 42 : status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2834 : validation_level,
2835 : validation,
2836 : authoritative,
2837 : flags);
2838 42 : fail:
2839 42 : TALLOC_FREE(frame);
2840 42 : return status;
2841 : }
2842 :
2843 : struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2844 : struct tevent_context *ev;
2845 : struct netlogon_creds_cli_context *context;
2846 : struct dcerpc_binding_handle *binding_handle;
2847 :
2848 : char *srv_name_slash;
2849 : enum dcerpc_AuthType auth_type;
2850 : enum dcerpc_AuthLevel auth_level;
2851 :
2852 : const char *site_name;
2853 : uint32_t dns_ttl;
2854 : struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2855 :
2856 : struct netlogon_creds_CredentialState *creds;
2857 : struct netlogon_creds_CredentialState tmp_creds;
2858 : struct netr_Authenticator req_auth;
2859 : struct netr_Authenticator rep_auth;
2860 : };
2861 :
2862 : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2863 : NTSTATUS status);
2864 : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2865 :
2866 0 : struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2867 : struct tevent_context *ev,
2868 : struct netlogon_creds_cli_context *context,
2869 : struct dcerpc_binding_handle *b,
2870 : const char *site_name,
2871 : uint32_t dns_ttl,
2872 : struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2873 : {
2874 0 : struct tevent_req *req;
2875 0 : struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2876 0 : struct tevent_req *subreq;
2877 :
2878 0 : req = tevent_req_create(mem_ctx, &state,
2879 : struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2880 0 : if (req == NULL) {
2881 0 : return NULL;
2882 : }
2883 :
2884 0 : state->ev = ev;
2885 0 : state->context = context;
2886 0 : state->binding_handle = b;
2887 :
2888 0 : state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2889 : context->server.computer);
2890 0 : if (tevent_req_nomem(state->srv_name_slash, req)) {
2891 0 : return tevent_req_post(req, ev);
2892 : }
2893 :
2894 0 : state->site_name = site_name;
2895 0 : state->dns_ttl = dns_ttl;
2896 0 : state->dns_names = dns_names;
2897 :
2898 0 : dcerpc_binding_handle_auth_info(state->binding_handle,
2899 0 : &state->auth_type,
2900 0 : &state->auth_level);
2901 :
2902 0 : subreq = netlogon_creds_cli_lock_send(state, state->ev,
2903 0 : state->context);
2904 0 : if (tevent_req_nomem(subreq, req)) {
2905 0 : return tevent_req_post(req, ev);
2906 : }
2907 :
2908 0 : tevent_req_set_callback(subreq,
2909 : netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2910 : req);
2911 :
2912 0 : return req;
2913 : }
2914 :
2915 0 : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2916 : NTSTATUS status)
2917 : {
2918 0 : struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2919 0 : tevent_req_data(req,
2920 : struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2921 :
2922 0 : if (state->creds == NULL) {
2923 0 : return;
2924 : }
2925 :
2926 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2927 0 : !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2928 0 : !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2929 0 : !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2930 0 : !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2931 0 : TALLOC_FREE(state->creds);
2932 0 : return;
2933 : }
2934 :
2935 0 : netlogon_creds_cli_delete(state->context, state->creds);
2936 0 : TALLOC_FREE(state->creds);
2937 : }
2938 :
2939 : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2940 :
2941 0 : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2942 : {
2943 0 : struct tevent_req *req =
2944 0 : tevent_req_callback_data(subreq,
2945 : struct tevent_req);
2946 0 : struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2947 0 : tevent_req_data(req,
2948 : struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2949 0 : NTSTATUS status;
2950 :
2951 0 : status = netlogon_creds_cli_lock_recv(subreq, state,
2952 : &state->creds);
2953 0 : TALLOC_FREE(subreq);
2954 0 : if (tevent_req_nterror(req, status)) {
2955 0 : return;
2956 : }
2957 :
2958 0 : if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2959 0 : switch (state->auth_level) {
2960 0 : case DCERPC_AUTH_LEVEL_INTEGRITY:
2961 : case DCERPC_AUTH_LEVEL_PRIVACY:
2962 0 : break;
2963 0 : default:
2964 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2965 0 : return;
2966 : }
2967 : } else {
2968 0 : uint32_t tmp = state->creds->negotiate_flags;
2969 :
2970 0 : if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2971 : /*
2972 : * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2973 : * it should be used, which means
2974 : * we had a chance to verify no downgrade
2975 : * happened.
2976 : *
2977 : * This relies on netlogon_creds_cli_check*
2978 : * being called before, as first request after
2979 : * the DCERPC bind.
2980 : */
2981 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2982 0 : return;
2983 : }
2984 : }
2985 :
2986 : /*
2987 : * we defer all callbacks in order to cleanup
2988 : * the database record.
2989 : */
2990 0 : tevent_req_defer_callback(req, state->ev);
2991 :
2992 0 : state->tmp_creds = *state->creds;
2993 0 : status = netlogon_creds_client_authenticator(&state->tmp_creds,
2994 : &state->req_auth);
2995 0 : if (tevent_req_nterror(req, status)) {
2996 0 : return;
2997 : }
2998 0 : ZERO_STRUCT(state->rep_auth);
2999 :
3000 0 : subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
3001 : state->binding_handle,
3002 0 : state->srv_name_slash,
3003 : state->tmp_creds.computer_name,
3004 : &state->req_auth,
3005 : &state->rep_auth,
3006 : state->site_name,
3007 : state->dns_ttl,
3008 : state->dns_names);
3009 0 : if (tevent_req_nomem(subreq, req)) {
3010 0 : status = NT_STATUS_NO_MEMORY;
3011 0 : netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3012 0 : return;
3013 : }
3014 :
3015 0 : tevent_req_set_callback(subreq,
3016 : netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
3017 : req);
3018 : }
3019 :
3020 0 : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
3021 : {
3022 0 : struct tevent_req *req =
3023 0 : tevent_req_callback_data(subreq,
3024 : struct tevent_req);
3025 0 : struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
3026 0 : tevent_req_data(req,
3027 : struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
3028 0 : NTSTATUS status;
3029 0 : NTSTATUS result;
3030 0 : bool ok;
3031 :
3032 : /*
3033 : * We use state->dns_names as the memory context, as this is
3034 : * the only in/out variable and it has been overwritten by the
3035 : * out parameter from the server.
3036 : *
3037 : * We need to preserve the return value until the caller can use it.
3038 : */
3039 0 : status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
3040 : &result);
3041 0 : TALLOC_FREE(subreq);
3042 0 : if (tevent_req_nterror(req, status)) {
3043 0 : netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3044 0 : return;
3045 : }
3046 :
3047 0 : ok = netlogon_creds_client_check(&state->tmp_creds,
3048 0 : &state->rep_auth.cred);
3049 0 : if (!ok) {
3050 0 : status = NT_STATUS_ACCESS_DENIED;
3051 0 : tevent_req_nterror(req, status);
3052 0 : netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3053 0 : return;
3054 : }
3055 :
3056 0 : *state->creds = state->tmp_creds;
3057 0 : status = netlogon_creds_cli_store(state->context,
3058 : state->creds);
3059 0 : TALLOC_FREE(state->creds);
3060 :
3061 0 : if (tevent_req_nterror(req, status)) {
3062 0 : netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3063 0 : return;
3064 : }
3065 :
3066 0 : if (tevent_req_nterror(req, result)) {
3067 0 : netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
3068 0 : return;
3069 : }
3070 :
3071 0 : tevent_req_done(req);
3072 : }
3073 :
3074 0 : NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
3075 : {
3076 0 : NTSTATUS status;
3077 :
3078 0 : if (tevent_req_is_nterror(req, &status)) {
3079 0 : netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3080 0 : tevent_req_received(req);
3081 0 : return status;
3082 : }
3083 :
3084 0 : tevent_req_received(req);
3085 0 : return NT_STATUS_OK;
3086 : }
3087 :
3088 0 : NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
3089 : struct netlogon_creds_cli_context *context,
3090 : struct dcerpc_binding_handle *b,
3091 : const char *site_name,
3092 : uint32_t dns_ttl,
3093 : struct NL_DNS_NAME_INFO_ARRAY *dns_names)
3094 : {
3095 0 : TALLOC_CTX *frame = talloc_stackframe();
3096 0 : struct tevent_context *ev;
3097 0 : struct tevent_req *req;
3098 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
3099 :
3100 0 : ev = samba_tevent_context_init(frame);
3101 0 : if (ev == NULL) {
3102 0 : goto fail;
3103 : }
3104 0 : req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
3105 : site_name,
3106 : dns_ttl,
3107 : dns_names);
3108 0 : if (req == NULL) {
3109 0 : goto fail;
3110 : }
3111 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3112 0 : goto fail;
3113 : }
3114 0 : status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
3115 0 : fail:
3116 0 : TALLOC_FREE(frame);
3117 0 : return status;
3118 : }
3119 :
3120 : struct netlogon_creds_cli_ServerGetTrustInfo_state {
3121 : struct tevent_context *ev;
3122 : struct netlogon_creds_cli_context *context;
3123 : struct dcerpc_binding_handle *binding_handle;
3124 :
3125 : char *srv_name_slash;
3126 : enum dcerpc_AuthType auth_type;
3127 : enum dcerpc_AuthLevel auth_level;
3128 :
3129 : struct samr_Password new_owf_password;
3130 : struct samr_Password old_owf_password;
3131 : struct netr_TrustInfo *trust_info;
3132 :
3133 : struct netlogon_creds_CredentialState *creds;
3134 : struct netlogon_creds_CredentialState tmp_creds;
3135 : struct netr_Authenticator req_auth;
3136 : struct netr_Authenticator rep_auth;
3137 : };
3138 :
3139 : static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3140 : NTSTATUS status);
3141 : static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
3142 :
3143 0 : struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
3144 : struct tevent_context *ev,
3145 : struct netlogon_creds_cli_context *context,
3146 : struct dcerpc_binding_handle *b)
3147 : {
3148 0 : struct tevent_req *req;
3149 0 : struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
3150 0 : struct tevent_req *subreq;
3151 :
3152 0 : req = tevent_req_create(mem_ctx, &state,
3153 : struct netlogon_creds_cli_ServerGetTrustInfo_state);
3154 0 : if (req == NULL) {
3155 0 : return NULL;
3156 : }
3157 :
3158 0 : state->ev = ev;
3159 0 : state->context = context;
3160 0 : state->binding_handle = b;
3161 :
3162 0 : state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3163 : context->server.computer);
3164 0 : if (tevent_req_nomem(state->srv_name_slash, req)) {
3165 0 : return tevent_req_post(req, ev);
3166 : }
3167 :
3168 0 : dcerpc_binding_handle_auth_info(state->binding_handle,
3169 0 : &state->auth_type,
3170 0 : &state->auth_level);
3171 :
3172 0 : subreq = netlogon_creds_cli_lock_send(state, state->ev,
3173 0 : state->context);
3174 0 : if (tevent_req_nomem(subreq, req)) {
3175 0 : return tevent_req_post(req, ev);
3176 : }
3177 :
3178 0 : tevent_req_set_callback(subreq,
3179 : netlogon_creds_cli_ServerGetTrustInfo_locked,
3180 : req);
3181 :
3182 0 : return req;
3183 : }
3184 :
3185 0 : static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3186 : NTSTATUS status)
3187 : {
3188 0 : struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3189 0 : tevent_req_data(req,
3190 : struct netlogon_creds_cli_ServerGetTrustInfo_state);
3191 :
3192 0 : if (state->creds == NULL) {
3193 0 : return;
3194 : }
3195 :
3196 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3197 0 : !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3198 0 : !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3199 0 : !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3200 0 : !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3201 0 : TALLOC_FREE(state->creds);
3202 0 : return;
3203 : }
3204 :
3205 0 : netlogon_creds_cli_delete(state->context, state->creds);
3206 0 : TALLOC_FREE(state->creds);
3207 : }
3208 :
3209 : static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3210 :
3211 0 : static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3212 : {
3213 0 : struct tevent_req *req =
3214 0 : tevent_req_callback_data(subreq,
3215 : struct tevent_req);
3216 0 : struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3217 0 : tevent_req_data(req,
3218 : struct netlogon_creds_cli_ServerGetTrustInfo_state);
3219 0 : NTSTATUS status;
3220 :
3221 0 : status = netlogon_creds_cli_lock_recv(subreq, state,
3222 : &state->creds);
3223 0 : TALLOC_FREE(subreq);
3224 0 : if (tevent_req_nterror(req, status)) {
3225 0 : return;
3226 : }
3227 :
3228 0 : if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3229 0 : switch (state->auth_level) {
3230 0 : case DCERPC_AUTH_LEVEL_PRIVACY:
3231 0 : break;
3232 0 : default:
3233 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3234 0 : return;
3235 : }
3236 : } else {
3237 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3238 0 : return;
3239 : }
3240 :
3241 : /*
3242 : * we defer all callbacks in order to cleanup
3243 : * the database record.
3244 : */
3245 0 : tevent_req_defer_callback(req, state->ev);
3246 :
3247 0 : state->tmp_creds = *state->creds;
3248 0 : status = netlogon_creds_client_authenticator(&state->tmp_creds,
3249 : &state->req_auth);
3250 0 : if (tevent_req_nterror(req, status)) {
3251 0 : return;
3252 : }
3253 0 : ZERO_STRUCT(state->rep_auth);
3254 :
3255 0 : subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3256 : state->binding_handle,
3257 0 : state->srv_name_slash,
3258 : state->tmp_creds.account_name,
3259 : state->tmp_creds.secure_channel_type,
3260 : state->tmp_creds.computer_name,
3261 : &state->req_auth,
3262 : &state->rep_auth,
3263 : &state->new_owf_password,
3264 : &state->old_owf_password,
3265 : &state->trust_info);
3266 0 : if (tevent_req_nomem(subreq, req)) {
3267 0 : status = NT_STATUS_NO_MEMORY;
3268 0 : netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3269 0 : return;
3270 : }
3271 :
3272 0 : tevent_req_set_callback(subreq,
3273 : netlogon_creds_cli_ServerGetTrustInfo_done,
3274 : req);
3275 : }
3276 :
3277 0 : static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3278 : {
3279 0 : struct tevent_req *req =
3280 0 : tevent_req_callback_data(subreq,
3281 : struct tevent_req);
3282 0 : struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3283 0 : tevent_req_data(req,
3284 : struct netlogon_creds_cli_ServerGetTrustInfo_state);
3285 0 : NTSTATUS status;
3286 0 : NTSTATUS result;
3287 0 : const struct samr_Password zero = {};
3288 0 : bool cmp;
3289 0 : bool ok;
3290 :
3291 : /*
3292 : * We use state->dns_names as the memory context, as this is
3293 : * the only in/out variable and it has been overwritten by the
3294 : * out parameter from the server.
3295 : *
3296 : * We need to preserve the return value until the caller can use it.
3297 : */
3298 0 : status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3299 0 : TALLOC_FREE(subreq);
3300 0 : if (tevent_req_nterror(req, status)) {
3301 0 : netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3302 0 : return;
3303 : }
3304 :
3305 0 : ok = netlogon_creds_client_check(&state->tmp_creds,
3306 0 : &state->rep_auth.cred);
3307 0 : if (!ok) {
3308 0 : status = NT_STATUS_ACCESS_DENIED;
3309 0 : tevent_req_nterror(req, status);
3310 0 : netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3311 0 : return;
3312 : }
3313 :
3314 0 : cmp = mem_equal_const_time(state->new_owf_password.hash,
3315 : zero.hash, sizeof(zero.hash));
3316 0 : if (!cmp) {
3317 0 : status = netlogon_creds_des_decrypt(&state->tmp_creds,
3318 : &state->new_owf_password);
3319 0 : if (tevent_req_nterror(req, status)) {
3320 0 : netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3321 0 : return;
3322 : }
3323 : }
3324 0 : cmp = mem_equal_const_time(state->old_owf_password.hash,
3325 : zero.hash, sizeof(zero.hash));
3326 0 : if (!cmp) {
3327 0 : status = netlogon_creds_des_decrypt(&state->tmp_creds,
3328 : &state->old_owf_password);
3329 0 : if (tevent_req_nterror(req, status)) {
3330 0 : netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3331 0 : return;
3332 : }
3333 : }
3334 :
3335 0 : *state->creds = state->tmp_creds;
3336 0 : status = netlogon_creds_cli_store(state->context,
3337 : state->creds);
3338 0 : TALLOC_FREE(state->creds);
3339 0 : if (tevent_req_nterror(req, status)) {
3340 0 : netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3341 0 : return;
3342 : }
3343 :
3344 0 : if (tevent_req_nterror(req, result)) {
3345 0 : netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3346 0 : return;
3347 : }
3348 :
3349 0 : tevent_req_done(req);
3350 : }
3351 :
3352 0 : NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3353 : TALLOC_CTX *mem_ctx,
3354 : struct samr_Password *new_owf_password,
3355 : struct samr_Password *old_owf_password,
3356 : struct netr_TrustInfo **trust_info)
3357 : {
3358 0 : struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3359 0 : tevent_req_data(req,
3360 : struct netlogon_creds_cli_ServerGetTrustInfo_state);
3361 0 : NTSTATUS status;
3362 :
3363 0 : if (tevent_req_is_nterror(req, &status)) {
3364 0 : netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3365 0 : tevent_req_received(req);
3366 0 : return status;
3367 : }
3368 :
3369 0 : if (new_owf_password != NULL) {
3370 0 : *new_owf_password = state->new_owf_password;
3371 : }
3372 0 : if (old_owf_password != NULL) {
3373 0 : *old_owf_password = state->old_owf_password;
3374 : }
3375 0 : if (trust_info != NULL) {
3376 0 : *trust_info = talloc_move(mem_ctx, &state->trust_info);
3377 : }
3378 :
3379 0 : tevent_req_received(req);
3380 0 : return NT_STATUS_OK;
3381 : }
3382 :
3383 0 : NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3384 : struct netlogon_creds_cli_context *context,
3385 : struct dcerpc_binding_handle *b,
3386 : TALLOC_CTX *mem_ctx,
3387 : struct samr_Password *new_owf_password,
3388 : struct samr_Password *old_owf_password,
3389 : struct netr_TrustInfo **trust_info)
3390 : {
3391 0 : TALLOC_CTX *frame = talloc_stackframe();
3392 0 : struct tevent_context *ev;
3393 0 : struct tevent_req *req;
3394 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
3395 :
3396 0 : ev = samba_tevent_context_init(frame);
3397 0 : if (ev == NULL) {
3398 0 : goto fail;
3399 : }
3400 0 : req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3401 0 : if (req == NULL) {
3402 0 : goto fail;
3403 : }
3404 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3405 0 : goto fail;
3406 : }
3407 0 : status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3408 : mem_ctx,
3409 : new_owf_password,
3410 : old_owf_password,
3411 : trust_info);
3412 0 : fail:
3413 0 : TALLOC_FREE(frame);
3414 0 : return status;
3415 : }
3416 :
3417 : struct netlogon_creds_cli_GetForestTrustInformation_state {
3418 : struct tevent_context *ev;
3419 : struct netlogon_creds_cli_context *context;
3420 : struct dcerpc_binding_handle *binding_handle;
3421 :
3422 : char *srv_name_slash;
3423 : enum dcerpc_AuthType auth_type;
3424 : enum dcerpc_AuthLevel auth_level;
3425 :
3426 : uint32_t flags;
3427 : struct lsa_ForestTrustInformation *forest_trust_info;
3428 :
3429 : struct netlogon_creds_CredentialState *creds;
3430 : struct netlogon_creds_CredentialState tmp_creds;
3431 : struct netr_Authenticator req_auth;
3432 : struct netr_Authenticator rep_auth;
3433 : };
3434 :
3435 : static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3436 : NTSTATUS status);
3437 : static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3438 :
3439 0 : struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3440 : struct tevent_context *ev,
3441 : struct netlogon_creds_cli_context *context,
3442 : struct dcerpc_binding_handle *b)
3443 : {
3444 0 : struct tevent_req *req;
3445 0 : struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3446 0 : struct tevent_req *subreq;
3447 :
3448 0 : req = tevent_req_create(mem_ctx, &state,
3449 : struct netlogon_creds_cli_GetForestTrustInformation_state);
3450 0 : if (req == NULL) {
3451 0 : return NULL;
3452 : }
3453 :
3454 0 : state->ev = ev;
3455 0 : state->context = context;
3456 0 : state->binding_handle = b;
3457 :
3458 0 : state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3459 : context->server.computer);
3460 0 : if (tevent_req_nomem(state->srv_name_slash, req)) {
3461 0 : return tevent_req_post(req, ev);
3462 : }
3463 :
3464 0 : state->flags = 0;
3465 :
3466 0 : dcerpc_binding_handle_auth_info(state->binding_handle,
3467 0 : &state->auth_type,
3468 0 : &state->auth_level);
3469 :
3470 0 : subreq = netlogon_creds_cli_lock_send(state, state->ev,
3471 0 : state->context);
3472 0 : if (tevent_req_nomem(subreq, req)) {
3473 0 : return tevent_req_post(req, ev);
3474 : }
3475 :
3476 0 : tevent_req_set_callback(subreq,
3477 : netlogon_creds_cli_GetForestTrustInformation_locked,
3478 : req);
3479 :
3480 0 : return req;
3481 : }
3482 :
3483 0 : static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3484 : NTSTATUS status)
3485 : {
3486 0 : struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3487 0 : tevent_req_data(req,
3488 : struct netlogon_creds_cli_GetForestTrustInformation_state);
3489 :
3490 0 : if (state->creds == NULL) {
3491 0 : return;
3492 : }
3493 :
3494 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3495 0 : !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3496 0 : !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3497 0 : !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3498 0 : !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3499 0 : TALLOC_FREE(state->creds);
3500 0 : return;
3501 : }
3502 :
3503 0 : netlogon_creds_cli_delete(state->context, state->creds);
3504 0 : TALLOC_FREE(state->creds);
3505 : }
3506 :
3507 : static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3508 :
3509 0 : static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3510 : {
3511 0 : struct tevent_req *req =
3512 0 : tevent_req_callback_data(subreq,
3513 : struct tevent_req);
3514 0 : struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3515 0 : tevent_req_data(req,
3516 : struct netlogon_creds_cli_GetForestTrustInformation_state);
3517 0 : NTSTATUS status;
3518 :
3519 0 : status = netlogon_creds_cli_lock_recv(subreq, state,
3520 : &state->creds);
3521 0 : TALLOC_FREE(subreq);
3522 0 : if (tevent_req_nterror(req, status)) {
3523 0 : return;
3524 : }
3525 :
3526 0 : if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3527 0 : switch (state->auth_level) {
3528 0 : case DCERPC_AUTH_LEVEL_INTEGRITY:
3529 : case DCERPC_AUTH_LEVEL_PRIVACY:
3530 0 : break;
3531 0 : default:
3532 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3533 0 : return;
3534 : }
3535 : } else {
3536 0 : uint32_t tmp = state->creds->negotiate_flags;
3537 :
3538 0 : if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3539 : /*
3540 : * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3541 : * it should be used, which means
3542 : * we had a chance to verify no downgrade
3543 : * happened.
3544 : *
3545 : * This relies on netlogon_creds_cli_check*
3546 : * being called before, as first request after
3547 : * the DCERPC bind.
3548 : */
3549 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3550 0 : return;
3551 : }
3552 : }
3553 :
3554 : /*
3555 : * we defer all callbacks in order to cleanup
3556 : * the database record.
3557 : */
3558 0 : tevent_req_defer_callback(req, state->ev);
3559 :
3560 0 : state->tmp_creds = *state->creds;
3561 0 : status = netlogon_creds_client_authenticator(&state->tmp_creds,
3562 : &state->req_auth);
3563 0 : if (tevent_req_nterror(req, status)) {
3564 0 : return;
3565 : }
3566 0 : ZERO_STRUCT(state->rep_auth);
3567 :
3568 0 : subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3569 : state->binding_handle,
3570 0 : state->srv_name_slash,
3571 : state->tmp_creds.computer_name,
3572 : &state->req_auth,
3573 : &state->rep_auth,
3574 : state->flags,
3575 : &state->forest_trust_info);
3576 0 : if (tevent_req_nomem(subreq, req)) {
3577 0 : status = NT_STATUS_NO_MEMORY;
3578 0 : netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3579 0 : return;
3580 : }
3581 :
3582 0 : tevent_req_set_callback(subreq,
3583 : netlogon_creds_cli_GetForestTrustInformation_done,
3584 : req);
3585 : }
3586 :
3587 0 : static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3588 : {
3589 0 : struct tevent_req *req =
3590 0 : tevent_req_callback_data(subreq,
3591 : struct tevent_req);
3592 0 : struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3593 0 : tevent_req_data(req,
3594 : struct netlogon_creds_cli_GetForestTrustInformation_state);
3595 0 : NTSTATUS status;
3596 0 : NTSTATUS result;
3597 0 : bool ok;
3598 :
3599 : /*
3600 : * We use state->dns_names as the memory context, as this is
3601 : * the only in/out variable and it has been overwritten by the
3602 : * out parameter from the server.
3603 : *
3604 : * We need to preserve the return value until the caller can use it.
3605 : */
3606 0 : status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3607 0 : TALLOC_FREE(subreq);
3608 0 : if (tevent_req_nterror(req, status)) {
3609 0 : netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3610 0 : return;
3611 : }
3612 :
3613 0 : ok = netlogon_creds_client_check(&state->tmp_creds,
3614 0 : &state->rep_auth.cred);
3615 0 : if (!ok) {
3616 0 : status = NT_STATUS_ACCESS_DENIED;
3617 0 : tevent_req_nterror(req, status);
3618 0 : netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3619 0 : return;
3620 : }
3621 :
3622 0 : *state->creds = state->tmp_creds;
3623 0 : status = netlogon_creds_cli_store(state->context,
3624 : state->creds);
3625 0 : TALLOC_FREE(state->creds);
3626 :
3627 0 : if (tevent_req_nterror(req, status)) {
3628 0 : netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3629 0 : return;
3630 : }
3631 :
3632 0 : if (tevent_req_nterror(req, result)) {
3633 0 : netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3634 0 : return;
3635 : }
3636 :
3637 0 : tevent_req_done(req);
3638 : }
3639 :
3640 0 : NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3641 : TALLOC_CTX *mem_ctx,
3642 : struct lsa_ForestTrustInformation **forest_trust_info)
3643 : {
3644 0 : struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3645 0 : tevent_req_data(req,
3646 : struct netlogon_creds_cli_GetForestTrustInformation_state);
3647 0 : NTSTATUS status;
3648 :
3649 0 : if (tevent_req_is_nterror(req, &status)) {
3650 0 : netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3651 0 : tevent_req_received(req);
3652 0 : return status;
3653 : }
3654 :
3655 0 : *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3656 :
3657 0 : tevent_req_received(req);
3658 0 : return NT_STATUS_OK;
3659 : }
3660 :
3661 0 : NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3662 : struct netlogon_creds_cli_context *context,
3663 : struct dcerpc_binding_handle *b,
3664 : TALLOC_CTX *mem_ctx,
3665 : struct lsa_ForestTrustInformation **forest_trust_info)
3666 : {
3667 0 : TALLOC_CTX *frame = talloc_stackframe();
3668 0 : struct tevent_context *ev;
3669 0 : struct tevent_req *req;
3670 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
3671 :
3672 0 : ev = samba_tevent_context_init(frame);
3673 0 : if (ev == NULL) {
3674 0 : goto fail;
3675 : }
3676 0 : req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3677 0 : if (req == NULL) {
3678 0 : goto fail;
3679 : }
3680 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3681 0 : goto fail;
3682 : }
3683 0 : status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3684 : mem_ctx,
3685 : forest_trust_info);
3686 0 : fail:
3687 0 : TALLOC_FREE(frame);
3688 0 : return status;
3689 : }
3690 : struct netlogon_creds_cli_SendToSam_state {
3691 : struct tevent_context *ev;
3692 : struct netlogon_creds_cli_context *context;
3693 : struct dcerpc_binding_handle *binding_handle;
3694 :
3695 : char *srv_name_slash;
3696 : enum dcerpc_AuthType auth_type;
3697 : enum dcerpc_AuthLevel auth_level;
3698 :
3699 : DATA_BLOB opaque;
3700 :
3701 : struct netlogon_creds_CredentialState *creds;
3702 : struct netlogon_creds_CredentialState tmp_creds;
3703 : struct netr_Authenticator req_auth;
3704 : struct netr_Authenticator rep_auth;
3705 : };
3706 :
3707 : static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3708 : NTSTATUS status);
3709 : static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3710 :
3711 0 : struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3712 : struct tevent_context *ev,
3713 : struct netlogon_creds_cli_context *context,
3714 : struct dcerpc_binding_handle *b,
3715 : struct netr_SendToSamBase *message)
3716 : {
3717 0 : struct tevent_req *req;
3718 0 : struct netlogon_creds_cli_SendToSam_state *state;
3719 0 : struct tevent_req *subreq;
3720 0 : enum ndr_err_code ndr_err;
3721 :
3722 0 : req = tevent_req_create(mem_ctx, &state,
3723 : struct netlogon_creds_cli_SendToSam_state);
3724 0 : if (req == NULL) {
3725 0 : return NULL;
3726 : }
3727 :
3728 0 : state->ev = ev;
3729 0 : state->context = context;
3730 0 : state->binding_handle = b;
3731 :
3732 0 : state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3733 : context->server.computer);
3734 0 : if (tevent_req_nomem(state->srv_name_slash, req)) {
3735 0 : return tevent_req_post(req, ev);
3736 : }
3737 :
3738 0 : ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3739 : (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3740 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3741 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3742 0 : tevent_req_nterror(req, status);
3743 0 : return tevent_req_post(req, ev);
3744 : }
3745 :
3746 0 : dcerpc_binding_handle_auth_info(state->binding_handle,
3747 0 : &state->auth_type,
3748 0 : &state->auth_level);
3749 :
3750 0 : subreq = netlogon_creds_cli_lock_send(state, state->ev,
3751 0 : state->context);
3752 0 : if (tevent_req_nomem(subreq, req)) {
3753 0 : return tevent_req_post(req, ev);
3754 : }
3755 :
3756 0 : tevent_req_set_callback(subreq,
3757 : netlogon_creds_cli_SendToSam_locked,
3758 : req);
3759 :
3760 0 : return req;
3761 : }
3762 :
3763 0 : static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3764 : NTSTATUS status)
3765 : {
3766 0 : struct netlogon_creds_cli_SendToSam_state *state =
3767 0 : tevent_req_data(req,
3768 : struct netlogon_creds_cli_SendToSam_state);
3769 :
3770 0 : if (state->creds == NULL) {
3771 0 : return;
3772 : }
3773 :
3774 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3775 0 : !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3776 0 : !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3777 0 : !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3778 0 : !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3779 0 : TALLOC_FREE(state->creds);
3780 0 : return;
3781 : }
3782 :
3783 0 : netlogon_creds_cli_delete(state->context, state->creds);
3784 0 : TALLOC_FREE(state->creds);
3785 : }
3786 :
3787 : static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3788 :
3789 0 : static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3790 : {
3791 0 : struct tevent_req *req =
3792 0 : tevent_req_callback_data(subreq,
3793 : struct tevent_req);
3794 0 : struct netlogon_creds_cli_SendToSam_state *state =
3795 0 : tevent_req_data(req,
3796 : struct netlogon_creds_cli_SendToSam_state);
3797 0 : NTSTATUS status;
3798 :
3799 0 : status = netlogon_creds_cli_lock_recv(subreq, state,
3800 : &state->creds);
3801 0 : TALLOC_FREE(subreq);
3802 0 : if (tevent_req_nterror(req, status)) {
3803 0 : return;
3804 : }
3805 :
3806 0 : if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3807 0 : switch (state->auth_level) {
3808 0 : case DCERPC_AUTH_LEVEL_INTEGRITY:
3809 : case DCERPC_AUTH_LEVEL_PRIVACY:
3810 0 : break;
3811 0 : default:
3812 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3813 0 : return;
3814 : }
3815 : } else {
3816 0 : uint32_t tmp = state->creds->negotiate_flags;
3817 :
3818 0 : if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3819 : /*
3820 : * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3821 : * it should be used, which means
3822 : * we had a chance to verify no downgrade
3823 : * happened.
3824 : *
3825 : * This relies on netlogon_creds_cli_check*
3826 : * being called before, as first request after
3827 : * the DCERPC bind.
3828 : */
3829 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3830 0 : return;
3831 : }
3832 : }
3833 :
3834 : /*
3835 : * we defer all callbacks in order to cleanup
3836 : * the database record.
3837 : */
3838 0 : tevent_req_defer_callback(req, state->ev);
3839 :
3840 0 : state->tmp_creds = *state->creds;
3841 0 : status = netlogon_creds_client_authenticator(&state->tmp_creds,
3842 : &state->req_auth);
3843 0 : if (tevent_req_nterror(req, status)) {
3844 0 : return;
3845 : }
3846 0 : ZERO_STRUCT(state->rep_auth);
3847 :
3848 0 : if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3849 0 : status = netlogon_creds_aes_encrypt(&state->tmp_creds,
3850 : state->opaque.data,
3851 : state->opaque.length);
3852 0 : if (tevent_req_nterror(req, status)) {
3853 0 : netlogon_creds_cli_SendToSam_cleanup(req, status);
3854 0 : return;
3855 : }
3856 : } else {
3857 0 : status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
3858 : state->opaque.data,
3859 : state->opaque.length);
3860 0 : if (tevent_req_nterror(req, status)) {
3861 0 : netlogon_creds_cli_SendToSam_cleanup(req, status);
3862 0 : return;
3863 : }
3864 : }
3865 :
3866 0 : subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3867 : state->binding_handle,
3868 0 : state->srv_name_slash,
3869 : state->tmp_creds.computer_name,
3870 : &state->req_auth,
3871 : &state->rep_auth,
3872 : state->opaque.data,
3873 0 : state->opaque.length);
3874 0 : if (tevent_req_nomem(subreq, req)) {
3875 0 : status = NT_STATUS_NO_MEMORY;
3876 0 : netlogon_creds_cli_SendToSam_cleanup(req, status);
3877 0 : return;
3878 : }
3879 :
3880 0 : tevent_req_set_callback(subreq,
3881 : netlogon_creds_cli_SendToSam_done,
3882 : req);
3883 : }
3884 :
3885 0 : static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3886 : {
3887 0 : struct tevent_req *req =
3888 0 : tevent_req_callback_data(subreq,
3889 : struct tevent_req);
3890 0 : struct netlogon_creds_cli_SendToSam_state *state =
3891 0 : tevent_req_data(req,
3892 : struct netlogon_creds_cli_SendToSam_state);
3893 0 : NTSTATUS status;
3894 0 : NTSTATUS result;
3895 0 : bool ok;
3896 :
3897 0 : status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3898 0 : TALLOC_FREE(subreq);
3899 0 : if (tevent_req_nterror(req, status)) {
3900 0 : netlogon_creds_cli_SendToSam_cleanup(req, status);
3901 0 : return;
3902 : }
3903 :
3904 0 : ok = netlogon_creds_client_check(&state->tmp_creds,
3905 0 : &state->rep_auth.cred);
3906 0 : if (!ok) {
3907 0 : status = NT_STATUS_ACCESS_DENIED;
3908 0 : tevent_req_nterror(req, status);
3909 0 : netlogon_creds_cli_SendToSam_cleanup(req, status);
3910 0 : return;
3911 : }
3912 :
3913 0 : *state->creds = state->tmp_creds;
3914 0 : status = netlogon_creds_cli_store(state->context,
3915 : state->creds);
3916 0 : TALLOC_FREE(state->creds);
3917 :
3918 0 : if (tevent_req_nterror(req, status)) {
3919 0 : netlogon_creds_cli_SendToSam_cleanup(req, status);
3920 0 : return;
3921 : }
3922 :
3923 : /*
3924 : * Creds must be stored before we send back application errors
3925 : * e.g. NT_STATUS_NOT_IMPLEMENTED
3926 : */
3927 0 : if (tevent_req_nterror(req, result)) {
3928 0 : netlogon_creds_cli_SendToSam_cleanup(req, result);
3929 0 : return;
3930 : }
3931 :
3932 0 : tevent_req_done(req);
3933 : }
3934 :
3935 0 : NTSTATUS netlogon_creds_cli_SendToSam_recv(struct tevent_req *req)
3936 : {
3937 0 : NTSTATUS status;
3938 :
3939 0 : if (tevent_req_is_nterror(req, &status)) {
3940 0 : netlogon_creds_cli_SendToSam_cleanup(req, status);
3941 0 : tevent_req_received(req);
3942 0 : return status;
3943 : }
3944 :
3945 0 : tevent_req_received(req);
3946 0 : return NT_STATUS_OK;
3947 : }
3948 :
3949 0 : NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3950 : struct dcerpc_binding_handle *b,
3951 : struct netr_SendToSamBase *message)
3952 : {
3953 0 : TALLOC_CTX *frame = talloc_stackframe();
3954 0 : struct tevent_context *ev;
3955 0 : struct tevent_req *req;
3956 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
3957 :
3958 0 : ev = samba_tevent_context_init(frame);
3959 0 : if (ev == NULL) {
3960 0 : goto fail;
3961 : }
3962 0 : req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3963 0 : if (req == NULL) {
3964 0 : goto fail;
3965 : }
3966 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3967 0 : goto fail;
3968 : }
3969 0 : status = netlogon_creds_cli_SendToSam_recv(req);
3970 0 : fail:
3971 0 : TALLOC_FREE(frame);
3972 0 : return status;
3973 : }
3974 :
3975 : struct netlogon_creds_cli_LogonGetDomainInfo_state {
3976 : struct tevent_context *ev;
3977 : struct netlogon_creds_cli_context *context;
3978 : struct dcerpc_binding_handle *binding_handle;
3979 :
3980 : char *srv_name_slash;
3981 : enum dcerpc_AuthType auth_type;
3982 : enum dcerpc_AuthLevel auth_level;
3983 :
3984 : uint32_t level;
3985 : union netr_WorkstationInfo *query;
3986 : union netr_DomainInfo *info;
3987 :
3988 : struct netlogon_creds_CredentialState *creds;
3989 : struct netlogon_creds_CredentialState tmp_creds;
3990 : struct netr_Authenticator req_auth;
3991 : struct netr_Authenticator rep_auth;
3992 : };
3993 :
3994 : static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
3995 : NTSTATUS status);
3996 : static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq);
3997 :
3998 0 : struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
3999 : struct tevent_context *ev,
4000 : struct netlogon_creds_cli_context *context,
4001 : struct dcerpc_binding_handle *b,
4002 : uint32_t level,
4003 : union netr_WorkstationInfo *query)
4004 : {
4005 0 : struct tevent_req *req;
4006 0 : struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
4007 0 : struct tevent_req *subreq;
4008 :
4009 0 : req = tevent_req_create(mem_ctx, &state,
4010 : struct netlogon_creds_cli_LogonGetDomainInfo_state);
4011 0 : if (req == NULL) {
4012 0 : return NULL;
4013 : }
4014 :
4015 0 : state->ev = ev;
4016 0 : state->context = context;
4017 0 : state->binding_handle = b;
4018 :
4019 0 : state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
4020 : context->server.computer);
4021 0 : if (tevent_req_nomem(state->srv_name_slash, req)) {
4022 0 : return tevent_req_post(req, ev);
4023 : }
4024 :
4025 0 : state->level = level;
4026 0 : state->query = query;
4027 0 : state->info = talloc_zero(state, union netr_DomainInfo);
4028 0 : if (tevent_req_nomem(state->info, req)) {
4029 0 : return tevent_req_post(req, ev);
4030 : }
4031 :
4032 0 : dcerpc_binding_handle_auth_info(state->binding_handle,
4033 0 : &state->auth_type,
4034 0 : &state->auth_level);
4035 :
4036 0 : subreq = netlogon_creds_cli_lock_send(state, state->ev,
4037 0 : state->context);
4038 0 : if (tevent_req_nomem(subreq, req)) {
4039 0 : return tevent_req_post(req, ev);
4040 : }
4041 :
4042 0 : tevent_req_set_callback(subreq,
4043 : netlogon_creds_cli_LogonGetDomainInfo_locked,
4044 : req);
4045 :
4046 0 : return req;
4047 : }
4048 :
4049 0 : static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
4050 : NTSTATUS status)
4051 : {
4052 0 : struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4053 0 : tevent_req_data(req,
4054 : struct netlogon_creds_cli_LogonGetDomainInfo_state);
4055 :
4056 0 : if (state->creds == NULL) {
4057 0 : return;
4058 : }
4059 :
4060 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
4061 0 : !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
4062 0 : !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
4063 0 : !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
4064 0 : !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
4065 0 : TALLOC_FREE(state->creds);
4066 0 : return;
4067 : }
4068 :
4069 0 : netlogon_creds_cli_delete(state->context, state->creds);
4070 : }
4071 :
4072 : static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq);
4073 :
4074 0 : static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq)
4075 : {
4076 0 : struct tevent_req *req =
4077 0 : tevent_req_callback_data(subreq,
4078 : struct tevent_req);
4079 0 : struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4080 0 : tevent_req_data(req,
4081 : struct netlogon_creds_cli_LogonGetDomainInfo_state);
4082 0 : NTSTATUS status;
4083 :
4084 0 : status = netlogon_creds_cli_lock_recv(subreq, state,
4085 : &state->creds);
4086 0 : TALLOC_FREE(subreq);
4087 0 : if (tevent_req_nterror(req, status)) {
4088 0 : return;
4089 : }
4090 :
4091 0 : if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
4092 0 : switch (state->auth_level) {
4093 0 : case DCERPC_AUTH_LEVEL_INTEGRITY:
4094 : case DCERPC_AUTH_LEVEL_PRIVACY:
4095 0 : break;
4096 0 : default:
4097 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
4098 0 : return;
4099 : }
4100 : } else {
4101 0 : uint32_t tmp = state->creds->negotiate_flags;
4102 :
4103 0 : if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
4104 : /*
4105 : * if DCERPC_AUTH_TYPE_SCHANNEL is supported
4106 : * it should be used, which means
4107 : * we had a chance to verify no downgrade
4108 : * happened.
4109 : *
4110 : * This relies on netlogon_creds_cli_check*
4111 : * being called before, as first request after
4112 : * the DCERPC bind.
4113 : */
4114 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
4115 0 : return;
4116 : }
4117 : }
4118 :
4119 : /*
4120 : * we defer all callbacks in order to cleanup
4121 : * the database record.
4122 : */
4123 0 : tevent_req_defer_callback(req, state->ev);
4124 :
4125 0 : state->tmp_creds = *state->creds;
4126 0 : status = netlogon_creds_client_authenticator(&state->tmp_creds,
4127 : &state->req_auth);
4128 0 : if (tevent_req_nterror(req, status)) {
4129 0 : return;
4130 : }
4131 0 : ZERO_STRUCT(state->rep_auth);
4132 :
4133 0 : subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev,
4134 : state->binding_handle,
4135 0 : state->srv_name_slash,
4136 : state->tmp_creds.computer_name,
4137 : &state->req_auth,
4138 : &state->rep_auth,
4139 : state->level,
4140 : state->query,
4141 : state->info);
4142 0 : if (tevent_req_nomem(subreq, req)) {
4143 0 : status = NT_STATUS_NO_MEMORY;
4144 0 : netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4145 0 : return;
4146 : }
4147 :
4148 0 : tevent_req_set_callback(subreq,
4149 : netlogon_creds_cli_LogonGetDomainInfo_done,
4150 : req);
4151 : }
4152 :
4153 0 : static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
4154 : {
4155 0 : struct tevent_req *req =
4156 0 : tevent_req_callback_data(subreq,
4157 : struct tevent_req);
4158 0 : struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4159 0 : tevent_req_data(req,
4160 : struct netlogon_creds_cli_LogonGetDomainInfo_state);
4161 0 : NTSTATUS status;
4162 0 : NTSTATUS result;
4163 0 : bool ok;
4164 :
4165 : /*
4166 : * We use state->dns_names as the memory context, as this is
4167 : * the only in/out variable and it has been overwritten by the
4168 : * out parameter from the server.
4169 : *
4170 : * We need to preserve the return value until the caller can use it.
4171 : */
4172 0 : status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result);
4173 0 : TALLOC_FREE(subreq);
4174 0 : if (tevent_req_nterror(req, status)) {
4175 0 : netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4176 0 : return;
4177 : }
4178 :
4179 0 : ok = netlogon_creds_client_check(&state->tmp_creds,
4180 0 : &state->rep_auth.cred);
4181 0 : if (!ok) {
4182 0 : status = NT_STATUS_ACCESS_DENIED;
4183 0 : tevent_req_nterror(req, status);
4184 0 : netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4185 0 : return;
4186 : }
4187 :
4188 0 : if (tevent_req_nterror(req, result)) {
4189 0 : netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
4190 0 : return;
4191 : }
4192 :
4193 0 : *state->creds = state->tmp_creds;
4194 0 : status = netlogon_creds_cli_store(state->context,
4195 : state->creds);
4196 0 : if (tevent_req_nterror(req, status)) {
4197 0 : netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4198 0 : return;
4199 : }
4200 :
4201 0 : tevent_req_done(req);
4202 : }
4203 :
4204 0 : NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
4205 : TALLOC_CTX *mem_ctx,
4206 : union netr_DomainInfo **info)
4207 : {
4208 0 : struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4209 0 : tevent_req_data(req,
4210 : struct netlogon_creds_cli_LogonGetDomainInfo_state);
4211 0 : NTSTATUS status;
4212 :
4213 0 : if (tevent_req_is_nterror(req, &status)) {
4214 0 : netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4215 0 : tevent_req_received(req);
4216 0 : return status;
4217 : }
4218 :
4219 0 : *info = talloc_move(mem_ctx, &state->info);
4220 :
4221 0 : tevent_req_received(req);
4222 0 : return NT_STATUS_OK;
4223 : }
4224 :
4225 0 : NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
4226 : struct netlogon_creds_cli_context *context,
4227 : struct dcerpc_binding_handle *b,
4228 : TALLOC_CTX *mem_ctx,
4229 : uint32_t level,
4230 : union netr_WorkstationInfo *query,
4231 : union netr_DomainInfo **info)
4232 : {
4233 0 : TALLOC_CTX *frame = talloc_stackframe();
4234 0 : struct tevent_context *ev;
4235 0 : struct tevent_req *req;
4236 0 : NTSTATUS status = NT_STATUS_OK;
4237 :
4238 0 : ev = samba_tevent_context_init(frame);
4239 0 : if (ev == NULL) {
4240 0 : goto fail;
4241 : }
4242 0 : req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
4243 : level, query);
4244 0 : if (req == NULL) {
4245 0 : goto fail;
4246 : }
4247 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4248 0 : goto fail;
4249 : }
4250 0 : status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,
4251 : mem_ctx,
4252 : info);
4253 0 : fail:
4254 0 : TALLOC_FREE(frame);
4255 0 : return status;
4256 : }
|