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/>.
24 #include "system/time.h"
25 #include "libcli/auth/libcli_auth.h"
26 #include "../libcli/security/dom_sid.h"
27 #include "lib/util/util_str_escape.h"
29 #ifndef HAVE_GNUTLS_AES_CFB8
30 #include "lib/crypto/aes.h"
33 #include "lib/crypto/gnutls_helpers.h"
34 #include <gnutls/gnutls.h>
35 #include <gnutls/crypto.h>
37 bool netlogon_creds_is_random_challenge(const struct netr_Credential
*challenge
)
40 * If none of the first 5 bytes of the client challenge is unique, the
41 * server MUST fail session-key negotiation without further processing
42 * of the following steps.
45 if (challenge
->data
[1] == challenge
->data
[0] &&
46 challenge
->data
[2] == challenge
->data
[0] &&
47 challenge
->data
[3] == challenge
->data
[0] &&
48 challenge
->data
[4] == challenge
->data
[0])
56 void netlogon_creds_random_challenge(struct netr_Credential
*challenge
)
58 ZERO_STRUCTP(challenge
);
59 while (!netlogon_creds_is_random_challenge(challenge
)) {
60 generate_random_buffer(challenge
->data
, sizeof(challenge
->data
));
64 static NTSTATUS
netlogon_creds_step_crypt(struct netlogon_creds_CredentialState
*creds
,
65 const struct netr_Credential
*in
,
66 struct netr_Credential
*out
)
71 if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
72 memcpy(out
->data
, in
->data
, sizeof(out
->data
));
74 status
= netlogon_creds_aes_encrypt(creds
,
77 if (!NT_STATUS_IS_OK(status
)) {
81 rc
= des_crypt112(out
->data
, in
->data
, creds
->session_key
, SAMBA_GNUTLS_ENCRYPT
);
83 return gnutls_error_to_ntstatus(rc
,
84 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
92 initialise the credentials state for old-style 64 bit session keys
94 this call is made after the netr_ServerReqChallenge call
96 static NTSTATUS
netlogon_creds_init_64bit(struct netlogon_creds_CredentialState
*creds
,
97 const struct netr_Credential
*client_challenge
,
98 const struct netr_Credential
*server_challenge
,
99 const struct samr_Password
*machine_password
)
105 sum
[0] = IVAL(client_challenge
->data
, 0) + IVAL(server_challenge
->data
, 0);
106 sum
[1] = IVAL(client_challenge
->data
, 4) + IVAL(server_challenge
->data
, 4);
108 SIVAL(sum2
,0,sum
[0]);
109 SIVAL(sum2
,4,sum
[1]);
111 ZERO_ARRAY(creds
->session_key
);
113 rc
= des_crypt128(creds
->session_key
, sum2
, machine_password
->hash
);
115 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
122 initialise the credentials state for ADS-style 128 bit session keys
124 this call is made after the netr_ServerReqChallenge call
126 static NTSTATUS
netlogon_creds_init_128bit(struct netlogon_creds_CredentialState
*creds
,
127 const struct netr_Credential
*client_challenge
,
128 const struct netr_Credential
*server_challenge
,
129 const struct samr_Password
*machine_password
)
131 uint8_t zero
[4] = {0};
132 uint8_t tmp
[gnutls_hash_get_len(GNUTLS_MAC_MD5
)];
133 gnutls_hash_hd_t hash_hnd
= NULL
;
136 ZERO_ARRAY(creds
->session_key
);
138 rc
= gnutls_hash_init(&hash_hnd
, GNUTLS_DIG_MD5
);
140 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
143 rc
= gnutls_hash(hash_hnd
, zero
, sizeof(zero
));
145 gnutls_hash_deinit(hash_hnd
, NULL
);
146 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
148 rc
= gnutls_hash(hash_hnd
, client_challenge
->data
, 8);
150 gnutls_hash_deinit(hash_hnd
, NULL
);
151 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
153 rc
= gnutls_hash(hash_hnd
, server_challenge
->data
, 8);
155 gnutls_hash_deinit(hash_hnd
, NULL
);
156 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
159 gnutls_hash_deinit(hash_hnd
, tmp
);
161 /* This doesn't require HMAC MD5 RFC2104 as the hash is only 16 bytes */
162 rc
= gnutls_hmac_fast(GNUTLS_MAC_MD5
,
163 machine_password
->hash
,
164 sizeof(machine_password
->hash
),
171 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
178 initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
180 this call is made after the netr_ServerReqChallenge call
182 static NTSTATUS
netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState
*creds
,
183 const struct netr_Credential
*client_challenge
,
184 const struct netr_Credential
*server_challenge
,
185 const struct samr_Password
*machine_password
)
187 gnutls_hmac_hd_t hmac_hnd
= NULL
;
188 uint8_t digest
[gnutls_hash_get_len(GNUTLS_MAC_SHA256
)];
191 ZERO_ARRAY(creds
->session_key
);
193 rc
= gnutls_hmac_init(&hmac_hnd
,
195 machine_password
->hash
,
196 sizeof(machine_password
->hash
));
198 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HMAC_NOT_SUPPORTED
);
200 rc
= gnutls_hmac(hmac_hnd
,
201 client_challenge
->data
,
204 gnutls_hmac_deinit(hmac_hnd
, NULL
);
205 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HMAC_NOT_SUPPORTED
);
207 rc
= gnutls_hmac(hmac_hnd
,
208 server_challenge
->data
,
211 gnutls_hmac_deinit(hmac_hnd
, NULL
);
212 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HMAC_NOT_SUPPORTED
);
214 gnutls_hmac_deinit(hmac_hnd
, digest
);
216 memcpy(creds
->session_key
, digest
, sizeof(creds
->session_key
));
223 static NTSTATUS
netlogon_creds_first_step(struct netlogon_creds_CredentialState
*creds
,
224 const struct netr_Credential
*client_challenge
,
225 const struct netr_Credential
*server_challenge
)
229 status
= netlogon_creds_step_crypt(creds
,
232 if (!NT_STATUS_IS_OK(status
)) {
236 status
= netlogon_creds_step_crypt(creds
,
239 if (!NT_STATUS_IS_OK(status
)) {
243 creds
->seed
= creds
->client
;
249 step the credentials to the next element in the chain, updating the
250 current client and server credentials and the seed
252 static NTSTATUS
netlogon_creds_step(struct netlogon_creds_CredentialState
*creds
)
254 struct netr_Credential time_cred
;
257 DEBUG(5,("\tseed %08x:%08x\n",
258 IVAL(creds
->seed
.data
, 0), IVAL(creds
->seed
.data
, 4)));
260 SIVAL(time_cred
.data
, 0, IVAL(creds
->seed
.data
, 0) + creds
->sequence
);
261 SIVAL(time_cred
.data
, 4, IVAL(creds
->seed
.data
, 4));
263 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred
.data
, 0), IVAL(time_cred
.data
, 4)));
265 status
= netlogon_creds_step_crypt(creds
,
268 if (!NT_STATUS_IS_OK(status
)) {
272 DEBUG(5,("\tCLIENT %08x:%08x\n",
273 IVAL(creds
->client
.data
, 0), IVAL(creds
->client
.data
, 4)));
275 SIVAL(time_cred
.data
, 0, IVAL(creds
->seed
.data
, 0) + creds
->sequence
+ 1);
276 SIVAL(time_cred
.data
, 4, IVAL(creds
->seed
.data
, 4));
278 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
279 IVAL(time_cred
.data
, 0), IVAL(time_cred
.data
, 4)));
281 status
= netlogon_creds_step_crypt(creds
, &time_cred
, &creds
->server
);
282 if (!NT_STATUS_IS_OK(status
)) {
286 DEBUG(5,("\tSERVER %08x:%08x\n",
287 IVAL(creds
->server
.data
, 0), IVAL(creds
->server
.data
, 4)));
289 creds
->seed
= time_cred
;
295 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
297 NTSTATUS
netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState
*creds
,
298 struct netr_LMSessionKey
*key
)
301 struct netr_LMSessionKey tmp
;
303 rc
= des_crypt56_gnutls(tmp
.key
, key
->key
, creds
->session_key
, SAMBA_GNUTLS_ENCRYPT
);
305 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
313 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
315 NTSTATUS
netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState
*creds
,
316 struct netr_LMSessionKey
*key
)
319 struct netr_LMSessionKey tmp
;
321 rc
= des_crypt56_gnutls(tmp
.key
, key
->key
, creds
->session_key
, SAMBA_GNUTLS_DECRYPT
);
323 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
331 DES encrypt a 16 byte password buffer using the session key
333 NTSTATUS
netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState
*creds
,
334 struct samr_Password
*pass
)
336 struct samr_Password tmp
;
339 rc
= des_crypt112_16(tmp
.hash
, pass
->hash
, creds
->session_key
, SAMBA_GNUTLS_ENCRYPT
);
341 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
349 DES decrypt a 16 byte password buffer using the session key
351 NTSTATUS
netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState
*creds
,
352 struct samr_Password
*pass
)
354 struct samr_Password tmp
;
357 rc
= des_crypt112_16(tmp
.hash
, pass
->hash
, creds
->session_key
, SAMBA_GNUTLS_DECRYPT
);
359 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
367 ARCFOUR encrypt/decrypt a password buffer using the session key
369 NTSTATUS
netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState
*creds
,
373 gnutls_cipher_hd_t cipher_hnd
= NULL
;
374 gnutls_datum_t session_key
= {
375 .data
= creds
->session_key
,
376 .size
= sizeof(creds
->session_key
),
380 rc
= gnutls_cipher_init(&cipher_hnd
,
381 GNUTLS_CIPHER_ARCFOUR_128
,
385 return gnutls_error_to_ntstatus(rc
,
386 NT_STATUS_CRYPTO_SYSTEM_INVALID
);
388 rc
= gnutls_cipher_encrypt(cipher_hnd
,
391 gnutls_cipher_deinit(cipher_hnd
);
393 return gnutls_error_to_ntstatus(rc
,
394 NT_STATUS_CRYPTO_SYSTEM_INVALID
);
401 AES encrypt a password buffer using the session key
403 NTSTATUS
netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState
*creds
,
407 #ifdef HAVE_GNUTLS_AES_CFB8
408 gnutls_cipher_hd_t cipher_hnd
= NULL
;
409 gnutls_datum_t key
= {
410 .data
= creds
->session_key
,
411 .size
= sizeof(creds
->session_key
),
414 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8
);
415 uint8_t _iv
[iv_size
];
416 gnutls_datum_t iv
= {
424 rc
= gnutls_cipher_init(&cipher_hnd
,
425 GNUTLS_CIPHER_AES_128_CFB8
,
429 return gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
432 rc
= gnutls_cipher_encrypt(cipher_hnd
, data
, len
);
433 gnutls_cipher_deinit(cipher_hnd
);
435 return gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
438 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
440 uint8_t iv
[AES_BLOCK_SIZE
] = {0};
442 AES_set_encrypt_key(creds
->session_key
, 128, &key
);
444 aes_cfb8_encrypt(data
, data
, len
, &key
, iv
, AES_ENCRYPT
);
445 #endif /* HAVE_GNUTLS_AES_CFB8 */
451 AES decrypt a password buffer using the session key
453 NTSTATUS
netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState
*creds
, uint8_t *data
, size_t len
)
455 #ifdef HAVE_GNUTLS_AES_CFB8
456 gnutls_cipher_hd_t cipher_hnd
= NULL
;
457 gnutls_datum_t key
= {
458 .data
= creds
->session_key
,
459 .size
= sizeof(creds
->session_key
),
462 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8
);
463 uint8_t _iv
[iv_size
];
464 gnutls_datum_t iv
= {
472 rc
= gnutls_cipher_init(&cipher_hnd
,
473 GNUTLS_CIPHER_AES_128_CFB8
,
477 return gnutls_error_to_ntstatus(rc
,
478 NT_STATUS_CRYPTO_SYSTEM_INVALID
);
481 rc
= gnutls_cipher_decrypt(cipher_hnd
, data
, len
);
482 gnutls_cipher_deinit(cipher_hnd
);
484 return gnutls_error_to_ntstatus(rc
,
485 NT_STATUS_CRYPTO_SYSTEM_INVALID
);
488 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
490 uint8_t iv
[AES_BLOCK_SIZE
] = {0};
492 AES_set_encrypt_key(creds
->session_key
, 128, &key
);
494 aes_cfb8_encrypt(data
, data
, len
, &key
, iv
, AES_DECRYPT
);
495 #endif /* HAVE_GNUTLS_AES_CFB8 */
500 /*****************************************************************
501 The above functions are common to the client and server interface
502 next comes the client specific functions
503 ******************************************************************/
506 initialise the credentials chain and return the first client
510 struct netlogon_creds_CredentialState
*netlogon_creds_client_init(TALLOC_CTX
*mem_ctx
,
511 const char *client_account
,
512 const char *client_computer_name
,
513 uint16_t secure_channel_type
,
514 const struct netr_Credential
*client_challenge
,
515 const struct netr_Credential
*server_challenge
,
516 const struct samr_Password
*machine_password
,
517 struct netr_Credential
*initial_credential
,
518 uint32_t negotiate_flags
)
520 struct netlogon_creds_CredentialState
*creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
527 creds
->sequence
= time(NULL
);
528 creds
->negotiate_flags
= negotiate_flags
;
529 creds
->secure_channel_type
= secure_channel_type
;
531 creds
->computer_name
= talloc_strdup(creds
, client_computer_name
);
532 if (!creds
->computer_name
) {
536 creds
->account_name
= talloc_strdup(creds
, client_account
);
537 if (!creds
->account_name
) {
542 dump_data_pw("Client chall", client_challenge
->data
, sizeof(client_challenge
->data
));
543 dump_data_pw("Server chall", server_challenge
->data
, sizeof(server_challenge
->data
));
544 dump_data_pw("Machine Pass", machine_password
->hash
, sizeof(machine_password
->hash
));
546 if (negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
547 status
= netlogon_creds_init_hmac_sha256(creds
,
551 if (!NT_STATUS_IS_OK(status
)) {
555 } else if (negotiate_flags
& NETLOGON_NEG_STRONG_KEYS
) {
556 status
= netlogon_creds_init_128bit(creds
,
560 if (!NT_STATUS_IS_OK(status
)) {
565 status
= netlogon_creds_init_64bit(creds
,
569 if (!NT_STATUS_IS_OK(status
)) {
575 status
= netlogon_creds_first_step(creds
,
578 if (!NT_STATUS_IS_OK(status
)) {
583 dump_data_pw("Session key", creds
->session_key
, 16);
584 dump_data_pw("Credential ", creds
->client
.data
, 8);
586 *initial_credential
= creds
->client
;
591 initialise the credentials structure with only a session key. The caller better know what they are doing!
594 struct netlogon_creds_CredentialState
*netlogon_creds_client_init_session_key(TALLOC_CTX
*mem_ctx
,
595 const uint8_t session_key
[16])
597 struct netlogon_creds_CredentialState
*creds
;
599 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
604 memcpy(creds
->session_key
, session_key
, 16);
610 step the credentials to the next element in the chain, updating the
611 current client and server credentials and the seed
613 produce the next authenticator in the sequence ready to send to
617 netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState
*creds
,
618 struct netr_Authenticator
*next
)
620 uint32_t t32n
= (uint32_t)time(NULL
);
624 * we always increment and ignore an overflow here
626 creds
->sequence
+= 2;
628 if (t32n
> creds
->sequence
) {
630 * we may increment more
632 creds
->sequence
= t32n
;
634 uint32_t d
= creds
->sequence
- t32n
;
636 if (d
>= INT32_MAX
) {
638 * got an overflow of time_t vs. uint32_t
640 creds
->sequence
= t32n
;
644 status
= netlogon_creds_step(creds
);
645 if (!NT_STATUS_IS_OK(status
)) {
649 next
->cred
= creds
->client
;
650 next
->timestamp
= creds
->sequence
;
656 check that a credentials reply from a server is correct
658 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState
*creds
,
659 const struct netr_Credential
*received_credentials
)
661 if (!received_credentials
||
662 !mem_equal_const_time(received_credentials
->data
, creds
->server
.data
, 8)) {
663 DEBUG(2,("credentials check failed\n"));
670 /*****************************************************************
671 The above functions are common to the client and server interface
672 next comes the server specific functions
673 ******************************************************************/
676 check that a credentials reply from a server is correct
678 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState
*creds
,
679 const struct netr_Credential
*received_credentials
)
681 if (!mem_equal_const_time(received_credentials
->data
, creds
->client
.data
, 8)) {
682 DEBUG(2,("credentials check failed\n"));
683 dump_data_pw("client creds", creds
->client
.data
, 8);
684 dump_data_pw("calc creds", received_credentials
->data
, 8);
691 initialise the credentials chain and return the first server
694 struct netlogon_creds_CredentialState
*netlogon_creds_server_init(TALLOC_CTX
*mem_ctx
,
695 const char *client_account
,
696 const char *client_computer_name
,
697 uint16_t secure_channel_type
,
698 const struct netr_Credential
*client_challenge
,
699 const struct netr_Credential
*server_challenge
,
700 const struct samr_Password
*machine_password
,
701 const struct netr_Credential
*credentials_in
,
702 struct netr_Credential
*credentials_out
,
703 uint32_t negotiate_flags
)
706 struct netlogon_creds_CredentialState
*creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
714 creds
->negotiate_flags
= negotiate_flags
;
715 creds
->secure_channel_type
= secure_channel_type
;
717 dump_data_pw("Client chall", client_challenge
->data
, sizeof(client_challenge
->data
));
718 dump_data_pw("Server chall", server_challenge
->data
, sizeof(server_challenge
->data
));
719 dump_data_pw("Machine Pass", machine_password
->hash
, sizeof(machine_password
->hash
));
721 ok
= netlogon_creds_is_random_challenge(client_challenge
);
723 DBG_WARNING("CVE-2020-1472(ZeroLogon): "
724 "non-random client challenge rejected for "
725 "client_account[%s] client_computer_name[%s]\n",
726 log_escape(mem_ctx
, client_account
),
727 log_escape(mem_ctx
, client_computer_name
));
728 dump_data(DBGLVL_WARNING
,
729 client_challenge
->data
,
730 sizeof(client_challenge
->data
));
735 creds
->computer_name
= talloc_strdup(creds
, client_computer_name
);
736 if (!creds
->computer_name
) {
740 creds
->account_name
= talloc_strdup(creds
, client_account
);
741 if (!creds
->account_name
) {
746 if (negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
747 status
= netlogon_creds_init_hmac_sha256(creds
,
751 if (!NT_STATUS_IS_OK(status
)) {
755 } else if (negotiate_flags
& NETLOGON_NEG_STRONG_KEYS
) {
756 status
= netlogon_creds_init_128bit(creds
,
760 if (!NT_STATUS_IS_OK(status
)) {
765 status
= netlogon_creds_init_64bit(creds
,
769 if (!NT_STATUS_IS_OK(status
)) {
775 status
= netlogon_creds_first_step(creds
,
778 if (!NT_STATUS_IS_OK(status
)) {
783 dump_data_pw("Session key", creds
->session_key
, 16);
784 dump_data_pw("Client Credential ", creds
->client
.data
, 8);
785 dump_data_pw("Server Credential ", creds
->server
.data
, 8);
787 dump_data_pw("Credentials in", credentials_in
->data
, sizeof(credentials_in
->data
));
789 /* And before we leak information about the machine account
790 * password, check that they got the first go right */
791 if (!netlogon_creds_server_check_internal(creds
, credentials_in
)) {
796 *credentials_out
= creds
->server
;
798 dump_data_pw("Credentials out", credentials_out
->data
, sizeof(credentials_out
->data
));
803 NTSTATUS
netlogon_creds_server_step_check(struct netlogon_creds_CredentialState
*creds
,
804 const struct netr_Authenticator
*received_authenticator
,
805 struct netr_Authenticator
*return_authenticator
)
809 if (!received_authenticator
|| !return_authenticator
) {
810 return NT_STATUS_INVALID_PARAMETER
;
814 return NT_STATUS_ACCESS_DENIED
;
817 creds
->sequence
= received_authenticator
->timestamp
;
818 status
= netlogon_creds_step(creds
);
819 if (!NT_STATUS_IS_OK(status
)) {
820 ZERO_STRUCTP(return_authenticator
);
824 if (netlogon_creds_server_check_internal(creds
, &received_authenticator
->cred
)) {
825 return_authenticator
->cred
= creds
->server
;
826 return_authenticator
->timestamp
= 0;
829 ZERO_STRUCTP(return_authenticator
);
830 return NT_STATUS_ACCESS_DENIED
;
834 static NTSTATUS
netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState
*creds
,
835 uint16_t validation_level
,
836 union netr_Validation
*validation
,
839 struct netr_SamBaseInfo
*base
= NULL
;
842 if (validation
== NULL
) {
843 return NT_STATUS_INVALID_PARAMETER
;
846 switch (validation_level
) {
848 if (validation
->sam2
) {
849 base
= &validation
->sam2
->base
;
853 if (validation
->sam3
) {
854 base
= &validation
->sam3
->base
;
858 if (validation
->sam6
) {
859 base
= &validation
->sam6
->base
;
863 /* If we can't find it, we can't very well decrypt it */
864 return NT_STATUS_INVALID_INFO_CLASS
;
868 return NT_STATUS_INVALID_INFO_CLASS
;
871 /* find and decyrpt the session keys, return in parameters above */
872 if (validation_level
== 6) {
873 /* they aren't encrypted! */
874 } else if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
875 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
876 if (!all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
878 status
= netlogon_creds_aes_encrypt(
881 sizeof(base
->key
.key
));
883 status
= netlogon_creds_aes_decrypt(
886 sizeof(base
->key
.key
));
888 if (!NT_STATUS_IS_OK(status
)) {
893 if (!all_zero(base
->LMSessKey
.key
,
894 sizeof(base
->LMSessKey
.key
))) {
896 status
= netlogon_creds_aes_encrypt(
899 sizeof(base
->LMSessKey
.key
));
901 status
= netlogon_creds_aes_decrypt(
904 sizeof(base
->LMSessKey
.key
));
906 if (!NT_STATUS_IS_OK(status
)) {
910 } else if (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
) {
911 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
912 if (!all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
913 status
= netlogon_creds_arcfour_crypt(creds
,
915 sizeof(base
->key
.key
));
916 if (!NT_STATUS_IS_OK(status
)) {
921 if (!all_zero(base
->LMSessKey
.key
,
922 sizeof(base
->LMSessKey
.key
))) {
923 status
= netlogon_creds_arcfour_crypt(creds
,
925 sizeof(base
->LMSessKey
.key
));
926 if (!NT_STATUS_IS_OK(status
)) {
931 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
932 if (!all_zero(base
->LMSessKey
.key
,
933 sizeof(base
->LMSessKey
.key
))) {
935 status
= netlogon_creds_des_encrypt_LMKey(creds
,
938 status
= netlogon_creds_des_decrypt_LMKey(creds
,
941 if (!NT_STATUS_IS_OK(status
)) {
950 NTSTATUS
netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState
*creds
,
951 uint16_t validation_level
,
952 union netr_Validation
*validation
)
954 return netlogon_creds_crypt_samlogon_validation(creds
,
960 NTSTATUS
netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState
*creds
,
961 uint16_t validation_level
,
962 union netr_Validation
*validation
)
964 return netlogon_creds_crypt_samlogon_validation(creds
,
970 static NTSTATUS
netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState
*creds
,
971 enum netr_LogonInfoClass level
,
972 union netr_LogonLevel
*logon
,
978 return NT_STATUS_INVALID_PARAMETER
;
982 case NetlogonInteractiveInformation
:
983 case NetlogonInteractiveTransitiveInformation
:
984 case NetlogonServiceInformation
:
985 case NetlogonServiceTransitiveInformation
:
986 if (logon
->password
== NULL
) {
987 return NT_STATUS_INVALID_PARAMETER
;
990 if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
993 h
= logon
->password
->lmpassword
.hash
;
994 if (!all_zero(h
, 16)) {
996 status
= netlogon_creds_aes_encrypt(
1001 status
= netlogon_creds_aes_decrypt(
1006 if (!NT_STATUS_IS_OK(status
)) {
1011 h
= logon
->password
->ntpassword
.hash
;
1012 if (!all_zero(h
, 16)) {
1014 status
= netlogon_creds_aes_encrypt(creds
,
1018 status
= netlogon_creds_aes_decrypt(creds
,
1022 if (!NT_STATUS_IS_OK(status
)) {
1026 } else if (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
) {
1029 h
= logon
->password
->lmpassword
.hash
;
1030 if (!all_zero(h
, 16)) {
1031 status
= netlogon_creds_arcfour_crypt(creds
,
1034 if (!NT_STATUS_IS_OK(status
)) {
1039 h
= logon
->password
->ntpassword
.hash
;
1040 if (!all_zero(h
, 16)) {
1041 status
= netlogon_creds_arcfour_crypt(creds
,
1044 if (!NT_STATUS_IS_OK(status
)) {
1049 struct samr_Password
*p
;
1051 p
= &logon
->password
->lmpassword
;
1052 if (!all_zero(p
->hash
, 16)) {
1054 status
= netlogon_creds_des_encrypt(creds
, p
);
1056 status
= netlogon_creds_des_decrypt(creds
, p
);
1058 if (!NT_STATUS_IS_OK(status
)) {
1062 p
= &logon
->password
->ntpassword
;
1063 if (!all_zero(p
->hash
, 16)) {
1065 status
= netlogon_creds_des_encrypt(creds
, p
);
1067 status
= netlogon_creds_des_decrypt(creds
, p
);
1069 if (!NT_STATUS_IS_OK(status
)) {
1076 case NetlogonNetworkInformation
:
1077 case NetlogonNetworkTransitiveInformation
:
1080 case NetlogonGenericInformation
:
1081 if (logon
->generic
== NULL
) {
1082 return NT_STATUS_INVALID_PARAMETER
;
1085 if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
1087 status
= netlogon_creds_aes_encrypt(
1089 logon
->generic
->data
,
1090 logon
->generic
->length
);
1092 status
= netlogon_creds_aes_decrypt(
1094 logon
->generic
->data
,
1095 logon
->generic
->length
);
1097 if (!NT_STATUS_IS_OK(status
)) {
1100 } else if (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
) {
1101 status
= netlogon_creds_arcfour_crypt(creds
,
1102 logon
->generic
->data
,
1103 logon
->generic
->length
);
1104 if (!NT_STATUS_IS_OK(status
)) {
1108 /* Using DES to verify kerberos tickets makes no sense */
1113 return NT_STATUS_OK
;
1116 NTSTATUS
netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState
*creds
,
1117 enum netr_LogonInfoClass level
,
1118 union netr_LogonLevel
*logon
)
1120 return netlogon_creds_crypt_samlogon_logon(creds
, level
, logon
, false);
1123 NTSTATUS
netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState
*creds
,
1124 enum netr_LogonInfoClass level
,
1125 union netr_LogonLevel
*logon
)
1127 return netlogon_creds_crypt_samlogon_logon(creds
, level
, logon
, true);
1130 union netr_LogonLevel
*netlogon_creds_shallow_copy_logon(TALLOC_CTX
*mem_ctx
,
1131 enum netr_LogonInfoClass level
,
1132 const union netr_LogonLevel
*in
)
1134 union netr_LogonLevel
*out
;
1140 out
= talloc(mem_ctx
, union netr_LogonLevel
);
1148 case NetlogonInteractiveInformation
:
1149 case NetlogonInteractiveTransitiveInformation
:
1150 case NetlogonServiceInformation
:
1151 case NetlogonServiceTransitiveInformation
:
1152 if (in
->password
== NULL
) {
1156 out
->password
= talloc(out
, struct netr_PasswordInfo
);
1157 if (out
->password
== NULL
) {
1161 *out
->password
= *in
->password
;
1165 case NetlogonNetworkInformation
:
1166 case NetlogonNetworkTransitiveInformation
:
1169 case NetlogonGenericInformation
:
1170 if (in
->generic
== NULL
) {
1174 out
->generic
= talloc(out
, struct netr_GenericInfo
);
1175 if (out
->generic
== NULL
) {
1179 *out
->generic
= *in
->generic
;
1181 if (in
->generic
->data
== NULL
) {
1185 if (in
->generic
->length
== 0) {
1189 out
->generic
->data
= talloc_memdup(out
->generic
,
1191 in
->generic
->length
);
1192 if (out
->generic
->data
== NULL
) {
1204 copy a netlogon_creds_CredentialState struct
1207 struct netlogon_creds_CredentialState
*netlogon_creds_copy(
1208 TALLOC_CTX
*mem_ctx
,
1209 const struct netlogon_creds_CredentialState
*creds_in
)
1211 struct netlogon_creds_CredentialState
*creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
1217 creds
->sequence
= creds_in
->sequence
;
1218 creds
->negotiate_flags
= creds_in
->negotiate_flags
;
1219 creds
->secure_channel_type
= creds_in
->secure_channel_type
;
1221 creds
->computer_name
= talloc_strdup(creds
, creds_in
->computer_name
);
1222 if (!creds
->computer_name
) {
1226 creds
->account_name
= talloc_strdup(creds
, creds_in
->account_name
);
1227 if (!creds
->account_name
) {
1232 if (creds_in
->sid
) {
1233 creds
->sid
= dom_sid_dup(creds
, creds_in
->sid
);
1240 memcpy(creds
->session_key
, creds_in
->session_key
, sizeof(creds
->session_key
));
1241 memcpy(creds
->seed
.data
, creds_in
->seed
.data
, sizeof(creds
->seed
.data
));
1242 memcpy(creds
->client
.data
, creds_in
->client
.data
, sizeof(creds
->client
.data
));
1243 memcpy(creds
->server
.data
, creds_in
->server
.data
, sizeof(creds
->server
.data
));