s3: smbd: Change SMB_VFS_GET_NT_ACL() -> SMB_VFS_GET_NT_ACL_AT() in inherit_new_acl().
[Samba.git] / libcli / auth / credentials.c
blobc541eeff47037034a69dcd4daabadfa2929fa323
1 /*
2 Unix SMB/CIFS implementation.
4 code to manipulate domain credentials
6 Copyright (C) Andrew Tridgell 1997-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "system/time.h"
25 #include "libcli/auth/libcli_auth.h"
26 #include "../libcli/security/dom_sid.h"
28 #ifndef HAVE_GNUTLS_AES_CFB8
29 #include "lib/crypto/aes.h"
30 #endif
32 #include "lib/crypto/gnutls_helpers.h"
33 #include <gnutls/gnutls.h>
34 #include <gnutls/crypto.h>
36 static NTSTATUS netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
37 const struct netr_Credential *in,
38 struct netr_Credential *out)
40 NTSTATUS status;
41 int rc;
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,
47 out->data,
48 sizeof(out->data));
49 if (!NT_STATUS_IS_OK(status)) {
50 return status;
52 } else {
53 rc = des_crypt112(out->data, in->data, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
54 if (rc != 0) {
55 return gnutls_error_to_ntstatus(rc,
56 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
60 return NT_STATUS_OK;
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)
73 uint32_t sum[2];
74 uint8_t sum2[8];
75 int rc;
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);
80 SIVAL(sum2,0,sum[0]);
81 SIVAL(sum2,4,sum[1]);
83 ZERO_ARRAY(creds->session_key);
85 rc = des_crypt128(creds->session_key, sum2, machine_password->hash);
86 if (rc != 0) {
87 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
90 return NT_STATUS_OK;
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;
106 int rc;
108 ZERO_ARRAY(creds->session_key);
110 rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
111 if (rc < 0) {
112 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
115 rc = gnutls_hash(hash_hnd, zero, sizeof(zero));
116 if (rc < 0) {
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);
121 if (rc < 0) {
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);
126 if (rc < 0) {
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),
137 tmp,
138 sizeof(tmp),
139 creds->session_key);
140 ZERO_ARRAY(tmp);
142 if (rc < 0) {
143 return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
146 return NT_STATUS_OK;
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)];
161 int rc;
163 ZERO_ARRAY(creds->session_key);
165 rc = gnutls_hmac_init(&hmac_hnd,
166 GNUTLS_MAC_SHA256,
167 machine_password->hash,
168 sizeof(machine_password->hash));
169 if (rc < 0) {
170 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
172 rc = gnutls_hmac(hmac_hnd,
173 client_challenge->data,
175 if (rc < 0) {
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,
182 if (rc < 0) {
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));
190 ZERO_ARRAY(digest);
192 return NT_STATUS_OK;
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)
199 NTSTATUS status;
201 status = netlogon_creds_step_crypt(creds,
202 client_challenge,
203 &creds->client);
204 if (!NT_STATUS_IS_OK(status)) {
205 return status;
208 status = netlogon_creds_step_crypt(creds,
209 server_challenge,
210 &creds->server);
211 if (!NT_STATUS_IS_OK(status)) {
212 return status;
215 creds->seed = creds->client;
217 return NT_STATUS_OK;
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;
227 NTSTATUS status;
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,
238 &time_cred,
239 &creds->client);
240 if (!NT_STATUS_IS_OK(status)) {
241 return 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)) {
255 return status;
258 DEBUG(5,("\tSERVER %08x:%08x\n",
259 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
261 creds->seed = time_cred;
263 return NT_STATUS_OK;
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)
272 int rc;
273 struct netr_LMSessionKey tmp;
275 rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
276 if (rc < 0) {
277 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
279 *key = tmp;
281 return NT_STATUS_OK;
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)
290 int rc;
291 struct netr_LMSessionKey tmp;
293 rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_DECRYPT);
294 if (rc < 0) {
295 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
297 *key = tmp;
299 return NT_STATUS_OK;
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;
309 int rc;
311 rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
312 if (rc < 0) {
313 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
315 *pass = tmp;
317 return NT_STATUS_OK;
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;
327 int rc;
329 rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_DECRYPT);
330 if (rc < 0) {
331 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
333 *pass = tmp;
335 return NT_STATUS_OK;
339 ARCFOUR encrypt/decrypt a password buffer using the session key
341 NTSTATUS netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds,
342 uint8_t *data,
343 size_t len)
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),
350 int rc;
352 rc = gnutls_cipher_init(&cipher_hnd,
353 GNUTLS_CIPHER_ARCFOUR_128,
354 &session_key,
355 NULL);
356 if (rc < 0) {
357 return gnutls_error_to_ntstatus(rc,
358 NT_STATUS_CRYPTO_SYSTEM_INVALID);
360 rc = gnutls_cipher_encrypt(cipher_hnd,
361 data,
362 len);
363 gnutls_cipher_deinit(cipher_hnd);
364 if (rc < 0) {
365 return gnutls_error_to_ntstatus(rc,
366 NT_STATUS_CRYPTO_SYSTEM_INVALID);
369 return NT_STATUS_OK;
373 AES encrypt a password buffer using the session key
375 NTSTATUS netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds,
376 uint8_t *data,
377 size_t len)
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),
385 uint32_t iv_size =
386 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
387 uint8_t _iv[iv_size];
388 gnutls_datum_t iv = {
389 .data = _iv,
390 .size = iv_size,
392 int rc;
394 ZERO_ARRAY(_iv);
396 rc = gnutls_cipher_init(&cipher_hnd,
397 GNUTLS_CIPHER_AES_128_CFB8,
398 &key,
399 &iv);
400 if (rc < 0) {
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);
406 if (rc < 0) {
407 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
410 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
411 AES_KEY key;
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 */
419 return NT_STATUS_OK;
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),
433 uint32_t iv_size =
434 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
435 uint8_t _iv[iv_size];
436 gnutls_datum_t iv = {
437 .data = _iv,
438 .size = iv_size,
440 int rc;
442 ZERO_ARRAY(_iv);
444 rc = gnutls_cipher_init(&cipher_hnd,
445 GNUTLS_CIPHER_AES_128_CFB8,
446 &key,
447 &iv);
448 if (rc < 0) {
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);
455 if (rc < 0) {
456 return gnutls_error_to_ntstatus(rc,
457 NT_STATUS_CRYPTO_SYSTEM_INVALID);
460 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
461 AES_KEY key;
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 */
469 return NT_STATUS_OK;
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
479 credentials
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);
493 NTSTATUS status;
495 if (!creds) {
496 return NULL;
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) {
505 talloc_free(creds);
506 return NULL;
508 creds->account_name = talloc_strdup(creds, client_account);
509 if (!creds->account_name) {
510 talloc_free(creds);
511 return NULL;
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,
520 client_challenge,
521 server_challenge,
522 machine_password);
523 if (!NT_STATUS_IS_OK(status)) {
524 talloc_free(creds);
525 return NULL;
527 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
528 status = netlogon_creds_init_128bit(creds,
529 client_challenge,
530 server_challenge,
531 machine_password);
532 if (!NT_STATUS_IS_OK(status)) {
533 talloc_free(creds);
534 return NULL;
536 } else {
537 status = netlogon_creds_init_64bit(creds,
538 client_challenge,
539 server_challenge,
540 machine_password);
541 if (!NT_STATUS_IS_OK(status)) {
542 talloc_free(creds);
543 return NULL;
547 status = netlogon_creds_first_step(creds,
548 client_challenge,
549 server_challenge);
550 if (!NT_STATUS_IS_OK(status)) {
551 talloc_free(creds);
552 return NULL;
555 dump_data_pw("Session key", creds->session_key, 16);
556 dump_data_pw("Credential ", creds->client.data, 8);
558 *initial_credential = creds->client;
559 return creds;
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);
572 if (!creds) {
573 return NULL;
576 memcpy(creds->session_key, session_key, 16);
578 return creds;
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
586 the server
588 NTSTATUS
589 netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
590 struct netr_Authenticator *next)
592 uint32_t t32n = (uint32_t)time(NULL);
593 NTSTATUS status;
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;
605 } else {
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)) {
618 return status;
621 next->cred = creds->client;
622 next->timestamp = creds->sequence;
624 return NT_STATUS_OK;
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"));
636 return false;
638 return true;
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);
657 return false;
659 return true;
663 initialise the credentials chain and return the first server
664 credentials
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);
679 NTSTATUS status;
682 if (!creds) {
683 return NULL;
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) {
695 talloc_free(creds);
696 return NULL;
698 creds->account_name = talloc_strdup(creds, client_account);
699 if (!creds->account_name) {
700 talloc_free(creds);
701 return NULL;
704 if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
705 status = netlogon_creds_init_hmac_sha256(creds,
706 client_challenge,
707 server_challenge,
708 machine_password);
709 if (!NT_STATUS_IS_OK(status)) {
710 talloc_free(creds);
711 return NULL;
713 } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
714 status = netlogon_creds_init_128bit(creds,
715 client_challenge,
716 server_challenge,
717 machine_password);
718 if (!NT_STATUS_IS_OK(status)) {
719 talloc_free(creds);
720 return NULL;
722 } else {
723 status = netlogon_creds_init_64bit(creds,
724 client_challenge,
725 server_challenge,
726 machine_password);
727 if (!NT_STATUS_IS_OK(status)) {
728 talloc_free(creds);
729 return NULL;
733 status = netlogon_creds_first_step(creds,
734 client_challenge,
735 server_challenge);
736 if (!NT_STATUS_IS_OK(status)) {
737 talloc_free(creds);
738 return NULL;
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)) {
750 talloc_free(creds);
751 return NULL;
754 *credentials_out = creds->server;
756 dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
758 return creds;
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)
765 NTSTATUS status;
767 if (!received_authenticator || !return_authenticator) {
768 return NT_STATUS_INVALID_PARAMETER;
771 if (!creds) {
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);
779 return status;
782 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
783 return_authenticator->cred = creds->server;
784 return_authenticator->timestamp = 0;
785 return NT_STATUS_OK;
786 } else {
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,
795 bool do_encrypt)
797 struct netr_SamBaseInfo *base = NULL;
798 NTSTATUS status;
800 if (validation == NULL) {
801 return NT_STATUS_INVALID_PARAMETER;
804 switch (validation_level) {
805 case 2:
806 if (validation->sam2) {
807 base = &validation->sam2->base;
809 break;
810 case 3:
811 if (validation->sam3) {
812 base = &validation->sam3->base;
814 break;
815 case 6:
816 if (validation->sam6) {
817 base = &validation->sam6->base;
819 break;
820 default:
821 /* If we can't find it, we can't very well decrypt it */
822 return NT_STATUS_INVALID_INFO_CLASS;
825 if (!base) {
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))) {
835 if (do_encrypt) {
836 status = netlogon_creds_aes_encrypt(
837 creds,
838 base->key.key,
839 sizeof(base->key.key));
840 } else {
841 status = netlogon_creds_aes_decrypt(
842 creds,
843 base->key.key,
844 sizeof(base->key.key));
846 if (!NT_STATUS_IS_OK(status)) {
847 return status;
851 if (!all_zero(base->LMSessKey.key,
852 sizeof(base->LMSessKey.key))) {
853 if (do_encrypt) {
854 status = netlogon_creds_aes_encrypt(
855 creds,
856 base->LMSessKey.key,
857 sizeof(base->LMSessKey.key));
858 } else {
859 status = netlogon_creds_aes_decrypt(
860 creds,
861 base->LMSessKey.key,
862 sizeof(base->LMSessKey.key));
864 if (!NT_STATUS_IS_OK(status)) {
865 return 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,
872 base->key.key,
873 sizeof(base->key.key));
874 if (!NT_STATUS_IS_OK(status)) {
875 return status;
879 if (!all_zero(base->LMSessKey.key,
880 sizeof(base->LMSessKey.key))) {
881 status = netlogon_creds_arcfour_crypt(creds,
882 base->LMSessKey.key,
883 sizeof(base->LMSessKey.key));
884 if (!NT_STATUS_IS_OK(status)) {
885 return status;
888 } else {
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))) {
892 if (do_encrypt) {
893 status = netlogon_creds_des_encrypt_LMKey(creds,
894 &base->LMSessKey);
895 } else {
896 status = netlogon_creds_des_decrypt_LMKey(creds,
897 &base->LMSessKey);
899 if (!NT_STATUS_IS_OK(status)) {
900 return status;
905 return NT_STATUS_OK;
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,
913 validation_level,
914 validation,
915 false);
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,
923 validation_level,
924 validation,
925 true);
928 static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
929 enum netr_LogonInfoClass level,
930 union netr_LogonLevel *logon,
931 bool do_encrypt)
933 NTSTATUS status;
935 if (logon == NULL) {
936 return NT_STATUS_INVALID_PARAMETER;
939 switch (level) {
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) {
949 uint8_t *h;
951 h = logon->password->lmpassword.hash;
952 if (!all_zero(h, 16)) {
953 if (do_encrypt) {
954 status = netlogon_creds_aes_encrypt(
955 creds,
957 16);
958 } else {
959 status = netlogon_creds_aes_decrypt(
960 creds,
962 16);
964 if (!NT_STATUS_IS_OK(status)) {
965 return status;
969 h = logon->password->ntpassword.hash;
970 if (!all_zero(h, 16)) {
971 if (do_encrypt) {
972 status = netlogon_creds_aes_encrypt(creds,
974 16);
975 } else {
976 status = netlogon_creds_aes_decrypt(creds,
978 16);
980 if (!NT_STATUS_IS_OK(status)) {
981 return status;
984 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
985 uint8_t *h;
987 h = logon->password->lmpassword.hash;
988 if (!all_zero(h, 16)) {
989 status = netlogon_creds_arcfour_crypt(creds,
991 16);
992 if (!NT_STATUS_IS_OK(status)) {
993 return status;
997 h = logon->password->ntpassword.hash;
998 if (!all_zero(h, 16)) {
999 status = netlogon_creds_arcfour_crypt(creds,
1001 16);
1002 if (!NT_STATUS_IS_OK(status)) {
1003 return status;
1006 } else {
1007 struct samr_Password *p;
1009 p = &logon->password->lmpassword;
1010 if (!all_zero(p->hash, 16)) {
1011 if (do_encrypt) {
1012 status = netlogon_creds_des_encrypt(creds, p);
1013 } else {
1014 status = netlogon_creds_des_decrypt(creds, p);
1016 if (!NT_STATUS_IS_OK(status)) {
1017 return status;
1020 p = &logon->password->ntpassword;
1021 if (!all_zero(p->hash, 16)) {
1022 if (do_encrypt) {
1023 status = netlogon_creds_des_encrypt(creds, p);
1024 } else {
1025 status = netlogon_creds_des_decrypt(creds, p);
1027 if (!NT_STATUS_IS_OK(status)) {
1028 return status;
1032 break;
1034 case NetlogonNetworkInformation:
1035 case NetlogonNetworkTransitiveInformation:
1036 break;
1038 case NetlogonGenericInformation:
1039 if (logon->generic == NULL) {
1040 return NT_STATUS_INVALID_PARAMETER;
1043 if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1044 if (do_encrypt) {
1045 status = netlogon_creds_aes_encrypt(
1046 creds,
1047 logon->generic->data,
1048 logon->generic->length);
1049 } else {
1050 status = netlogon_creds_aes_decrypt(
1051 creds,
1052 logon->generic->data,
1053 logon->generic->length);
1055 if (!NT_STATUS_IS_OK(status)) {
1056 return 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)) {
1063 return status;
1065 } else {
1066 /* Using DES to verify kerberos tickets makes no sense */
1068 break;
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;
1094 if (in == NULL) {
1095 return NULL;
1098 out = talloc(mem_ctx, union netr_LogonLevel);
1099 if (out == NULL) {
1100 return NULL;
1103 *out = *in;
1105 switch (level) {
1106 case NetlogonInteractiveInformation:
1107 case NetlogonInteractiveTransitiveInformation:
1108 case NetlogonServiceInformation:
1109 case NetlogonServiceTransitiveInformation:
1110 if (in->password == NULL) {
1111 return out;
1114 out->password = talloc(out, struct netr_PasswordInfo);
1115 if (out->password == NULL) {
1116 talloc_free(out);
1117 return NULL;
1119 *out->password = *in->password;
1121 return out;
1123 case NetlogonNetworkInformation:
1124 case NetlogonNetworkTransitiveInformation:
1125 break;
1127 case NetlogonGenericInformation:
1128 if (in->generic == NULL) {
1129 return out;
1132 out->generic = talloc(out, struct netr_GenericInfo);
1133 if (out->generic == NULL) {
1134 talloc_free(out);
1135 return NULL;
1137 *out->generic = *in->generic;
1139 if (in->generic->data == NULL) {
1140 return out;
1143 if (in->generic->length == 0) {
1144 return out;
1147 out->generic->data = talloc_memdup(out->generic,
1148 in->generic->data,
1149 in->generic->length);
1150 if (out->generic->data == NULL) {
1151 talloc_free(out);
1152 return NULL;
1155 return out;
1158 return out;
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);
1171 if (!creds) {
1172 return NULL;
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) {
1181 talloc_free(creds);
1182 return NULL;
1184 creds->account_name = talloc_strdup(creds, creds_in->account_name);
1185 if (!creds->account_name) {
1186 talloc_free(creds);
1187 return NULL;
1190 if (creds_in->sid) {
1191 creds->sid = dom_sid_dup(creds, creds_in->sid);
1192 if (!creds->sid) {
1193 talloc_free(creds);
1194 return NULL;
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));
1203 return creds;