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