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