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