smbd: Make sure smb_fname->st is valid in smbd_dirptr_get_entry
[Samba.git] / libcli / auth / credentials.c
bloba7f56e75e9e7568bc4956ef8d56ad0e3afd8fa01
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"
27 #include "lib/util/util_str_escape.h"
29 #ifndef HAVE_GNUTLS_AES_CFB8
30 #include "lib/crypto/aes.h"
31 #endif
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])
50 return false;
53 return true;
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)
68 NTSTATUS status;
69 int rc;
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,
75 out->data,
76 sizeof(out->data));
77 if (!NT_STATUS_IS_OK(status)) {
78 return status;
80 } else {
81 rc = des_crypt112(out->data, in->data, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
82 if (rc != 0) {
83 return gnutls_error_to_ntstatus(rc,
84 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
88 return NT_STATUS_OK;
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)
101 uint32_t sum[2];
102 uint8_t sum2[8];
103 int rc;
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);
114 if (rc != 0) {
115 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
118 return NT_STATUS_OK;
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;
134 int rc;
136 ZERO_ARRAY(creds->session_key);
138 rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
139 if (rc < 0) {
140 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
143 rc = gnutls_hash(hash_hnd, zero, sizeof(zero));
144 if (rc < 0) {
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);
149 if (rc < 0) {
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);
154 if (rc < 0) {
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),
165 tmp,
166 sizeof(tmp),
167 creds->session_key);
168 ZERO_ARRAY(tmp);
170 if (rc < 0) {
171 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
174 return NT_STATUS_OK;
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)];
189 int rc;
191 ZERO_ARRAY(creds->session_key);
193 rc = gnutls_hmac_init(&hmac_hnd,
194 GNUTLS_MAC_SHA256,
195 machine_password->hash,
196 sizeof(machine_password->hash));
197 if (rc < 0) {
198 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
200 rc = gnutls_hmac(hmac_hnd,
201 client_challenge->data,
203 if (rc < 0) {
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,
210 if (rc < 0) {
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));
218 ZERO_ARRAY(digest);
220 return NT_STATUS_OK;
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)
227 NTSTATUS status;
229 status = netlogon_creds_step_crypt(creds,
230 client_challenge,
231 &creds->client);
232 if (!NT_STATUS_IS_OK(status)) {
233 return status;
236 status = netlogon_creds_step_crypt(creds,
237 server_challenge,
238 &creds->server);
239 if (!NT_STATUS_IS_OK(status)) {
240 return status;
243 creds->seed = creds->client;
245 return NT_STATUS_OK;
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;
255 NTSTATUS status;
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,
266 &time_cred,
267 &creds->client);
268 if (!NT_STATUS_IS_OK(status)) {
269 return 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)) {
283 return status;
286 DEBUG(5,("\tSERVER %08x:%08x\n",
287 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
289 creds->seed = time_cred;
291 return NT_STATUS_OK;
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)
300 int rc;
301 struct netr_LMSessionKey tmp;
303 rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
304 if (rc < 0) {
305 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
307 *key = tmp;
309 return NT_STATUS_OK;
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)
318 int rc;
319 struct netr_LMSessionKey tmp;
321 rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_DECRYPT);
322 if (rc < 0) {
323 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
325 *key = tmp;
327 return NT_STATUS_OK;
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;
337 int rc;
339 rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
340 if (rc < 0) {
341 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
343 *pass = tmp;
345 return NT_STATUS_OK;
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;
355 int rc;
357 rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_DECRYPT);
358 if (rc < 0) {
359 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
361 *pass = tmp;
363 return NT_STATUS_OK;
367 ARCFOUR encrypt/decrypt a password buffer using the session key
369 NTSTATUS netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds,
370 uint8_t *data,
371 size_t len)
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),
378 int rc;
380 rc = gnutls_cipher_init(&cipher_hnd,
381 GNUTLS_CIPHER_ARCFOUR_128,
382 &session_key,
383 NULL);
384 if (rc < 0) {
385 return gnutls_error_to_ntstatus(rc,
386 NT_STATUS_CRYPTO_SYSTEM_INVALID);
388 rc = gnutls_cipher_encrypt(cipher_hnd,
389 data,
390 len);
391 gnutls_cipher_deinit(cipher_hnd);
392 if (rc < 0) {
393 return gnutls_error_to_ntstatus(rc,
394 NT_STATUS_CRYPTO_SYSTEM_INVALID);
397 return NT_STATUS_OK;
401 AES encrypt a password buffer using the session key
403 NTSTATUS netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds,
404 uint8_t *data,
405 size_t len)
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),
413 uint32_t iv_size =
414 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
415 uint8_t _iv[iv_size];
416 gnutls_datum_t iv = {
417 .data = _iv,
418 .size = iv_size,
420 int rc;
422 ZERO_ARRAY(_iv);
424 rc = gnutls_cipher_init(&cipher_hnd,
425 GNUTLS_CIPHER_AES_128_CFB8,
426 &key,
427 &iv);
428 if (rc < 0) {
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);
434 if (rc < 0) {
435 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
438 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
439 AES_KEY key;
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 */
447 return NT_STATUS_OK;
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),
461 uint32_t iv_size =
462 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
463 uint8_t _iv[iv_size];
464 gnutls_datum_t iv = {
465 .data = _iv,
466 .size = iv_size,
468 int rc;
470 ZERO_ARRAY(_iv);
472 rc = gnutls_cipher_init(&cipher_hnd,
473 GNUTLS_CIPHER_AES_128_CFB8,
474 &key,
475 &iv);
476 if (rc < 0) {
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);
483 if (rc < 0) {
484 return gnutls_error_to_ntstatus(rc,
485 NT_STATUS_CRYPTO_SYSTEM_INVALID);
488 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
489 AES_KEY key;
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 */
497 return NT_STATUS_OK;
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
507 credentials
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);
521 NTSTATUS status;
523 if (!creds) {
524 return NULL;
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) {
533 talloc_free(creds);
534 return NULL;
536 creds->account_name = talloc_strdup(creds, client_account);
537 if (!creds->account_name) {
538 talloc_free(creds);
539 return NULL;
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,
548 client_challenge,
549 server_challenge,
550 machine_password);
551 if (!NT_STATUS_IS_OK(status)) {
552 talloc_free(creds);
553 return NULL;
555 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
556 status = netlogon_creds_init_128bit(creds,
557 client_challenge,
558 server_challenge,
559 machine_password);
560 if (!NT_STATUS_IS_OK(status)) {
561 talloc_free(creds);
562 return NULL;
564 } else {
565 status = netlogon_creds_init_64bit(creds,
566 client_challenge,
567 server_challenge,
568 machine_password);
569 if (!NT_STATUS_IS_OK(status)) {
570 talloc_free(creds);
571 return NULL;
575 status = netlogon_creds_first_step(creds,
576 client_challenge,
577 server_challenge);
578 if (!NT_STATUS_IS_OK(status)) {
579 talloc_free(creds);
580 return NULL;
583 dump_data_pw("Session key", creds->session_key, 16);
584 dump_data_pw("Credential ", creds->client.data, 8);
586 *initial_credential = creds->client;
587 return creds;
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);
600 if (!creds) {
601 return NULL;
604 memcpy(creds->session_key, session_key, 16);
606 return creds;
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
614 the server
616 NTSTATUS
617 netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
618 struct netr_Authenticator *next)
620 uint32_t t32n = (uint32_t)time(NULL);
621 NTSTATUS status;
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;
633 } else {
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)) {
646 return status;
649 next->cred = creds->client;
650 next->timestamp = creds->sequence;
652 return NT_STATUS_OK;
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"));
664 return false;
666 return true;
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);
685 return false;
687 return true;
691 initialise the credentials chain and return the first server
692 credentials
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);
707 NTSTATUS status;
708 bool ok;
710 if (!creds) {
711 return NULL;
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);
722 if (!ok) {
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));
731 talloc_free(creds);
732 return NULL;
735 creds->computer_name = talloc_strdup(creds, client_computer_name);
736 if (!creds->computer_name) {
737 talloc_free(creds);
738 return NULL;
740 creds->account_name = talloc_strdup(creds, client_account);
741 if (!creds->account_name) {
742 talloc_free(creds);
743 return NULL;
746 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
747 status = netlogon_creds_init_hmac_sha256(creds,
748 client_challenge,
749 server_challenge,
750 machine_password);
751 if (!NT_STATUS_IS_OK(status)) {
752 talloc_free(creds);
753 return NULL;
755 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
756 status = netlogon_creds_init_128bit(creds,
757 client_challenge,
758 server_challenge,
759 machine_password);
760 if (!NT_STATUS_IS_OK(status)) {
761 talloc_free(creds);
762 return NULL;
764 } else {
765 status = netlogon_creds_init_64bit(creds,
766 client_challenge,
767 server_challenge,
768 machine_password);
769 if (!NT_STATUS_IS_OK(status)) {
770 talloc_free(creds);
771 return NULL;
775 status = netlogon_creds_first_step(creds,
776 client_challenge,
777 server_challenge);
778 if (!NT_STATUS_IS_OK(status)) {
779 talloc_free(creds);
780 return NULL;
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)) {
792 talloc_free(creds);
793 return NULL;
796 *credentials_out = creds->server;
798 dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
800 return creds;
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)
807 NTSTATUS status;
809 if (!received_authenticator || !return_authenticator) {
810 return NT_STATUS_INVALID_PARAMETER;
813 if (!creds) {
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);
821 return status;
824 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
825 return_authenticator->cred = creds->server;
826 return_authenticator->timestamp = 0;
827 return NT_STATUS_OK;
828 } else {
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,
837 bool do_encrypt)
839 struct netr_SamBaseInfo *base = NULL;
840 NTSTATUS status;
842 if (validation == NULL) {
843 return NT_STATUS_INVALID_PARAMETER;
846 switch (validation_level) {
847 case 2:
848 if (validation->sam2) {
849 base = &validation->sam2->base;
851 break;
852 case 3:
853 if (validation->sam3) {
854 base = &validation->sam3->base;
856 break;
857 case 6:
858 if (validation->sam6) {
859 base = &validation->sam6->base;
861 break;
862 default:
863 /* If we can't find it, we can't very well decrypt it */
864 return NT_STATUS_INVALID_INFO_CLASS;
867 if (!base) {
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))) {
877 if (do_encrypt) {
878 status = netlogon_creds_aes_encrypt(
879 creds,
880 base->key.key,
881 sizeof(base->key.key));
882 } else {
883 status = netlogon_creds_aes_decrypt(
884 creds,
885 base->key.key,
886 sizeof(base->key.key));
888 if (!NT_STATUS_IS_OK(status)) {
889 return status;
893 if (!all_zero(base->LMSessKey.key,
894 sizeof(base->LMSessKey.key))) {
895 if (do_encrypt) {
896 status = netlogon_creds_aes_encrypt(
897 creds,
898 base->LMSessKey.key,
899 sizeof(base->LMSessKey.key));
900 } else {
901 status = netlogon_creds_aes_decrypt(
902 creds,
903 base->LMSessKey.key,
904 sizeof(base->LMSessKey.key));
906 if (!NT_STATUS_IS_OK(status)) {
907 return 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,
914 base->key.key,
915 sizeof(base->key.key));
916 if (!NT_STATUS_IS_OK(status)) {
917 return status;
921 if (!all_zero(base->LMSessKey.key,
922 sizeof(base->LMSessKey.key))) {
923 status = netlogon_creds_arcfour_crypt(creds,
924 base->LMSessKey.key,
925 sizeof(base->LMSessKey.key));
926 if (!NT_STATUS_IS_OK(status)) {
927 return status;
930 } else {
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))) {
934 if (do_encrypt) {
935 status = netlogon_creds_des_encrypt_LMKey(creds,
936 &base->LMSessKey);
937 } else {
938 status = netlogon_creds_des_decrypt_LMKey(creds,
939 &base->LMSessKey);
941 if (!NT_STATUS_IS_OK(status)) {
942 return status;
947 return NT_STATUS_OK;
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,
955 validation_level,
956 validation,
957 false);
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,
965 validation_level,
966 validation,
967 true);
970 static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
971 enum netr_LogonInfoClass level,
972 union netr_LogonLevel *logon,
973 bool do_encrypt)
975 NTSTATUS status;
977 if (logon == NULL) {
978 return NT_STATUS_INVALID_PARAMETER;
981 switch (level) {
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) {
991 uint8_t *h;
993 h = logon->password->lmpassword.hash;
994 if (!all_zero(h, 16)) {
995 if (do_encrypt) {
996 status = netlogon_creds_aes_encrypt(
997 creds,
999 16);
1000 } else {
1001 status = netlogon_creds_aes_decrypt(
1002 creds,
1004 16);
1006 if (!NT_STATUS_IS_OK(status)) {
1007 return status;
1011 h = logon->password->ntpassword.hash;
1012 if (!all_zero(h, 16)) {
1013 if (do_encrypt) {
1014 status = netlogon_creds_aes_encrypt(creds,
1016 16);
1017 } else {
1018 status = netlogon_creds_aes_decrypt(creds,
1020 16);
1022 if (!NT_STATUS_IS_OK(status)) {
1023 return status;
1026 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
1027 uint8_t *h;
1029 h = logon->password->lmpassword.hash;
1030 if (!all_zero(h, 16)) {
1031 status = netlogon_creds_arcfour_crypt(creds,
1033 16);
1034 if (!NT_STATUS_IS_OK(status)) {
1035 return status;
1039 h = logon->password->ntpassword.hash;
1040 if (!all_zero(h, 16)) {
1041 status = netlogon_creds_arcfour_crypt(creds,
1043 16);
1044 if (!NT_STATUS_IS_OK(status)) {
1045 return status;
1048 } else {
1049 struct samr_Password *p;
1051 p = &logon->password->lmpassword;
1052 if (!all_zero(p->hash, 16)) {
1053 if (do_encrypt) {
1054 status = netlogon_creds_des_encrypt(creds, p);
1055 } else {
1056 status = netlogon_creds_des_decrypt(creds, p);
1058 if (!NT_STATUS_IS_OK(status)) {
1059 return status;
1062 p = &logon->password->ntpassword;
1063 if (!all_zero(p->hash, 16)) {
1064 if (do_encrypt) {
1065 status = netlogon_creds_des_encrypt(creds, p);
1066 } else {
1067 status = netlogon_creds_des_decrypt(creds, p);
1069 if (!NT_STATUS_IS_OK(status)) {
1070 return status;
1074 break;
1076 case NetlogonNetworkInformation:
1077 case NetlogonNetworkTransitiveInformation:
1078 break;
1080 case NetlogonGenericInformation:
1081 if (logon->generic == NULL) {
1082 return NT_STATUS_INVALID_PARAMETER;
1085 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1086 if (do_encrypt) {
1087 status = netlogon_creds_aes_encrypt(
1088 creds,
1089 logon->generic->data,
1090 logon->generic->length);
1091 } else {
1092 status = netlogon_creds_aes_decrypt(
1093 creds,
1094 logon->generic->data,
1095 logon->generic->length);
1097 if (!NT_STATUS_IS_OK(status)) {
1098 return 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)) {
1105 return status;
1107 } else {
1108 /* Using DES to verify kerberos tickets makes no sense */
1110 break;
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;
1136 if (in == NULL) {
1137 return NULL;
1140 out = talloc(mem_ctx, union netr_LogonLevel);
1141 if (out == NULL) {
1142 return NULL;
1145 *out = *in;
1147 switch (level) {
1148 case NetlogonInteractiveInformation:
1149 case NetlogonInteractiveTransitiveInformation:
1150 case NetlogonServiceInformation:
1151 case NetlogonServiceTransitiveInformation:
1152 if (in->password == NULL) {
1153 return out;
1156 out->password = talloc(out, struct netr_PasswordInfo);
1157 if (out->password == NULL) {
1158 talloc_free(out);
1159 return NULL;
1161 *out->password = *in->password;
1163 return out;
1165 case NetlogonNetworkInformation:
1166 case NetlogonNetworkTransitiveInformation:
1167 break;
1169 case NetlogonGenericInformation:
1170 if (in->generic == NULL) {
1171 return out;
1174 out->generic = talloc(out, struct netr_GenericInfo);
1175 if (out->generic == NULL) {
1176 talloc_free(out);
1177 return NULL;
1179 *out->generic = *in->generic;
1181 if (in->generic->data == NULL) {
1182 return out;
1185 if (in->generic->length == 0) {
1186 return out;
1189 out->generic->data = talloc_memdup(out->generic,
1190 in->generic->data,
1191 in->generic->length);
1192 if (out->generic->data == NULL) {
1193 talloc_free(out);
1194 return NULL;
1197 return out;
1200 return out;
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);
1213 if (!creds) {
1214 return NULL;
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) {
1223 talloc_free(creds);
1224 return NULL;
1226 creds->account_name = talloc_strdup(creds, creds_in->account_name);
1227 if (!creds->account_name) {
1228 talloc_free(creds);
1229 return NULL;
1232 if (creds_in->sid) {
1233 creds->sid = dom_sid_dup(creds, creds_in->sid);
1234 if (!creds->sid) {
1235 talloc_free(creds);
1236 return NULL;
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));
1245 return creds;