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