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