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