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