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