libcli/auth/netlogon_creds_cli.c
[metze/samba/wip.git] / libcli / auth / netlogon_creds_cli.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    module to store/fetch session keys for the schannel client
5
6    Copyright (C) Stefan Metzmacher 2013
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include <tevent.h>
25 #include "lib/util/tevent_ntstatus.h"
26 #include "lib/dbwrap/dbwrap.h"
27 #include "lib/dbwrap/dbwrap_rbt.h"
28 #include "lib/util/util_tdb.h"
29 #include "libcli/security/security.h"
30 #include "../lib/param/param.h"
31 #include "../libcli/auth/schannel.h"
32 #include "../librpc/gen_ndr/ndr_schannel.h"
33 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
34 #include "netlogon_creds_cli.h"
35
36 struct netlogon_creds_cli_context {
37         struct {
38                 const char *computer;
39                 const char *account;
40                 uint32_t proposed_flags;
41                 uint32_t required_flags;
42                 enum netr_SchannelType type;
43         } client;
44
45         struct {
46                 const char *computer;
47                 const char *netbios_domain;
48                 uint32_t cached_flags;
49                 bool try_validation6;
50                 bool try_logon_ex;
51                 bool try_logon_with;
52         } server;
53
54         struct {
55                 const char *key_name;
56                 TDB_DATA key_data;
57                 struct db_context *ctx;
58                 struct g_lock_ctx *g_ctx;
59         } db;
60 };
61
62 static NTSTATUS netlogon_creds_cli_context_common(
63                                 const char *client_computer,
64                                 const char *client_account,
65                                 enum netr_SchannelType type,
66                                 uint32_t proposed_flags,
67                                 uint32_t required_flags,
68                                 const char *server_computer,
69                                 const char *server_netbios_domain,
70                                 TALLOC_CTX *mem_ctx,
71                                 struct netlogon_creds_cli_context **_context)
72 {
73         struct netlogon_creds_cli_context *context = NULL;
74
75         *_context = NULL;
76
77         context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
78         if (context == NULL) {
79                 return NT_STATUS_NO_MEMORY;
80         }
81
82         context->client.computer = talloc_strdup(context, client_computer);
83         if (context->client.computer == NULL) {
84                 talloc_free(context);
85                 return NT_STATUS_NO_MEMORY;
86         }
87
88         context->client.account = talloc_strdup(context, client_account);
89         if (context->client.account == NULL) {
90                 talloc_free(context);
91                 return NT_STATUS_NO_MEMORY;
92         }
93
94         context->client.proposed_flags = proposed_flags;
95         context->client.required_flags = required_flags;
96         context->client.type = type;
97
98         context->server.computer = talloc_strdup(context, server_computer);
99         if (context->server.computer == NULL) {
100                 talloc_free(context);
101                 return NT_STATUS_NO_MEMORY;
102         }
103
104         context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
105         if (context->server.netbios_domain == NULL) {
106                 talloc_free(context);
107                 return NT_STATUS_NO_MEMORY;
108         }
109
110         context->db.key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%s/%s]",
111                                              client_computer,
112                                              client_account,
113                                              server_computer,
114                                              server_netbios_domain);
115         if (context->db.key_name == NULL) {
116                 talloc_free(context);
117                 return NT_STATUS_NO_MEMORY;
118         }
119
120         context->db.key_data = string_term_tdb_data(context->db.key_name);
121
122         *_context = context;
123         return NT_STATUS_OK;
124 }
125
126 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
127                                 const char *client_account,
128                                 enum netr_SchannelType type,
129                                 const char *server_computer,
130                                 const char *server_netbios_domain,
131                                 TALLOC_CTX *mem_ctx,
132                                 struct netlogon_creds_cli_context **_context)
133 {
134         static struct db_context *global_db = NULL;
135         char *fname = NULL;
136         NTSTATUS status;
137         struct netlogon_creds_cli_context *context = NULL;
138         const char *client_computer;
139         uint32_t proposed_flags;
140         uint32_t required_flags = 0;
141         bool reject_md5_servers = false;
142         bool require_strong_key = false;
143         int require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
144
145         *_context = NULL;
146
147         client_computer = lpcfg_netbios_name(lp_ctx);
148
149         //TODO: add lpcfp_reject_md5_servers()
150         reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
151                                              "__default__",
152                                              "reject md5 servers",
153                                              reject_md5_servers);
154         /*
155          * allow overwrite per domain
156          * reject md5 servers:<netbios_domain>
157          */
158         reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
159                                              "reject md5 servers",
160                                              server_netbios_domain,
161                                              reject_md5_servers);
162
163         //TODO: add lpcfp_require_strong_key()
164         require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
165                                              "__default__",
166                                              "require strong key",
167                                              require_strong_key);
168         /*
169          * allow overwrite per domain
170          * require strong key:<netbios_domain>
171          */
172         require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
173                                              "require strong key",
174                                              server_netbios_domain,
175                                              require_strong_key);
176
177         proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
178         proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
179
180         if (reject_md5_servers) {
181                 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
182                 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
183                 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
184         }
185
186         if (require_strong_key) {
187                 required_flags |= NETLOGON_NEG_STRONG_KEYS;
188                 required_flags |= NETLOGON_NEG_ARCFOUR;
189                 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
190         }
191
192         if (require_sign_or_seal == true) {
193                 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
194         }
195
196         status = netlogon_creds_cli_context_common(client_account,
197                                                    client_computer,
198                                                    type,
199                                                    proposed_flags,
200                                                    required_flags,
201                                                    server_computer,
202                                                    server_netbios_domain,
203                                                    mem_ctx,
204                                                    &context);
205         if (!NT_STATUS_IS_OK(status)) {
206                 return status;
207         }
208
209         if (global_db != NULL) {
210                 context->db.ctx = global_db;
211                 *_context = context;
212                 return NT_STATUS_OK;
213         }
214
215         fname = lpcfg_private_db_path(context, lp_ctx, "netlogon_creds_cli");
216         if (fname == NULL) {
217                 talloc_free(context);
218                 return NT_STATUS_NO_MEMORY;
219         }
220
221         global_db = dbwrap_local_open(talloc_autofree_context(), lp_ctx,
222                                       fname, 0,
223                                       TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
224                                       O_RDWR|O_CREAT,
225                                       0600, DBWRAP_LOCK_ORDER_2);
226         if (global_db == NULL) {
227                 DEBUG(0,("netlogon_creds_cli_context_global: Failed to open %s - %s\n",
228                          fname, strerror(errno)));
229                 talloc_free(context);
230                 return NT_STATUS_NO_MEMORY;
231         }
232         TALLOC_FREE(fname);
233
234         context->db.ctx = global_db;
235         *_context = context;
236         return NT_STATUS_OK;
237 }
238
239 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_account,
240                                 const char *client_computer,
241                                 enum netr_SchannelType type,
242                                 uint32_t proposed_flags,
243                                 uint32_t required_flags,
244                                 const char *server_computer,
245                                 const char *server_netbios_domain,
246                                 TALLOC_CTX *mem_ctx,
247                                 struct netlogon_creds_cli_context **_context)
248 {
249         NTSTATUS status;
250         struct netlogon_creds_cli_context *context = NULL;
251
252         *_context = NULL;
253
254         status = netlogon_creds_cli_context_common(client_account,
255                                                  client_computer,
256                                                  type,
257                                                  proposed_flags,
258                                                  required_flags,
259                                                  server_computer,
260                                                  server_netbios_domain,
261                                                  mem_ctx,
262                                                  &context);
263         if (!NT_STATUS_IS_OK(status)) {
264                 return status;
265         }
266
267         context->db.ctx = db_open_rbt(context);
268         if (context->db.ctx == NULL) {
269                 talloc_free(context);
270                 return NT_STATUS_NO_MEMORY;
271         }
272
273         *_context = context;
274         return NT_STATUS_OK;
275 }
276
277 struct netlogon_creds_cli_fetch_state {
278         TALLOC_CTX *mem_ctx;
279         struct netlogon_creds_CredentialState *creds;
280         NTSTATUS status;
281 };
282
283 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
284                                             void *private_data)
285 {
286         struct netlogon_creds_cli_fetch_state *state =
287                 (struct netlogon_creds_cli_fetch_state *)private_data;
288         enum ndr_err_code ndr_err;
289         DATA_BLOB blob;
290
291         state->creds = talloc_zero(state->mem_ctx,
292                                    struct netlogon_creds_CredentialState);
293         if (state->creds == NULL) {
294                 state->status = NT_STATUS_NO_MEMORY;
295                 return;
296         }
297
298         blob.data = data.dptr;
299         blob.length = data.dsize;
300
301         ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
302                 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
303         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
304                 TALLOC_FREE(state->creds);
305                 state->status = ndr_map_error2ntstatus(ndr_err);
306                 return;
307         }
308
309         state->status = NT_STATUS_OK;
310 }
311
312 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
313                                 TALLOC_CTX *mem_ctx,
314                                 struct netlogon_creds_CredentialState **_creds)
315 {
316         NTSTATUS status;
317         struct netlogon_creds_cli_fetch_state fstate = {
318                 .mem_ctx = mem_ctx,
319                 .status = NT_STATUS_INTERNAL_ERROR,
320         };
321         static const struct netr_Credential zero_creds;
322
323         *_creds = NULL;
324
325         status = dbwrap_parse_record(context->db.ctx,
326                                      context->db.key_data,
327                                      netlogon_creds_cli_fetch_parser,
328                                      &fstate);
329         if (!NT_STATUS_IS_OK(status)) {
330                 return status;
331         }
332         status = fstate.status;
333         if (!NT_STATUS_IS_OK(status)) {
334                 return status;
335         }
336
337         /*
338          * mark it as invalid for step operations.
339          */
340         fstate.creds->sequence = 0;
341         fstate.creds->seed = zero_creds;
342         fstate.creds->client = zero_creds;
343         fstate.creds->server = zero_creds;
344
345         if (context->server.cached_flags == fstate.creds->negotiate_flags) {
346                 *_creds = fstate.creds;
347                 return NT_STATUS_OK;
348         }
349
350         context->server.cached_flags = fstate.creds->negotiate_flags;
351         context->server.try_validation6 = true;
352         context->server.try_logon_ex = true;
353         context->server.try_logon_with = true;
354
355         if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
356                 context->server.try_validation6 = false;
357                 context->server.try_logon_ex = false;
358         }
359         if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
360                 context->server.try_validation6 = false;
361         }
362
363         *_creds = fstate.creds;
364         return NT_STATUS_OK;
365 }
366
367 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
368                         const struct netlogon_creds_CredentialState *creds1)
369 {
370         TALLOC_CTX *frame = talloc_stackframe();
371         struct netlogon_creds_CredentialState *creds2;
372         NTSTATUS status;
373
374         status = netlogon_creds_cli_get(context, frame, &creds2);
375         if (!NT_STATUS_IS_OK(status)) {
376                 TALLOC_FREE(frame);
377                 return false;
378         }
379
380         if (creds1->negotiate_flags != creds2->negotiate_flags) {
381                 TALLOC_FREE(frame);
382                 return false;
383         }
384         if (memcmp(creds1->session_key, creds2->session_key, 16) != 0) {
385                 TALLOC_FREE(frame);
386                 return false;
387         }
388
389         if (creds1->sequence != creds2->sequence) {
390                 TALLOC_FREE(frame);
391                 return false;
392         }
393
394         if (memcmp(&creds1->seed, &creds2->seed, sizeof(creds2->seed)) != 0) {
395                 TALLOC_FREE(frame);
396                 return false;
397         }
398
399         if (memcmp(&creds1->client, &creds2->client, sizeof(creds2->client)) != 0) {
400                 TALLOC_FREE(frame);
401                 return false;
402         }
403
404         if (memcmp(&creds1->server, &creds2->server, sizeof(creds2->server)) != 0) {
405                 TALLOC_FREE(frame);
406                 return false;
407         }
408
409         if (creds1->secure_channel_type != creds2->secure_channel_type) {
410                 TALLOC_FREE(frame);
411                 return false;
412         }
413
414         if (!strequal(creds1->computer_name, creds2->computer_name)) {
415                 TALLOC_FREE(frame);
416                 return false;
417         }
418
419         if (!strequal(creds1->account_name, creds2->account_name)) {
420                 TALLOC_FREE(frame);
421                 return false;
422         }
423
424         if (dom_sid_compare(creds1->sid, creds2->sid) != 0) {
425                 TALLOC_FREE(frame);
426                 return false;
427         }
428
429         TALLOC_FREE(frame);
430         return true;
431 }
432
433 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
434                                   struct netlogon_creds_CredentialState **_creds)
435 {
436         struct netlogon_creds_CredentialState *creds = *_creds;
437         NTSTATUS status;
438         enum ndr_err_code ndr_err;
439         DATA_BLOB blob;
440         TDB_DATA data;
441         static const struct netr_Credential zero_creds;
442         bool valid = false;
443
444         *_creds = NULL;
445
446         if (creds->sequence != 0) {
447                 valid = true;
448         } else if (memcmp(&creds->seed, &zero_creds, sizeof(zero_creds)) != 0) {
449                 valid = true;
450         } else if (memcmp(&creds->client, &zero_creds, sizeof(zero_creds)) != 0) {
451                 valid = true;
452         } else if (memcmp(&creds->server, &zero_creds, sizeof(zero_creds)) != 0) {
453                 valid = true;
454         }
455
456         if (!valid) {
457                 /*
458                  * this was the result of netlogon_creds_cli_get()
459                  * which only gives a valid read only session key.
460                  */
461                 TALLOC_FREE(creds);
462                 return NT_STATUS_INVALID_PAGE_PROTECTION;
463         }
464
465         ndr_err = ndr_push_struct_blob(&blob, creds, creds,
466                 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
467         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
468                 TALLOC_FREE(creds);
469                 status = ndr_map_error2ntstatus(ndr_err);
470                 return status;
471         }
472
473         data.dptr = blob.data;
474         data.dsize = blob.length;
475
476         status = dbwrap_store(context->db.ctx,
477                               context->db.key_data,
478                               data, TDB_REPLACE);
479         TALLOC_FREE(creds);
480         if (!NT_STATUS_IS_OK(status)) {
481                 return status;
482         }
483
484         return NT_STATUS_OK;
485 }
486
487 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
488                                    struct netlogon_creds_CredentialState **_creds)
489 {
490         struct netlogon_creds_CredentialState *creds = *_creds;
491         NTSTATUS status;
492         static const struct netr_Credential zero_creds;
493         bool valid = false;
494
495         *_creds = NULL;
496
497         if (creds->sequence != 0) {
498                 valid = true;
499         } else if (memcmp(&creds->seed, &zero_creds, sizeof(zero_creds)) != 0) {
500                 valid = true;
501         } else if (memcmp(&creds->client, &zero_creds, sizeof(zero_creds)) != 0) {
502                 valid = true;
503         } else if (memcmp(&creds->server, &zero_creds, sizeof(zero_creds)) != 0) {
504                 valid = true;
505         }
506
507         if (!valid) {
508                 /*
509                  * this was the result of netlogon_creds_cli_get()
510                  * which only gives a valid read only session key.
511                  */
512                 TALLOC_FREE(creds);
513                 return NT_STATUS_INVALID_PAGE_PROTECTION;
514         }
515
516         status = dbwrap_delete(context->db.ctx,
517                                context->db.key_data);
518         TALLOC_FREE(creds);
519         if (!NT_STATUS_IS_OK(status)) {
520                 return status;
521         }
522
523         return NT_STATUS_OK;
524 }
525
526 struct netlogon_creds_cli_lock_state {
527         struct netlogon_creds_CredentialState *creds;
528 };
529
530 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
531                                 struct tevent_context *ev,
532                                 struct netlogon_creds_cli_context *context)
533 {
534         struct tevent_req *req;
535         struct netlogon_creds_cli_lock_state *state;
536         struct netlogon_creds_cli_fetch_state fstate = {
537                 .status = NT_STATUS_INTERNAL_ERROR,
538         };
539         NTSTATUS status;
540
541         req = tevent_req_create(mem_ctx, &state,
542                                 struct netlogon_creds_cli_lock_state);
543         if (req == NULL) {
544                 return NULL;
545         }
546
547         fstate.mem_ctx = state;
548         status = dbwrap_parse_record(context->db.ctx,
549                                      context->db.key_data,
550                                      netlogon_creds_cli_fetch_parser,
551                                      &fstate);
552         if (tevent_req_nterror(req, status)) {
553                 return tevent_req_post(req, ev);
554         }
555         status = fstate.status;
556         if (tevent_req_nterror(req, status)) {
557                 return tevent_req_post(req, ev);
558         }
559
560         if (context->server.cached_flags == fstate.creds->negotiate_flags) {
561                 state->creds = fstate.creds;
562                 tevent_req_done(req);
563                 return tevent_req_post(req, ev);
564         }
565
566         context->server.cached_flags = fstate.creds->negotiate_flags;
567         context->server.try_validation6 = true;
568         context->server.try_logon_ex = true;
569         context->server.try_logon_with = true;
570
571         if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
572                 context->server.try_validation6 = false;
573                 context->server.try_logon_ex = false;
574         }
575         if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
576                 context->server.try_validation6 = false;
577         }
578
579         state->creds = fstate.creds;
580         tevent_req_done(req);
581         return tevent_req_post(req, ev);
582 }
583
584 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
585                         TALLOC_CTX *mem_ctx,
586                         struct netlogon_creds_CredentialState **creds)
587 {
588         struct netlogon_creds_cli_lock_state *state =
589                 tevent_req_data(req,
590                 struct netlogon_creds_cli_lock_state);
591         NTSTATUS status;
592
593         if (tevent_req_is_nterror(req, &status)) {
594                 tevent_req_received(req);
595                 return status;
596         }
597
598         *creds = talloc_move(mem_ctx, &state->creds);
599         tevent_req_received(req);
600         return NT_STATUS_OK;
601 }
602
603 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
604                         TALLOC_CTX *mem_ctx,
605                         struct netlogon_creds_CredentialState **creds)
606 {
607         TALLOC_CTX *frame = talloc_stackframe();
608         struct tevent_context *ev;
609         struct tevent_req *req;
610         NTSTATUS status = NT_STATUS_NO_MEMORY;
611
612         ev = samba_tevent_context_init(frame);
613         if (ev == NULL) {
614                 goto fail;
615         }
616         req = netlogon_creds_cli_lock_send(frame, ev, context);
617         if (req == NULL) {
618                 goto fail;
619         }
620         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
621                 goto fail;
622         }
623         status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
624  fail:
625         TALLOC_FREE(frame);
626         return status;
627 }
628
629 struct netlogon_creds_cli_auth_state {
630         struct tevent_context *ev;
631         struct netlogon_creds_cli_context *context;
632         struct dcerpc_binding_handle *binding_handle;
633         struct samr_Password current_nt_hash;
634         struct samr_Password previous_nt_hash;
635         struct samr_Password used_nt_hash;
636         char *srv_name_slash;
637         uint32_t current_flags;
638         struct netr_Credential client_challenge;
639         struct netr_Credential server_challenge;
640         struct netlogon_creds_CredentialState *creds;
641         struct netr_Credential client_credential;
642         struct netr_Credential server_credential;
643         uint32_t rid;
644         bool try_auth3;
645         bool try_auth2;
646         bool require_auth2;
647         bool try_previous_nt_hash;
648 };
649
650 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
651
652 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
653                                 struct tevent_context *ev,
654                                 struct netlogon_creds_cli_context *context,
655                                 struct dcerpc_binding_handle *b,
656                                 struct samr_Password current_nt_hash,
657                                 const struct samr_Password *previous_nt_hash)
658 {
659         struct tevent_req *req;
660         struct netlogon_creds_cli_auth_state *state;
661         NTSTATUS status;
662
663         req = tevent_req_create(mem_ctx, &state,
664                                 struct netlogon_creds_cli_auth_state);
665         if (req == NULL) {
666                 return NULL;
667         }
668
669         state->ev = ev;
670         state->context = context;
671         state->binding_handle = b;
672         state->current_nt_hash = current_nt_hash;
673         if (previous_nt_hash != NULL) {
674                 state->previous_nt_hash = *previous_nt_hash;
675                 state->try_previous_nt_hash = true;
676         }
677
678         state->used_nt_hash = state->current_nt_hash;
679
680         if (context->client.required_flags & NETLOGON_NEG_SUPPORTS_AES) {
681                 state->try_auth2 = true;
682                 state->require_auth2 = true;
683         }
684
685         if (context->client.required_flags & NETLOGON_NEG_STRONG_KEYS) {
686                 state->try_auth2 = true;
687                 state->require_auth2 = true;
688         }
689
690         state->current_flags = context->client.proposed_flags;
691
692         if (state->current_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
693                 state->try_auth3 = true;
694                 state->try_auth2 = true;
695         }
696
697         state->srv_name_slash = talloc_asprintf(state, "\\%s",
698                                                 context->server.computer);
699         if (tevent_req_nomem(state->srv_name_slash, req)) {
700                 return tevent_req_post(req, ev);
701         }
702
703         status = dbwrap_delete(state->context->db.ctx,
704                                state->context->db.key_data);
705         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
706                 status = NT_STATUS_OK;
707         }
708         if (tevent_req_nterror(req, status)) {
709                 return tevent_req_post(req, ev);
710         }
711
712         netlogon_creds_cli_auth_challenge_start(req);
713
714         if (!tevent_req_is_in_progress(req)) {
715                 return tevent_req_post(req, ev);
716         }
717
718         return req;
719 }
720
721 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
722
723 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
724 {
725         struct netlogon_creds_cli_auth_state *state =
726                 tevent_req_data(req,
727                 struct netlogon_creds_cli_auth_state);
728         struct tevent_req *subreq;
729
730         generate_random_buffer(state->client_challenge.data,
731                                sizeof(state->client_challenge.data));
732
733         subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
734                                                 state->binding_handle,
735                                                 state->srv_name_slash,
736                                                 state->context->client.computer,
737                                                 &state->client_challenge,
738                                                 &state->server_challenge);
739         if (tevent_req_nomem(subreq, req)) {
740                 return;
741         }
742         tevent_req_set_callback(subreq,
743                                 netlogon_creds_cli_auth_challenge_done,
744                                 req);
745 }
746
747 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
748
749 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
750 {
751         struct tevent_req *req =
752                 tevent_req_callback_data(subreq,
753                 struct tevent_req);
754         struct netlogon_creds_cli_auth_state *state =
755                 tevent_req_data(req,
756                 struct netlogon_creds_cli_auth_state);
757         NTSTATUS status;
758         NTSTATUS result;
759
760         status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
761         TALLOC_FREE(subreq);
762         if (tevent_req_nterror(req, status)) {
763                 return;
764         }
765         if (tevent_req_nterror(req, result)) {
766                 return;
767         }
768
769         /* Calculate the session key and client credentials */
770
771         state->creds = netlogon_creds_client_init(state,
772                                                   state->context->client.account,
773                                                   state->context->client.computer,
774                                                   &state->client_challenge,
775                                                   &state->server_challenge,
776                                                   &state->used_nt_hash,
777                                                   &state->client_credential,
778                                                   state->current_flags);
779         if (tevent_req_nomem(state->creds, req)) {
780                 return;
781         }
782
783         if (state->try_auth3) {
784                 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
785                                                 state->binding_handle,
786                                                 state->srv_name_slash,
787                                                 state->context->client.account,
788                                                 state->context->client.type,
789                                                 state->context->client.computer,
790                                                 &state->client_credential,
791                                                 &state->server_credential,
792                                                 &state->creds->negotiate_flags,
793                                                 &state->rid);
794                 if (tevent_req_nomem(subreq, req)) {
795                         return;
796                 }
797         } else if (state->try_auth2) {
798                 state->rid = 0;
799
800                 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
801                                                 state->binding_handle,
802                                                 state->srv_name_slash,
803                                                 state->context->client.account,
804                                                 state->context->client.type,
805                                                 state->context->client.computer,
806                                                 &state->client_credential,
807                                                 &state->server_credential,
808                                                 &state->creds->negotiate_flags);
809                 if (tevent_req_nomem(subreq, req)) {
810                         return;
811                 }
812         } else {
813                 state->rid = 0;
814                 /*
815                  * keep old samba versions happy.
816                  */
817                 state->creds->negotiate_flags = NETLOGON_NEG_AUTHENTICATED_RPC;
818
819                 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
820                                                 state->binding_handle,
821                                                 state->srv_name_slash,
822                                                 state->context->client.account,
823                                                 state->context->client.type,
824                                                 state->context->client.computer,
825                                                 &state->client_credential,
826                                                 &state->server_credential);
827                 if (tevent_req_nomem(subreq, req)) {
828                         return;
829                 }
830         }
831         tevent_req_set_callback(subreq,
832                                 netlogon_creds_cli_auth_srvauth_done,
833                                 req);
834 }
835
836 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
837 {
838         struct tevent_req *req =
839                 tevent_req_callback_data(subreq,
840                 struct tevent_req);
841         struct netlogon_creds_cli_auth_state *state =
842                 tevent_req_data(req,
843                 struct netlogon_creds_cli_auth_state);
844         NTSTATUS status;
845         NTSTATUS result;
846         bool ok;
847         enum ndr_err_code ndr_err;
848         DATA_BLOB blob;
849         TDB_DATA data;
850         uint32_t tmp_flags;
851
852         if (state->try_auth3) {
853                 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
854                                                               &result);
855                 TALLOC_FREE(subreq);
856                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
857                         state->try_auth3 = false;
858                         TALLOC_FREE(state->creds);
859                         netlogon_creds_cli_auth_challenge_start(req);
860                         return;
861                 }
862                 if (tevent_req_nterror(req, status)) {
863                         return;
864                 }
865         } else if (state->try_auth2) {
866                 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
867                                                               &result);
868                 TALLOC_FREE(subreq);
869                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
870                         state->try_auth2 = false;
871                         if (state->require_auth2) {
872                                 status = NT_STATUS_DOWNGRADE_DETECTED;
873                                 tevent_req_nterror(req, status);
874                                 return;
875                         }
876                         TALLOC_FREE(state->creds);
877                         netlogon_creds_cli_auth_challenge_start(req);
878                         return;
879                 }
880                 if (tevent_req_nterror(req, status)) {
881                         return;
882                 }
883         } else {
884                 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
885                                                              &result);
886                 TALLOC_FREE(subreq);
887                 if (tevent_req_nterror(req, status)) {
888                         return;
889                 }
890         }
891
892         tmp_flags = state->creds->negotiate_flags;
893         tmp_flags &= state->context->client.required_flags;
894         if (tmp_flags != state->context->client.required_flags) {
895                 if (NT_STATUS_IS_OK(result)) {
896                         tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
897                         return;
898                 }
899                 tevent_req_nterror(req, result);
900                 return;
901         }
902
903         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
904                 tmp_flags = state->context->client.proposed_flags;
905                 if (state->current_flags != tmp_flags) {
906                         if (!state->try_previous_nt_hash) {
907                                 /*
908                                  * we already retried, giving up...
909                                  */
910                                 tevent_req_nterror(req, result);
911                                 return;
912                         }
913
914                         /*
915                          * lets retry with the old nt hash.
916                          */
917                         state->used_nt_hash = state->previous_nt_hash;
918                         state->try_previous_nt_hash = false;
919                         state->current_flags = tmp_flags;
920                         TALLOC_FREE(state->creds);
921                         netlogon_creds_cli_auth_challenge_start(req);
922                         return;
923                 }
924
925                 /*
926                  * lets retry with the negotiated flags
927                  */
928                 state->current_flags = state->creds->negotiate_flags;
929                 TALLOC_FREE(state->creds);
930                 netlogon_creds_cli_auth_challenge_start(req);
931                 return;
932         }
933
934         ok = netlogon_creds_client_check(state->creds,
935                                          &state->server_credential);
936         if (!ok) {
937                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
938                 return;
939         }
940
941         ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
942                 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
943         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
944                 status = ndr_map_error2ntstatus(ndr_err);
945                 tevent_req_nterror(req, status);
946                 return;
947         }
948
949         data.dptr = blob.data;
950         data.dsize = blob.length;
951
952         status = dbwrap_store(state->context->db.ctx,
953                               state->context->db.key_data,
954                               data, TDB_REPLACE);
955         if (tevent_req_nterror(req, status)) {
956                 return;
957         }
958
959         tevent_req_done(req);
960 }
961
962 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req)
963 {
964         NTSTATUS status;
965
966         if (tevent_req_is_nterror(req, &status)) {
967                 tevent_req_received(req);
968                 return status;
969         }
970
971         tevent_req_received(req);
972         return NT_STATUS_OK;
973 }
974
975 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
976                                  struct dcerpc_binding_handle *b,
977                                  struct samr_Password current_nt_hash,
978                                  const struct samr_Password *previous_nt_hash)
979 {
980         TALLOC_CTX *frame = talloc_stackframe();
981         struct tevent_context *ev;
982         struct tevent_req *req;
983         NTSTATUS status = NT_STATUS_NO_MEMORY;
984
985         ev = samba_tevent_context_init(frame);
986         if (ev == NULL) {
987                 goto fail;
988         }
989         req = netlogon_creds_cli_auth_send(frame, ev, context, b,
990                                            current_nt_hash,
991                                            previous_nt_hash);
992         if (req == NULL) {
993                 goto fail;
994         }
995         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
996                 goto fail;
997         }
998         status = netlogon_creds_cli_auth_recv(req);
999  fail:
1000         TALLOC_FREE(frame);
1001         return status;
1002 }
1003
1004 struct netlogon_creds_cli_check_state {
1005         struct tevent_context *ev;
1006         struct netlogon_creds_cli_context *context;
1007         struct dcerpc_binding_handle *binding_handle;
1008
1009         char *srv_name_slash;
1010         char *cli_name_slash;
1011
1012         union netr_Capabilities caps;
1013
1014         struct netlogon_creds_CredentialState *creds;
1015         struct netlogon_creds_CredentialState tmp_creds;
1016         struct netr_Authenticator req_auth;
1017         struct netr_Authenticator rep_auth;
1018 };
1019
1020 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1021                                                      NTSTATUS status);
1022 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1023
1024 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1025                                 struct tevent_context *ev,
1026                                 struct netlogon_creds_cli_context *context,
1027                                 struct dcerpc_binding_handle *b)
1028 {
1029         struct tevent_req *req;
1030         struct netlogon_creds_cli_check_state *state;
1031         struct tevent_req *subreq;
1032
1033         req = tevent_req_create(mem_ctx, &state,
1034                                 struct netlogon_creds_cli_check_state);
1035         if (req == NULL) {
1036                 return NULL;
1037         }
1038
1039         state->ev = ev;
1040         state->context = context;
1041         state->binding_handle = b;
1042
1043         state->srv_name_slash = talloc_asprintf(state, "\\%s",
1044                                                 context->server.computer);
1045         if (tevent_req_nomem(state->srv_name_slash, req)) {
1046                 return tevent_req_post(req, ev);
1047         }
1048
1049         state->cli_name_slash = talloc_asprintf(state, "\\%s",
1050                                                 context->client.computer);
1051         if (tevent_req_nomem(state->cli_name_slash, req)) {
1052                 return tevent_req_post(req, ev);
1053         }
1054
1055         /*
1056          * TODO
1057          * verify DCERPC_AUTH_TYPE_SCHANNEL
1058          */
1059
1060         subreq = netlogon_creds_cli_lock_send(state, state->ev,
1061                                               state->context);
1062         if (tevent_req_nomem(subreq, req)) {
1063                 return tevent_req_post(req, ev);
1064         }
1065
1066         tevent_req_set_callback(subreq,
1067                                 netlogon_creds_cli_check_locked,
1068                                 req);
1069
1070         return req;
1071 }
1072
1073 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1074                                              NTSTATUS status)
1075 {
1076         struct netlogon_creds_cli_check_state *state =
1077                 tevent_req_data(req,
1078                 struct netlogon_creds_cli_check_state);
1079
1080         if (state->creds == NULL) {
1081                 return;
1082         }
1083
1084         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1085             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED)) {
1086                 TALLOC_FREE(state->creds);
1087                 return;
1088         }
1089
1090         netlogon_creds_cli_delete(state->context, &state->creds);
1091 }
1092
1093 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1094
1095 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1096 {
1097         struct tevent_req *req =
1098                 tevent_req_callback_data(subreq,
1099                 struct tevent_req);
1100         struct netlogon_creds_cli_check_state *state =
1101                 tevent_req_data(req,
1102                 struct netlogon_creds_cli_check_state);
1103         NTSTATUS status;
1104
1105         status = netlogon_creds_cli_lock_recv(subreq, state,
1106                                               &state->creds);
1107         TALLOC_FREE(subreq);
1108         if (tevent_req_nterror(req, status)) {
1109                 return;
1110         }
1111
1112         /*
1113          * we defer all callbacks in order to cleanup
1114          * the database record.
1115          */
1116         tevent_req_defer_callback(req, state->ev);
1117
1118         state->tmp_creds = *state->creds;
1119         netlogon_creds_client_authenticator(&state->tmp_creds,
1120                                             &state->req_auth);
1121         ZERO_STRUCT(state->rep_auth);
1122
1123         subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1124                                                 state->binding_handle,
1125                                                 state->srv_name_slash,
1126                                                 state->cli_name_slash,
1127                                                 &state->req_auth,
1128                                                 &state->rep_auth,
1129                                                 1,
1130                                                 &state->caps);
1131         if (tevent_req_nomem(subreq, req)) {
1132                 status = NT_STATUS_NO_MEMORY;
1133                 netlogon_creds_cli_check_cleanup(req, status);
1134                 return;
1135         }
1136         tevent_req_set_callback(subreq,
1137                                 netlogon_creds_cli_check_caps,
1138                                 req);
1139 }
1140
1141 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1142 {
1143         struct tevent_req *req =
1144                 tevent_req_callback_data(subreq,
1145                 struct tevent_req);
1146         struct netlogon_creds_cli_check_state *state =
1147                 tevent_req_data(req,
1148                 struct netlogon_creds_cli_check_state);
1149         NTSTATUS status;
1150         NTSTATUS result;
1151         bool ok;
1152
1153         status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1154                                                          &result);
1155         TALLOC_FREE(subreq);
1156         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1157                 status = NT_STATUS_OK;
1158                 result = NT_STATUS_NOT_IMPLEMENTED;
1159         }
1160         if (tevent_req_nterror(req, status)) {
1161                 netlogon_creds_cli_check_cleanup(req, status);
1162                 return;
1163         }
1164
1165         if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1166                 if (tevent_req_nterror(req, result)) {
1167                         netlogon_creds_cli_check_cleanup(req, result);
1168                         return;
1169                 }
1170         }
1171
1172         ok = netlogon_creds_client_check(&state->tmp_creds,
1173                                          &state->rep_auth.cred);
1174         if (!ok) {
1175                 status = NT_STATUS_ACCESS_DENIED;
1176                 tevent_req_nterror(req, status);
1177                 netlogon_creds_cli_check_cleanup(req, status);
1178                 return;
1179         }
1180
1181         if (tevent_req_nterror(req, result)) {
1182                 netlogon_creds_cli_check_cleanup(req, result);
1183                 return;
1184         }
1185
1186         if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1187                 status = NT_STATUS_DOWNGRADE_DETECTED;
1188                 tevent_req_nterror(req, status);
1189                 netlogon_creds_cli_check_cleanup(req, status);
1190                 return;
1191         }
1192
1193         if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1194                 status = NT_STATUS_DOWNGRADE_DETECTED;
1195                 tevent_req_nterror(req, status);
1196                 netlogon_creds_cli_check_cleanup(req, status);
1197                 return;
1198         }
1199
1200         *state->creds = state->tmp_creds;
1201         status = netlogon_creds_cli_store(state->context,
1202                                           &state->creds);
1203         if (tevent_req_nterror(req, status)) {
1204                 netlogon_creds_cli_check_cleanup(req, status);
1205                 return;
1206         }
1207
1208         tevent_req_done(req);
1209 }
1210
1211 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1212 {
1213         NTSTATUS status;
1214
1215         if (tevent_req_is_nterror(req, &status)) {
1216                 netlogon_creds_cli_check_cleanup(req, status);
1217                 tevent_req_received(req);
1218                 return status;
1219         }
1220
1221         tevent_req_received(req);
1222         return NT_STATUS_OK;
1223 }
1224
1225 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1226                                   struct dcerpc_binding_handle *b)
1227 {
1228         TALLOC_CTX *frame = talloc_stackframe();
1229         struct tevent_context *ev;
1230         struct tevent_req *req;
1231         NTSTATUS status = NT_STATUS_NO_MEMORY;
1232
1233         ev = samba_tevent_context_init(frame);
1234         if (ev == NULL) {
1235                 goto fail;
1236         }
1237         req = netlogon_creds_cli_check_send(frame, ev, context, b);
1238         if (req == NULL) {
1239                 goto fail;
1240         }
1241         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1242                 goto fail;
1243         }
1244         status = netlogon_creds_cli_check_recv(req);
1245  fail:
1246         TALLOC_FREE(frame);
1247         return status;
1248 }
1249
1250 struct netlogon_creds_cli_ServerPasswordSet_state {
1251         struct tevent_context *ev;
1252         struct netlogon_creds_cli_context *context;
1253         struct dcerpc_binding_handle *binding_handle;
1254         uint32_t old_timeout;
1255
1256         const char *new_password;
1257
1258         char *srv_name_slash;
1259
1260         struct netr_CryptPassword crypt_password;
1261         struct samr_Password samr_password;
1262
1263         struct netlogon_creds_CredentialState *creds;
1264         struct netlogon_creds_CredentialState tmp_creds;
1265         struct netr_Authenticator req_auth;
1266         struct netr_Authenticator rep_auth;
1267 };
1268
1269 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1270                                                      NTSTATUS status);
1271 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1272
1273 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1274                                 struct tevent_context *ev,
1275                                 struct netlogon_creds_cli_context *context,
1276                                 struct dcerpc_binding_handle *b,
1277                                 const char *new_password)
1278 {
1279         struct tevent_req *req;
1280         struct netlogon_creds_cli_ServerPasswordSet_state *state;
1281         struct tevent_req *subreq;
1282
1283         req = tevent_req_create(mem_ctx, &state,
1284                                 struct netlogon_creds_cli_ServerPasswordSet_state);
1285         if (req == NULL) {
1286                 return NULL;
1287         }
1288
1289         state->ev = ev;
1290         state->context = context;
1291         state->binding_handle = b;
1292
1293         state->new_password = talloc_strdup(state, new_password);
1294         if (tevent_req_nomem(state->new_password, req)) {
1295                 return tevent_req_post(req, ev);
1296         }
1297         talloc_set_name_const(state->new_password, "<new_password>");
1298
1299         state->srv_name_slash = talloc_asprintf(state, "\\%s",
1300                                                 context->server.computer);
1301         if (tevent_req_nomem(state->srv_name_slash, req)) {
1302                 return tevent_req_post(req, ev);
1303         }
1304
1305         /*
1306          * TODO
1307          * verify DCERPC_AUTH_TYPE_SCHANNEL
1308          */
1309
1310         subreq = netlogon_creds_cli_lock_send(state, state->ev,
1311                                               state->context);
1312         if (tevent_req_nomem(subreq, req)) {
1313                 return tevent_req_post(req, ev);
1314         }
1315
1316         tevent_req_set_callback(subreq,
1317                                 netlogon_creds_cli_ServerPasswordSet_locked,
1318                                 req);
1319
1320         return req;
1321 }
1322
1323 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1324                                                          NTSTATUS status)
1325 {
1326         struct netlogon_creds_cli_ServerPasswordSet_state *state =
1327                 tevent_req_data(req,
1328                 struct netlogon_creds_cli_ServerPasswordSet_state);
1329
1330         if (state->creds == NULL) {
1331                 return;
1332         }
1333
1334         dcerpc_binding_handle_set_timeout(state->binding_handle,
1335                                           state->old_timeout);
1336
1337         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1338                 TALLOC_FREE(state->creds);
1339                 return;
1340         }
1341
1342         netlogon_creds_cli_delete(state->context, &state->creds);
1343 }
1344
1345 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1346
1347 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1348 {
1349         struct tevent_req *req =
1350                 tevent_req_callback_data(subreq,
1351                 struct tevent_req);
1352         struct netlogon_creds_cli_ServerPasswordSet_state *state =
1353                 tevent_req_data(req,
1354                 struct netlogon_creds_cli_ServerPasswordSet_state);
1355         NTSTATUS status;
1356
1357         status = netlogon_creds_cli_lock_recv(subreq, state,
1358                                               &state->creds);
1359         TALLOC_FREE(subreq);
1360         if (tevent_req_nterror(req, status)) {
1361                 return;
1362         }
1363
1364         state->old_timeout = dcerpc_binding_handle_set_timeout(
1365                                 state->binding_handle, 600000);
1366
1367         /*
1368          * we defer all callbacks in order to cleanup
1369          * the database record.
1370          */
1371         tevent_req_defer_callback(req, state->ev);
1372
1373         state->tmp_creds = *state->creds;
1374         netlogon_creds_client_authenticator(&state->tmp_creds,
1375                                             &state->req_auth);
1376         ZERO_STRUCT(state->rep_auth);
1377
1378         if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1379                 struct samr_CryptPassword password_buf;
1380
1381                 encode_pw_buffer(password_buf.data,
1382                                  state->new_password, STR_UNICODE);
1383
1384                 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1385                         netlogon_creds_aes_encrypt(&state->tmp_creds,
1386                                                    password_buf.data, 516);
1387                 } else {
1388                         netlogon_creds_arcfour_crypt(&state->tmp_creds,
1389                                                      password_buf.data, 516);
1390                 }
1391
1392                 memcpy(state->crypt_password.data, password_buf.data, 512);
1393                 state->crypt_password.length = IVAL(password_buf.data, 512);
1394                 ZERO_STRUCT(password_buf);
1395
1396                 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1397                                         state->binding_handle,
1398                                         state->srv_name_slash,
1399                                         state->tmp_creds.account_name,
1400                                         /* TODO: state->tmp_creds.secure_channel_type, */
1401                                         state->context->client.type,
1402                                         state->tmp_creds.computer_name,
1403                                         &state->req_auth,
1404                                         &state->rep_auth,
1405                                         &state->crypt_password);
1406                 if (tevent_req_nomem(subreq, req)) {
1407                         status = NT_STATUS_NO_MEMORY;
1408                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1409                         return;
1410                 }
1411         } else {
1412                 E_md4hash(state->new_password, state->samr_password.hash);
1413                 netlogon_creds_des_encrypt(&state->tmp_creds,
1414                                            &state->samr_password);
1415
1416                 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1417                                         state->binding_handle,
1418                                         state->srv_name_slash,
1419                                         state->tmp_creds.account_name,
1420                                         state->tmp_creds.secure_channel_type,
1421                                         state->tmp_creds.computer_name,
1422                                         &state->req_auth,
1423                                         &state->rep_auth,
1424                                         &state->samr_password);
1425                 if (tevent_req_nomem(subreq, req)) {
1426                         status = NT_STATUS_NO_MEMORY;
1427                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1428                         return;
1429                 }
1430         }
1431
1432         tevent_req_set_callback(subreq,
1433                                 netlogon_creds_cli_ServerPasswordSet_done,
1434                                 req);
1435 }
1436
1437 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1438 {
1439         struct tevent_req *req =
1440                 tevent_req_callback_data(subreq,
1441                 struct tevent_req);
1442         struct netlogon_creds_cli_ServerPasswordSet_state *state =
1443                 tevent_req_data(req,
1444                 struct netlogon_creds_cli_ServerPasswordSet_state);
1445         NTSTATUS status;
1446         NTSTATUS result;
1447         bool ok;
1448
1449         if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1450                 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
1451                                                              &result);
1452                 TALLOC_FREE(subreq);
1453                 if (tevent_req_nterror(req, status)) {
1454                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1455                         return;
1456                 }
1457         } else {
1458                 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
1459                                                             &result);
1460                 TALLOC_FREE(subreq);
1461                 if (tevent_req_nterror(req, status)) {
1462                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1463                         return;
1464                 }
1465         }
1466
1467         ok = netlogon_creds_client_check(&state->tmp_creds,
1468                                          &state->rep_auth.cred);
1469         if (!ok) {
1470                 status = NT_STATUS_ACCESS_DENIED;
1471                 tevent_req_nterror(req, status);
1472                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1473                 return;
1474         }
1475
1476         if (tevent_req_nterror(req, result)) {
1477                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
1478                 return;
1479         }
1480
1481         dcerpc_binding_handle_set_timeout(state->binding_handle,
1482                                           state->old_timeout);
1483
1484         *state->creds = state->tmp_creds;
1485         status = netlogon_creds_cli_store(state->context,
1486                                           &state->creds);
1487         if (tevent_req_nterror(req, status)) {
1488                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1489                 return;
1490         }
1491
1492         tevent_req_done(req);
1493 }
1494
1495 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
1496 {
1497         NTSTATUS status;
1498
1499         if (tevent_req_is_nterror(req, &status)) {
1500                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1501                 tevent_req_received(req);
1502                 return status;
1503         }
1504
1505         tevent_req_received(req);
1506         return NT_STATUS_OK;
1507 }
1508
1509 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
1510                                 struct netlogon_creds_cli_context *context,
1511                                 struct dcerpc_binding_handle *b,
1512                                 const char *new_password)
1513 {
1514         TALLOC_CTX *frame = talloc_stackframe();
1515         struct tevent_context *ev;
1516         struct tevent_req *req;
1517         NTSTATUS status = NT_STATUS_NO_MEMORY;
1518
1519         ev = samba_tevent_context_init(frame);
1520         if (ev == NULL) {
1521                 goto fail;
1522         }
1523         req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
1524                                                         new_password);
1525         if (req == NULL) {
1526                 goto fail;
1527         }
1528         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1529                 goto fail;
1530         }
1531         status = netlogon_creds_cli_ServerPasswordSet_recv(req);
1532  fail:
1533         TALLOC_FREE(frame);
1534         return status;
1535 }
1536
1537 struct netlogon_creds_cli_LogonSamLogon_state {
1538         struct tevent_context *ev;
1539         struct netlogon_creds_cli_context *context;
1540         struct dcerpc_binding_handle *binding_handle;
1541
1542         char *srv_name_slash;
1543         char *cli_name_slash;
1544
1545         enum netr_LogonInfoClass logon_level;
1546         const union netr_LogonLevel *const_logon;
1547         union netr_LogonLevel *logon;
1548         uint32_t flags;
1549
1550         uint16_t validation_level;
1551         union netr_Validation *validation;
1552         uint8_t authoritative;
1553
1554         /*
1555          * do we need encryption at the application layer?
1556          */
1557         bool user_encrypt;
1558
1559         /*
1560          * the read only credentials before we started the operation
1561          */
1562         struct netlogon_creds_CredentialState *ro_creds;
1563
1564         struct netlogon_creds_CredentialState *lk_creds;
1565
1566         struct netlogon_creds_CredentialState tmp_creds;
1567         struct netr_Authenticator req_auth;
1568         struct netr_Authenticator rep_auth;
1569 };
1570
1571 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
1572 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
1573                                                      NTSTATUS status);
1574
1575 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
1576                                 struct tevent_context *ev,
1577                                 struct netlogon_creds_cli_context *context,
1578                                 struct dcerpc_binding_handle *b,
1579                                 enum netr_LogonInfoClass logon_level,
1580                                 const union netr_LogonLevel *logon,
1581                                 uint32_t flags)
1582 {
1583         struct tevent_req *req;
1584         struct netlogon_creds_cli_LogonSamLogon_state *state;
1585
1586         req = tevent_req_create(mem_ctx, &state,
1587                                 struct netlogon_creds_cli_LogonSamLogon_state);
1588         if (req == NULL) {
1589                 return NULL;
1590         }
1591
1592         state->ev = ev;
1593         state->context = context;
1594         state->binding_handle = b;
1595
1596         state->logon_level = logon_level;
1597         state->const_logon = logon;
1598         state->flags = flags;
1599
1600         state->srv_name_slash = talloc_asprintf(state, "\\%s",
1601                                                 context->server.computer);
1602         if (tevent_req_nomem(state->srv_name_slash, req)) {
1603                 return tevent_req_post(req, ev);
1604         }
1605
1606         state->cli_name_slash = talloc_asprintf(state, "\\%s",
1607                                                 context->client.computer);
1608         if (tevent_req_nomem(state->cli_name_slash, req)) {
1609                 return tevent_req_post(req, ev);
1610         }
1611
1612         switch (logon_level) {
1613         case NetlogonInteractiveInformation:
1614         case NetlogonInteractiveTransitiveInformation:
1615         case NetlogonServiceInformation:
1616         case NetlogonServiceTransitiveInformation:
1617         case NetlogonGenericInformation:
1618                 state->user_encrypt = true;
1619                 break;
1620
1621         case NetlogonNetworkInformation:
1622         case NetlogonNetworkTransitiveInformation:
1623                 break;
1624         }
1625
1626         state->validation = talloc_zero(state, union netr_Validation);
1627         if (tevent_req_nomem(state->validation, req)) {
1628                 return tevent_req_post(req, ev);
1629         }
1630
1631         /*
1632          * TODO
1633          * verify DCERPC_AUTH_TYPE_SCHANNEL
1634          * for try_logon_ex.
1635          *
1636          * and DCERPC_AUTH_LEVEL_PRIVACY for
1637          * try_validation6
1638          */
1639
1640         netlogon_creds_cli_LogonSamLogon_start(req);
1641
1642         if (!tevent_req_is_in_progress(req)) {
1643                 return tevent_req_post(req, ev);
1644         }
1645
1646         /*
1647          * we defer all callbacks in order to cleanup
1648          * the database record.
1649          */
1650         tevent_req_defer_callback(req, state->ev);
1651         return req;
1652 }
1653
1654 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
1655                                                      NTSTATUS status)
1656 {
1657         struct netlogon_creds_cli_LogonSamLogon_state *state =
1658                 tevent_req_data(req,
1659                 struct netlogon_creds_cli_LogonSamLogon_state);
1660
1661         if (state->lk_creds == NULL) {
1662                 return;
1663         }
1664
1665         if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1666                 TALLOC_FREE(state->lk_creds);
1667                 return;
1668         }
1669
1670         netlogon_creds_cli_delete(state->context, &state->lk_creds);
1671 }
1672
1673 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
1674
1675 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
1676 {
1677         struct netlogon_creds_cli_LogonSamLogon_state *state =
1678                 tevent_req_data(req,
1679                 struct netlogon_creds_cli_LogonSamLogon_state);
1680         struct tevent_req *subreq;
1681         NTSTATUS status;
1682
1683         TALLOC_FREE(state->ro_creds);
1684         TALLOC_FREE(state->logon);
1685
1686         if (state->context->server.try_logon_ex) {
1687                 if (state->context->server.try_validation6) {
1688                         state->validation_level = 6;
1689                 } else {
1690                         state->validation_level = 3;
1691                         state->user_encrypt = true;
1692                 }
1693
1694                 state->logon = netlogon_creds_shallow_copy_logon(state,
1695                                                         state->logon_level,
1696                                                         state->const_logon);
1697                 if (tevent_req_nomem(state->logon, req)) {
1698                         status = NT_STATUS_NO_MEMORY;
1699                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1700                         return;
1701                 }
1702
1703                 if (state->user_encrypt) {
1704                         status = netlogon_creds_cli_get(state->context,
1705                                                         state,
1706                                                         &state->ro_creds);
1707                         if (!NT_STATUS_IS_OK(status)) {
1708                                 status = NT_STATUS_ACCESS_DENIED;
1709                                 tevent_req_nterror(req, status);
1710                                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1711                                 return;
1712                         }
1713
1714                         netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
1715                                                               state->logon_level,
1716                                                               state->logon);
1717                 }
1718
1719                 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
1720                                                 state->binding_handle,
1721                                                 state->srv_name_slash,
1722                                                 state->cli_name_slash,
1723                                                 state->logon_level,
1724                                                 state->logon,
1725                                                 state->validation_level,
1726                                                 state->validation,
1727                                                 &state->authoritative,
1728                                                 &state->flags);
1729                 if (tevent_req_nomem(subreq, req)) {
1730                         status = NT_STATUS_NO_MEMORY;
1731                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1732                         return;
1733                 }
1734                 tevent_req_set_callback(subreq,
1735                                         netlogon_creds_cli_LogonSamLogon_done,
1736                                         req);
1737                 return;
1738         }
1739
1740         if (state->lk_creds == NULL) {
1741                 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1742                                                       state->context);
1743                 if (tevent_req_nomem(subreq, req)) {
1744                         status = NT_STATUS_NO_MEMORY;
1745                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1746                         return;
1747                 }
1748                 tevent_req_set_callback(subreq,
1749                                         netlogon_creds_cli_LogonSamLogon_done,
1750                                         req);
1751                 return;
1752         }
1753
1754         state->tmp_creds = *state->lk_creds;
1755         netlogon_creds_client_authenticator(&state->tmp_creds,
1756                                             &state->req_auth);
1757         ZERO_STRUCT(state->rep_auth);
1758
1759         state->logon = netlogon_creds_shallow_copy_logon(state,
1760                                                 state->logon_level,
1761                                                 state->const_logon);
1762         if (tevent_req_nomem(state->logon, req)) {
1763                 status = NT_STATUS_NO_MEMORY;
1764                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1765                 return;
1766         }
1767
1768         netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
1769                                               state->logon_level,
1770                                               state->logon);
1771
1772         state->validation_level = 3;
1773
1774         if (state->context->server.try_logon_with) {
1775                 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
1776                                                 state->binding_handle,
1777                                                 state->srv_name_slash,
1778                                                 state->cli_name_slash,
1779                                                 &state->req_auth,
1780                                                 &state->rep_auth,
1781                                                 state->logon_level,
1782                                                 state->logon,
1783                                                 state->validation_level,
1784                                                 state->validation,
1785                                                 &state->authoritative,
1786                                                 &state->flags);
1787                 if (tevent_req_nomem(subreq, req)) {
1788                         status = NT_STATUS_NO_MEMORY;
1789                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1790                         return;
1791                 }
1792         } else {
1793                 state->flags = 0;
1794
1795                 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
1796                                                 state->binding_handle,
1797                                                 state->srv_name_slash,
1798                                                 state->cli_name_slash,
1799                                                 &state->req_auth,
1800                                                 &state->rep_auth,
1801                                                 state->logon_level,
1802                                                 state->logon,
1803                                                 state->validation_level,
1804                                                 state->validation,
1805                                                 &state->authoritative);
1806                 if (tevent_req_nomem(subreq, req)) {
1807                         status = NT_STATUS_NO_MEMORY;
1808                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1809                         return;
1810                 }
1811         }
1812
1813         tevent_req_set_callback(subreq,
1814                                 netlogon_creds_cli_LogonSamLogon_done,
1815                                 req);
1816 }
1817
1818 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
1819 {
1820         struct tevent_req *req =
1821                 tevent_req_callback_data(subreq,
1822                 struct tevent_req);
1823         struct netlogon_creds_cli_LogonSamLogon_state *state =
1824                 tevent_req_data(req,
1825                 struct netlogon_creds_cli_LogonSamLogon_state);
1826         NTSTATUS status;
1827         NTSTATUS result;
1828         bool ok;
1829
1830         if (state->context->server.try_logon_ex) {
1831                 status = dcerpc_netr_LogonSamLogonEx_recv(subreq, state,
1832                                                           &result);
1833                 TALLOC_FREE(subreq);
1834                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1835                         state->context->server.try_validation6 = false;
1836                         state->context->server.try_logon_ex = false;
1837                         netlogon_creds_cli_LogonSamLogon_start(req);
1838                         return;
1839                 }
1840                 if (tevent_req_nterror(req, status)) {
1841                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1842                         return;
1843                 }
1844
1845                 if ((state->validation_level == 6) &&
1846                     (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
1847                      NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
1848                      NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
1849                 {
1850                         state->context->server.try_validation6 = false;
1851                         netlogon_creds_cli_LogonSamLogon_start(req);
1852                         return;
1853                 }
1854
1855                 if (tevent_req_nterror(req, result)) {
1856                         netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
1857                         return;
1858                 }
1859
1860                 if (state->ro_creds == NULL) {
1861                         tevent_req_done(req);
1862                         return;
1863                 }
1864
1865                 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
1866                 if (!ok) {
1867                         status = NT_STATUS_ACCESS_DENIED;
1868                         tevent_req_nterror(req, status);
1869                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1870                         return;
1871                 }
1872
1873                 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
1874                                                         state->validation_level,
1875                                                         state->validation);
1876
1877                 tevent_req_done(req);
1878                 return;
1879         }
1880
1881         if (state->lk_creds == NULL) {
1882                 status = netlogon_creds_cli_lock_recv(subreq, state,
1883                                                       &state->lk_creds);
1884                 TALLOC_FREE(subreq);
1885                 if (tevent_req_nterror(req, status)) {
1886                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1887                         return;
1888                 }
1889
1890                 netlogon_creds_cli_LogonSamLogon_start(req);
1891                 return;
1892         }
1893
1894         if (state->context->server.try_logon_with) {
1895                 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq, state,
1896                                                                  &result);
1897                 TALLOC_FREE(subreq);
1898                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1899                         state->context->server.try_logon_with = false;
1900                         netlogon_creds_cli_LogonSamLogon_start(req);
1901                         return;
1902                 }
1903                 if (tevent_req_nterror(req, status)) {
1904                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1905                         return;
1906                 }
1907         } else {
1908                 status = dcerpc_netr_LogonSamLogon_recv(subreq, state,
1909                                                         &result);
1910                 TALLOC_FREE(subreq);
1911                 if (tevent_req_nterror(req, status)) {
1912                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1913                         return;
1914                 }
1915         }
1916
1917         ok = netlogon_creds_client_check(&state->tmp_creds,
1918                                          &state->rep_auth.cred);
1919         if (!ok) {
1920                 status = NT_STATUS_ACCESS_DENIED;
1921                 tevent_req_nterror(req, status);
1922                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1923                 return;
1924         }
1925
1926         *state->lk_creds = state->tmp_creds;
1927         status = netlogon_creds_cli_store(state->context,
1928                                           &state->lk_creds);
1929         if (tevent_req_nterror(req, status)) {
1930                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1931                 return;
1932         }
1933
1934         if (tevent_req_nterror(req, result)) {
1935                 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
1936                 return;
1937         }
1938
1939         netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
1940                                                 state->validation_level,
1941                                                 state->validation);
1942
1943         tevent_req_done(req);
1944 }
1945
1946 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
1947                                         TALLOC_CTX *mem_ctx,
1948                                         uint16_t *validation_level,
1949                                         union netr_Validation **validation,
1950                                         uint8_t *authoritative,
1951                                         uint32_t *flags)
1952 {
1953         struct netlogon_creds_cli_LogonSamLogon_state *state =
1954                 tevent_req_data(req,
1955                 struct netlogon_creds_cli_LogonSamLogon_state);
1956         NTSTATUS status;
1957
1958         if (tevent_req_is_nterror(req, &status)) {
1959                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
1960                 tevent_req_received(req);
1961                 return status;
1962         }
1963
1964         *validation_level = state->validation_level;
1965         *validation = talloc_move(mem_ctx, &state->validation);
1966         *authoritative = state->authoritative;
1967         *flags = state->flags;
1968
1969         tevent_req_received(req);
1970         return NT_STATUS_OK;
1971 }
1972
1973 NTSTATUS netlogon_creds_cli_LogonSamLogon(
1974                                 struct netlogon_creds_cli_context *context,
1975                                 struct dcerpc_binding_handle *b,
1976                                 enum netr_LogonInfoClass logon_level,
1977                                 const union netr_LogonLevel *logon,
1978                                 TALLOC_CTX *mem_ctx,
1979                                 uint16_t *validation_level,
1980                                 union netr_Validation **validation,
1981                                 uint8_t *authoritative,
1982                                 uint32_t *flags)
1983 {
1984         TALLOC_CTX *frame = talloc_stackframe();
1985         struct tevent_context *ev;
1986         struct tevent_req *req;
1987         NTSTATUS status = NT_STATUS_NO_MEMORY;
1988
1989         ev = samba_tevent_context_init(frame);
1990         if (ev == NULL) {
1991                 goto fail;
1992         }
1993         req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
1994                                                     logon_level, logon,
1995                                                     *flags);
1996         if (req == NULL) {
1997                 goto fail;
1998         }
1999         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2000                 goto fail;
2001         }
2002         status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2003                                                        validation_level,
2004                                                        validation,
2005                                                        authoritative,
2006                                                        flags);
2007  fail:
2008         TALLOC_FREE(frame);
2009         return status;
2010 }