python:gp: Print a nice message if cepces-submit can't be found
[Samba.git] / libcli / auth / credentials.c
blob02e6fc6852b084a47a94c4c422c40ea83a6c7395
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 #include "lib/crypto/gnutls_helpers.h"
30 #include <gnutls/gnutls.h>
31 #include <gnutls/crypto.h>
33 bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge)
36 * If none of the first 5 bytes of the client challenge is unique, the
37 * server MUST fail session-key negotiation without further processing
38 * of the following steps.
41 if (challenge->data[1] == challenge->data[0] &&
42 challenge->data[2] == challenge->data[0] &&
43 challenge->data[3] == challenge->data[0] &&
44 challenge->data[4] == challenge->data[0])
46 return false;
49 return true;
52 void netlogon_creds_random_challenge(struct netr_Credential *challenge)
54 ZERO_STRUCTP(challenge);
55 while (!netlogon_creds_is_random_challenge(challenge)) {
56 generate_random_buffer(challenge->data, sizeof(challenge->data));
60 static NTSTATUS netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
61 const struct netr_Credential *in,
62 struct netr_Credential *out)
64 NTSTATUS status;
65 int rc;
67 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
68 memcpy(out->data, in->data, sizeof(out->data));
70 status = netlogon_creds_aes_encrypt(creds,
71 out->data,
72 sizeof(out->data));
73 if (!NT_STATUS_IS_OK(status)) {
74 return status;
76 } else {
77 rc = des_crypt112(out->data, in->data, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
78 if (rc != 0) {
79 return gnutls_error_to_ntstatus(rc,
80 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
84 return NT_STATUS_OK;
88 initialise the credentials state for old-style 64 bit session keys
90 this call is made after the netr_ServerReqChallenge call
92 static NTSTATUS netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
93 const struct netr_Credential *client_challenge,
94 const struct netr_Credential *server_challenge,
95 const struct samr_Password *machine_password)
97 uint32_t sum[2];
98 uint8_t sum2[8];
99 int rc;
101 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
102 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
104 SIVAL(sum2,0,sum[0]);
105 SIVAL(sum2,4,sum[1]);
107 ZERO_ARRAY(creds->session_key);
109 rc = des_crypt128(creds->session_key, sum2, machine_password->hash);
110 if (rc != 0) {
111 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
114 return NT_STATUS_OK;
118 initialise the credentials state for ADS-style 128 bit session keys
120 this call is made after the netr_ServerReqChallenge call
122 static NTSTATUS netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
123 const struct netr_Credential *client_challenge,
124 const struct netr_Credential *server_challenge,
125 const struct samr_Password *machine_password)
127 uint8_t zero[4] = {0};
128 uint8_t tmp[gnutls_hash_get_len(GNUTLS_MAC_MD5)];
129 gnutls_hash_hd_t hash_hnd = NULL;
130 int rc;
132 ZERO_ARRAY(creds->session_key);
134 rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
135 if (rc < 0) {
136 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
139 rc = gnutls_hash(hash_hnd, zero, sizeof(zero));
140 if (rc < 0) {
141 gnutls_hash_deinit(hash_hnd, NULL);
142 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
144 rc = gnutls_hash(hash_hnd, client_challenge->data, 8);
145 if (rc < 0) {
146 gnutls_hash_deinit(hash_hnd, NULL);
147 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
149 rc = gnutls_hash(hash_hnd, server_challenge->data, 8);
150 if (rc < 0) {
151 gnutls_hash_deinit(hash_hnd, NULL);
152 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
155 gnutls_hash_deinit(hash_hnd, tmp);
157 /* This doesn't require HMAC MD5 RFC2104 as the hash is only 16 bytes */
158 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
159 machine_password->hash,
160 sizeof(machine_password->hash),
161 tmp,
162 sizeof(tmp),
163 creds->session_key);
164 ZERO_ARRAY(tmp);
166 if (rc < 0) {
167 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
170 return NT_STATUS_OK;
174 initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
176 this call is made after the netr_ServerReqChallenge call
178 static NTSTATUS netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState *creds,
179 const struct netr_Credential *client_challenge,
180 const struct netr_Credential *server_challenge,
181 const struct samr_Password *machine_password)
183 gnutls_hmac_hd_t hmac_hnd = NULL;
184 uint8_t digest[gnutls_hash_get_len(GNUTLS_MAC_SHA256)];
185 int rc;
187 ZERO_ARRAY(creds->session_key);
189 rc = gnutls_hmac_init(&hmac_hnd,
190 GNUTLS_MAC_SHA256,
191 machine_password->hash,
192 sizeof(machine_password->hash));
193 if (rc < 0) {
194 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
196 rc = gnutls_hmac(hmac_hnd,
197 client_challenge->data,
199 if (rc < 0) {
200 gnutls_hmac_deinit(hmac_hnd, NULL);
201 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
203 rc = gnutls_hmac(hmac_hnd,
204 server_challenge->data,
206 if (rc < 0) {
207 gnutls_hmac_deinit(hmac_hnd, NULL);
208 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
210 gnutls_hmac_deinit(hmac_hnd, digest);
212 memcpy(creds->session_key, digest, sizeof(creds->session_key));
214 ZERO_ARRAY(digest);
216 return NT_STATUS_OK;
219 static NTSTATUS netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
220 const struct netr_Credential *client_challenge,
221 const struct netr_Credential *server_challenge)
223 NTSTATUS status;
225 status = netlogon_creds_step_crypt(creds,
226 client_challenge,
227 &creds->client);
228 if (!NT_STATUS_IS_OK(status)) {
229 return status;
232 status = netlogon_creds_step_crypt(creds,
233 server_challenge,
234 &creds->server);
235 if (!NT_STATUS_IS_OK(status)) {
236 return status;
239 creds->seed = creds->client;
241 return NT_STATUS_OK;
245 step the credentials to the next element in the chain, updating the
246 current client and server credentials and the seed
248 static NTSTATUS netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
250 struct netr_Credential time_cred;
251 NTSTATUS status;
253 DEBUG(5,("\tseed %08x:%08x\n",
254 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
256 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
257 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
259 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
261 status = netlogon_creds_step_crypt(creds,
262 &time_cred,
263 &creds->client);
264 if (!NT_STATUS_IS_OK(status)) {
265 return status;
268 DEBUG(5,("\tCLIENT %08x:%08x\n",
269 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
271 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
272 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
274 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
275 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
277 status = netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
278 if (!NT_STATUS_IS_OK(status)) {
279 return status;
282 DEBUG(5,("\tSERVER %08x:%08x\n",
283 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
285 creds->seed = time_cred;
287 return NT_STATUS_OK;
291 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
293 NTSTATUS netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds,
294 struct netr_LMSessionKey *key)
296 int rc;
297 struct netr_LMSessionKey tmp;
299 rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
300 if (rc < 0) {
301 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
303 *key = tmp;
305 return NT_STATUS_OK;
309 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
311 NTSTATUS netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds,
312 struct netr_LMSessionKey *key)
314 int rc;
315 struct netr_LMSessionKey tmp;
317 rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_DECRYPT);
318 if (rc < 0) {
319 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
321 *key = tmp;
323 return NT_STATUS_OK;
327 DES encrypt a 16 byte password buffer using the session key
329 NTSTATUS netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds,
330 struct samr_Password *pass)
332 struct samr_Password tmp;
333 int rc;
335 rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
336 if (rc < 0) {
337 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
339 *pass = tmp;
341 return NT_STATUS_OK;
345 DES decrypt a 16 byte password buffer using the session key
347 NTSTATUS netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds,
348 struct samr_Password *pass)
350 struct samr_Password tmp;
351 int rc;
353 rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_DECRYPT);
354 if (rc < 0) {
355 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
357 *pass = tmp;
359 return NT_STATUS_OK;
363 ARCFOUR encrypt/decrypt a password buffer using the session key
365 NTSTATUS netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds,
366 uint8_t *data,
367 size_t len)
369 gnutls_cipher_hd_t cipher_hnd = NULL;
370 gnutls_datum_t session_key = {
371 .data = creds->session_key,
372 .size = sizeof(creds->session_key),
374 int rc;
376 rc = gnutls_cipher_init(&cipher_hnd,
377 GNUTLS_CIPHER_ARCFOUR_128,
378 &session_key,
379 NULL);
380 if (rc < 0) {
381 return gnutls_error_to_ntstatus(rc,
382 NT_STATUS_CRYPTO_SYSTEM_INVALID);
384 rc = gnutls_cipher_encrypt(cipher_hnd,
385 data,
386 len);
387 gnutls_cipher_deinit(cipher_hnd);
388 if (rc < 0) {
389 return gnutls_error_to_ntstatus(rc,
390 NT_STATUS_CRYPTO_SYSTEM_INVALID);
393 return NT_STATUS_OK;
397 AES encrypt a password buffer using the session key
399 NTSTATUS netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds,
400 uint8_t *data,
401 size_t len)
403 gnutls_cipher_hd_t cipher_hnd = NULL;
404 gnutls_datum_t key = {
405 .data = creds->session_key,
406 .size = sizeof(creds->session_key),
408 uint32_t iv_size =
409 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
410 uint8_t _iv[iv_size];
411 gnutls_datum_t iv = {
412 .data = _iv,
413 .size = iv_size,
415 int rc;
417 ZERO_ARRAY(_iv);
419 rc = gnutls_cipher_init(&cipher_hnd,
420 GNUTLS_CIPHER_AES_128_CFB8,
421 &key,
422 &iv);
423 if (rc < 0) {
424 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
427 rc = gnutls_cipher_encrypt(cipher_hnd, data, len);
428 gnutls_cipher_deinit(cipher_hnd);
429 if (rc < 0) {
430 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
433 return NT_STATUS_OK;
437 AES decrypt a password buffer using the session key
439 NTSTATUS netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
441 gnutls_cipher_hd_t cipher_hnd = NULL;
442 gnutls_datum_t key = {
443 .data = creds->session_key,
444 .size = sizeof(creds->session_key),
446 uint32_t iv_size =
447 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
448 uint8_t _iv[iv_size];
449 gnutls_datum_t iv = {
450 .data = _iv,
451 .size = iv_size,
453 int rc;
455 ZERO_ARRAY(_iv);
457 rc = gnutls_cipher_init(&cipher_hnd,
458 GNUTLS_CIPHER_AES_128_CFB8,
459 &key,
460 &iv);
461 if (rc < 0) {
462 return gnutls_error_to_ntstatus(rc,
463 NT_STATUS_CRYPTO_SYSTEM_INVALID);
466 rc = gnutls_cipher_decrypt(cipher_hnd, data, len);
467 gnutls_cipher_deinit(cipher_hnd);
468 if (rc < 0) {
469 return gnutls_error_to_ntstatus(rc,
470 NT_STATUS_CRYPTO_SYSTEM_INVALID);
473 return NT_STATUS_OK;
476 /*****************************************************************
477 The above functions are common to the client and server interface
478 next comes the client specific functions
479 ******************************************************************/
482 initialise the credentials chain and return the first client
483 credentials
486 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
487 const char *client_account,
488 const char *client_computer_name,
489 uint16_t secure_channel_type,
490 const struct netr_Credential *client_challenge,
491 const struct netr_Credential *server_challenge,
492 const struct samr_Password *machine_password,
493 struct netr_Credential *initial_credential,
494 uint32_t negotiate_flags)
496 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
497 NTSTATUS status;
499 if (!creds) {
500 return NULL;
503 creds->sequence = time(NULL);
504 creds->negotiate_flags = negotiate_flags;
505 creds->secure_channel_type = secure_channel_type;
507 creds->computer_name = talloc_strdup(creds, client_computer_name);
508 if (!creds->computer_name) {
509 talloc_free(creds);
510 return NULL;
512 creds->account_name = talloc_strdup(creds, client_account);
513 if (!creds->account_name) {
514 talloc_free(creds);
515 return NULL;
518 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
519 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
520 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
522 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
523 status = netlogon_creds_init_hmac_sha256(creds,
524 client_challenge,
525 server_challenge,
526 machine_password);
527 if (!NT_STATUS_IS_OK(status)) {
528 talloc_free(creds);
529 return NULL;
531 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
532 status = netlogon_creds_init_128bit(creds,
533 client_challenge,
534 server_challenge,
535 machine_password);
536 if (!NT_STATUS_IS_OK(status)) {
537 talloc_free(creds);
538 return NULL;
540 } else {
541 status = netlogon_creds_init_64bit(creds,
542 client_challenge,
543 server_challenge,
544 machine_password);
545 if (!NT_STATUS_IS_OK(status)) {
546 talloc_free(creds);
547 return NULL;
551 status = netlogon_creds_first_step(creds,
552 client_challenge,
553 server_challenge);
554 if (!NT_STATUS_IS_OK(status)) {
555 talloc_free(creds);
556 return NULL;
559 dump_data_pw("Session key", creds->session_key, 16);
560 dump_data_pw("Credential ", creds->client.data, 8);
562 *initial_credential = creds->client;
563 return creds;
567 initialise the credentials structure with only a session key. The caller better know what they are doing!
570 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
571 const uint8_t session_key[16])
573 struct netlogon_creds_CredentialState *creds;
575 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
576 if (!creds) {
577 return NULL;
580 memcpy(creds->session_key, session_key, 16);
582 return creds;
586 step the credentials to the next element in the chain, updating the
587 current client and server credentials and the seed
589 produce the next authenticator in the sequence ready to send to
590 the server
592 NTSTATUS
593 netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
594 struct netr_Authenticator *next)
596 uint32_t t32n = (uint32_t)time(NULL);
597 NTSTATUS status;
600 * we always increment and ignore an overflow here
602 creds->sequence += 2;
604 if (t32n > creds->sequence) {
606 * we may increment more
608 creds->sequence = t32n;
609 } else {
610 uint32_t d = creds->sequence - t32n;
612 if (d >= INT32_MAX) {
614 * got an overflow of time_t vs. uint32_t
616 creds->sequence = t32n;
620 status = netlogon_creds_step(creds);
621 if (!NT_STATUS_IS_OK(status)) {
622 return status;
625 next->cred = creds->client;
626 next->timestamp = creds->sequence;
628 return NT_STATUS_OK;
632 check that a credentials reply from a server is correct
634 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
635 const struct netr_Credential *received_credentials)
637 if (!received_credentials ||
638 !mem_equal_const_time(received_credentials->data, creds->server.data, 8)) {
639 DEBUG(2,("credentials check failed\n"));
640 return false;
642 return true;
646 /*****************************************************************
647 The above functions are common to the client and server interface
648 next comes the server specific functions
649 ******************************************************************/
652 check that a credentials reply from a server is correct
654 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
655 const struct netr_Credential *received_credentials)
657 if (!mem_equal_const_time(received_credentials->data, creds->client.data, 8)) {
658 DEBUG(2,("credentials check failed\n"));
659 dump_data_pw("client creds", creds->client.data, 8);
660 dump_data_pw("calc creds", received_credentials->data, 8);
661 return false;
663 return true;
667 initialise the credentials chain and return the first server
668 credentials
670 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
671 const char *client_account,
672 const char *client_computer_name,
673 uint16_t secure_channel_type,
674 const struct netr_Credential *client_challenge,
675 const struct netr_Credential *server_challenge,
676 const struct samr_Password *machine_password,
677 const struct netr_Credential *credentials_in,
678 struct netr_Credential *credentials_out,
679 uint32_t negotiate_flags)
682 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
683 NTSTATUS status;
684 bool ok;
686 if (!creds) {
687 return NULL;
690 creds->negotiate_flags = negotiate_flags;
691 creds->secure_channel_type = secure_channel_type;
693 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
694 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
695 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
697 ok = netlogon_creds_is_random_challenge(client_challenge);
698 if (!ok) {
699 DBG_WARNING("CVE-2020-1472(ZeroLogon): "
700 "non-random client challenge rejected for "
701 "client_account[%s] client_computer_name[%s]\n",
702 log_escape(mem_ctx, client_account),
703 log_escape(mem_ctx, client_computer_name));
704 dump_data(DBGLVL_WARNING,
705 client_challenge->data,
706 sizeof(client_challenge->data));
707 talloc_free(creds);
708 return NULL;
711 creds->computer_name = talloc_strdup(creds, client_computer_name);
712 if (!creds->computer_name) {
713 talloc_free(creds);
714 return NULL;
716 creds->account_name = talloc_strdup(creds, client_account);
717 if (!creds->account_name) {
718 talloc_free(creds);
719 return NULL;
722 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
723 status = netlogon_creds_init_hmac_sha256(creds,
724 client_challenge,
725 server_challenge,
726 machine_password);
727 if (!NT_STATUS_IS_OK(status)) {
728 talloc_free(creds);
729 return NULL;
731 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
732 status = netlogon_creds_init_128bit(creds,
733 client_challenge,
734 server_challenge,
735 machine_password);
736 if (!NT_STATUS_IS_OK(status)) {
737 talloc_free(creds);
738 return NULL;
740 } else {
741 status = netlogon_creds_init_64bit(creds,
742 client_challenge,
743 server_challenge,
744 machine_password);
745 if (!NT_STATUS_IS_OK(status)) {
746 talloc_free(creds);
747 return NULL;
751 status = netlogon_creds_first_step(creds,
752 client_challenge,
753 server_challenge);
754 if (!NT_STATUS_IS_OK(status)) {
755 talloc_free(creds);
756 return NULL;
759 dump_data_pw("Session key", creds->session_key, 16);
760 dump_data_pw("Client Credential ", creds->client.data, 8);
761 dump_data_pw("Server Credential ", creds->server.data, 8);
763 dump_data_pw("Credentials in", credentials_in->data, sizeof(credentials_in->data));
765 /* And before we leak information about the machine account
766 * password, check that they got the first go right */
767 if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
768 talloc_free(creds);
769 return NULL;
772 *credentials_out = creds->server;
774 dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
776 return creds;
779 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
780 const struct netr_Authenticator *received_authenticator,
781 struct netr_Authenticator *return_authenticator)
783 NTSTATUS status;
785 if (!received_authenticator || !return_authenticator) {
786 return NT_STATUS_INVALID_PARAMETER;
789 if (!creds) {
790 return NT_STATUS_ACCESS_DENIED;
793 creds->sequence = received_authenticator->timestamp;
794 status = netlogon_creds_step(creds);
795 if (!NT_STATUS_IS_OK(status)) {
796 ZERO_STRUCTP(return_authenticator);
797 return status;
800 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
801 return_authenticator->cred = creds->server;
802 return_authenticator->timestamp = 0;
803 return NT_STATUS_OK;
804 } else {
805 ZERO_STRUCTP(return_authenticator);
806 return NT_STATUS_ACCESS_DENIED;
810 static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
811 uint16_t validation_level,
812 union netr_Validation *validation,
813 bool do_encrypt)
815 struct netr_SamBaseInfo *base = NULL;
816 NTSTATUS status;
818 if (validation == NULL) {
819 return NT_STATUS_INVALID_PARAMETER;
822 switch (validation_level) {
823 case 2:
824 if (validation->sam2) {
825 base = &validation->sam2->base;
827 break;
828 case 3:
829 if (validation->sam3) {
830 base = &validation->sam3->base;
832 break;
833 case 6:
834 if (validation->sam6) {
835 base = &validation->sam6->base;
837 break;
838 default:
839 /* If we can't find it, we can't very well decrypt it */
840 return NT_STATUS_INVALID_INFO_CLASS;
843 if (!base) {
844 return NT_STATUS_INVALID_INFO_CLASS;
847 /* find and decyrpt the session keys, return in parameters above */
848 if (validation_level == 6) {
849 /* they aren't encrypted! */
850 } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
851 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
852 if (!all_zero(base->key.key, sizeof(base->key.key))) {
853 if (do_encrypt) {
854 status = netlogon_creds_aes_encrypt(
855 creds,
856 base->key.key,
857 sizeof(base->key.key));
858 } else {
859 status = netlogon_creds_aes_decrypt(
860 creds,
861 base->key.key,
862 sizeof(base->key.key));
864 if (!NT_STATUS_IS_OK(status)) {
865 return status;
869 if (!all_zero(base->LMSessKey.key,
870 sizeof(base->LMSessKey.key))) {
871 if (do_encrypt) {
872 status = netlogon_creds_aes_encrypt(
873 creds,
874 base->LMSessKey.key,
875 sizeof(base->LMSessKey.key));
876 } else {
877 status = netlogon_creds_aes_decrypt(
878 creds,
879 base->LMSessKey.key,
880 sizeof(base->LMSessKey.key));
882 if (!NT_STATUS_IS_OK(status)) {
883 return status;
886 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
887 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
888 if (!all_zero(base->key.key, sizeof(base->key.key))) {
889 status = netlogon_creds_arcfour_crypt(creds,
890 base->key.key,
891 sizeof(base->key.key));
892 if (!NT_STATUS_IS_OK(status)) {
893 return status;
897 if (!all_zero(base->LMSessKey.key,
898 sizeof(base->LMSessKey.key))) {
899 status = netlogon_creds_arcfour_crypt(creds,
900 base->LMSessKey.key,
901 sizeof(base->LMSessKey.key));
902 if (!NT_STATUS_IS_OK(status)) {
903 return status;
906 } else {
907 /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
908 if (!all_zero(base->LMSessKey.key,
909 sizeof(base->LMSessKey.key))) {
910 if (do_encrypt) {
911 status = netlogon_creds_des_encrypt_LMKey(creds,
912 &base->LMSessKey);
913 } else {
914 status = netlogon_creds_des_decrypt_LMKey(creds,
915 &base->LMSessKey);
917 if (!NT_STATUS_IS_OK(status)) {
918 return status;
923 return NT_STATUS_OK;
926 NTSTATUS netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
927 uint16_t validation_level,
928 union netr_Validation *validation)
930 return netlogon_creds_crypt_samlogon_validation(creds,
931 validation_level,
932 validation,
933 false);
936 NTSTATUS netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
937 uint16_t validation_level,
938 union netr_Validation *validation)
940 return netlogon_creds_crypt_samlogon_validation(creds,
941 validation_level,
942 validation,
943 true);
946 static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
947 enum netr_LogonInfoClass level,
948 union netr_LogonLevel *logon,
949 bool do_encrypt)
951 NTSTATUS status;
953 if (logon == NULL) {
954 return NT_STATUS_INVALID_PARAMETER;
957 switch (level) {
958 case NetlogonInteractiveInformation:
959 case NetlogonInteractiveTransitiveInformation:
960 case NetlogonServiceInformation:
961 case NetlogonServiceTransitiveInformation:
962 if (logon->password == NULL) {
963 return NT_STATUS_INVALID_PARAMETER;
966 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
967 uint8_t *h;
969 h = logon->password->lmpassword.hash;
970 if (!all_zero(h, 16)) {
971 if (do_encrypt) {
972 status = netlogon_creds_aes_encrypt(
973 creds,
975 16);
976 } else {
977 status = netlogon_creds_aes_decrypt(
978 creds,
980 16);
982 if (!NT_STATUS_IS_OK(status)) {
983 return status;
987 h = logon->password->ntpassword.hash;
988 if (!all_zero(h, 16)) {
989 if (do_encrypt) {
990 status = netlogon_creds_aes_encrypt(creds,
992 16);
993 } else {
994 status = netlogon_creds_aes_decrypt(creds,
996 16);
998 if (!NT_STATUS_IS_OK(status)) {
999 return status;
1002 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
1003 uint8_t *h;
1005 h = logon->password->lmpassword.hash;
1006 if (!all_zero(h, 16)) {
1007 status = netlogon_creds_arcfour_crypt(creds,
1009 16);
1010 if (!NT_STATUS_IS_OK(status)) {
1011 return status;
1015 h = logon->password->ntpassword.hash;
1016 if (!all_zero(h, 16)) {
1017 status = netlogon_creds_arcfour_crypt(creds,
1019 16);
1020 if (!NT_STATUS_IS_OK(status)) {
1021 return status;
1024 } else {
1025 struct samr_Password *p;
1027 p = &logon->password->lmpassword;
1028 if (!all_zero(p->hash, 16)) {
1029 if (do_encrypt) {
1030 status = netlogon_creds_des_encrypt(creds, p);
1031 } else {
1032 status = netlogon_creds_des_decrypt(creds, p);
1034 if (!NT_STATUS_IS_OK(status)) {
1035 return status;
1038 p = &logon->password->ntpassword;
1039 if (!all_zero(p->hash, 16)) {
1040 if (do_encrypt) {
1041 status = netlogon_creds_des_encrypt(creds, p);
1042 } else {
1043 status = netlogon_creds_des_decrypt(creds, p);
1045 if (!NT_STATUS_IS_OK(status)) {
1046 return status;
1050 break;
1052 case NetlogonNetworkInformation:
1053 case NetlogonNetworkTransitiveInformation:
1054 break;
1056 case NetlogonGenericInformation:
1057 if (logon->generic == NULL) {
1058 return NT_STATUS_INVALID_PARAMETER;
1061 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1062 if (do_encrypt) {
1063 status = netlogon_creds_aes_encrypt(
1064 creds,
1065 logon->generic->data,
1066 logon->generic->length);
1067 } else {
1068 status = netlogon_creds_aes_decrypt(
1069 creds,
1070 logon->generic->data,
1071 logon->generic->length);
1073 if (!NT_STATUS_IS_OK(status)) {
1074 return status;
1076 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
1077 status = netlogon_creds_arcfour_crypt(creds,
1078 logon->generic->data,
1079 logon->generic->length);
1080 if (!NT_STATUS_IS_OK(status)) {
1081 return status;
1083 } else {
1084 /* Using DES to verify kerberos tickets makes no sense */
1086 break;
1089 return NT_STATUS_OK;
1092 NTSTATUS netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
1093 enum netr_LogonInfoClass level,
1094 union netr_LogonLevel *logon)
1096 return netlogon_creds_crypt_samlogon_logon(creds, level, logon, false);
1099 NTSTATUS netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
1100 enum netr_LogonInfoClass level,
1101 union netr_LogonLevel *logon)
1103 return netlogon_creds_crypt_samlogon_logon(creds, level, logon, true);
1106 union netr_LogonLevel *netlogon_creds_shallow_copy_logon(TALLOC_CTX *mem_ctx,
1107 enum netr_LogonInfoClass level,
1108 const union netr_LogonLevel *in)
1110 union netr_LogonLevel *out;
1112 if (in == NULL) {
1113 return NULL;
1116 out = talloc(mem_ctx, union netr_LogonLevel);
1117 if (out == NULL) {
1118 return NULL;
1121 *out = *in;
1123 switch (level) {
1124 case NetlogonInteractiveInformation:
1125 case NetlogonInteractiveTransitiveInformation:
1126 case NetlogonServiceInformation:
1127 case NetlogonServiceTransitiveInformation:
1128 if (in->password == NULL) {
1129 return out;
1132 out->password = talloc(out, struct netr_PasswordInfo);
1133 if (out->password == NULL) {
1134 talloc_free(out);
1135 return NULL;
1137 *out->password = *in->password;
1139 return out;
1141 case NetlogonNetworkInformation:
1142 case NetlogonNetworkTransitiveInformation:
1143 break;
1145 case NetlogonGenericInformation:
1146 if (in->generic == NULL) {
1147 return out;
1150 out->generic = talloc(out, struct netr_GenericInfo);
1151 if (out->generic == NULL) {
1152 talloc_free(out);
1153 return NULL;
1155 *out->generic = *in->generic;
1157 if (in->generic->data == NULL) {
1158 return out;
1161 if (in->generic->length == 0) {
1162 return out;
1165 out->generic->data = talloc_memdup(out->generic,
1166 in->generic->data,
1167 in->generic->length);
1168 if (out->generic->data == NULL) {
1169 talloc_free(out);
1170 return NULL;
1173 return out;
1176 return out;
1180 copy a netlogon_creds_CredentialState struct
1183 struct netlogon_creds_CredentialState *netlogon_creds_copy(
1184 TALLOC_CTX *mem_ctx,
1185 const struct netlogon_creds_CredentialState *creds_in)
1187 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
1189 if (!creds) {
1190 return NULL;
1193 creds->sequence = creds_in->sequence;
1194 creds->negotiate_flags = creds_in->negotiate_flags;
1195 creds->secure_channel_type = creds_in->secure_channel_type;
1197 creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
1198 if (!creds->computer_name) {
1199 talloc_free(creds);
1200 return NULL;
1202 creds->account_name = talloc_strdup(creds, creds_in->account_name);
1203 if (!creds->account_name) {
1204 talloc_free(creds);
1205 return NULL;
1208 if (creds_in->sid) {
1209 creds->sid = dom_sid_dup(creds, creds_in->sid);
1210 if (!creds->sid) {
1211 talloc_free(creds);
1212 return NULL;
1216 memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
1217 memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
1218 memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
1219 memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
1221 return creds;