081b18efb0e301161ddf644e110b78274a7aba5d
[samba.git] / libcli / auth / netlogon_creds_cli.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    module to store/fetch session keys for the schannel client
5
6    Copyright (C) Stefan Metzmacher 2013
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include <tevent.h>
25 #include "lib/util/tevent_ntstatus.h"
26 #include "lib/dbwrap/dbwrap.h"
27 #include "lib/dbwrap/dbwrap_rbt.h"
28 #include "lib/util/util_tdb.h"
29 #include "libcli/security/security.h"
30 #include "../lib/param/param.h"
31 #include "../libcli/auth/schannel.h"
32 #include "../librpc/gen_ndr/ndr_schannel.h"
33 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
34 #include "../librpc/gen_ndr/ndr_netlogon.h"
35 #include "../librpc/gen_ndr/server_id.h"
36 #include "netlogon_creds_cli.h"
37 #include "source3/include/messages.h"
38 #include "source3/include/g_lock.h"
39 #include "libds/common/roles.h"
40 #include "lib/crypto/crypto.h"
41 #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         struct netlogon_creds_cli_locked_state *locked_state;
1088 };
1089
1090 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
1091 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1092
1093 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1094                                 struct tevent_context *ev,
1095                                 struct netlogon_creds_cli_context *context,
1096                                 struct dcerpc_binding_handle *b,
1097                                 uint8_t num_nt_hashes,
1098                                 const struct samr_Password * const *nt_hashes)
1099 {
1100         struct tevent_req *req;
1101         struct netlogon_creds_cli_auth_state *state;
1102         struct netlogon_creds_cli_locked_state *locked_state;
1103         NTSTATUS status;
1104
1105         req = tevent_req_create(mem_ctx, &state,
1106                                 struct netlogon_creds_cli_auth_state);
1107         if (req == NULL) {
1108                 return NULL;
1109         }
1110
1111         state->ev = ev;
1112         state->context = context;
1113         state->binding_handle = b;
1114         if (num_nt_hashes < 1) {
1115                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1116                 return tevent_req_post(req, ev);
1117         }
1118         if (num_nt_hashes > 4) {
1119                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1120                 return tevent_req_post(req, ev);
1121         }
1122
1123         state->num_nt_hashes = num_nt_hashes;
1124         state->idx_nt_hashes = 0;
1125         state->nt_hashes = nt_hashes;
1126
1127         if (context->db.locked_state != NULL) {
1128                 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
1129                 return tevent_req_post(req, ev);
1130         }
1131
1132         locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
1133         if (tevent_req_nomem(locked_state, req)) {
1134                 return tevent_req_post(req, ev);
1135         }
1136         talloc_set_destructor(locked_state,
1137                               netlogon_creds_cli_locked_state_destructor);
1138         locked_state->context = context;
1139
1140         context->db.locked_state = locked_state;
1141         state->locked_state = locked_state;
1142
1143         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1144                                                 context->server.computer);
1145         if (tevent_req_nomem(state->srv_name_slash, req)) {
1146                 return tevent_req_post(req, ev);
1147         }
1148
1149         state->try_auth3 = true;
1150         state->try_auth2 = true;
1151
1152         if (context->client.required_flags != 0) {
1153                 state->require_auth2 = true;
1154         }
1155
1156         state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1157         state->current_flags = context->client.proposed_flags;
1158
1159         if (context->db.g_ctx != NULL) {
1160                 struct tevent_req *subreq;
1161
1162                 subreq = g_lock_lock_send(state, ev,
1163                                           context->db.g_ctx,
1164                                           context->db.key_name,
1165                                           G_LOCK_WRITE);
1166                 if (tevent_req_nomem(subreq, req)) {
1167                         return tevent_req_post(req, ev);
1168                 }
1169                 tevent_req_set_callback(subreq,
1170                                         netlogon_creds_cli_auth_locked,
1171                                         req);
1172
1173                 return req;
1174         }
1175
1176         status = dbwrap_purge(state->context->db.ctx,
1177                               state->context->db.key_data);
1178         if (tevent_req_nterror(req, status)) {
1179                 return tevent_req_post(req, ev);
1180         }
1181
1182         netlogon_creds_cli_auth_challenge_start(req);
1183         if (!tevent_req_is_in_progress(req)) {
1184                 return tevent_req_post(req, ev);
1185         }
1186
1187         return req;
1188 }
1189
1190 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1191 {
1192         struct tevent_req *req =
1193                 tevent_req_callback_data(subreq,
1194                 struct tevent_req);
1195         struct netlogon_creds_cli_auth_state *state =
1196                 tevent_req_data(req,
1197                 struct netlogon_creds_cli_auth_state);
1198         NTSTATUS status;
1199
1200         status = g_lock_lock_recv(subreq);
1201         TALLOC_FREE(subreq);
1202         if (tevent_req_nterror(req, status)) {
1203                 return;
1204         }
1205         state->locked_state->is_glocked = true;
1206
1207         status = dbwrap_purge(state->context->db.ctx,
1208                               state->context->db.key_data);
1209         if (tevent_req_nterror(req, status)) {
1210                 return;
1211         }
1212
1213         netlogon_creds_cli_auth_challenge_start(req);
1214 }
1215
1216 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1217
1218 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1219 {
1220         struct netlogon_creds_cli_auth_state *state =
1221                 tevent_req_data(req,
1222                 struct netlogon_creds_cli_auth_state);
1223         struct tevent_req *subreq;
1224
1225         TALLOC_FREE(state->creds);
1226
1227         generate_random_buffer(state->client_challenge.data,
1228                                sizeof(state->client_challenge.data));
1229
1230         subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1231                                                 state->binding_handle,
1232                                                 state->srv_name_slash,
1233                                                 state->context->client.computer,
1234                                                 &state->client_challenge,
1235                                                 &state->server_challenge);
1236         if (tevent_req_nomem(subreq, req)) {
1237                 return;
1238         }
1239         tevent_req_set_callback(subreq,
1240                                 netlogon_creds_cli_auth_challenge_done,
1241                                 req);
1242 }
1243
1244 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1245
1246 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1247 {
1248         struct tevent_req *req =
1249                 tevent_req_callback_data(subreq,
1250                 struct tevent_req);
1251         struct netlogon_creds_cli_auth_state *state =
1252                 tevent_req_data(req,
1253                 struct netlogon_creds_cli_auth_state);
1254         NTSTATUS status;
1255         NTSTATUS result;
1256
1257         status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1258         TALLOC_FREE(subreq);
1259         if (tevent_req_nterror(req, status)) {
1260                 return;
1261         }
1262         if (tevent_req_nterror(req, result)) {
1263                 return;
1264         }
1265
1266         if (!state->try_auth3 && !state->try_auth2) {
1267                 state->current_flags = 0;
1268         }
1269
1270         /* Calculate the session key and client credentials */
1271
1272         state->creds = netlogon_creds_client_init(state,
1273                                                   state->context->client.account,
1274                                                   state->context->client.computer,
1275                                                   state->context->client.type,
1276                                                   &state->client_challenge,
1277                                                   &state->server_challenge,
1278                                                   state->used_nt_hash,
1279                                                   &state->client_credential,
1280                                                   state->current_flags);
1281         if (tevent_req_nomem(state->creds, req)) {
1282                 return;
1283         }
1284
1285         if (state->try_auth3) {
1286                 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1287                                                 state->binding_handle,
1288                                                 state->srv_name_slash,
1289                                                 state->context->client.account,
1290                                                 state->context->client.type,
1291                                                 state->context->client.computer,
1292                                                 &state->client_credential,
1293                                                 &state->server_credential,
1294                                                 &state->creds->negotiate_flags,
1295                                                 &state->rid);
1296                 if (tevent_req_nomem(subreq, req)) {
1297                         return;
1298                 }
1299         } else if (state->try_auth2) {
1300                 state->rid = 0;
1301
1302                 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1303                                                 state->binding_handle,
1304                                                 state->srv_name_slash,
1305                                                 state->context->client.account,
1306                                                 state->context->client.type,
1307                                                 state->context->client.computer,
1308                                                 &state->client_credential,
1309                                                 &state->server_credential,
1310                                                 &state->creds->negotiate_flags);
1311                 if (tevent_req_nomem(subreq, req)) {
1312                         return;
1313                 }
1314         } else {
1315                 state->rid = 0;
1316
1317                 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1318                                                 state->binding_handle,
1319                                                 state->srv_name_slash,
1320                                                 state->context->client.account,
1321                                                 state->context->client.type,
1322                                                 state->context->client.computer,
1323                                                 &state->client_credential,
1324                                                 &state->server_credential);
1325                 if (tevent_req_nomem(subreq, req)) {
1326                         return;
1327                 }
1328         }
1329         tevent_req_set_callback(subreq,
1330                                 netlogon_creds_cli_auth_srvauth_done,
1331                                 req);
1332 }
1333
1334 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1335 {
1336         struct tevent_req *req =
1337                 tevent_req_callback_data(subreq,
1338                 struct tevent_req);
1339         struct netlogon_creds_cli_auth_state *state =
1340                 tevent_req_data(req,
1341                 struct netlogon_creds_cli_auth_state);
1342         NTSTATUS status;
1343         NTSTATUS result;
1344         bool ok;
1345         enum ndr_err_code ndr_err;
1346         DATA_BLOB blob;
1347         TDB_DATA data;
1348         uint32_t tmp_flags;
1349
1350         if (state->try_auth3) {
1351                 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1352                                                               &result);
1353                 TALLOC_FREE(subreq);
1354                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1355                         state->try_auth3 = false;
1356                         netlogon_creds_cli_auth_challenge_start(req);
1357                         return;
1358                 }
1359                 if (tevent_req_nterror(req, status)) {
1360                         return;
1361                 }
1362         } else if (state->try_auth2) {
1363                 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1364                                                               &result);
1365                 TALLOC_FREE(subreq);
1366                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1367                         state->try_auth2 = false;
1368                         if (state->require_auth2) {
1369                                 status = NT_STATUS_DOWNGRADE_DETECTED;
1370                                 tevent_req_nterror(req, status);
1371                                 return;
1372                         }
1373                         netlogon_creds_cli_auth_challenge_start(req);
1374                         return;
1375                 }
1376                 if (tevent_req_nterror(req, status)) {
1377                         return;
1378                 }
1379         } else {
1380                 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1381                                                              &result);
1382                 TALLOC_FREE(subreq);
1383                 if (tevent_req_nterror(req, status)) {
1384                         return;
1385                 }
1386         }
1387
1388         if (!NT_STATUS_IS_OK(result) &&
1389             !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1390         {
1391                 tevent_req_nterror(req, result);
1392                 return;
1393         }
1394
1395         tmp_flags = state->creds->negotiate_flags;
1396         tmp_flags &= state->context->client.required_flags;
1397         if (tmp_flags != state->context->client.required_flags) {
1398                 if (NT_STATUS_IS_OK(result)) {
1399                         tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1400                         return;
1401                 }
1402                 tevent_req_nterror(req, result);
1403                 return;
1404         }
1405
1406         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1407
1408                 tmp_flags = state->context->client.proposed_flags;
1409                 if ((state->current_flags == tmp_flags) &&
1410                     (state->creds->negotiate_flags != tmp_flags))
1411                 {
1412                         /*
1413                          * lets retry with the negotiated flags
1414                          */
1415                         state->current_flags = state->creds->negotiate_flags;
1416                         netlogon_creds_cli_auth_challenge_start(req);
1417                         return;
1418                 }
1419
1420                 state->idx_nt_hashes += 1;
1421                 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1422                         /*
1423                          * we already retried, giving up...
1424                          */
1425                         tevent_req_nterror(req, result);
1426                         return;
1427                 }
1428
1429                 /*
1430                  * lets retry with the old nt hash.
1431                  */
1432                 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1433                 state->current_flags = state->context->client.proposed_flags;
1434                 netlogon_creds_cli_auth_challenge_start(req);
1435                 return;
1436         }
1437
1438         ok = netlogon_creds_client_check(state->creds,
1439                                          &state->server_credential);
1440         if (!ok) {
1441                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1442                 return;
1443         }
1444
1445         ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1446                 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1447         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1448                 status = ndr_map_error2ntstatus(ndr_err);
1449                 tevent_req_nterror(req, status);
1450                 return;
1451         }
1452
1453         data.dptr = blob.data;
1454         data.dsize = blob.length;
1455
1456         status = dbwrap_store(state->context->db.ctx,
1457                               state->context->db.key_data,
1458                               data, TDB_REPLACE);
1459         TALLOC_FREE(state->locked_state);
1460         if (tevent_req_nterror(req, status)) {
1461                 return;
1462         }
1463
1464         tevent_req_done(req);
1465 }
1466
1467 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1468                                       uint8_t *idx_nt_hashes)
1469 {
1470         struct netlogon_creds_cli_auth_state *state =
1471                 tevent_req_data(req,
1472                 struct netlogon_creds_cli_auth_state);
1473         NTSTATUS status;
1474
1475         *idx_nt_hashes = 0;
1476
1477         if (tevent_req_is_nterror(req, &status)) {
1478                 tevent_req_received(req);
1479                 return status;
1480         }
1481
1482         *idx_nt_hashes = state->idx_nt_hashes;
1483         tevent_req_received(req);
1484         return NT_STATUS_OK;
1485 }
1486
1487 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1488                                  struct dcerpc_binding_handle *b,
1489                                  uint8_t num_nt_hashes,
1490                                  const struct samr_Password * const *nt_hashes,
1491                                  uint8_t *idx_nt_hashes)
1492 {
1493         TALLOC_CTX *frame = talloc_stackframe();
1494         struct tevent_context *ev;
1495         struct tevent_req *req;
1496         NTSTATUS status = NT_STATUS_NO_MEMORY;
1497
1498         *idx_nt_hashes = 0;
1499
1500         ev = samba_tevent_context_init(frame);
1501         if (ev == NULL) {
1502                 goto fail;
1503         }
1504         req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1505                                            num_nt_hashes, nt_hashes);
1506         if (req == NULL) {
1507                 goto fail;
1508         }
1509         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1510                 goto fail;
1511         }
1512         status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1513  fail:
1514         TALLOC_FREE(frame);
1515         return status;
1516 }
1517
1518 struct netlogon_creds_cli_check_state {
1519         struct tevent_context *ev;
1520         struct netlogon_creds_cli_context *context;
1521         struct dcerpc_binding_handle *binding_handle;
1522
1523         char *srv_name_slash;
1524
1525         union netr_Capabilities caps;
1526
1527         struct netlogon_creds_CredentialState *creds;
1528         struct netr_Authenticator req_auth;
1529         struct netr_Authenticator rep_auth;
1530 };
1531
1532 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1533                                              NTSTATUS status);
1534 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1535
1536 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1537                                 struct tevent_context *ev,
1538                                 struct netlogon_creds_cli_context *context,
1539                                 struct dcerpc_binding_handle *b)
1540 {
1541         struct tevent_req *req;
1542         struct netlogon_creds_cli_check_state *state;
1543         struct tevent_req *subreq;
1544         enum dcerpc_AuthType auth_type;
1545         enum dcerpc_AuthLevel auth_level;
1546         NTSTATUS status;
1547
1548         req = tevent_req_create(mem_ctx, &state,
1549                                 struct netlogon_creds_cli_check_state);
1550         if (req == NULL) {
1551                 return NULL;
1552         }
1553
1554         state->ev = ev;
1555         state->context = context;
1556         state->binding_handle = b;
1557
1558         if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1559                 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1560                 return tevent_req_post(req, ev);
1561         }
1562
1563         status = netlogon_creds_cli_get_internal(context, state,
1564                                                  &state->creds);
1565         if (tevent_req_nterror(req, status)) {
1566                 return tevent_req_post(req, ev);
1567         }
1568
1569         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1570                                                 context->server.computer);
1571         if (tevent_req_nomem(state->srv_name_slash, req)) {
1572                 return tevent_req_post(req, ev);
1573         }
1574
1575         dcerpc_binding_handle_auth_info(state->binding_handle,
1576                                         &auth_type, &auth_level);
1577
1578         if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1579                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1580                 return tevent_req_post(req, ev);
1581         }
1582
1583         switch (auth_level) {
1584         case DCERPC_AUTH_LEVEL_INTEGRITY:
1585         case DCERPC_AUTH_LEVEL_PRIVACY:
1586                 break;
1587         default:
1588                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1589                 return tevent_req_post(req, ev);
1590         }
1591
1592         /*
1593          * we defer all callbacks in order to cleanup
1594          * the database record.
1595          */
1596         tevent_req_defer_callback(req, state->ev);
1597
1598         netlogon_creds_client_authenticator(state->creds, &state->req_auth);
1599         ZERO_STRUCT(state->rep_auth);
1600
1601         subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1602                                                 state->binding_handle,
1603                                                 state->srv_name_slash,
1604                                                 state->context->client.computer,
1605                                                 &state->req_auth,
1606                                                 &state->rep_auth,
1607                                                 1,
1608                                                 &state->caps);
1609         if (tevent_req_nomem(subreq, req)) {
1610                 return tevent_req_post(req, ev);
1611         }
1612
1613         tevent_req_set_callback(subreq,
1614                                 netlogon_creds_cli_check_caps,
1615                                 req);
1616
1617         return req;
1618 }
1619
1620 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1621                                              NTSTATUS status)
1622 {
1623         struct netlogon_creds_cli_check_state *state =
1624                 tevent_req_data(req,
1625                 struct netlogon_creds_cli_check_state);
1626
1627         if (state->creds == NULL) {
1628                 return;
1629         }
1630
1631         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1632             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1633             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1634             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1635             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1636                 TALLOC_FREE(state->creds);
1637                 return;
1638         }
1639
1640         netlogon_creds_cli_delete_lck(state->context);
1641         TALLOC_FREE(state->creds);
1642 }
1643
1644 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1645 {
1646         struct tevent_req *req =
1647                 tevent_req_callback_data(subreq,
1648                 struct tevent_req);
1649         struct netlogon_creds_cli_check_state *state =
1650                 tevent_req_data(req,
1651                 struct netlogon_creds_cli_check_state);
1652         NTSTATUS status;
1653         NTSTATUS result;
1654         bool ok;
1655
1656         status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1657                                                        &result);
1658         TALLOC_FREE(subreq);
1659         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1660                 /*
1661                  * Note that the negotiated flags are already checked
1662                  * for our required flags after the ServerAuthenticate3/2 call.
1663                  */
1664                 uint32_t negotiated = state->creds->negotiate_flags;
1665
1666                 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1667                         /*
1668                          * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1669                          * already, we expect this to work!
1670                          */
1671                         status = NT_STATUS_DOWNGRADE_DETECTED;
1672                         tevent_req_nterror(req, status);
1673                         netlogon_creds_cli_check_cleanup(req, status);
1674                         return;
1675                 }
1676
1677                 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1678                         /*
1679                          * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1680                          * we expect this to work at least as far as the
1681                          * NOT_SUPPORTED error handled below!
1682                          *
1683                          * NT 4.0 and Old Samba servers are not
1684                          * allowed without "require strong key = no"
1685                          */
1686                         status = NT_STATUS_DOWNGRADE_DETECTED;
1687                         tevent_req_nterror(req, status);
1688                         netlogon_creds_cli_check_cleanup(req, status);
1689                         return;
1690                 }
1691
1692                 /*
1693                  * If we not require NETLOGON_NEG_SUPPORTS_AES or
1694                  * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1695                  * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1696                  *
1697                  * This is needed against NT 4.0 and old Samba servers.
1698                  *
1699                  * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1700                  * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1701                  * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1702                  * with the next request as the sequence number processing
1703                  * gets out of sync.
1704                  */
1705                 netlogon_creds_cli_check_cleanup(req, status);
1706                 tevent_req_done(req);
1707                 return;
1708         }
1709         if (tevent_req_nterror(req, status)) {
1710                 netlogon_creds_cli_check_cleanup(req, status);
1711                 return;
1712         }
1713
1714         if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1715                 /*
1716                  * Note that the negotiated flags are already checked
1717                  * for our required flags after the ServerAuthenticate3/2 call.
1718                  */
1719                 uint32_t negotiated = state->creds->negotiate_flags;
1720
1721                 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1722                         /*
1723                          * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1724                          * already, we expect this to work!
1725                          */
1726                         status = NT_STATUS_DOWNGRADE_DETECTED;
1727                         tevent_req_nterror(req, status);
1728                         netlogon_creds_cli_check_cleanup(req, status);
1729                         return;
1730                 }
1731
1732                 /*
1733                  * This is ok, the server does not support
1734                  * NETLOGON_NEG_SUPPORTS_AES.
1735                  *
1736                  * netr_LogonGetCapabilities() was
1737                  * netr_LogonDummyRoutine1() before
1738                  * NETLOGON_NEG_SUPPORTS_AES was invented.
1739                  */
1740                 netlogon_creds_cli_check_cleanup(req, result);
1741                 tevent_req_done(req);
1742                 return;
1743         }
1744
1745         ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1746         if (!ok) {
1747                 status = NT_STATUS_ACCESS_DENIED;
1748                 tevent_req_nterror(req, status);
1749                 netlogon_creds_cli_check_cleanup(req, status);
1750                 return;
1751         }
1752
1753         if (tevent_req_nterror(req, result)) {
1754                 netlogon_creds_cli_check_cleanup(req, result);
1755                 return;
1756         }
1757
1758         if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1759                 status = NT_STATUS_DOWNGRADE_DETECTED;
1760                 tevent_req_nterror(req, status);
1761                 netlogon_creds_cli_check_cleanup(req, status);
1762                 return;
1763         }
1764
1765         /*
1766          * This is the key check that makes this check secure.  If we
1767          * get OK here (rather than NOT_SUPPORTED), then the server
1768          * did support AES. If the server only proposed STRONG_KEYS
1769          * and not AES, then it should have failed with
1770          * NOT_IMPLEMENTED. We always send AES as a client, so the
1771          * server should always have returned it.
1772          */
1773         if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1774                 status = NT_STATUS_DOWNGRADE_DETECTED;
1775                 tevent_req_nterror(req, status);
1776                 netlogon_creds_cli_check_cleanup(req, status);
1777                 return;
1778         }
1779
1780         status = netlogon_creds_cli_store_internal(state->context,
1781                                                    state->creds);
1782         if (tevent_req_nterror(req, status)) {
1783                 return;
1784         }
1785
1786         tevent_req_done(req);
1787 }
1788
1789 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1790 {
1791         NTSTATUS status;
1792
1793         if (tevent_req_is_nterror(req, &status)) {
1794                 netlogon_creds_cli_check_cleanup(req, status);
1795                 tevent_req_received(req);
1796                 return status;
1797         }
1798
1799         tevent_req_received(req);
1800         return NT_STATUS_OK;
1801 }
1802
1803 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1804                                   struct dcerpc_binding_handle *b)
1805 {
1806         TALLOC_CTX *frame = talloc_stackframe();
1807         struct tevent_context *ev;
1808         struct tevent_req *req;
1809         NTSTATUS status = NT_STATUS_NO_MEMORY;
1810
1811         ev = samba_tevent_context_init(frame);
1812         if (ev == NULL) {
1813                 goto fail;
1814         }
1815         req = netlogon_creds_cli_check_send(frame, ev, context, b);
1816         if (req == NULL) {
1817                 goto fail;
1818         }
1819         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1820                 goto fail;
1821         }
1822         status = netlogon_creds_cli_check_recv(req);
1823  fail:
1824         TALLOC_FREE(frame);
1825         return status;
1826 }
1827
1828 struct netlogon_creds_cli_ServerPasswordSet_state {
1829         struct tevent_context *ev;
1830         struct netlogon_creds_cli_context *context;
1831         struct dcerpc_binding_handle *binding_handle;
1832         uint32_t old_timeout;
1833
1834         char *srv_name_slash;
1835         enum dcerpc_AuthType auth_type;
1836         enum dcerpc_AuthLevel auth_level;
1837
1838         struct samr_CryptPassword samr_crypt_password;
1839         struct netr_CryptPassword netr_crypt_password;
1840         struct samr_Password samr_password;
1841
1842         struct netlogon_creds_CredentialState *creds;
1843         struct netlogon_creds_CredentialState tmp_creds;
1844         struct netr_Authenticator req_auth;
1845         struct netr_Authenticator rep_auth;
1846 };
1847
1848 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1849                                                      NTSTATUS status);
1850 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1851
1852 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1853                                 struct tevent_context *ev,
1854                                 struct netlogon_creds_cli_context *context,
1855                                 struct dcerpc_binding_handle *b,
1856                                 const DATA_BLOB *new_password,
1857                                 const uint32_t *new_version)
1858 {
1859         struct tevent_req *req;
1860         struct netlogon_creds_cli_ServerPasswordSet_state *state;
1861         struct tevent_req *subreq;
1862         bool ok;
1863
1864         req = tevent_req_create(mem_ctx, &state,
1865                                 struct netlogon_creds_cli_ServerPasswordSet_state);
1866         if (req == NULL) {
1867                 return NULL;
1868         }
1869
1870         state->ev = ev;
1871         state->context = context;
1872         state->binding_handle = b;
1873
1874         if (new_password->length < 14) {
1875                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1876                 return tevent_req_post(req, ev);
1877         }
1878
1879         /*
1880          * netr_ServerPasswordSet
1881          */
1882         mdfour(state->samr_password.hash, new_password->data, new_password->length);
1883
1884         /*
1885          * netr_ServerPasswordSet2
1886          */
1887         ok = set_pw_in_buffer(state->samr_crypt_password.data,
1888                               new_password);
1889         if (!ok) {
1890                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1891                 return tevent_req_post(req, ev);
1892         }
1893
1894         if (new_version != NULL) {
1895                 struct NL_PASSWORD_VERSION version;
1896                 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1897                 uint32_t ofs = 512 - len;
1898                 uint8_t *p;
1899
1900                 if (len > 500) {
1901                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1902                         return tevent_req_post(req, ev);
1903                 }
1904                 ofs -= 12;
1905
1906                 version.ReservedField = 0;
1907                 version.PasswordVersionNumber = *new_version;
1908                 version.PasswordVersionPresent =
1909                         NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1910
1911                 p = state->samr_crypt_password.data + ofs;
1912                 SIVAL(p, 0, version.ReservedField);
1913                 SIVAL(p, 4, version.PasswordVersionNumber);
1914                 SIVAL(p, 8, version.PasswordVersionPresent);
1915         }
1916
1917         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1918                                                 context->server.computer);
1919         if (tevent_req_nomem(state->srv_name_slash, req)) {
1920                 return tevent_req_post(req, ev);
1921         }
1922
1923         dcerpc_binding_handle_auth_info(state->binding_handle,
1924                                         &state->auth_type,
1925                                         &state->auth_level);
1926
1927         subreq = netlogon_creds_cli_lock_send(state, state->ev,
1928                                               state->context);
1929         if (tevent_req_nomem(subreq, req)) {
1930                 return tevent_req_post(req, ev);
1931         }
1932
1933         tevent_req_set_callback(subreq,
1934                                 netlogon_creds_cli_ServerPasswordSet_locked,
1935                                 req);
1936
1937         return req;
1938 }
1939
1940 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1941                                                          NTSTATUS status)
1942 {
1943         struct netlogon_creds_cli_ServerPasswordSet_state *state =
1944                 tevent_req_data(req,
1945                 struct netlogon_creds_cli_ServerPasswordSet_state);
1946
1947         if (state->creds == NULL) {
1948                 return;
1949         }
1950
1951         dcerpc_binding_handle_set_timeout(state->binding_handle,
1952                                           state->old_timeout);
1953
1954         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1955             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1956             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1957             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1958             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1959                 TALLOC_FREE(state->creds);
1960                 return;
1961         }
1962
1963         netlogon_creds_cli_delete(state->context, state->creds);
1964         TALLOC_FREE(state->creds);
1965 }
1966
1967 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1968
1969 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1970 {
1971         struct tevent_req *req =
1972                 tevent_req_callback_data(subreq,
1973                 struct tevent_req);
1974         struct netlogon_creds_cli_ServerPasswordSet_state *state =
1975                 tevent_req_data(req,
1976                 struct netlogon_creds_cli_ServerPasswordSet_state);
1977         NTSTATUS status;
1978
1979         status = netlogon_creds_cli_lock_recv(subreq, state,
1980                                               &state->creds);
1981         TALLOC_FREE(subreq);
1982         if (tevent_req_nterror(req, status)) {
1983                 return;
1984         }
1985
1986         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1987                 switch (state->auth_level) {
1988                 case DCERPC_AUTH_LEVEL_INTEGRITY:
1989                 case DCERPC_AUTH_LEVEL_PRIVACY:
1990                         break;
1991                 default:
1992                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1993                         return;
1994                 }
1995         } else {
1996                 uint32_t tmp = state->creds->negotiate_flags;
1997
1998                 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1999                         /*
2000                          * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2001                          * it should be used, which means
2002                          * we had a chance to verify no downgrade
2003                          * happened.
2004                          *
2005                          * This relies on netlogon_creds_cli_check*
2006                          * being called before, as first request after
2007                          * the DCERPC bind.
2008                          */
2009                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2010                         return;
2011                 }
2012         }
2013
2014         state->old_timeout = dcerpc_binding_handle_set_timeout(
2015                                 state->binding_handle, 600000);
2016
2017         /*
2018          * we defer all callbacks in order to cleanup
2019          * the database record.
2020          */
2021         tevent_req_defer_callback(req, state->ev);
2022
2023         state->tmp_creds = *state->creds;
2024         netlogon_creds_client_authenticator(&state->tmp_creds,
2025                                             &state->req_auth);
2026         ZERO_STRUCT(state->rep_auth);
2027
2028         if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2029
2030                 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
2031                         netlogon_creds_aes_encrypt(&state->tmp_creds,
2032                                         state->samr_crypt_password.data,
2033                                         516);
2034                 } else {
2035                         netlogon_creds_arcfour_crypt(&state->tmp_creds,
2036                                         state->samr_crypt_password.data,
2037                                         516);
2038                 }
2039
2040                 memcpy(state->netr_crypt_password.data,
2041                        state->samr_crypt_password.data, 512);
2042                 state->netr_crypt_password.length =
2043                         IVAL(state->samr_crypt_password.data, 512);
2044
2045                 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2046                                         state->binding_handle,
2047                                         state->srv_name_slash,
2048                                         state->tmp_creds.account_name,
2049                                         state->tmp_creds.secure_channel_type,
2050                                         state->tmp_creds.computer_name,
2051                                         &state->req_auth,
2052                                         &state->rep_auth,
2053                                         &state->netr_crypt_password);
2054                 if (tevent_req_nomem(subreq, req)) {
2055                         status = NT_STATUS_NO_MEMORY;
2056                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2057                         return;
2058                 }
2059         } else {
2060                 netlogon_creds_des_encrypt(&state->tmp_creds,
2061                                            &state->samr_password);
2062
2063                 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2064                                         state->binding_handle,
2065                                         state->srv_name_slash,
2066                                         state->tmp_creds.account_name,
2067                                         state->tmp_creds.secure_channel_type,
2068                                         state->tmp_creds.computer_name,
2069                                         &state->req_auth,
2070                                         &state->rep_auth,
2071                                         &state->samr_password);
2072                 if (tevent_req_nomem(subreq, req)) {
2073                         status = NT_STATUS_NO_MEMORY;
2074                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2075                         return;
2076                 }
2077         }
2078
2079         tevent_req_set_callback(subreq,
2080                                 netlogon_creds_cli_ServerPasswordSet_done,
2081                                 req);
2082 }
2083
2084 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2085 {
2086         struct tevent_req *req =
2087                 tevent_req_callback_data(subreq,
2088                 struct tevent_req);
2089         struct netlogon_creds_cli_ServerPasswordSet_state *state =
2090                 tevent_req_data(req,
2091                 struct netlogon_creds_cli_ServerPasswordSet_state);
2092         NTSTATUS status;
2093         NTSTATUS result;
2094         bool ok;
2095
2096         if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2097                 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2098                                                              &result);
2099                 TALLOC_FREE(subreq);
2100                 if (tevent_req_nterror(req, status)) {
2101                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2102                         return;
2103                 }
2104         } else {
2105                 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2106                                                             &result);
2107                 TALLOC_FREE(subreq);
2108                 if (tevent_req_nterror(req, status)) {
2109                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2110                         return;
2111                 }
2112         }
2113
2114         ok = netlogon_creds_client_check(&state->tmp_creds,
2115                                          &state->rep_auth.cred);
2116         if (!ok) {
2117                 status = NT_STATUS_ACCESS_DENIED;
2118                 tevent_req_nterror(req, status);
2119                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2120                 return;
2121         }
2122
2123         if (tevent_req_nterror(req, result)) {
2124                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2125                 return;
2126         }
2127
2128         dcerpc_binding_handle_set_timeout(state->binding_handle,
2129                                           state->old_timeout);
2130
2131         *state->creds = state->tmp_creds;
2132         status = netlogon_creds_cli_store(state->context,
2133                                           state->creds);
2134         TALLOC_FREE(state->creds);
2135         if (tevent_req_nterror(req, status)) {
2136                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2137                 return;
2138         }
2139
2140         tevent_req_done(req);
2141 }
2142
2143 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2144 {
2145         NTSTATUS status;
2146
2147         if (tevent_req_is_nterror(req, &status)) {
2148                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2149                 tevent_req_received(req);
2150                 return status;
2151         }
2152
2153         tevent_req_received(req);
2154         return NT_STATUS_OK;
2155 }
2156
2157 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2158                                 struct netlogon_creds_cli_context *context,
2159                                 struct dcerpc_binding_handle *b,
2160                                 const DATA_BLOB *new_password,
2161                                 const uint32_t *new_version)
2162 {
2163         TALLOC_CTX *frame = talloc_stackframe();
2164         struct tevent_context *ev;
2165         struct tevent_req *req;
2166         NTSTATUS status = NT_STATUS_NO_MEMORY;
2167
2168         ev = samba_tevent_context_init(frame);
2169         if (ev == NULL) {
2170                 goto fail;
2171         }
2172         req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2173                                                         new_password,
2174                                                         new_version);
2175         if (req == NULL) {
2176                 goto fail;
2177         }
2178         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2179                 goto fail;
2180         }
2181         status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2182  fail:
2183         TALLOC_FREE(frame);
2184         return status;
2185 }
2186
2187 struct netlogon_creds_cli_LogonSamLogon_state {
2188         struct tevent_context *ev;
2189         struct netlogon_creds_cli_context *context;
2190         struct dcerpc_binding_handle *binding_handle;
2191
2192         char *srv_name_slash;
2193
2194         enum netr_LogonInfoClass logon_level;
2195         const union netr_LogonLevel *const_logon;
2196         union netr_LogonLevel *logon;
2197         uint32_t flags;
2198
2199         uint16_t validation_level;
2200         union netr_Validation *validation;
2201         uint8_t authoritative;
2202
2203         /*
2204          * do we need encryption at the application layer?
2205          */
2206         bool user_encrypt;
2207         bool try_logon_ex;
2208         bool try_validation6;
2209
2210         /*
2211          * the read only credentials before we started the operation
2212          * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2213          */
2214         struct netlogon_creds_CredentialState *ro_creds;
2215
2216         /*
2217          * The (locked) credentials used for the credential chain
2218          * used for netr_LogonSamLogonWithFlags() or
2219          * netr_LogonSamLogonWith().
2220          */
2221         struct netlogon_creds_CredentialState *lk_creds;
2222
2223         /*
2224          * While we have locked the global credentials (lk_creds above)
2225          * we operate an a temporary copy, because a server
2226          * may not support netr_LogonSamLogonWithFlags() and
2227          * didn't process our netr_Authenticator, so we need to
2228          * restart from lk_creds.
2229          */
2230         struct netlogon_creds_CredentialState tmp_creds;
2231         struct netr_Authenticator req_auth;
2232         struct netr_Authenticator rep_auth;
2233 };
2234
2235 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2236 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2237                                                      NTSTATUS status);
2238
2239 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2240                                 struct tevent_context *ev,
2241                                 struct netlogon_creds_cli_context *context,
2242                                 struct dcerpc_binding_handle *b,
2243                                 enum netr_LogonInfoClass logon_level,
2244                                 const union netr_LogonLevel *logon,
2245                                 uint32_t flags)
2246 {
2247         struct tevent_req *req;
2248         struct netlogon_creds_cli_LogonSamLogon_state *state;
2249
2250         req = tevent_req_create(mem_ctx, &state,
2251                                 struct netlogon_creds_cli_LogonSamLogon_state);
2252         if (req == NULL) {
2253                 return NULL;
2254         }
2255
2256         state->ev = ev;
2257         state->context = context;
2258         state->binding_handle = b;
2259
2260         state->logon_level = logon_level;
2261         state->const_logon = logon;
2262         state->flags = flags;
2263
2264         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2265                                                 context->server.computer);
2266         if (tevent_req_nomem(state->srv_name_slash, req)) {
2267                 return tevent_req_post(req, ev);
2268         }
2269
2270         switch (logon_level) {
2271         case NetlogonInteractiveInformation:
2272         case NetlogonInteractiveTransitiveInformation:
2273         case NetlogonServiceInformation:
2274         case NetlogonServiceTransitiveInformation:
2275         case NetlogonGenericInformation:
2276                 state->user_encrypt = true;
2277                 break;
2278
2279         case NetlogonNetworkInformation:
2280         case NetlogonNetworkTransitiveInformation:
2281                 break;
2282         }
2283
2284         state->validation = talloc_zero(state, union netr_Validation);
2285         if (tevent_req_nomem(state->validation, req)) {
2286                 return tevent_req_post(req, ev);
2287         }
2288
2289         netlogon_creds_cli_LogonSamLogon_start(req);
2290         if (!tevent_req_is_in_progress(req)) {
2291                 return tevent_req_post(req, ev);
2292         }
2293
2294         /*
2295          * we defer all callbacks in order to cleanup
2296          * the database record.
2297          */
2298         tevent_req_defer_callback(req, state->ev);
2299         return req;
2300 }
2301
2302 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2303                                                      NTSTATUS status)
2304 {
2305         struct netlogon_creds_cli_LogonSamLogon_state *state =
2306                 tevent_req_data(req,
2307                 struct netlogon_creds_cli_LogonSamLogon_state);
2308
2309         if (state->lk_creds == NULL) {
2310                 return;
2311         }
2312
2313         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2314                 /*
2315                  * This is a hack to recover from a bug in old
2316                  * Samba servers, when LogonSamLogonEx() fails:
2317                  *
2318                  * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2319                  *
2320                  * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2321                  *
2322                  * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2323                  * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2324                  * If the sign/seal check fails.
2325                  *
2326                  * In that case we need to cleanup the netlogon session.
2327                  *
2328                  * It's the job of the caller to disconnect the current
2329                  * connection, if netlogon_creds_cli_LogonSamLogon()
2330                  * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2331                  */
2332                 if (!state->context->server.try_logon_with) {
2333                         status = NT_STATUS_NETWORK_ACCESS_DENIED;
2334                 }
2335         }
2336
2337         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2338             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2339             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2340             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2341             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2342                 TALLOC_FREE(state->lk_creds);
2343                 return;
2344         }
2345
2346         netlogon_creds_cli_delete(state->context, state->lk_creds);
2347         TALLOC_FREE(state->lk_creds);
2348 }
2349
2350 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2351
2352 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2353 {
2354         struct netlogon_creds_cli_LogonSamLogon_state *state =
2355                 tevent_req_data(req,
2356                 struct netlogon_creds_cli_LogonSamLogon_state);
2357         struct tevent_req *subreq;
2358         NTSTATUS status;
2359         enum dcerpc_AuthType auth_type;
2360         enum dcerpc_AuthLevel auth_level;
2361
2362         TALLOC_FREE(state->ro_creds);
2363         TALLOC_FREE(state->logon);
2364         ZERO_STRUCTP(state->validation);
2365
2366         dcerpc_binding_handle_auth_info(state->binding_handle,
2367                                         &auth_type, &auth_level);
2368
2369         state->try_logon_ex = state->context->server.try_logon_ex;
2370         state->try_validation6 = state->context->server.try_validation6;
2371
2372         if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2373                 state->try_logon_ex = false;
2374         }
2375
2376         if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2377                 state->try_validation6 = false;
2378         }
2379
2380         if (state->try_logon_ex) {
2381                 if (state->try_validation6) {
2382                         state->validation_level = 6;
2383                 } else {
2384                         state->validation_level = 3;
2385                         state->user_encrypt = true;
2386                 }
2387
2388                 state->logon = netlogon_creds_shallow_copy_logon(state,
2389                                                         state->logon_level,
2390                                                         state->const_logon);
2391                 if (tevent_req_nomem(state->logon, req)) {
2392                         status = NT_STATUS_NO_MEMORY;
2393                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2394                         return;
2395                 }
2396
2397                 if (state->user_encrypt) {
2398                         status = netlogon_creds_cli_get(state->context,
2399                                                         state,
2400                                                         &state->ro_creds);
2401                         if (!NT_STATUS_IS_OK(status)) {
2402                                 status = NT_STATUS_ACCESS_DENIED;
2403                                 tevent_req_nterror(req, status);
2404                                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2405                                 return;
2406                         }
2407
2408                         netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2409                                                               state->logon_level,
2410                                                               state->logon);
2411                 }
2412
2413                 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2414                                                 state->binding_handle,
2415                                                 state->srv_name_slash,
2416                                                 state->context->client.computer,
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                 tevent_req_set_callback(subreq,
2429                                         netlogon_creds_cli_LogonSamLogon_done,
2430                                         req);
2431                 return;
2432         }
2433
2434         if (state->lk_creds == NULL) {
2435                 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2436                                                       state->context);
2437                 if (tevent_req_nomem(subreq, req)) {
2438                         status = NT_STATUS_NO_MEMORY;
2439                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2440                         return;
2441                 }
2442                 tevent_req_set_callback(subreq,
2443                                         netlogon_creds_cli_LogonSamLogon_done,
2444                                         req);
2445                 return;
2446         }
2447
2448         state->tmp_creds = *state->lk_creds;
2449         netlogon_creds_client_authenticator(&state->tmp_creds,
2450                                             &state->req_auth);
2451         ZERO_STRUCT(state->rep_auth);
2452
2453         state->logon = netlogon_creds_shallow_copy_logon(state,
2454                                                 state->logon_level,
2455                                                 state->const_logon);
2456         if (tevent_req_nomem(state->logon, req)) {
2457                 status = NT_STATUS_NO_MEMORY;
2458                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2459                 return;
2460         }
2461
2462         netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2463                                               state->logon_level,
2464                                               state->logon);
2465
2466         state->validation_level = 3;
2467
2468         if (state->context->server.try_logon_with) {
2469                 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2470                                                 state->binding_handle,
2471                                                 state->srv_name_slash,
2472                                                 state->context->client.computer,
2473                                                 &state->req_auth,
2474                                                 &state->rep_auth,
2475                                                 state->logon_level,
2476                                                 state->logon,
2477                                                 state->validation_level,
2478                                                 state->validation,
2479                                                 &state->authoritative,
2480                                                 &state->flags);
2481                 if (tevent_req_nomem(subreq, req)) {
2482                         status = NT_STATUS_NO_MEMORY;
2483                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2484                         return;
2485                 }
2486         } else {
2487                 state->flags = 0;
2488
2489                 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2490                                                 state->binding_handle,
2491                                                 state->srv_name_slash,
2492                                                 state->context->client.computer,
2493                                                 &state->req_auth,
2494                                                 &state->rep_auth,
2495                                                 state->logon_level,
2496                                                 state->logon,
2497                                                 state->validation_level,
2498                                                 state->validation,
2499                                                 &state->authoritative);
2500                 if (tevent_req_nomem(subreq, req)) {
2501                         status = NT_STATUS_NO_MEMORY;
2502                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2503                         return;
2504                 }
2505         }
2506
2507         tevent_req_set_callback(subreq,
2508                                 netlogon_creds_cli_LogonSamLogon_done,
2509                                 req);
2510 }
2511
2512 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2513 {
2514         struct tevent_req *req =
2515                 tevent_req_callback_data(subreq,
2516                 struct tevent_req);
2517         struct netlogon_creds_cli_LogonSamLogon_state *state =
2518                 tevent_req_data(req,
2519                 struct netlogon_creds_cli_LogonSamLogon_state);
2520         NTSTATUS status;
2521         NTSTATUS result;
2522         bool ok;
2523
2524         if (state->try_logon_ex) {
2525                 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2526                                                           state->validation,
2527                                                           &result);
2528                 TALLOC_FREE(subreq);
2529                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2530                         state->context->server.try_validation6 = false;
2531                         state->context->server.try_logon_ex = false;
2532                         netlogon_creds_cli_LogonSamLogon_start(req);
2533                         return;
2534                 }
2535                 if (tevent_req_nterror(req, status)) {
2536                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2537                         return;
2538                 }
2539
2540                 if ((state->validation_level == 6) &&
2541                     (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2542                      NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2543                      NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2544                 {
2545                         state->context->server.try_validation6 = false;
2546                         netlogon_creds_cli_LogonSamLogon_start(req);
2547                         return;
2548                 }
2549
2550                 if (tevent_req_nterror(req, result)) {
2551                         netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2552                         return;
2553                 }
2554
2555                 if (state->ro_creds == NULL) {
2556                         tevent_req_done(req);
2557                         return;
2558                 }
2559
2560                 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2561                 if (!ok) {
2562                         /*
2563                          * We got a race, lets retry with on authenticator
2564                          * protection.
2565                          *
2566                          * netlogon_creds_cli_LogonSamLogon_start()
2567                          * will TALLOC_FREE(state->ro_creds);
2568                          */
2569                         state->try_logon_ex = false;
2570                         netlogon_creds_cli_LogonSamLogon_start(req);
2571                         return;
2572                 }
2573
2574                 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2575                                                         state->validation_level,
2576                                                         state->validation);
2577
2578                 tevent_req_done(req);
2579                 return;
2580         }
2581
2582         if (state->lk_creds == NULL) {
2583                 status = netlogon_creds_cli_lock_recv(subreq, state,
2584                                                       &state->lk_creds);
2585                 TALLOC_FREE(subreq);
2586                 if (tevent_req_nterror(req, status)) {
2587                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2588                         return;
2589                 }
2590
2591                 netlogon_creds_cli_LogonSamLogon_start(req);
2592                 return;
2593         }
2594
2595         if (state->context->server.try_logon_with) {
2596                 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2597                                                                  state->validation,
2598                                                                  &result);
2599                 TALLOC_FREE(subreq);
2600                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2601                         state->context->server.try_logon_with = false;
2602                         netlogon_creds_cli_LogonSamLogon_start(req);
2603                         return;
2604                 }
2605                 if (tevent_req_nterror(req, status)) {
2606                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2607                         return;
2608                 }
2609         } else {
2610                 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2611                                                         state->validation,
2612                                                         &result);
2613                 TALLOC_FREE(subreq);
2614                 if (tevent_req_nterror(req, status)) {
2615                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2616                         return;
2617                 }
2618         }
2619
2620         ok = netlogon_creds_client_check(&state->tmp_creds,
2621                                          &state->rep_auth.cred);
2622         if (!ok) {
2623                 status = NT_STATUS_ACCESS_DENIED;
2624                 tevent_req_nterror(req, status);
2625                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2626                 return;
2627         }
2628
2629         *state->lk_creds = state->tmp_creds;
2630         status = netlogon_creds_cli_store(state->context,
2631                                           state->lk_creds);
2632         TALLOC_FREE(state->lk_creds);
2633
2634         if (tevent_req_nterror(req, status)) {
2635                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2636                 return;
2637         }
2638
2639         if (tevent_req_nterror(req, result)) {
2640                 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2641                 return;
2642         }
2643
2644         netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2645                                                 state->validation_level,
2646                                                 state->validation);
2647
2648         tevent_req_done(req);
2649 }
2650
2651 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2652                                         TALLOC_CTX *mem_ctx,
2653                                         uint16_t *validation_level,
2654                                         union netr_Validation **validation,
2655                                         uint8_t *authoritative,
2656                                         uint32_t *flags)
2657 {
2658         struct netlogon_creds_cli_LogonSamLogon_state *state =
2659                 tevent_req_data(req,
2660                 struct netlogon_creds_cli_LogonSamLogon_state);
2661         NTSTATUS status;
2662
2663         /* authoritative is also returned on error */
2664         *authoritative = state->authoritative;
2665
2666         if (tevent_req_is_nterror(req, &status)) {
2667                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2668                 tevent_req_received(req);
2669                 return status;
2670         }
2671
2672         *validation_level = state->validation_level;
2673         *validation = talloc_move(mem_ctx, &state->validation);
2674         *flags = state->flags;
2675
2676         tevent_req_received(req);
2677         return NT_STATUS_OK;
2678 }
2679
2680 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2681                                 struct netlogon_creds_cli_context *context,
2682                                 struct dcerpc_binding_handle *b,
2683                                 enum netr_LogonInfoClass logon_level,
2684                                 const union netr_LogonLevel *logon,
2685                                 TALLOC_CTX *mem_ctx,
2686                                 uint16_t *validation_level,
2687                                 union netr_Validation **validation,
2688                                 uint8_t *authoritative,
2689                                 uint32_t *flags)
2690 {
2691         TALLOC_CTX *frame = talloc_stackframe();
2692         struct tevent_context *ev;
2693         struct tevent_req *req;
2694         NTSTATUS status = NT_STATUS_NO_MEMORY;
2695
2696         ev = samba_tevent_context_init(frame);
2697         if (ev == NULL) {
2698                 goto fail;
2699         }
2700         req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2701                                                     logon_level, logon,
2702                                                     *flags);
2703         if (req == NULL) {
2704                 goto fail;
2705         }
2706         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2707                 goto fail;
2708         }
2709         status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2710                                                        validation_level,
2711                                                        validation,
2712                                                        authoritative,
2713                                                        flags);
2714  fail:
2715         TALLOC_FREE(frame);
2716         return status;
2717 }
2718
2719 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2720         struct tevent_context *ev;
2721         struct netlogon_creds_cli_context *context;
2722         struct dcerpc_binding_handle *binding_handle;
2723
2724         char *srv_name_slash;
2725         enum dcerpc_AuthType auth_type;
2726         enum dcerpc_AuthLevel auth_level;
2727
2728         const char *site_name;
2729         uint32_t dns_ttl;
2730         struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2731
2732         struct netlogon_creds_CredentialState *creds;
2733         struct netlogon_creds_CredentialState tmp_creds;
2734         struct netr_Authenticator req_auth;
2735         struct netr_Authenticator rep_auth;
2736 };
2737
2738 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2739                                                      NTSTATUS status);
2740 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2741
2742 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2743                                                                              struct tevent_context *ev,
2744                                                                              struct netlogon_creds_cli_context *context,
2745                                                                              struct dcerpc_binding_handle *b,
2746                                                                              const char *site_name,
2747                                                                              uint32_t dns_ttl,
2748                                                                              struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2749 {
2750         struct tevent_req *req;
2751         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2752         struct tevent_req *subreq;
2753
2754         req = tevent_req_create(mem_ctx, &state,
2755                                 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2756         if (req == NULL) {
2757                 return NULL;
2758         }
2759
2760         state->ev = ev;
2761         state->context = context;
2762         state->binding_handle = b;
2763
2764         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2765                                                 context->server.computer);
2766         if (tevent_req_nomem(state->srv_name_slash, req)) {
2767                 return tevent_req_post(req, ev);
2768         }
2769
2770         state->site_name = site_name;
2771         state->dns_ttl = dns_ttl;
2772         state->dns_names = dns_names;
2773
2774         dcerpc_binding_handle_auth_info(state->binding_handle,
2775                                         &state->auth_type,
2776                                         &state->auth_level);
2777
2778         subreq = netlogon_creds_cli_lock_send(state, state->ev,
2779                                               state->context);
2780         if (tevent_req_nomem(subreq, req)) {
2781                 return tevent_req_post(req, ev);
2782         }
2783
2784         tevent_req_set_callback(subreq,
2785                                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2786                                 req);
2787
2788         return req;
2789 }
2790
2791 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2792                                                          NTSTATUS status)
2793 {
2794         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2795                 tevent_req_data(req,
2796                 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2797
2798         if (state->creds == NULL) {
2799                 return;
2800         }
2801
2802         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2803             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2804             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2805             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2806             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2807                 TALLOC_FREE(state->creds);
2808                 return;
2809         }
2810
2811         netlogon_creds_cli_delete(state->context, state->creds);
2812         TALLOC_FREE(state->creds);
2813 }
2814
2815 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2816
2817 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2818 {
2819         struct tevent_req *req =
2820                 tevent_req_callback_data(subreq,
2821                 struct tevent_req);
2822         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2823                 tevent_req_data(req,
2824                 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2825         NTSTATUS status;
2826
2827         status = netlogon_creds_cli_lock_recv(subreq, state,
2828                                               &state->creds);
2829         TALLOC_FREE(subreq);
2830         if (tevent_req_nterror(req, status)) {
2831                 return;
2832         }
2833
2834         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2835                 switch (state->auth_level) {
2836                 case DCERPC_AUTH_LEVEL_INTEGRITY:
2837                 case DCERPC_AUTH_LEVEL_PRIVACY:
2838                         break;
2839                 default:
2840                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2841                         return;
2842                 }
2843         } else {
2844                 uint32_t tmp = state->creds->negotiate_flags;
2845
2846                 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2847                         /*
2848                          * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2849                          * it should be used, which means
2850                          * we had a chance to verify no downgrade
2851                          * happened.
2852                          *
2853                          * This relies on netlogon_creds_cli_check*
2854                          * being called before, as first request after
2855                          * the DCERPC bind.
2856                          */
2857                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2858                         return;
2859                 }
2860         }
2861
2862         /*
2863          * we defer all callbacks in order to cleanup
2864          * the database record.
2865          */
2866         tevent_req_defer_callback(req, state->ev);
2867
2868         state->tmp_creds = *state->creds;
2869         netlogon_creds_client_authenticator(&state->tmp_creds,
2870                                             &state->req_auth);
2871         ZERO_STRUCT(state->rep_auth);
2872
2873         subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2874                                                                     state->binding_handle,
2875                                                                     state->srv_name_slash,
2876                                                                     state->tmp_creds.computer_name,
2877                                                                     &state->req_auth,
2878                                                                     &state->rep_auth,
2879                                                                     state->site_name,
2880                                                                     state->dns_ttl,
2881                                                                     state->dns_names);
2882         if (tevent_req_nomem(subreq, req)) {
2883                 status = NT_STATUS_NO_MEMORY;
2884                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2885                 return;
2886         }
2887
2888         tevent_req_set_callback(subreq,
2889                                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2890                                 req);
2891 }
2892
2893 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2894 {
2895         struct tevent_req *req =
2896                 tevent_req_callback_data(subreq,
2897                 struct tevent_req);
2898         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2899                 tevent_req_data(req,
2900                 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2901         NTSTATUS status;
2902         NTSTATUS result;
2903         bool ok;
2904
2905         /*
2906          * We use state->dns_names as the memory context, as this is
2907          * the only in/out variable and it has been overwritten by the
2908          * out parameter from the server.
2909          *
2910          * We need to preserve the return value until the caller can use it.
2911          */
2912         status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2913                                                                     &result);
2914         TALLOC_FREE(subreq);
2915         if (tevent_req_nterror(req, status)) {
2916                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2917                 return;
2918         }
2919
2920         ok = netlogon_creds_client_check(&state->tmp_creds,
2921                                          &state->rep_auth.cred);
2922         if (!ok) {
2923                 status = NT_STATUS_ACCESS_DENIED;
2924                 tevent_req_nterror(req, status);
2925                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2926                 return;
2927         }
2928
2929         *state->creds = state->tmp_creds;
2930         status = netlogon_creds_cli_store(state->context,
2931                                           state->creds);
2932         TALLOC_FREE(state->creds);
2933
2934         if (tevent_req_nterror(req, status)) {
2935                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2936                 return;
2937         }
2938
2939         if (tevent_req_nterror(req, result)) {
2940                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2941                 return;
2942         }
2943
2944         tevent_req_done(req);
2945 }
2946
2947 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2948 {
2949         NTSTATUS status;
2950
2951         if (tevent_req_is_nterror(req, &status)) {
2952                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2953                 tevent_req_received(req);
2954                 return status;
2955         }
2956
2957         tevent_req_received(req);
2958         return NT_STATUS_OK;
2959 }
2960
2961 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2962                                 struct netlogon_creds_cli_context *context,
2963                                 struct dcerpc_binding_handle *b,
2964                                 const char *site_name,
2965                                 uint32_t dns_ttl,
2966                                 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2967 {
2968         TALLOC_CTX *frame = talloc_stackframe();
2969         struct tevent_context *ev;
2970         struct tevent_req *req;
2971         NTSTATUS status = NT_STATUS_NO_MEMORY;
2972
2973         ev = samba_tevent_context_init(frame);
2974         if (ev == NULL) {
2975                 goto fail;
2976         }
2977         req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2978                                                                         site_name,
2979                                                                         dns_ttl,
2980                                                                         dns_names);
2981         if (req == NULL) {
2982                 goto fail;
2983         }
2984         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2985                 goto fail;
2986         }
2987         status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2988  fail:
2989         TALLOC_FREE(frame);
2990         return status;
2991 }
2992
2993 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2994         struct tevent_context *ev;
2995         struct netlogon_creds_cli_context *context;
2996         struct dcerpc_binding_handle *binding_handle;
2997
2998         char *srv_name_slash;
2999         enum dcerpc_AuthType auth_type;
3000         enum dcerpc_AuthLevel auth_level;
3001
3002         struct samr_Password new_owf_password;
3003         struct samr_Password old_owf_password;
3004         struct netr_TrustInfo *trust_info;
3005
3006         struct netlogon_creds_CredentialState *creds;
3007         struct netlogon_creds_CredentialState tmp_creds;
3008         struct netr_Authenticator req_auth;
3009         struct netr_Authenticator rep_auth;
3010 };
3011
3012 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3013                                                      NTSTATUS status);
3014 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
3015
3016 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
3017                                         struct tevent_context *ev,
3018                                         struct netlogon_creds_cli_context *context,
3019                                         struct dcerpc_binding_handle *b)
3020 {
3021         struct tevent_req *req;
3022         struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
3023         struct tevent_req *subreq;
3024
3025         req = tevent_req_create(mem_ctx, &state,
3026                                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3027         if (req == NULL) {
3028                 return NULL;
3029         }
3030
3031         state->ev = ev;
3032         state->context = context;
3033         state->binding_handle = b;
3034
3035         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3036                                                 context->server.computer);
3037         if (tevent_req_nomem(state->srv_name_slash, req)) {
3038                 return tevent_req_post(req, ev);
3039         }
3040
3041         dcerpc_binding_handle_auth_info(state->binding_handle,
3042                                         &state->auth_type,
3043                                         &state->auth_level);
3044
3045         subreq = netlogon_creds_cli_lock_send(state, state->ev,
3046                                               state->context);
3047         if (tevent_req_nomem(subreq, req)) {
3048                 return tevent_req_post(req, ev);
3049         }
3050
3051         tevent_req_set_callback(subreq,
3052                                 netlogon_creds_cli_ServerGetTrustInfo_locked,
3053                                 req);
3054
3055         return req;
3056 }
3057
3058 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3059                                                          NTSTATUS status)
3060 {
3061         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3062                 tevent_req_data(req,
3063                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3064
3065         if (state->creds == NULL) {
3066                 return;
3067         }
3068
3069         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3070             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3071             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3072             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3073             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3074                 TALLOC_FREE(state->creds);
3075                 return;
3076         }
3077
3078         netlogon_creds_cli_delete(state->context, state->creds);
3079         TALLOC_FREE(state->creds);
3080 }
3081
3082 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3083
3084 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3085 {
3086         struct tevent_req *req =
3087                 tevent_req_callback_data(subreq,
3088                 struct tevent_req);
3089         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3090                 tevent_req_data(req,
3091                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3092         NTSTATUS status;
3093
3094         status = netlogon_creds_cli_lock_recv(subreq, state,
3095                                               &state->creds);
3096         TALLOC_FREE(subreq);
3097         if (tevent_req_nterror(req, status)) {
3098                 return;
3099         }
3100
3101         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3102                 switch (state->auth_level) {
3103                 case DCERPC_AUTH_LEVEL_PRIVACY:
3104                         break;
3105                 default:
3106                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3107                         return;
3108                 }
3109         } else {
3110                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3111                 return;
3112         }
3113
3114         /*
3115          * we defer all callbacks in order to cleanup
3116          * the database record.
3117          */
3118         tevent_req_defer_callback(req, state->ev);
3119
3120         state->tmp_creds = *state->creds;
3121         netlogon_creds_client_authenticator(&state->tmp_creds,
3122                                             &state->req_auth);
3123         ZERO_STRUCT(state->rep_auth);
3124
3125         subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3126                                                      state->binding_handle,
3127                                                      state->srv_name_slash,
3128                                                      state->tmp_creds.account_name,
3129                                                      state->tmp_creds.secure_channel_type,
3130                                                      state->tmp_creds.computer_name,
3131                                                      &state->req_auth,
3132                                                      &state->rep_auth,
3133                                                      &state->new_owf_password,
3134                                                      &state->old_owf_password,
3135                                                      &state->trust_info);
3136         if (tevent_req_nomem(subreq, req)) {
3137                 status = NT_STATUS_NO_MEMORY;
3138                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3139                 return;
3140         }
3141
3142         tevent_req_set_callback(subreq,
3143                                 netlogon_creds_cli_ServerGetTrustInfo_done,
3144                                 req);
3145 }
3146
3147 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3148 {
3149         struct tevent_req *req =
3150                 tevent_req_callback_data(subreq,
3151                 struct tevent_req);
3152         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3153                 tevent_req_data(req,
3154                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3155         NTSTATUS status;
3156         NTSTATUS result;
3157         const struct samr_Password zero = {};
3158         int cmp;
3159         bool ok;
3160
3161         /*
3162          * We use state->dns_names as the memory context, as this is
3163          * the only in/out variable and it has been overwritten by the
3164          * out parameter from the server.
3165          *
3166          * We need to preserve the return value until the caller can use it.
3167          */
3168         status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3169         TALLOC_FREE(subreq);
3170         if (tevent_req_nterror(req, status)) {
3171                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3172                 return;
3173         }
3174
3175         ok = netlogon_creds_client_check(&state->tmp_creds,
3176                                          &state->rep_auth.cred);
3177         if (!ok) {
3178                 status = NT_STATUS_ACCESS_DENIED;
3179                 tevent_req_nterror(req, status);
3180                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3181                 return;
3182         }
3183
3184         cmp = memcmp(state->new_owf_password.hash,
3185                      zero.hash, sizeof(zero.hash));
3186         if (cmp != 0) {
3187                 netlogon_creds_des_decrypt(&state->tmp_creds,
3188                                            &state->new_owf_password);
3189         }
3190         cmp = memcmp(state->old_owf_password.hash,
3191                      zero.hash, sizeof(zero.hash));
3192         if (cmp != 0) {
3193                 netlogon_creds_des_decrypt(&state->tmp_creds,
3194                                            &state->old_owf_password);
3195         }
3196
3197         *state->creds = state->tmp_creds;
3198         status = netlogon_creds_cli_store(state->context,
3199                                           state->creds);
3200         TALLOC_FREE(state->creds);
3201         if (tevent_req_nterror(req, status)) {
3202                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3203                 return;
3204         }
3205
3206         if (tevent_req_nterror(req, result)) {
3207                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3208                 return;
3209         }
3210
3211         tevent_req_done(req);
3212 }
3213
3214 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3215                                         TALLOC_CTX *mem_ctx,
3216                                         struct samr_Password *new_owf_password,
3217                                         struct samr_Password *old_owf_password,
3218                                         struct netr_TrustInfo **trust_info)
3219 {
3220         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3221                 tevent_req_data(req,
3222                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3223         NTSTATUS status;
3224
3225         if (tevent_req_is_nterror(req, &status)) {
3226                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3227                 tevent_req_received(req);
3228                 return status;
3229         }
3230
3231         if (new_owf_password != NULL) {
3232                 *new_owf_password = state->new_owf_password;
3233         }
3234         if (old_owf_password != NULL) {
3235                 *old_owf_password = state->old_owf_password;
3236         }
3237         if (trust_info != NULL) {
3238                 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3239         }
3240
3241         tevent_req_received(req);
3242         return NT_STATUS_OK;
3243 }
3244
3245 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3246                                 struct netlogon_creds_cli_context *context,
3247                                 struct dcerpc_binding_handle *b,
3248                                 TALLOC_CTX *mem_ctx,
3249                                 struct samr_Password *new_owf_password,
3250                                 struct samr_Password *old_owf_password,
3251                                 struct netr_TrustInfo **trust_info)
3252 {
3253         TALLOC_CTX *frame = talloc_stackframe();
3254         struct tevent_context *ev;
3255         struct tevent_req *req;
3256         NTSTATUS status = NT_STATUS_NO_MEMORY;
3257
3258         ev = samba_tevent_context_init(frame);
3259         if (ev == NULL) {
3260                 goto fail;
3261         }
3262         req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3263         if (req == NULL) {
3264                 goto fail;
3265         }
3266         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3267                 goto fail;
3268         }
3269         status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3270                                                             mem_ctx,
3271                                                             new_owf_password,
3272                                                             old_owf_password,
3273                                                             trust_info);
3274  fail:
3275         TALLOC_FREE(frame);
3276         return status;
3277 }
3278
3279 struct netlogon_creds_cli_GetForestTrustInformation_state {
3280         struct tevent_context *ev;
3281         struct netlogon_creds_cli_context *context;
3282         struct dcerpc_binding_handle *binding_handle;
3283
3284         char *srv_name_slash;
3285         enum dcerpc_AuthType auth_type;
3286         enum dcerpc_AuthLevel auth_level;
3287
3288         uint32_t flags;
3289         struct lsa_ForestTrustInformation *forest_trust_info;
3290
3291         struct netlogon_creds_CredentialState *creds;
3292         struct netlogon_creds_CredentialState tmp_creds;
3293         struct netr_Authenticator req_auth;
3294         struct netr_Authenticator rep_auth;
3295 };
3296
3297 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3298                                                      NTSTATUS status);
3299 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3300
3301 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3302                                         struct tevent_context *ev,
3303                                         struct netlogon_creds_cli_context *context,
3304                                         struct dcerpc_binding_handle *b)
3305 {
3306         struct tevent_req *req;
3307         struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3308         struct tevent_req *subreq;
3309
3310         req = tevent_req_create(mem_ctx, &state,
3311                                 struct netlogon_creds_cli_GetForestTrustInformation_state);
3312         if (req == NULL) {
3313                 return NULL;
3314         }
3315
3316         state->ev = ev;
3317         state->context = context;
3318         state->binding_handle = b;
3319
3320         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3321                                                 context->server.computer);
3322         if (tevent_req_nomem(state->srv_name_slash, req)) {
3323                 return tevent_req_post(req, ev);
3324         }
3325
3326         state->flags = 0;
3327
3328         dcerpc_binding_handle_auth_info(state->binding_handle,
3329                                         &state->auth_type,
3330                                         &state->auth_level);
3331
3332         subreq = netlogon_creds_cli_lock_send(state, state->ev,
3333                                               state->context);
3334         if (tevent_req_nomem(subreq, req)) {
3335                 return tevent_req_post(req, ev);
3336         }
3337
3338         tevent_req_set_callback(subreq,
3339                                 netlogon_creds_cli_GetForestTrustInformation_locked,
3340                                 req);
3341
3342         return req;
3343 }
3344
3345 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3346                                                          NTSTATUS status)
3347 {
3348         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3349                 tevent_req_data(req,
3350                 struct netlogon_creds_cli_GetForestTrustInformation_state);
3351
3352         if (state->creds == NULL) {
3353                 return;
3354         }
3355
3356         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3357             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3358             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3359             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3360             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3361                 TALLOC_FREE(state->creds);
3362                 return;
3363         }
3364
3365         netlogon_creds_cli_delete(state->context, state->creds);
3366         TALLOC_FREE(state->creds);
3367 }
3368
3369 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3370
3371 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3372 {
3373         struct tevent_req *req =
3374                 tevent_req_callback_data(subreq,
3375                 struct tevent_req);
3376         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3377                 tevent_req_data(req,
3378                 struct netlogon_creds_cli_GetForestTrustInformation_state);
3379         NTSTATUS status;
3380
3381         status = netlogon_creds_cli_lock_recv(subreq, state,
3382                                               &state->creds);
3383         TALLOC_FREE(subreq);
3384         if (tevent_req_nterror(req, status)) {
3385                 return;
3386         }
3387
3388         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3389                 switch (state->auth_level) {
3390                 case DCERPC_AUTH_LEVEL_INTEGRITY:
3391                 case DCERPC_AUTH_LEVEL_PRIVACY:
3392                         break;
3393                 default:
3394                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3395                         return;
3396                 }
3397         } else {
3398                 uint32_t tmp = state->creds->negotiate_flags;
3399
3400                 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3401                         /*
3402                          * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3403                          * it should be used, which means
3404                          * we had a chance to verify no downgrade
3405                          * happened.
3406                          *
3407                          * This relies on netlogon_creds_cli_check*
3408                          * being called before, as first request after
3409                          * the DCERPC bind.
3410                          */
3411                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3412                         return;
3413                 }
3414         }
3415
3416         /*
3417          * we defer all callbacks in order to cleanup
3418          * the database record.
3419          */
3420         tevent_req_defer_callback(req, state->ev);
3421
3422         state->tmp_creds = *state->creds;
3423         netlogon_creds_client_authenticator(&state->tmp_creds,
3424                                             &state->req_auth);
3425         ZERO_STRUCT(state->rep_auth);
3426
3427         subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3428                                                 state->binding_handle,
3429                                                 state->srv_name_slash,
3430                                                 state->tmp_creds.computer_name,
3431                                                 &state->req_auth,
3432                                                 &state->rep_auth,
3433                                                 state->flags,
3434                                                 &state->forest_trust_info);
3435         if (tevent_req_nomem(subreq, req)) {
3436                 status = NT_STATUS_NO_MEMORY;
3437                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3438                 return;
3439         }
3440
3441         tevent_req_set_callback(subreq,
3442                                 netlogon_creds_cli_GetForestTrustInformation_done,
3443                                 req);
3444 }
3445
3446 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3447 {
3448         struct tevent_req *req =
3449                 tevent_req_callback_data(subreq,
3450                 struct tevent_req);
3451         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3452                 tevent_req_data(req,
3453                 struct netlogon_creds_cli_GetForestTrustInformation_state);
3454         NTSTATUS status;
3455         NTSTATUS result;
3456         bool ok;
3457
3458         /*
3459          * We use state->dns_names as the memory context, as this is
3460          * the only in/out variable and it has been overwritten by the
3461          * out parameter from the server.
3462          *
3463          * We need to preserve the return value until the caller can use it.
3464          */
3465         status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3466         TALLOC_FREE(subreq);
3467         if (tevent_req_nterror(req, status)) {
3468                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3469                 return;
3470         }
3471
3472         ok = netlogon_creds_client_check(&state->tmp_creds,
3473                                          &state->rep_auth.cred);
3474         if (!ok) {
3475                 status = NT_STATUS_ACCESS_DENIED;
3476                 tevent_req_nterror(req, status);
3477                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3478                 return;
3479         }
3480
3481         *state->creds = state->tmp_creds;
3482         status = netlogon_creds_cli_store(state->context,
3483                                           state->creds);
3484         TALLOC_FREE(state->creds);
3485
3486         if (tevent_req_nterror(req, status)) {
3487                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3488                 return;
3489         }
3490
3491         if (tevent_req_nterror(req, result)) {
3492                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3493                 return;
3494         }
3495
3496         tevent_req_done(req);
3497 }
3498
3499 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3500                         TALLOC_CTX *mem_ctx,
3501                         struct lsa_ForestTrustInformation **forest_trust_info)
3502 {
3503         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3504                 tevent_req_data(req,
3505                 struct netlogon_creds_cli_GetForestTrustInformation_state);
3506         NTSTATUS status;
3507
3508         if (tevent_req_is_nterror(req, &status)) {
3509                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3510                 tevent_req_received(req);
3511                 return status;
3512         }
3513
3514         *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3515
3516         tevent_req_received(req);
3517         return NT_STATUS_OK;
3518 }
3519
3520 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3521                         struct netlogon_creds_cli_context *context,
3522                         struct dcerpc_binding_handle *b,
3523                         TALLOC_CTX *mem_ctx,
3524                         struct lsa_ForestTrustInformation **forest_trust_info)
3525 {
3526         TALLOC_CTX *frame = talloc_stackframe();
3527         struct tevent_context *ev;
3528         struct tevent_req *req;
3529         NTSTATUS status = NT_STATUS_NO_MEMORY;
3530
3531         ev = samba_tevent_context_init(frame);
3532         if (ev == NULL) {
3533                 goto fail;
3534         }
3535         req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3536         if (req == NULL) {
3537                 goto fail;
3538         }
3539         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3540                 goto fail;
3541         }
3542         status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3543                                                         mem_ctx,
3544                                                         forest_trust_info);
3545  fail:
3546         TALLOC_FREE(frame);
3547         return status;
3548 }
3549
3550 struct netlogon_creds_cli_SendToSam_state {
3551         struct tevent_context *ev;
3552         struct netlogon_creds_cli_context *context;
3553         struct dcerpc_binding_handle *binding_handle;
3554
3555         char *srv_name_slash;
3556         enum dcerpc_AuthType auth_type;
3557         enum dcerpc_AuthLevel auth_level;
3558
3559         DATA_BLOB opaque;
3560
3561         struct netlogon_creds_CredentialState *creds;
3562         struct netlogon_creds_CredentialState tmp_creds;
3563         struct netr_Authenticator req_auth;
3564         struct netr_Authenticator rep_auth;
3565 };
3566
3567 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3568                                                                  NTSTATUS status);
3569 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3570
3571 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3572                                                      struct tevent_context *ev,
3573                                                      struct netlogon_creds_cli_context *context,
3574                                                      struct dcerpc_binding_handle *b,
3575                                                      struct netr_SendToSamBase *message)
3576 {
3577         struct tevent_req *req;
3578         struct netlogon_creds_cli_SendToSam_state *state;
3579         struct tevent_req *subreq;
3580         enum ndr_err_code ndr_err;
3581
3582         req = tevent_req_create(mem_ctx, &state,
3583                                 struct netlogon_creds_cli_SendToSam_state);
3584         if (req == NULL) {
3585                 return NULL;
3586         }
3587
3588         state->ev = ev;
3589         state->context = context;
3590         state->binding_handle = b;
3591
3592         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3593                                                 context->server.computer);
3594         if (tevent_req_nomem(state->srv_name_slash, req)) {
3595                 return tevent_req_post(req, ev);
3596         }
3597
3598         ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3599                                        (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3600         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3601                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3602                 tevent_req_nterror(req, status);
3603                 return tevent_req_post(req, ev);
3604         }
3605
3606         dcerpc_binding_handle_auth_info(state->binding_handle,
3607                                         &state->auth_type,
3608                                         &state->auth_level);
3609
3610         subreq = netlogon_creds_cli_lock_send(state, state->ev,
3611                                               state->context);
3612         if (tevent_req_nomem(subreq, req)) {
3613                 return tevent_req_post(req, ev);
3614         }
3615
3616         tevent_req_set_callback(subreq,
3617                                 netlogon_creds_cli_SendToSam_locked,
3618                                 req);
3619
3620         return req;
3621 }
3622
3623 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3624                                                          NTSTATUS status)
3625 {
3626         struct netlogon_creds_cli_SendToSam_state *state =
3627                 tevent_req_data(req,
3628                 struct netlogon_creds_cli_SendToSam_state);
3629
3630         if (state->creds == NULL) {
3631                 return;
3632         }
3633
3634         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3635             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3636             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3637             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3638             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3639                 TALLOC_FREE(state->creds);
3640                 return;
3641         }
3642
3643         netlogon_creds_cli_delete(state->context, state->creds);
3644         TALLOC_FREE(state->creds);
3645 }
3646
3647 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3648
3649 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3650 {
3651         struct tevent_req *req =
3652                 tevent_req_callback_data(subreq,
3653                 struct tevent_req);
3654         struct netlogon_creds_cli_SendToSam_state *state =
3655                 tevent_req_data(req,
3656                 struct netlogon_creds_cli_SendToSam_state);
3657         NTSTATUS status;
3658
3659         status = netlogon_creds_cli_lock_recv(subreq, state,
3660                                               &state->creds);
3661         TALLOC_FREE(subreq);
3662         if (tevent_req_nterror(req, status)) {
3663                 return;
3664         }
3665
3666         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3667                 switch (state->auth_level) {
3668                 case DCERPC_AUTH_LEVEL_INTEGRITY:
3669                 case DCERPC_AUTH_LEVEL_PRIVACY:
3670                         break;
3671                 default:
3672                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3673                         return;
3674                 }
3675         } else {
3676                 uint32_t tmp = state->creds->negotiate_flags;
3677
3678                 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3679                         /*
3680                          * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3681                          * it should be used, which means
3682                          * we had a chance to verify no downgrade
3683                          * happened.
3684                          *
3685                          * This relies on netlogon_creds_cli_check*
3686                          * being called before, as first request after
3687                          * the DCERPC bind.
3688                          */
3689                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3690                         return;
3691                 }
3692         }
3693
3694         /*
3695          * we defer all callbacks in order to cleanup
3696          * the database record.
3697          */
3698         tevent_req_defer_callback(req, state->ev);
3699
3700         state->tmp_creds = *state->creds;
3701         netlogon_creds_client_authenticator(&state->tmp_creds,
3702                                             &state->req_auth);
3703         ZERO_STRUCT(state->rep_auth);
3704
3705         if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3706                 netlogon_creds_aes_encrypt(&state->tmp_creds,
3707                                            state->opaque.data,
3708                                            state->opaque.length);
3709         } else {
3710                 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3711                                              state->opaque.data,
3712                                              state->opaque.length);
3713         }
3714
3715         subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3716                                                      state->binding_handle,
3717                                                      state->srv_name_slash,
3718                                                      state->tmp_creds.computer_name,
3719                                                      &state->req_auth,
3720                                                      &state->rep_auth,
3721                                                      state->opaque.data,
3722                                                      state->opaque.length);
3723         if (tevent_req_nomem(subreq, req)) {
3724                 status = NT_STATUS_NO_MEMORY;
3725                 netlogon_creds_cli_SendToSam_cleanup(req, status);
3726                 return;
3727         }
3728
3729         tevent_req_set_callback(subreq,
3730                                 netlogon_creds_cli_SendToSam_done,
3731                                 req);
3732 }
3733
3734 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3735 {
3736         struct tevent_req *req =
3737                 tevent_req_callback_data(subreq,
3738                 struct tevent_req);
3739         struct netlogon_creds_cli_SendToSam_state *state =
3740                 tevent_req_data(req,
3741                 struct netlogon_creds_cli_SendToSam_state);
3742         NTSTATUS status;
3743         NTSTATUS result;
3744         bool ok;
3745
3746         status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3747         TALLOC_FREE(subreq);
3748         if (tevent_req_nterror(req, status)) {
3749                 netlogon_creds_cli_SendToSam_cleanup(req, status);
3750                 return;
3751         }
3752
3753         ok = netlogon_creds_client_check(&state->tmp_creds,
3754                                          &state->rep_auth.cred);
3755         if (!ok) {
3756                 status = NT_STATUS_ACCESS_DENIED;
3757                 tevent_req_nterror(req, status);
3758                 netlogon_creds_cli_SendToSam_cleanup(req, status);
3759                 return;
3760         }
3761
3762         *state->creds = state->tmp_creds;
3763         status = netlogon_creds_cli_store(state->context,
3764                                           state->creds);
3765         TALLOC_FREE(state->creds);
3766
3767         if (tevent_req_nterror(req, status)) {
3768                 netlogon_creds_cli_SendToSam_cleanup(req, status);
3769                 return;
3770         }
3771
3772         /*
3773          * Creds must be stored before we send back application errors
3774          * e.g. NT_STATUS_NOT_IMPLEMENTED
3775          */
3776         if (tevent_req_nterror(req, result)) {
3777                 netlogon_creds_cli_SendToSam_cleanup(req, result);
3778                 return;
3779         }
3780
3781         tevent_req_done(req);
3782 }
3783
3784 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3785                                       struct dcerpc_binding_handle *b,
3786                                       struct netr_SendToSamBase *message)
3787 {
3788         TALLOC_CTX *frame = talloc_stackframe();
3789         struct tevent_context *ev;
3790         struct tevent_req *req;
3791         NTSTATUS status = NT_STATUS_OK;
3792
3793         ev = samba_tevent_context_init(frame);
3794         if (ev == NULL) {
3795                 goto fail;
3796         }
3797         req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3798         if (req == NULL) {
3799                 goto fail;
3800         }
3801         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3802                 goto fail;
3803         }
3804
3805         /* Ignore the result */
3806  fail:
3807         TALLOC_FREE(frame);
3808         return status;
3809 }