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