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