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