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