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