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