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