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