s3/lib/ctdbd_conn: assert hdr following read/recv
[Samba.git] / libcli / auth / credentials.c
blobbaa436df71b6d6e73ce4edae0b64e8f974448d2d
1 /*
2 Unix SMB/CIFS implementation.
4 code to manipulate domain credentials
6 Copyright (C) Andrew Tridgell 1997-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
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.
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.
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/>.
23 #include "includes.h"
24 #include "system/time.h"
25 #include "libcli/auth/libcli_auth.h"
26 #include "../libcli/security/dom_sid.h"
28 #ifndef HAVE_GNUTLS_AES_CFB8
29 #include "lib/crypto/aes.h"
30 #endif
32 #include "lib/crypto/gnutls_helpers.h"
33 #include <gnutls/gnutls.h>
34 #include <gnutls/crypto.h>
36 static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
37 const struct netr_Credential *in,
38 struct netr_Credential *out)
40 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
41 memcpy(out->data, in->data, sizeof(out->data));
43 netlogon_creds_aes_encrypt(creds, out->data, sizeof(out->data));
44 } else {
45 des_crypt112(out->data, in->data, creds->session_key, 1);
50 initialise the credentials state for old-style 64 bit session keys
52 this call is made after the netr_ServerReqChallenge call
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)
59 uint32_t sum[2];
60 uint8_t sum2[8];
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);
65 SIVAL(sum2,0,sum[0]);
66 SIVAL(sum2,4,sum[1]);
68 ZERO_ARRAY(creds->session_key);
70 des_crypt128(creds->session_key, sum2, machine_password->hash);
74 initialise the credentials state for ADS-style 128 bit session keys
76 this call is made after the netr_ServerReqChallenge call
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)
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;
88 ZERO_ARRAY(creds->session_key);
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);
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);
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);
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);
111 gnutls_hash_deinit(hash_hnd, tmp);
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);
122 if (rc < 0) {
123 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
126 return NT_STATUS_OK;
130 initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
132 this call is made after the netr_ServerReqChallenge call
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)
139 gnutls_hmac_hd_t hmac_hnd = NULL;
140 uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)];
141 int rc;
143 ZERO_ARRAY(creds->session_key);
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);
152 rc = gnutls_hmac(hmac_hnd,
153 client_challenge->data,
155 if (rc < 0) {
156 gnutls_hmac_deinit(hmac_hnd, NULL);
157 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
159 rc = gnutls_hmac(hmac_hnd,
160 server_challenge->data,
162 if (rc < 0) {
163 gnutls_hmac_deinit(hmac_hnd, NULL);
164 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
166 gnutls_hmac_deinit(hmac_hnd, digest);
168 memcpy(creds->session_key, digest, sizeof(creds->session_key));
170 ZERO_ARRAY(digest);
172 return NT_STATUS_OK;
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)
179 netlogon_creds_step_crypt(creds, client_challenge, &creds->client);
181 netlogon_creds_step_crypt(creds, server_challenge, &creds->server);
183 creds->seed = creds->client;
187 step the credentials to the next element in the chain, updating the
188 current client and server credentials and the seed
190 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
192 struct netr_Credential time_cred;
194 DEBUG(5,("\tseed %08x:%08x\n",
195 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
197 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
198 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
200 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
202 netlogon_creds_step_crypt(creds, &time_cred, &creds->client);
204 DEBUG(5,("\tCLIENT %08x:%08x\n",
205 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
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));
210 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
211 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
213 netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
215 DEBUG(5,("\tSERVER %08x:%08x\n",
216 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
218 creds->seed = time_cred;
223 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
225 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
227 struct netr_LMSessionKey tmp;
228 des_crypt56(tmp.key, key->key, creds->session_key, 1);
229 *key = tmp;
233 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
235 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
237 struct netr_LMSessionKey tmp;
238 des_crypt56(tmp.key, key->key, creds->session_key, 0);
239 *key = tmp;
243 DES encrypt a 16 byte password buffer using the session key
245 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
247 struct samr_Password tmp;
248 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
249 *pass = tmp;
253 DES decrypt a 16 byte password buffer using the session key
255 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
257 struct samr_Password tmp;
258 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
259 *pass = tmp;
263 ARCFOUR encrypt/decrypt a password buffer using the session key
265 NTSTATUS netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds,
266 uint8_t *data,
267 size_t len)
269 gnutls_cipher_hd_t cipher_hnd = NULL;
270 gnutls_datum_t session_key = {
271 .data = creds->session_key,
272 .size = sizeof(creds->session_key),
274 int rc;
276 rc = gnutls_cipher_init(&cipher_hnd,
277 GNUTLS_CIPHER_ARCFOUR_128,
278 &session_key,
279 NULL);
280 if (rc < 0) {
281 return gnutls_error_to_ntstatus(rc,
282 NT_STATUS_CRYPTO_SYSTEM_INVALID);
284 rc = gnutls_cipher_encrypt(cipher_hnd,
285 data,
286 len);
287 gnutls_cipher_deinit(cipher_hnd);
288 if (rc < 0) {
289 return gnutls_error_to_ntstatus(rc,
290 NT_STATUS_CRYPTO_SYSTEM_INVALID);
293 return NT_STATUS_OK;
297 AES encrypt a password buffer using the session key
299 NTSTATUS netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds,
300 uint8_t *data,
301 size_t len)
303 #ifdef HAVE_GNUTLS_AES_CFB8
304 gnutls_cipher_hd_t cipher_hnd = NULL;
305 gnutls_datum_t key = {
306 .data = creds->session_key,
307 .size = sizeof(creds->session_key),
309 uint32_t iv_size =
310 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
311 uint8_t _iv[iv_size];
312 gnutls_datum_t iv = {
313 .data = _iv,
314 .size = iv_size,
316 int rc;
318 ZERO_ARRAY(_iv);
320 rc = gnutls_cipher_init(&cipher_hnd,
321 GNUTLS_CIPHER_AES_128_CFB8,
322 &key,
323 &iv);
324 if (rc < 0) {
325 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
328 rc = gnutls_cipher_encrypt(cipher_hnd, data, len);
329 gnutls_cipher_deinit(cipher_hnd);
330 if (rc < 0) {
331 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
334 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
335 AES_KEY key;
336 uint8_t iv[AES_BLOCK_SIZE] = {0};
338 AES_set_encrypt_key(creds->session_key, 128, &key);
340 aes_cfb8_encrypt(data, data, len, &key, iv, AES_ENCRYPT);
341 #endif /* HAVE_GNUTLS_AES_CFB8 */
343 return NT_STATUS_OK;
347 AES decrypt a password buffer using the session key
349 NTSTATUS netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
351 #ifdef HAVE_GNUTLS_AES_CFB8
352 gnutls_cipher_hd_t cipher_hnd = NULL;
353 gnutls_datum_t key = {
354 .data = creds->session_key,
355 .size = sizeof(creds->session_key),
357 uint32_t iv_size =
358 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
359 uint8_t _iv[iv_size];
360 gnutls_datum_t iv = {
361 .data = _iv,
362 .size = iv_size,
364 int rc;
366 ZERO_ARRAY(_iv);
368 rc = gnutls_cipher_init(&cipher_hnd,
369 GNUTLS_CIPHER_AES_128_CFB8,
370 &key,
371 &iv);
372 if (rc < 0) {
373 return gnutls_error_to_ntstatus(rc,
374 NT_STATUS_CRYPTO_SYSTEM_INVALID);
377 rc = gnutls_cipher_decrypt(cipher_hnd, data, len);
378 gnutls_cipher_deinit(cipher_hnd);
379 if (rc < 0) {
380 return gnutls_error_to_ntstatus(rc,
381 NT_STATUS_CRYPTO_SYSTEM_INVALID);
384 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
385 AES_KEY key;
386 uint8_t iv[AES_BLOCK_SIZE] = {0};
388 AES_set_encrypt_key(creds->session_key, 128, &key);
390 aes_cfb8_encrypt(data, data, len, &key, iv, AES_DECRYPT);
391 #endif /* HAVE_GNUTLS_AES_CFB8 */
393 return NT_STATUS_OK;
396 /*****************************************************************
397 The above functions are common to the client and server interface
398 next comes the client specific functions
399 ******************************************************************/
402 initialise the credentials chain and return the first client
403 credentials
406 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
407 const char *client_account,
408 const char *client_computer_name,
409 uint16_t secure_channel_type,
410 const struct netr_Credential *client_challenge,
411 const struct netr_Credential *server_challenge,
412 const struct samr_Password *machine_password,
413 struct netr_Credential *initial_credential,
414 uint32_t negotiate_flags)
416 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
417 NTSTATUS status;
419 if (!creds) {
420 return NULL;
423 creds->sequence = time(NULL);
424 creds->negotiate_flags = negotiate_flags;
425 creds->secure_channel_type = secure_channel_type;
427 creds->computer_name = talloc_strdup(creds, client_computer_name);
428 if (!creds->computer_name) {
429 talloc_free(creds);
430 return NULL;
432 creds->account_name = talloc_strdup(creds, client_account);
433 if (!creds->account_name) {
434 talloc_free(creds);
435 return NULL;
438 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
439 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
440 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
442 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
443 status = netlogon_creds_init_hmac_sha256(creds,
444 client_challenge,
445 server_challenge,
446 machine_password);
447 if (!NT_STATUS_IS_OK(status)) {
448 talloc_free(creds);
449 return NULL;
451 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
452 status = netlogon_creds_init_128bit(creds,
453 client_challenge,
454 server_challenge,
455 machine_password);
456 if (!NT_STATUS_IS_OK(status)) {
457 talloc_free(creds);
458 return NULL;
460 } else {
461 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
464 netlogon_creds_first_step(creds, client_challenge, server_challenge);
466 dump_data_pw("Session key", creds->session_key, 16);
467 dump_data_pw("Credential ", creds->client.data, 8);
469 *initial_credential = creds->client;
470 return creds;
474 initialise the credentials structure with only a session key. The caller better know what they are doing!
477 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
478 const uint8_t session_key[16])
480 struct netlogon_creds_CredentialState *creds;
482 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
483 if (!creds) {
484 return NULL;
487 memcpy(creds->session_key, session_key, 16);
489 return creds;
493 step the credentials to the next element in the chain, updating the
494 current client and server credentials and the seed
496 produce the next authenticator in the sequence ready to send to
497 the server
499 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
500 struct netr_Authenticator *next)
502 uint32_t t32n = (uint32_t)time(NULL);
505 * we always increment and ignore an overflow here
507 creds->sequence += 2;
509 if (t32n > creds->sequence) {
511 * we may increment more
513 creds->sequence = t32n;
514 } else {
515 uint32_t d = creds->sequence - t32n;
517 if (d >= INT32_MAX) {
519 * got an overflow of time_t vs. uint32_t
521 creds->sequence = t32n;
525 netlogon_creds_step(creds);
527 next->cred = creds->client;
528 next->timestamp = creds->sequence;
532 check that a credentials reply from a server is correct
534 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
535 const struct netr_Credential *received_credentials)
537 if (!received_credentials ||
538 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
539 DEBUG(2,("credentials check failed\n"));
540 return false;
542 return true;
546 /*****************************************************************
547 The above functions are common to the client and server interface
548 next comes the server specific functions
549 ******************************************************************/
552 check that a credentials reply from a server is correct
554 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
555 const struct netr_Credential *received_credentials)
557 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
558 DEBUG(2,("credentials check failed\n"));
559 dump_data_pw("client creds", creds->client.data, 8);
560 dump_data_pw("calc creds", received_credentials->data, 8);
561 return false;
563 return true;
567 initialise the credentials chain and return the first server
568 credentials
570 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
571 const char *client_account,
572 const char *client_computer_name,
573 uint16_t secure_channel_type,
574 const struct netr_Credential *client_challenge,
575 const struct netr_Credential *server_challenge,
576 const struct samr_Password *machine_password,
577 const struct netr_Credential *credentials_in,
578 struct netr_Credential *credentials_out,
579 uint32_t negotiate_flags)
582 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
584 if (!creds) {
585 return NULL;
588 creds->negotiate_flags = negotiate_flags;
589 creds->secure_channel_type = secure_channel_type;
591 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
592 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
593 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
595 creds->computer_name = talloc_strdup(creds, client_computer_name);
596 if (!creds->computer_name) {
597 talloc_free(creds);
598 return NULL;
600 creds->account_name = talloc_strdup(creds, client_account);
601 if (!creds->account_name) {
602 talloc_free(creds);
603 return NULL;
606 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
607 NTSTATUS status;
609 status = netlogon_creds_init_hmac_sha256(creds,
610 client_challenge,
611 server_challenge,
612 machine_password);
613 if (!NT_STATUS_IS_OK(status)) {
614 talloc_free(creds);
615 return NULL;
617 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
618 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
619 machine_password);
620 } else {
621 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
622 machine_password);
625 netlogon_creds_first_step(creds, client_challenge, server_challenge);
627 dump_data_pw("Session key", creds->session_key, 16);
628 dump_data_pw("Client Credential ", creds->client.data, 8);
629 dump_data_pw("Server Credential ", creds->server.data, 8);
631 dump_data_pw("Credentials in", credentials_in->data, sizeof(credentials_in->data));
633 /* And before we leak information about the machine account
634 * password, check that they got the first go right */
635 if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
636 talloc_free(creds);
637 return NULL;
640 *credentials_out = creds->server;
642 dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
644 return creds;
647 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
648 const struct netr_Authenticator *received_authenticator,
649 struct netr_Authenticator *return_authenticator)
651 if (!received_authenticator || !return_authenticator) {
652 return NT_STATUS_INVALID_PARAMETER;
655 if (!creds) {
656 return NT_STATUS_ACCESS_DENIED;
659 creds->sequence = received_authenticator->timestamp;
660 netlogon_creds_step(creds);
661 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
662 return_authenticator->cred = creds->server;
663 return_authenticator->timestamp = 0;
664 return NT_STATUS_OK;
665 } else {
666 ZERO_STRUCTP(return_authenticator);
667 return NT_STATUS_ACCESS_DENIED;
671 static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
672 uint16_t validation_level,
673 union netr_Validation *validation,
674 bool do_encrypt)
676 struct netr_SamBaseInfo *base = NULL;
677 NTSTATUS status;
679 if (validation == NULL) {
680 return NT_STATUS_INVALID_PARAMETER;
683 switch (validation_level) {
684 case 2:
685 if (validation->sam2) {
686 base = &validation->sam2->base;
688 break;
689 case 3:
690 if (validation->sam3) {
691 base = &validation->sam3->base;
693 break;
694 case 6:
695 if (validation->sam6) {
696 base = &validation->sam6->base;
698 break;
699 default:
700 /* If we can't find it, we can't very well decrypt it */
701 return NT_STATUS_INVALID_INFO_CLASS;
704 if (!base) {
705 return NT_STATUS_INVALID_INFO_CLASS;
708 /* find and decyrpt the session keys, return in parameters above */
709 if (validation_level == 6) {
710 /* they aren't encrypted! */
711 } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
712 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
713 if (!all_zero(base->key.key, sizeof(base->key.key))) {
714 if (do_encrypt) {
715 status = netlogon_creds_aes_encrypt(
716 creds,
717 base->key.key,
718 sizeof(base->key.key));
719 } else {
720 status = netlogon_creds_aes_decrypt(
721 creds,
722 base->key.key,
723 sizeof(base->key.key));
725 if (!NT_STATUS_IS_OK(status)) {
726 return status;
730 if (!all_zero(base->LMSessKey.key,
731 sizeof(base->LMSessKey.key))) {
732 if (do_encrypt) {
733 status = netlogon_creds_aes_encrypt(
734 creds,
735 base->LMSessKey.key,
736 sizeof(base->LMSessKey.key));
737 } else {
738 status = netlogon_creds_aes_decrypt(
739 creds,
740 base->LMSessKey.key,
741 sizeof(base->LMSessKey.key));
743 if (!NT_STATUS_IS_OK(status)) {
744 return status;
747 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
748 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
749 if (!all_zero(base->key.key, sizeof(base->key.key))) {
750 status = netlogon_creds_arcfour_crypt(creds,
751 base->key.key,
752 sizeof(base->key.key));
753 if (!NT_STATUS_IS_OK(status)) {
754 return status;
758 if (!all_zero(base->LMSessKey.key,
759 sizeof(base->LMSessKey.key))) {
760 status = netlogon_creds_arcfour_crypt(creds,
761 base->LMSessKey.key,
762 sizeof(base->LMSessKey.key));
763 if (!NT_STATUS_IS_OK(status)) {
764 return status;
767 } else {
768 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
769 if (!all_zero(base->LMSessKey.key,
770 sizeof(base->LMSessKey.key))) {
771 if (do_encrypt) {
772 netlogon_creds_des_encrypt_LMKey(creds,
773 &base->LMSessKey);
774 } else {
775 netlogon_creds_des_decrypt_LMKey(creds,
776 &base->LMSessKey);
781 return NT_STATUS_OK;
784 NTSTATUS netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
785 uint16_t validation_level,
786 union netr_Validation *validation)
788 return netlogon_creds_crypt_samlogon_validation(creds,
789 validation_level,
790 validation,
791 false);
794 NTSTATUS netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
795 uint16_t validation_level,
796 union netr_Validation *validation)
798 return netlogon_creds_crypt_samlogon_validation(creds,
799 validation_level,
800 validation,
801 true);
804 static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
805 enum netr_LogonInfoClass level,
806 union netr_LogonLevel *logon,
807 bool do_encrypt)
809 NTSTATUS status;
811 if (logon == NULL) {
812 return NT_STATUS_INVALID_PARAMETER;
815 switch (level) {
816 case NetlogonInteractiveInformation:
817 case NetlogonInteractiveTransitiveInformation:
818 case NetlogonServiceInformation:
819 case NetlogonServiceTransitiveInformation:
820 if (logon->password == NULL) {
821 return NT_STATUS_INVALID_PARAMETER;
824 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
825 uint8_t *h;
827 h = logon->password->lmpassword.hash;
828 if (!all_zero(h, 16)) {
829 if (do_encrypt) {
830 status = netlogon_creds_aes_encrypt(
831 creds,
833 16);
834 } else {
835 status = netlogon_creds_aes_decrypt(
836 creds,
838 16);
840 if (!NT_STATUS_IS_OK(status)) {
841 return status;
845 h = logon->password->ntpassword.hash;
846 if (!all_zero(h, 16)) {
847 if (do_encrypt) {
848 status = netlogon_creds_aes_encrypt(creds,
850 16);
851 } else {
852 status = netlogon_creds_aes_decrypt(creds,
854 16);
856 if (!NT_STATUS_IS_OK(status)) {
857 return status;
860 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
861 uint8_t *h;
863 h = logon->password->lmpassword.hash;
864 if (!all_zero(h, 16)) {
865 status = netlogon_creds_arcfour_crypt(creds,
867 16);
868 if (!NT_STATUS_IS_OK(status)) {
869 return status;
873 h = logon->password->ntpassword.hash;
874 if (!all_zero(h, 16)) {
875 status = netlogon_creds_arcfour_crypt(creds,
877 16);
878 if (!NT_STATUS_IS_OK(status)) {
879 return status;
882 } else {
883 struct samr_Password *p;
885 p = &logon->password->lmpassword;
886 if (!all_zero(p->hash, 16)) {
887 if (do_encrypt) {
888 netlogon_creds_des_encrypt(creds, p);
889 } else {
890 netlogon_creds_des_decrypt(creds, p);
893 p = &logon->password->ntpassword;
894 if (!all_zero(p->hash, 16)) {
895 if (do_encrypt) {
896 netlogon_creds_des_encrypt(creds, p);
897 } else {
898 netlogon_creds_des_decrypt(creds, p);
902 break;
904 case NetlogonNetworkInformation:
905 case NetlogonNetworkTransitiveInformation:
906 break;
908 case NetlogonGenericInformation:
909 if (logon->generic == NULL) {
910 return NT_STATUS_INVALID_PARAMETER;
913 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
914 if (do_encrypt) {
915 status = netlogon_creds_aes_encrypt(
916 creds,
917 logon->generic->data,
918 logon->generic->length);
919 } else {
920 status = netlogon_creds_aes_decrypt(
921 creds,
922 logon->generic->data,
923 logon->generic->length);
925 if (!NT_STATUS_IS_OK(status)) {
926 return status;
928 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
929 status = netlogon_creds_arcfour_crypt(creds,
930 logon->generic->data,
931 logon->generic->length);
932 if (!NT_STATUS_IS_OK(status)) {
933 return status;
935 } else {
936 /* Using DES to verify kerberos tickets makes no sense */
938 break;
941 return NT_STATUS_OK;
944 NTSTATUS netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
945 enum netr_LogonInfoClass level,
946 union netr_LogonLevel *logon)
948 return netlogon_creds_crypt_samlogon_logon(creds, level, logon, false);
951 NTSTATUS netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
952 enum netr_LogonInfoClass level,
953 union netr_LogonLevel *logon)
955 return netlogon_creds_crypt_samlogon_logon(creds, level, logon, true);
958 union netr_LogonLevel *netlogon_creds_shallow_copy_logon(TALLOC_CTX *mem_ctx,
959 enum netr_LogonInfoClass level,
960 const union netr_LogonLevel *in)
962 union netr_LogonLevel *out;
964 if (in == NULL) {
965 return NULL;
968 out = talloc(mem_ctx, union netr_LogonLevel);
969 if (out == NULL) {
970 return NULL;
973 *out = *in;
975 switch (level) {
976 case NetlogonInteractiveInformation:
977 case NetlogonInteractiveTransitiveInformation:
978 case NetlogonServiceInformation:
979 case NetlogonServiceTransitiveInformation:
980 if (in->password == NULL) {
981 return out;
984 out->password = talloc(out, struct netr_PasswordInfo);
985 if (out->password == NULL) {
986 talloc_free(out);
987 return NULL;
989 *out->password = *in->password;
991 return out;
993 case NetlogonNetworkInformation:
994 case NetlogonNetworkTransitiveInformation:
995 break;
997 case NetlogonGenericInformation:
998 if (in->generic == NULL) {
999 return out;
1002 out->generic = talloc(out, struct netr_GenericInfo);
1003 if (out->generic == NULL) {
1004 talloc_free(out);
1005 return NULL;
1007 *out->generic = *in->generic;
1009 if (in->generic->data == NULL) {
1010 return out;
1013 if (in->generic->length == 0) {
1014 return out;
1017 out->generic->data = talloc_memdup(out->generic,
1018 in->generic->data,
1019 in->generic->length);
1020 if (out->generic->data == NULL) {
1021 talloc_free(out);
1022 return NULL;
1025 return out;
1028 return out;
1032 copy a netlogon_creds_CredentialState struct
1035 struct netlogon_creds_CredentialState *netlogon_creds_copy(
1036 TALLOC_CTX *mem_ctx,
1037 const struct netlogon_creds_CredentialState *creds_in)
1039 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
1041 if (!creds) {
1042 return NULL;
1045 creds->sequence = creds_in->sequence;
1046 creds->negotiate_flags = creds_in->negotiate_flags;
1047 creds->secure_channel_type = creds_in->secure_channel_type;
1049 creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
1050 if (!creds->computer_name) {
1051 talloc_free(creds);
1052 return NULL;
1054 creds->account_name = talloc_strdup(creds, creds_in->account_name);
1055 if (!creds->account_name) {
1056 talloc_free(creds);
1057 return NULL;
1060 if (creds_in->sid) {
1061 creds->sid = dom_sid_dup(creds, creds_in->sid);
1062 if (!creds->sid) {
1063 talloc_free(creds);
1064 return NULL;
1068 memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
1069 memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
1070 memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
1071 memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
1073 return creds;