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