1252d0539cdfab22ee3b3911236a0612b46a9e43
[gd/samba-autobuild/.git] / libcli / auth / credentials.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    code to manipulate domain credentials
5
6    Copyright (C) Andrew Tridgell 1997-2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/time.h"
25 #include "../lib/crypto/crypto.h"
26 #include "libcli/auth/libcli_auth.h"
27 #include "../libcli/security/dom_sid.h"
28
29 #include "libcli/util/gnutls_error.h"
30 #include <gnutls/gnutls.h>
31 #include <gnutls/crypto.h>
32
33 static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
34                                       const struct netr_Credential *in,
35                                       struct netr_Credential *out)
36 {
37         if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
38                 AES_KEY key;
39                 uint8_t iv[AES_BLOCK_SIZE] = {0};
40
41                 AES_set_encrypt_key(creds->session_key, 128, &key);
42
43                 aes_cfb8_encrypt(in->data, out->data, 8, &key, iv, AES_ENCRYPT);
44         } else {
45                 des_crypt112(out->data, in->data, creds->session_key, 1);
46         }
47 }
48
49 /*
50   initialise the credentials state for old-style 64 bit session keys
51
52   this call is made after the netr_ServerReqChallenge call
53 */
54 static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
55                                       const struct netr_Credential *client_challenge,
56                                       const struct netr_Credential *server_challenge,
57                                       const struct samr_Password *machine_password)
58 {
59         uint32_t sum[2];
60         uint8_t sum2[8];
61
62         sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
63         sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
64
65         SIVAL(sum2,0,sum[0]);
66         SIVAL(sum2,4,sum[1]);
67
68         ZERO_ARRAY(creds->session_key);
69
70         des_crypt128(creds->session_key, sum2, machine_password->hash);
71 }
72
73 /*
74   initialise the credentials state for ADS-style 128 bit session keys
75
76   this call is made after the netr_ServerReqChallenge call
77 */
78 static NTSTATUS netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
79                                        const struct netr_Credential *client_challenge,
80                                        const struct netr_Credential *server_challenge,
81                                        const struct samr_Password *machine_password)
82 {
83         uint8_t zero[4] = {0};
84         uint8_t tmp[gnutls_hash_get_len(GNUTLS_MAC_MD5)];
85         gnutls_hash_hd_t hash_hnd = NULL;
86         int rc;
87
88         ZERO_ARRAY(creds->session_key);
89
90         rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
91         if (rc < 0) {
92                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
93         }
94
95         rc = gnutls_hash(hash_hnd, zero, sizeof(zero));
96         if (rc < 0) {
97                 gnutls_hash_deinit(hash_hnd, NULL);
98                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
99         }
100         rc = gnutls_hash(hash_hnd, client_challenge->data, 8);
101         if (rc < 0) {
102                 gnutls_hash_deinit(hash_hnd, NULL);
103                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
104         }
105         rc = gnutls_hash(hash_hnd, server_challenge->data, 8);
106         if (rc < 0) {
107                 gnutls_hash_deinit(hash_hnd, NULL);
108                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
109         }
110
111         gnutls_hash_deinit(hash_hnd, tmp);
112
113         /* This doesn't require HMAC MD5 RFC2104 as the hash is only 16 bytes */
114         rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
115                               machine_password->hash,
116                               sizeof(machine_password->hash),
117                               tmp,
118                               sizeof(tmp),
119                               creds->session_key);
120         ZERO_ARRAY(tmp);
121
122         if (rc < 0) {
123                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
124         }
125
126         return NT_STATUS_OK;
127 }
128
129 /*
130   initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
131
132   this call is made after the netr_ServerReqChallenge call
133 */
134 static NTSTATUS netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState *creds,
135                                                 const struct netr_Credential *client_challenge,
136                                                 const struct netr_Credential *server_challenge,
137                                                 const struct samr_Password *machine_password)
138 {
139         gnutls_hmac_hd_t hmac_hnd = NULL;
140         uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)];
141         int rc;
142
143         ZERO_ARRAY(creds->session_key);
144
145         rc = gnutls_hmac_init(&hmac_hnd,
146                               GNUTLS_MAC_SHA256,
147                               machine_password->hash,
148                               sizeof(machine_password->hash));
149         if (rc < 0) {
150                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
151         }
152         rc = gnutls_hmac(hmac_hnd,
153                          client_challenge->data,
154                          8);
155         if (rc < 0) {
156                 gnutls_hmac_deinit(hmac_hnd, NULL);
157                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
158         }
159         rc  = gnutls_hmac(hmac_hnd,
160                           server_challenge->data,
161                           8);
162         if (rc < 0) {
163                 gnutls_hmac_deinit(hmac_hnd, NULL);
164                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
165         }
166         gnutls_hmac_deinit(hmac_hnd, digest);
167
168         memcpy(creds->session_key, digest, sizeof(creds->session_key));
169
170         ZERO_ARRAY(digest);
171
172         return NT_STATUS_OK;
173 }
174
175 static void netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
176                                       const struct netr_Credential *client_challenge,
177                                       const struct netr_Credential *server_challenge)
178 {
179         netlogon_creds_step_crypt(creds, client_challenge, &creds->client);
180
181         netlogon_creds_step_crypt(creds, server_challenge, &creds->server);
182
183         creds->seed = creds->client;
184 }
185
186 /*
187   step the credentials to the next element in the chain, updating the
188   current client and server credentials and the seed
189 */
190 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
191 {
192         struct netr_Credential time_cred;
193
194         DEBUG(5,("\tseed        %08x:%08x\n",
195                  IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
196
197         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
198         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
199
200         DEBUG(5,("\tseed+time   %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
201
202         netlogon_creds_step_crypt(creds, &time_cred, &creds->client);
203
204         DEBUG(5,("\tCLIENT      %08x:%08x\n",
205                  IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
206
207         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
208         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
209
210         DEBUG(5,("\tseed+time+1 %08x:%08x\n",
211                  IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
212
213         netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
214
215         DEBUG(5,("\tSERVER      %08x:%08x\n",
216                  IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
217
218         creds->seed = time_cred;
219 }
220
221
222 /*
223   DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
224 */
225 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
226 {
227         struct netr_LMSessionKey tmp;
228         des_crypt56(tmp.key, key->key, creds->session_key, 1);
229         *key = tmp;
230 }
231
232 /*
233   DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
234 */
235 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
236 {
237         struct netr_LMSessionKey tmp;
238         des_crypt56(tmp.key, key->key, creds->session_key, 0);
239         *key = tmp;
240 }
241
242 /*
243   DES encrypt a 16 byte password buffer using the session key
244 */
245 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
246 {
247         struct samr_Password tmp;
248         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
249         *pass = tmp;
250 }
251
252 /*
253   DES decrypt a 16 byte password buffer using the session key
254 */
255 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
256 {
257         struct samr_Password tmp;
258         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
259         *pass = tmp;
260 }
261
262 /*
263   ARCFOUR encrypt/decrypt a password buffer using the session key
264 */
265 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
266 {
267         DATA_BLOB session_key = data_blob(creds->session_key, 16);
268
269         arcfour_crypt_blob(data, len, &session_key);
270
271         data_blob_free(&session_key);
272 }
273
274 /*
275   AES encrypt a password buffer using the session key
276 */
277 void netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
278 {
279         AES_KEY key;
280         uint8_t iv[AES_BLOCK_SIZE] = {0};
281
282         AES_set_encrypt_key(creds->session_key, 128, &key);
283
284         aes_cfb8_encrypt(data, data, len, &key, iv, AES_ENCRYPT);
285 }
286
287 /*
288   AES decrypt a password buffer using the session key
289 */
290 void netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
291 {
292         AES_KEY key;
293         uint8_t iv[AES_BLOCK_SIZE] = {0};
294
295         AES_set_encrypt_key(creds->session_key, 128, &key);
296
297         aes_cfb8_encrypt(data, data, len, &key, iv, AES_DECRYPT);
298 }
299
300 /*****************************************************************
301 The above functions are common to the client and server interface
302 next comes the client specific functions
303 ******************************************************************/
304
305 /*
306   initialise the credentials chain and return the first client
307   credentials
308 */
309
310 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
311                                                                   const char *client_account,
312                                                                   const char *client_computer_name,
313                                                                   uint16_t secure_channel_type,
314                                                                   const struct netr_Credential *client_challenge,
315                                                                   const struct netr_Credential *server_challenge,
316                                                                   const struct samr_Password *machine_password,
317                                                                   struct netr_Credential *initial_credential,
318                                                                   uint32_t negotiate_flags)
319 {
320         struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
321         NTSTATUS status;
322
323         if (!creds) {
324                 return NULL;
325         }
326
327         creds->sequence = time(NULL);
328         creds->negotiate_flags = negotiate_flags;
329         creds->secure_channel_type = secure_channel_type;
330
331         creds->computer_name = talloc_strdup(creds, client_computer_name);
332         if (!creds->computer_name) {
333                 talloc_free(creds);
334                 return NULL;
335         }
336         creds->account_name = talloc_strdup(creds, client_account);
337         if (!creds->account_name) {
338                 talloc_free(creds);
339                 return NULL;
340         }
341
342         dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
343         dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
344         dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
345
346         if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
347                 status = netlogon_creds_init_hmac_sha256(creds,
348                                                          client_challenge,
349                                                          server_challenge,
350                                                          machine_password);
351                 if (!NT_STATUS_IS_OK(status)) {
352                         talloc_free(creds);
353                         return NULL;
354                 }
355         } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
356                 status = netlogon_creds_init_128bit(creds,
357                                                     client_challenge,
358                                                     server_challenge,
359                                                     machine_password);
360                 if (!NT_STATUS_IS_OK(status)) {
361                         talloc_free(creds);
362                         return NULL;
363                 }
364         } else {
365                 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
366         }
367
368         netlogon_creds_first_step(creds, client_challenge, server_challenge);
369
370         dump_data_pw("Session key", creds->session_key, 16);
371         dump_data_pw("Credential ", creds->client.data, 8);
372
373         *initial_credential = creds->client;
374         return creds;
375 }
376
377 /*
378   initialise the credentials structure with only a session key.  The caller better know what they are doing!
379  */
380
381 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
382                                                                               const uint8_t session_key[16])
383 {
384         struct netlogon_creds_CredentialState *creds;
385
386         creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
387         if (!creds) {
388                 return NULL;
389         }
390
391         memcpy(creds->session_key, session_key, 16);
392
393         return creds;
394 }
395
396 /*
397   step the credentials to the next element in the chain, updating the
398   current client and server credentials and the seed
399
400   produce the next authenticator in the sequence ready to send to
401   the server
402 */
403 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
404                                 struct netr_Authenticator *next)
405 {
406         uint32_t t32n = (uint32_t)time(NULL);
407
408         /*
409          * we always increment and ignore an overflow here
410          */
411         creds->sequence += 2;
412
413         if (t32n > creds->sequence) {
414                 /*
415                  * we may increment more
416                  */
417                 creds->sequence = t32n;
418         } else {
419                 uint32_t d = creds->sequence - t32n;
420
421                 if (d >= INT32_MAX) {
422                         /*
423                          * got an overflow of time_t vs. uint32_t
424                          */
425                         creds->sequence = t32n;
426                 }
427         }
428
429         netlogon_creds_step(creds);
430
431         next->cred = creds->client;
432         next->timestamp = creds->sequence;
433 }
434
435 /*
436   check that a credentials reply from a server is correct
437 */
438 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
439                         const struct netr_Credential *received_credentials)
440 {
441         if (!received_credentials ||
442             memcmp(received_credentials->data, creds->server.data, 8) != 0) {
443                 DEBUG(2,("credentials check failed\n"));
444                 return false;
445         }
446         return true;
447 }
448
449
450 /*****************************************************************
451 The above functions are common to the client and server interface
452 next comes the server specific functions
453 ******************************************************************/
454
455 /*
456   check that a credentials reply from a server is correct
457 */
458 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
459                                                  const struct netr_Credential *received_credentials)
460 {
461         if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
462                 DEBUG(2,("credentials check failed\n"));
463                 dump_data_pw("client creds", creds->client.data, 8);
464                 dump_data_pw("calc   creds", received_credentials->data, 8);
465                 return false;
466         }
467         return true;
468 }
469
470 /*
471   initialise the credentials chain and return the first server
472   credentials
473 */
474 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
475                                                                   const char *client_account,
476                                                                   const char *client_computer_name,
477                                                                   uint16_t secure_channel_type,
478                                                                   const struct netr_Credential *client_challenge,
479                                                                   const struct netr_Credential *server_challenge,
480                                                                   const struct samr_Password *machine_password,
481                                                                   const struct netr_Credential *credentials_in,
482                                                                   struct netr_Credential *credentials_out,
483                                                                   uint32_t negotiate_flags)
484 {
485
486         struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
487
488         if (!creds) {
489                 return NULL;
490         }
491
492         creds->negotiate_flags = negotiate_flags;
493         creds->secure_channel_type = secure_channel_type;
494
495         dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
496         dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
497         dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
498
499         creds->computer_name = talloc_strdup(creds, client_computer_name);
500         if (!creds->computer_name) {
501                 talloc_free(creds);
502                 return NULL;
503         }
504         creds->account_name = talloc_strdup(creds, client_account);
505         if (!creds->account_name) {
506                 talloc_free(creds);
507                 return NULL;
508         }
509
510         if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
511                 NTSTATUS status;
512
513                 status = netlogon_creds_init_hmac_sha256(creds,
514                                                          client_challenge,
515                                                          server_challenge,
516                                                          machine_password);
517                 if (!NT_STATUS_IS_OK(status)) {
518                         talloc_free(creds);
519                         return NULL;
520                 }
521         } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
522                 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
523                                            machine_password);
524         } else {
525                 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
526                                           machine_password);
527         }
528
529         netlogon_creds_first_step(creds, client_challenge, server_challenge);
530
531         dump_data_pw("Session key", creds->session_key, 16);
532         dump_data_pw("Client Credential ", creds->client.data, 8);
533         dump_data_pw("Server Credential ", creds->server.data, 8);
534
535         dump_data_pw("Credentials in", credentials_in->data, sizeof(credentials_in->data));
536
537         /* And before we leak information about the machine account
538          * password, check that they got the first go right */
539         if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
540                 talloc_free(creds);
541                 return NULL;
542         }
543
544         *credentials_out = creds->server;
545
546         dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
547
548         return creds;
549 }
550
551 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
552                                  const struct netr_Authenticator *received_authenticator,
553                                  struct netr_Authenticator *return_authenticator)
554 {
555         if (!received_authenticator || !return_authenticator) {
556                 return NT_STATUS_INVALID_PARAMETER;
557         }
558
559         if (!creds) {
560                 return NT_STATUS_ACCESS_DENIED;
561         }
562
563         creds->sequence = received_authenticator->timestamp;
564         netlogon_creds_step(creds);
565         if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
566                 return_authenticator->cred = creds->server;
567                 return_authenticator->timestamp = 0;
568                 return NT_STATUS_OK;
569         } else {
570                 ZERO_STRUCTP(return_authenticator);
571                 return NT_STATUS_ACCESS_DENIED;
572         }
573 }
574
575 static void netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
576                                                      uint16_t validation_level,
577                                                      union netr_Validation *validation,
578                                                      bool do_encrypt)
579 {
580         struct netr_SamBaseInfo *base = NULL;
581
582         if (validation == NULL) {
583                 return;
584         }
585
586         switch (validation_level) {
587         case 2:
588                 if (validation->sam2) {
589                         base = &validation->sam2->base;
590                 }
591                 break;
592         case 3:
593                 if (validation->sam3) {
594                         base = &validation->sam3->base;
595                 }
596                 break;
597         case 6:
598                 if (validation->sam6) {
599                         base = &validation->sam6->base;
600                 }
601                 break;
602         default:
603                 /* If we can't find it, we can't very well decrypt it */
604                 return;
605         }
606
607         if (!base) {
608                 return;
609         }
610
611         /* find and decyrpt the session keys, return in parameters above */
612         if (validation_level == 6) {
613                 /* they aren't encrypted! */
614         } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
615                 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
616                 if (!all_zero(base->key.key, sizeof(base->key.key))) {
617                         if (do_encrypt) {
618                                 netlogon_creds_aes_encrypt(creds,
619                                             base->key.key,
620                                             sizeof(base->key.key));
621                         } else {
622                                 netlogon_creds_aes_decrypt(creds,
623                                             base->key.key,
624                                             sizeof(base->key.key));
625                         }
626                 }
627
628                 if (!all_zero(base->LMSessKey.key,
629                               sizeof(base->LMSessKey.key))) {
630                         if (do_encrypt) {
631                                 netlogon_creds_aes_encrypt(creds,
632                                             base->LMSessKey.key,
633                                             sizeof(base->LMSessKey.key));
634
635                         } else {
636                                 netlogon_creds_aes_decrypt(creds,
637                                             base->LMSessKey.key,
638                                             sizeof(base->LMSessKey.key));
639                         }
640                 }
641         } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
642                 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
643                 if (!all_zero(base->key.key, sizeof(base->key.key))) {
644                         netlogon_creds_arcfour_crypt(creds,
645                                             base->key.key,
646                                             sizeof(base->key.key));
647                 }
648
649                 if (!all_zero(base->LMSessKey.key,
650                               sizeof(base->LMSessKey.key))) {
651                         netlogon_creds_arcfour_crypt(creds,
652                                             base->LMSessKey.key,
653                                             sizeof(base->LMSessKey.key));
654                 }
655         } else {
656                 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
657                 if (!all_zero(base->LMSessKey.key,
658                               sizeof(base->LMSessKey.key))) {
659                         if (do_encrypt) {
660                                 netlogon_creds_des_encrypt_LMKey(creds,
661                                                 &base->LMSessKey);
662                         } else {
663                                 netlogon_creds_des_decrypt_LMKey(creds,
664                                                 &base->LMSessKey);
665                         }
666                 }
667         }
668 }
669
670 void netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
671                                                 uint16_t validation_level,
672                                                 union netr_Validation *validation)
673 {
674         netlogon_creds_crypt_samlogon_validation(creds, validation_level,
675                                                         validation, false);
676 }
677
678 void netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
679                                                 uint16_t validation_level,
680                                                 union netr_Validation *validation)
681 {
682         netlogon_creds_crypt_samlogon_validation(creds, validation_level,
683                                                         validation, true);
684 }
685
686 static void netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
687                                                 enum netr_LogonInfoClass level,
688                                                 union netr_LogonLevel *logon,
689                                                 bool do_encrypt)
690 {
691         if (logon == NULL) {
692                 return;
693         }
694
695         switch (level) {
696         case NetlogonInteractiveInformation:
697         case NetlogonInteractiveTransitiveInformation:
698         case NetlogonServiceInformation:
699         case NetlogonServiceTransitiveInformation:
700                 if (logon->password == NULL) {
701                         return;
702                 }
703
704                 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
705                         uint8_t *h;
706
707                         h = logon->password->lmpassword.hash;
708                         if (!all_zero(h, 16)) {
709                                 if (do_encrypt) {
710                                         netlogon_creds_aes_encrypt(creds, h, 16);
711                                 } else {
712                                         netlogon_creds_aes_decrypt(creds, h, 16);
713                                 }
714                         }
715
716                         h = logon->password->ntpassword.hash;
717                         if (!all_zero(h, 16)) {
718                                 if (do_encrypt) {
719                                         netlogon_creds_aes_encrypt(creds, h, 16);
720                                 } else {
721                                         netlogon_creds_aes_decrypt(creds, h, 16);
722                                 }
723                         }
724                 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
725                         uint8_t *h;
726
727                         h = logon->password->lmpassword.hash;
728                         if (!all_zero(h, 16)) {
729                                 netlogon_creds_arcfour_crypt(creds, h, 16);
730                         }
731
732                         h = logon->password->ntpassword.hash;
733                         if (!all_zero(h, 16)) {
734                                 netlogon_creds_arcfour_crypt(creds, h, 16);
735                         }
736                 } else {
737                         struct samr_Password *p;
738
739                         p = &logon->password->lmpassword;
740                         if (!all_zero(p->hash, 16)) {
741                                 if (do_encrypt) {
742                                         netlogon_creds_des_encrypt(creds, p);
743                                 } else {
744                                         netlogon_creds_des_decrypt(creds, p);
745                                 }
746                         }
747                         p = &logon->password->ntpassword;
748                         if (!all_zero(p->hash, 16)) {
749                                 if (do_encrypt) {
750                                         netlogon_creds_des_encrypt(creds, p);
751                                 } else {
752                                         netlogon_creds_des_decrypt(creds, p);
753                                 }
754                         }
755                 }
756                 break;
757
758         case NetlogonNetworkInformation:
759         case NetlogonNetworkTransitiveInformation:
760                 break;
761
762         case NetlogonGenericInformation:
763                 if (logon->generic == NULL) {
764                         return;
765                 }
766
767                 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
768                         if (do_encrypt) {
769                                 netlogon_creds_aes_encrypt(creds,
770                                                 logon->generic->data,
771                                                 logon->generic->length);
772                         } else {
773                                 netlogon_creds_aes_decrypt(creds,
774                                                 logon->generic->data,
775                                                 logon->generic->length);
776                         }
777                 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
778                         netlogon_creds_arcfour_crypt(creds,
779                                                      logon->generic->data,
780                                                      logon->generic->length);
781                 } else {
782                         /* Using DES to verify kerberos tickets makes no sense */
783                 }
784                 break;
785         }
786 }
787
788 void netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
789                                            enum netr_LogonInfoClass level,
790                                            union netr_LogonLevel *logon)
791 {
792         netlogon_creds_crypt_samlogon_logon(creds, level, logon, false);
793 }
794
795 void netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
796                                            enum netr_LogonInfoClass level,
797                                            union netr_LogonLevel *logon)
798 {
799         netlogon_creds_crypt_samlogon_logon(creds, level, logon, true);
800 }
801
802 union netr_LogonLevel *netlogon_creds_shallow_copy_logon(TALLOC_CTX *mem_ctx,
803                                         enum netr_LogonInfoClass level,
804                                         const union netr_LogonLevel *in)
805 {
806         union netr_LogonLevel *out;
807
808         if (in == NULL) {
809                 return NULL;
810         }
811
812         out = talloc(mem_ctx, union netr_LogonLevel);
813         if (out == NULL) {
814                 return NULL;
815         }
816
817         *out = *in;
818
819         switch (level) {
820         case NetlogonInteractiveInformation:
821         case NetlogonInteractiveTransitiveInformation:
822         case NetlogonServiceInformation:
823         case NetlogonServiceTransitiveInformation:
824                 if (in->password == NULL) {
825                         return out;
826                 }
827
828                 out->password = talloc(out, struct netr_PasswordInfo);
829                 if (out->password == NULL) {
830                         talloc_free(out);
831                         return NULL;
832                 }
833                 *out->password = *in->password;
834
835                 return out;
836
837         case NetlogonNetworkInformation:
838         case NetlogonNetworkTransitiveInformation:
839                 break;
840
841         case NetlogonGenericInformation:
842                 if (in->generic == NULL) {
843                         return out;
844                 }
845
846                 out->generic = talloc(out, struct netr_GenericInfo);
847                 if (out->generic == NULL) {
848                         talloc_free(out);
849                         return NULL;
850                 }
851                 *out->generic = *in->generic;
852
853                 if (in->generic->data == NULL) {
854                         return out;
855                 }
856
857                 if (in->generic->length == 0) {
858                         return out;
859                 }
860
861                 out->generic->data = talloc_memdup(out->generic,
862                                                    in->generic->data,
863                                                    in->generic->length);
864                 if (out->generic->data == NULL) {
865                         talloc_free(out);
866                         return NULL;
867                 }
868
869                 return out;
870         }
871
872         return out;
873 }
874
875 /*
876   copy a netlogon_creds_CredentialState struct
877 */
878
879 struct netlogon_creds_CredentialState *netlogon_creds_copy(
880         TALLOC_CTX *mem_ctx,
881         const struct netlogon_creds_CredentialState *creds_in)
882 {
883         struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
884
885         if (!creds) {
886                 return NULL;
887         }
888
889         creds->sequence                 = creds_in->sequence;
890         creds->negotiate_flags          = creds_in->negotiate_flags;
891         creds->secure_channel_type      = creds_in->secure_channel_type;
892
893         creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
894         if (!creds->computer_name) {
895                 talloc_free(creds);
896                 return NULL;
897         }
898         creds->account_name = talloc_strdup(creds, creds_in->account_name);
899         if (!creds->account_name) {
900                 talloc_free(creds);
901                 return NULL;
902         }
903
904         if (creds_in->sid) {
905                 creds->sid = dom_sid_dup(creds, creds_in->sid);
906                 if (!creds->sid) {
907                         talloc_free(creds);
908                         return NULL;
909                 }
910         }
911
912         memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
913         memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
914         memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
915         memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
916
917         return creds;
918 }