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