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"
28 #ifndef HAVE_GNUTLS_AES_CFB8
29 #include "lib/crypto/aes.h"
32 #include "lib/crypto/gnutls_helpers.h"
33 #include <gnutls/gnutls.h>
34 #include <gnutls/crypto.h>
36 static NTSTATUS
netlogon_creds_step_crypt(struct netlogon_creds_CredentialState
*creds
,
37 const struct netr_Credential
*in
,
38 struct netr_Credential
*out
)
43 if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
44 memcpy(out
->data
, in
->data
, sizeof(out
->data
));
46 status
= netlogon_creds_aes_encrypt(creds
,
49 if (!NT_STATUS_IS_OK(status
)) {
53 rc
= des_crypt112(out
->data
, in
->data
, creds
->session_key
, SAMBA_GNUTLS_ENCRYPT
);
55 return gnutls_error_to_ntstatus(rc
,
56 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
64 initialise the credentials state for old-style 64 bit session keys
66 this call is made after the netr_ServerReqChallenge call
68 static NTSTATUS
netlogon_creds_init_64bit(struct netlogon_creds_CredentialState
*creds
,
69 const struct netr_Credential
*client_challenge
,
70 const struct netr_Credential
*server_challenge
,
71 const struct samr_Password
*machine_password
)
77 sum
[0] = IVAL(client_challenge
->data
, 0) + IVAL(server_challenge
->data
, 0);
78 sum
[1] = IVAL(client_challenge
->data
, 4) + IVAL(server_challenge
->data
, 4);
83 ZERO_ARRAY(creds
->session_key
);
85 rc
= des_crypt128(creds
->session_key
, sum2
, machine_password
->hash
);
87 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
94 initialise the credentials state for ADS-style 128 bit session keys
96 this call is made after the netr_ServerReqChallenge call
98 static NTSTATUS
netlogon_creds_init_128bit(struct netlogon_creds_CredentialState
*creds
,
99 const struct netr_Credential
*client_challenge
,
100 const struct netr_Credential
*server_challenge
,
101 const struct samr_Password
*machine_password
)
103 uint8_t zero
[4] = {0};
104 uint8_t tmp
[gnutls_hash_get_len(GNUTLS_MAC_MD5
)];
105 gnutls_hash_hd_t hash_hnd
= NULL
;
108 ZERO_ARRAY(creds
->session_key
);
110 rc
= gnutls_hash_init(&hash_hnd
, GNUTLS_DIG_MD5
);
112 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
115 rc
= gnutls_hash(hash_hnd
, zero
, sizeof(zero
));
117 gnutls_hash_deinit(hash_hnd
, NULL
);
118 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
120 rc
= gnutls_hash(hash_hnd
, client_challenge
->data
, 8);
122 gnutls_hash_deinit(hash_hnd
, NULL
);
123 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
125 rc
= gnutls_hash(hash_hnd
, server_challenge
->data
, 8);
127 gnutls_hash_deinit(hash_hnd
, NULL
);
128 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
131 gnutls_hash_deinit(hash_hnd
, tmp
);
133 /* This doesn't require HMAC MD5 RFC2104 as the hash is only 16 bytes */
134 rc
= gnutls_hmac_fast(GNUTLS_MAC_MD5
,
135 machine_password
->hash
,
136 sizeof(machine_password
->hash
),
143 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
150 initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
152 this call is made after the netr_ServerReqChallenge call
154 static NTSTATUS
netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState
*creds
,
155 const struct netr_Credential
*client_challenge
,
156 const struct netr_Credential
*server_challenge
,
157 const struct samr_Password
*machine_password
)
159 gnutls_hmac_hd_t hmac_hnd
= NULL
;
160 uint8_t digest
[gnutls_hash_get_len(GNUTLS_MAC_SHA256
)];
163 ZERO_ARRAY(creds
->session_key
);
165 rc
= gnutls_hmac_init(&hmac_hnd
,
167 machine_password
->hash
,
168 sizeof(machine_password
->hash
));
170 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HMAC_NOT_SUPPORTED
);
172 rc
= gnutls_hmac(hmac_hnd
,
173 client_challenge
->data
,
176 gnutls_hmac_deinit(hmac_hnd
, NULL
);
177 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HMAC_NOT_SUPPORTED
);
179 rc
= gnutls_hmac(hmac_hnd
,
180 server_challenge
->data
,
183 gnutls_hmac_deinit(hmac_hnd
, NULL
);
184 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HMAC_NOT_SUPPORTED
);
186 gnutls_hmac_deinit(hmac_hnd
, digest
);
188 memcpy(creds
->session_key
, digest
, sizeof(creds
->session_key
));
195 static NTSTATUS
netlogon_creds_first_step(struct netlogon_creds_CredentialState
*creds
,
196 const struct netr_Credential
*client_challenge
,
197 const struct netr_Credential
*server_challenge
)
201 status
= netlogon_creds_step_crypt(creds
,
204 if (!NT_STATUS_IS_OK(status
)) {
208 status
= netlogon_creds_step_crypt(creds
,
211 if (!NT_STATUS_IS_OK(status
)) {
215 creds
->seed
= creds
->client
;
221 step the credentials to the next element in the chain, updating the
222 current client and server credentials and the seed
224 static NTSTATUS
netlogon_creds_step(struct netlogon_creds_CredentialState
*creds
)
226 struct netr_Credential time_cred
;
229 DEBUG(5,("\tseed %08x:%08x\n",
230 IVAL(creds
->seed
.data
, 0), IVAL(creds
->seed
.data
, 4)));
232 SIVAL(time_cred
.data
, 0, IVAL(creds
->seed
.data
, 0) + creds
->sequence
);
233 SIVAL(time_cred
.data
, 4, IVAL(creds
->seed
.data
, 4));
235 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred
.data
, 0), IVAL(time_cred
.data
, 4)));
237 status
= netlogon_creds_step_crypt(creds
,
240 if (!NT_STATUS_IS_OK(status
)) {
244 DEBUG(5,("\tCLIENT %08x:%08x\n",
245 IVAL(creds
->client
.data
, 0), IVAL(creds
->client
.data
, 4)));
247 SIVAL(time_cred
.data
, 0, IVAL(creds
->seed
.data
, 0) + creds
->sequence
+ 1);
248 SIVAL(time_cred
.data
, 4, IVAL(creds
->seed
.data
, 4));
250 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
251 IVAL(time_cred
.data
, 0), IVAL(time_cred
.data
, 4)));
253 status
= netlogon_creds_step_crypt(creds
, &time_cred
, &creds
->server
);
254 if (!NT_STATUS_IS_OK(status
)) {
258 DEBUG(5,("\tSERVER %08x:%08x\n",
259 IVAL(creds
->server
.data
, 0), IVAL(creds
->server
.data
, 4)));
261 creds
->seed
= time_cred
;
267 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
269 NTSTATUS
netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState
*creds
,
270 struct netr_LMSessionKey
*key
)
273 struct netr_LMSessionKey tmp
;
275 rc
= des_crypt56_gnutls(tmp
.key
, key
->key
, creds
->session_key
, SAMBA_GNUTLS_ENCRYPT
);
277 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
285 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
287 NTSTATUS
netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState
*creds
,
288 struct netr_LMSessionKey
*key
)
291 struct netr_LMSessionKey tmp
;
293 rc
= des_crypt56_gnutls(tmp
.key
, key
->key
, creds
->session_key
, SAMBA_GNUTLS_DECRYPT
);
295 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
303 DES encrypt a 16 byte password buffer using the session key
305 NTSTATUS
netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState
*creds
,
306 struct samr_Password
*pass
)
308 struct samr_Password tmp
;
311 rc
= des_crypt112_16(tmp
.hash
, pass
->hash
, creds
->session_key
, SAMBA_GNUTLS_ENCRYPT
);
313 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
321 DES decrypt a 16 byte password buffer using the session key
323 NTSTATUS
netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState
*creds
,
324 struct samr_Password
*pass
)
326 struct samr_Password tmp
;
329 rc
= des_crypt112_16(tmp
.hash
, pass
->hash
, creds
->session_key
, SAMBA_GNUTLS_DECRYPT
);
331 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
339 ARCFOUR encrypt/decrypt a password buffer using the session key
341 NTSTATUS
netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState
*creds
,
345 gnutls_cipher_hd_t cipher_hnd
= NULL
;
346 gnutls_datum_t session_key
= {
347 .data
= creds
->session_key
,
348 .size
= sizeof(creds
->session_key
),
352 rc
= gnutls_cipher_init(&cipher_hnd
,
353 GNUTLS_CIPHER_ARCFOUR_128
,
357 return gnutls_error_to_ntstatus(rc
,
358 NT_STATUS_CRYPTO_SYSTEM_INVALID
);
360 rc
= gnutls_cipher_encrypt(cipher_hnd
,
363 gnutls_cipher_deinit(cipher_hnd
);
365 return gnutls_error_to_ntstatus(rc
,
366 NT_STATUS_CRYPTO_SYSTEM_INVALID
);
373 AES encrypt a password buffer using the session key
375 NTSTATUS
netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState
*creds
,
379 #ifdef HAVE_GNUTLS_AES_CFB8
380 gnutls_cipher_hd_t cipher_hnd
= NULL
;
381 gnutls_datum_t key
= {
382 .data
= creds
->session_key
,
383 .size
= sizeof(creds
->session_key
),
386 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8
);
387 uint8_t _iv
[iv_size
];
388 gnutls_datum_t iv
= {
396 rc
= gnutls_cipher_init(&cipher_hnd
,
397 GNUTLS_CIPHER_AES_128_CFB8
,
401 return gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
404 rc
= gnutls_cipher_encrypt(cipher_hnd
, data
, len
);
405 gnutls_cipher_deinit(cipher_hnd
);
407 return gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
410 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
412 uint8_t iv
[AES_BLOCK_SIZE
] = {0};
414 AES_set_encrypt_key(creds
->session_key
, 128, &key
);
416 aes_cfb8_encrypt(data
, data
, len
, &key
, iv
, AES_ENCRYPT
);
417 #endif /* HAVE_GNUTLS_AES_CFB8 */
423 AES decrypt a password buffer using the session key
425 NTSTATUS
netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState
*creds
, uint8_t *data
, size_t len
)
427 #ifdef HAVE_GNUTLS_AES_CFB8
428 gnutls_cipher_hd_t cipher_hnd
= NULL
;
429 gnutls_datum_t key
= {
430 .data
= creds
->session_key
,
431 .size
= sizeof(creds
->session_key
),
434 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8
);
435 uint8_t _iv
[iv_size
];
436 gnutls_datum_t iv
= {
444 rc
= gnutls_cipher_init(&cipher_hnd
,
445 GNUTLS_CIPHER_AES_128_CFB8
,
449 return gnutls_error_to_ntstatus(rc
,
450 NT_STATUS_CRYPTO_SYSTEM_INVALID
);
453 rc
= gnutls_cipher_decrypt(cipher_hnd
, data
, len
);
454 gnutls_cipher_deinit(cipher_hnd
);
456 return gnutls_error_to_ntstatus(rc
,
457 NT_STATUS_CRYPTO_SYSTEM_INVALID
);
460 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
462 uint8_t iv
[AES_BLOCK_SIZE
] = {0};
464 AES_set_encrypt_key(creds
->session_key
, 128, &key
);
466 aes_cfb8_encrypt(data
, data
, len
, &key
, iv
, AES_DECRYPT
);
467 #endif /* HAVE_GNUTLS_AES_CFB8 */
472 /*****************************************************************
473 The above functions are common to the client and server interface
474 next comes the client specific functions
475 ******************************************************************/
478 initialise the credentials chain and return the first client
482 struct netlogon_creds_CredentialState
*netlogon_creds_client_init(TALLOC_CTX
*mem_ctx
,
483 const char *client_account
,
484 const char *client_computer_name
,
485 uint16_t secure_channel_type
,
486 const struct netr_Credential
*client_challenge
,
487 const struct netr_Credential
*server_challenge
,
488 const struct samr_Password
*machine_password
,
489 struct netr_Credential
*initial_credential
,
490 uint32_t negotiate_flags
)
492 struct netlogon_creds_CredentialState
*creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
499 creds
->sequence
= time(NULL
);
500 creds
->negotiate_flags
= negotiate_flags
;
501 creds
->secure_channel_type
= secure_channel_type
;
503 creds
->computer_name
= talloc_strdup(creds
, client_computer_name
);
504 if (!creds
->computer_name
) {
508 creds
->account_name
= talloc_strdup(creds
, client_account
);
509 if (!creds
->account_name
) {
514 dump_data_pw("Client chall", client_challenge
->data
, sizeof(client_challenge
->data
));
515 dump_data_pw("Server chall", server_challenge
->data
, sizeof(server_challenge
->data
));
516 dump_data_pw("Machine Pass", machine_password
->hash
, sizeof(machine_password
->hash
));
518 if (negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
519 status
= netlogon_creds_init_hmac_sha256(creds
,
523 if (!NT_STATUS_IS_OK(status
)) {
527 } else if (negotiate_flags
& NETLOGON_NEG_STRONG_KEYS
) {
528 status
= netlogon_creds_init_128bit(creds
,
532 if (!NT_STATUS_IS_OK(status
)) {
537 status
= netlogon_creds_init_64bit(creds
,
541 if (!NT_STATUS_IS_OK(status
)) {
547 status
= netlogon_creds_first_step(creds
,
550 if (!NT_STATUS_IS_OK(status
)) {
555 dump_data_pw("Session key", creds
->session_key
, 16);
556 dump_data_pw("Credential ", creds
->client
.data
, 8);
558 *initial_credential
= creds
->client
;
563 initialise the credentials structure with only a session key. The caller better know what they are doing!
566 struct netlogon_creds_CredentialState
*netlogon_creds_client_init_session_key(TALLOC_CTX
*mem_ctx
,
567 const uint8_t session_key
[16])
569 struct netlogon_creds_CredentialState
*creds
;
571 creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
576 memcpy(creds
->session_key
, session_key
, 16);
582 step the credentials to the next element in the chain, updating the
583 current client and server credentials and the seed
585 produce the next authenticator in the sequence ready to send to
589 netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState
*creds
,
590 struct netr_Authenticator
*next
)
592 uint32_t t32n
= (uint32_t)time(NULL
);
596 * we always increment and ignore an overflow here
598 creds
->sequence
+= 2;
600 if (t32n
> creds
->sequence
) {
602 * we may increment more
604 creds
->sequence
= t32n
;
606 uint32_t d
= creds
->sequence
- t32n
;
608 if (d
>= INT32_MAX
) {
610 * got an overflow of time_t vs. uint32_t
612 creds
->sequence
= t32n
;
616 status
= netlogon_creds_step(creds
);
617 if (!NT_STATUS_IS_OK(status
)) {
621 next
->cred
= creds
->client
;
622 next
->timestamp
= creds
->sequence
;
628 check that a credentials reply from a server is correct
630 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState
*creds
,
631 const struct netr_Credential
*received_credentials
)
633 if (!received_credentials
||
634 memcmp(received_credentials
->data
, creds
->server
.data
, 8) != 0) {
635 DEBUG(2,("credentials check failed\n"));
642 /*****************************************************************
643 The above functions are common to the client and server interface
644 next comes the server specific functions
645 ******************************************************************/
648 check that a credentials reply from a server is correct
650 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState
*creds
,
651 const struct netr_Credential
*received_credentials
)
653 if (memcmp(received_credentials
->data
, creds
->client
.data
, 8) != 0) {
654 DEBUG(2,("credentials check failed\n"));
655 dump_data_pw("client creds", creds
->client
.data
, 8);
656 dump_data_pw("calc creds", received_credentials
->data
, 8);
663 initialise the credentials chain and return the first server
666 struct netlogon_creds_CredentialState
*netlogon_creds_server_init(TALLOC_CTX
*mem_ctx
,
667 const char *client_account
,
668 const char *client_computer_name
,
669 uint16_t secure_channel_type
,
670 const struct netr_Credential
*client_challenge
,
671 const struct netr_Credential
*server_challenge
,
672 const struct samr_Password
*machine_password
,
673 const struct netr_Credential
*credentials_in
,
674 struct netr_Credential
*credentials_out
,
675 uint32_t negotiate_flags
)
678 struct netlogon_creds_CredentialState
*creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
686 creds
->negotiate_flags
= negotiate_flags
;
687 creds
->secure_channel_type
= secure_channel_type
;
689 dump_data_pw("Client chall", client_challenge
->data
, sizeof(client_challenge
->data
));
690 dump_data_pw("Server chall", server_challenge
->data
, sizeof(server_challenge
->data
));
691 dump_data_pw("Machine Pass", machine_password
->hash
, sizeof(machine_password
->hash
));
693 creds
->computer_name
= talloc_strdup(creds
, client_computer_name
);
694 if (!creds
->computer_name
) {
698 creds
->account_name
= talloc_strdup(creds
, client_account
);
699 if (!creds
->account_name
) {
704 if (negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
705 status
= netlogon_creds_init_hmac_sha256(creds
,
709 if (!NT_STATUS_IS_OK(status
)) {
713 } else if (negotiate_flags
& NETLOGON_NEG_STRONG_KEYS
) {
714 status
= netlogon_creds_init_128bit(creds
,
718 if (!NT_STATUS_IS_OK(status
)) {
723 status
= netlogon_creds_init_64bit(creds
,
727 if (!NT_STATUS_IS_OK(status
)) {
733 status
= netlogon_creds_first_step(creds
,
736 if (!NT_STATUS_IS_OK(status
)) {
741 dump_data_pw("Session key", creds
->session_key
, 16);
742 dump_data_pw("Client Credential ", creds
->client
.data
, 8);
743 dump_data_pw("Server Credential ", creds
->server
.data
, 8);
745 dump_data_pw("Credentials in", credentials_in
->data
, sizeof(credentials_in
->data
));
747 /* And before we leak information about the machine account
748 * password, check that they got the first go right */
749 if (!netlogon_creds_server_check_internal(creds
, credentials_in
)) {
754 *credentials_out
= creds
->server
;
756 dump_data_pw("Credentials out", credentials_out
->data
, sizeof(credentials_out
->data
));
761 NTSTATUS
netlogon_creds_server_step_check(struct netlogon_creds_CredentialState
*creds
,
762 const struct netr_Authenticator
*received_authenticator
,
763 struct netr_Authenticator
*return_authenticator
)
767 if (!received_authenticator
|| !return_authenticator
) {
768 return NT_STATUS_INVALID_PARAMETER
;
772 return NT_STATUS_ACCESS_DENIED
;
775 creds
->sequence
= received_authenticator
->timestamp
;
776 status
= netlogon_creds_step(creds
);
777 if (!NT_STATUS_IS_OK(status
)) {
778 ZERO_STRUCTP(return_authenticator
);
782 if (netlogon_creds_server_check_internal(creds
, &received_authenticator
->cred
)) {
783 return_authenticator
->cred
= creds
->server
;
784 return_authenticator
->timestamp
= 0;
787 ZERO_STRUCTP(return_authenticator
);
788 return NT_STATUS_ACCESS_DENIED
;
792 static NTSTATUS
netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState
*creds
,
793 uint16_t validation_level
,
794 union netr_Validation
*validation
,
797 struct netr_SamBaseInfo
*base
= NULL
;
800 if (validation
== NULL
) {
801 return NT_STATUS_INVALID_PARAMETER
;
804 switch (validation_level
) {
806 if (validation
->sam2
) {
807 base
= &validation
->sam2
->base
;
811 if (validation
->sam3
) {
812 base
= &validation
->sam3
->base
;
816 if (validation
->sam6
) {
817 base
= &validation
->sam6
->base
;
821 /* If we can't find it, we can't very well decrypt it */
822 return NT_STATUS_INVALID_INFO_CLASS
;
826 return NT_STATUS_INVALID_INFO_CLASS
;
829 /* find and decyrpt the session keys, return in parameters above */
830 if (validation_level
== 6) {
831 /* they aren't encrypted! */
832 } else if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
833 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
834 if (!all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
836 status
= netlogon_creds_aes_encrypt(
839 sizeof(base
->key
.key
));
841 status
= netlogon_creds_aes_decrypt(
844 sizeof(base
->key
.key
));
846 if (!NT_STATUS_IS_OK(status
)) {
851 if (!all_zero(base
->LMSessKey
.key
,
852 sizeof(base
->LMSessKey
.key
))) {
854 status
= netlogon_creds_aes_encrypt(
857 sizeof(base
->LMSessKey
.key
));
859 status
= netlogon_creds_aes_decrypt(
862 sizeof(base
->LMSessKey
.key
));
864 if (!NT_STATUS_IS_OK(status
)) {
868 } else if (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
) {
869 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
870 if (!all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
871 status
= netlogon_creds_arcfour_crypt(creds
,
873 sizeof(base
->key
.key
));
874 if (!NT_STATUS_IS_OK(status
)) {
879 if (!all_zero(base
->LMSessKey
.key
,
880 sizeof(base
->LMSessKey
.key
))) {
881 status
= netlogon_creds_arcfour_crypt(creds
,
883 sizeof(base
->LMSessKey
.key
));
884 if (!NT_STATUS_IS_OK(status
)) {
889 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
890 if (!all_zero(base
->LMSessKey
.key
,
891 sizeof(base
->LMSessKey
.key
))) {
893 status
= netlogon_creds_des_encrypt_LMKey(creds
,
896 status
= netlogon_creds_des_decrypt_LMKey(creds
,
899 if (!NT_STATUS_IS_OK(status
)) {
908 NTSTATUS
netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState
*creds
,
909 uint16_t validation_level
,
910 union netr_Validation
*validation
)
912 return netlogon_creds_crypt_samlogon_validation(creds
,
918 NTSTATUS
netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState
*creds
,
919 uint16_t validation_level
,
920 union netr_Validation
*validation
)
922 return netlogon_creds_crypt_samlogon_validation(creds
,
928 static NTSTATUS
netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState
*creds
,
929 enum netr_LogonInfoClass level
,
930 union netr_LogonLevel
*logon
,
936 return NT_STATUS_INVALID_PARAMETER
;
940 case NetlogonInteractiveInformation
:
941 case NetlogonInteractiveTransitiveInformation
:
942 case NetlogonServiceInformation
:
943 case NetlogonServiceTransitiveInformation
:
944 if (logon
->password
== NULL
) {
945 return NT_STATUS_INVALID_PARAMETER
;
948 if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
951 h
= logon
->password
->lmpassword
.hash
;
952 if (!all_zero(h
, 16)) {
954 status
= netlogon_creds_aes_encrypt(
959 status
= netlogon_creds_aes_decrypt(
964 if (!NT_STATUS_IS_OK(status
)) {
969 h
= logon
->password
->ntpassword
.hash
;
970 if (!all_zero(h
, 16)) {
972 status
= netlogon_creds_aes_encrypt(creds
,
976 status
= netlogon_creds_aes_decrypt(creds
,
980 if (!NT_STATUS_IS_OK(status
)) {
984 } else if (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
) {
987 h
= logon
->password
->lmpassword
.hash
;
988 if (!all_zero(h
, 16)) {
989 status
= netlogon_creds_arcfour_crypt(creds
,
992 if (!NT_STATUS_IS_OK(status
)) {
997 h
= logon
->password
->ntpassword
.hash
;
998 if (!all_zero(h
, 16)) {
999 status
= netlogon_creds_arcfour_crypt(creds
,
1002 if (!NT_STATUS_IS_OK(status
)) {
1007 struct samr_Password
*p
;
1009 p
= &logon
->password
->lmpassword
;
1010 if (!all_zero(p
->hash
, 16)) {
1012 status
= netlogon_creds_des_encrypt(creds
, p
);
1014 status
= netlogon_creds_des_decrypt(creds
, p
);
1016 if (!NT_STATUS_IS_OK(status
)) {
1020 p
= &logon
->password
->ntpassword
;
1021 if (!all_zero(p
->hash
, 16)) {
1023 status
= netlogon_creds_des_encrypt(creds
, p
);
1025 status
= netlogon_creds_des_decrypt(creds
, p
);
1027 if (!NT_STATUS_IS_OK(status
)) {
1034 case NetlogonNetworkInformation
:
1035 case NetlogonNetworkTransitiveInformation
:
1038 case NetlogonGenericInformation
:
1039 if (logon
->generic
== NULL
) {
1040 return NT_STATUS_INVALID_PARAMETER
;
1043 if (creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
1045 status
= netlogon_creds_aes_encrypt(
1047 logon
->generic
->data
,
1048 logon
->generic
->length
);
1050 status
= netlogon_creds_aes_decrypt(
1052 logon
->generic
->data
,
1053 logon
->generic
->length
);
1055 if (!NT_STATUS_IS_OK(status
)) {
1058 } else if (creds
->negotiate_flags
& NETLOGON_NEG_ARCFOUR
) {
1059 status
= netlogon_creds_arcfour_crypt(creds
,
1060 logon
->generic
->data
,
1061 logon
->generic
->length
);
1062 if (!NT_STATUS_IS_OK(status
)) {
1066 /* Using DES to verify kerberos tickets makes no sense */
1071 return NT_STATUS_OK
;
1074 NTSTATUS
netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState
*creds
,
1075 enum netr_LogonInfoClass level
,
1076 union netr_LogonLevel
*logon
)
1078 return netlogon_creds_crypt_samlogon_logon(creds
, level
, logon
, false);
1081 NTSTATUS
netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState
*creds
,
1082 enum netr_LogonInfoClass level
,
1083 union netr_LogonLevel
*logon
)
1085 return netlogon_creds_crypt_samlogon_logon(creds
, level
, logon
, true);
1088 union netr_LogonLevel
*netlogon_creds_shallow_copy_logon(TALLOC_CTX
*mem_ctx
,
1089 enum netr_LogonInfoClass level
,
1090 const union netr_LogonLevel
*in
)
1092 union netr_LogonLevel
*out
;
1098 out
= talloc(mem_ctx
, union netr_LogonLevel
);
1106 case NetlogonInteractiveInformation
:
1107 case NetlogonInteractiveTransitiveInformation
:
1108 case NetlogonServiceInformation
:
1109 case NetlogonServiceTransitiveInformation
:
1110 if (in
->password
== NULL
) {
1114 out
->password
= talloc(out
, struct netr_PasswordInfo
);
1115 if (out
->password
== NULL
) {
1119 *out
->password
= *in
->password
;
1123 case NetlogonNetworkInformation
:
1124 case NetlogonNetworkTransitiveInformation
:
1127 case NetlogonGenericInformation
:
1128 if (in
->generic
== NULL
) {
1132 out
->generic
= talloc(out
, struct netr_GenericInfo
);
1133 if (out
->generic
== NULL
) {
1137 *out
->generic
= *in
->generic
;
1139 if (in
->generic
->data
== NULL
) {
1143 if (in
->generic
->length
== 0) {
1147 out
->generic
->data
= talloc_memdup(out
->generic
,
1149 in
->generic
->length
);
1150 if (out
->generic
->data
== NULL
) {
1162 copy a netlogon_creds_CredentialState struct
1165 struct netlogon_creds_CredentialState
*netlogon_creds_copy(
1166 TALLOC_CTX
*mem_ctx
,
1167 const struct netlogon_creds_CredentialState
*creds_in
)
1169 struct netlogon_creds_CredentialState
*creds
= talloc_zero(mem_ctx
, struct netlogon_creds_CredentialState
);
1175 creds
->sequence
= creds_in
->sequence
;
1176 creds
->negotiate_flags
= creds_in
->negotiate_flags
;
1177 creds
->secure_channel_type
= creds_in
->secure_channel_type
;
1179 creds
->computer_name
= talloc_strdup(creds
, creds_in
->computer_name
);
1180 if (!creds
->computer_name
) {
1184 creds
->account_name
= talloc_strdup(creds
, creds_in
->account_name
);
1185 if (!creds
->account_name
) {
1190 if (creds_in
->sid
) {
1191 creds
->sid
= dom_sid_dup(creds
, creds_in
->sid
);
1198 memcpy(creds
->session_key
, creds_in
->session_key
, sizeof(creds
->session_key
));
1199 memcpy(creds
->seed
.data
, creds_in
->seed
.data
, sizeof(creds
->seed
.data
));
1200 memcpy(creds
->client
.data
, creds_in
->client
.data
, sizeof(creds
->client
.data
));
1201 memcpy(creds
->server
.data
, creds_in
->server
.data
, sizeof(creds
->server
.data
));