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