2012-12-07 04:05:00 +04:00
/*
2003-12-01 07:13:43 +03:00
Unix SMB / CIFS implementation .
code to manipulate domain credentials
Copyright ( C ) Andrew Tridgell 1997 - 2003
2004-05-15 11:51:38 +04:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2004
2012-12-07 04:05:00 +04:00
2003-12-01 07:13:43 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-12-01 07:13:43 +03:00
( at your option ) any later version .
2012-12-07 04:05:00 +04:00
2003-12-01 07:13:43 +03:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2012-12-07 04:05:00 +04:00
2003-12-01 07:13:43 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-12-01 07:13:43 +03:00
*/
# include "includes.h"
2004-11-02 03:24:21 +03:00
# include "system/time.h"
2008-09-24 17:30:23 +04:00
# include "../lib/crypto/crypto.h"
2006-03-25 21:47:47 +03:00
# include "libcli/auth/libcli_auth.h"
2010-08-23 18:02:23 +04:00
# include "../libcli/security/dom_sid.h"
2003-12-01 07:13:43 +03:00
2009-08-25 13:25:47 +04:00
static void netlogon_creds_step_crypt ( struct netlogon_creds_CredentialState * creds ,
const struct netr_Credential * in ,
struct netr_Credential * out )
{
2009-08-27 19:28:35 +04:00
if ( creds - > negotiate_flags & NETLOGON_NEG_SUPPORTS_AES ) {
AES_KEY key ;
uint8_t iv [ AES_BLOCK_SIZE ] ;
AES_set_encrypt_key ( creds - > session_key , 128 , & key ) ;
ZERO_STRUCT ( iv ) ;
aes_cfb8_encrypt ( in - > data , out - > data , 8 , & key , iv , AES_ENCRYPT ) ;
} else {
des_crypt112 ( out - > data , in - > data , creds - > session_key , 1 ) ;
}
2009-08-25 13:25:47 +04:00
}
2003-12-01 15:41:54 +03:00
/*
2004-06-04 03:15:16 +04:00
initialise the credentials state for old - style 64 bit session keys
2003-12-02 01:13:11 +03:00
this call is made after the netr_ServerReqChallenge call
2003-12-01 15:41:54 +03:00
*/
2009-04-06 16:53:01 +04:00
static void netlogon_creds_init_64bit ( struct netlogon_creds_CredentialState * creds ,
const struct netr_Credential * client_challenge ,
const struct netr_Credential * server_challenge ,
const struct samr_Password * machine_password )
2003-12-01 07:13:43 +03:00
{
2004-05-25 20:24:13 +04:00
uint32_t sum [ 2 ] ;
2004-05-25 21:50:17 +04:00
uint8_t sum2 [ 8 ] ;
2003-12-01 07:13:43 +03:00
sum [ 0 ] = IVAL ( client_challenge - > data , 0 ) + IVAL ( server_challenge - > data , 0 ) ;
sum [ 1 ] = IVAL ( client_challenge - > data , 4 ) + IVAL ( server_challenge - > data , 4 ) ;
SIVAL ( sum2 , 0 , sum [ 0 ] ) ;
SIVAL ( sum2 , 4 , sum [ 1 ] ) ;
2004-06-04 03:15:16 +04:00
ZERO_STRUCT ( creds - > session_key ) ;
2003-12-01 07:13:43 +03:00
2004-06-05 07:14:59 +04:00
des_crypt128 ( creds - > session_key , sum2 , machine_password - > hash ) ;
2004-06-04 03:15:16 +04:00
}
/*
initialise the credentials state for ADS - style 128 bit session keys
this call is made after the netr_ServerReqChallenge call
*/
2009-04-06 16:53:01 +04:00
static void netlogon_creds_init_128bit ( struct netlogon_creds_CredentialState * creds ,
const struct netr_Credential * client_challenge ,
const struct netr_Credential * server_challenge ,
const struct samr_Password * machine_password )
2004-06-04 03:15:16 +04:00
{
unsigned char zero [ 4 ] , tmp [ 16 ] ;
HMACMD5Context ctx ;
2013-06-08 09:48:40 +04:00
MD5_CTX md5 ;
2004-06-04 03:15:16 +04:00
ZERO_STRUCT ( creds - > session_key ) ;
memset ( zero , 0 , sizeof ( zero ) ) ;
2012-12-07 04:05:00 +04:00
hmac_md5_init_rfc2104 ( machine_password - > hash , sizeof ( machine_password - > hash ) , & ctx ) ;
2004-06-04 03:15:16 +04:00
MD5Init ( & md5 ) ;
MD5Update ( & md5 , zero , sizeof ( zero ) ) ;
MD5Update ( & md5 , client_challenge - > data , 8 ) ;
MD5Update ( & md5 , server_challenge - > data , 8 ) ;
MD5Final ( tmp , & md5 ) ;
2004-06-05 07:14:59 +04:00
hmac_md5_update ( tmp , sizeof ( tmp ) , & ctx ) ;
2004-06-04 03:15:16 +04:00
hmac_md5_final ( creds - > session_key , & ctx ) ;
2009-08-25 13:25:47 +04:00
}
2004-06-04 03:15:16 +04:00
2009-08-27 19:28:35 +04:00
/*
initialise the credentials state for AES / HMAC - SHA256 - style 128 bit session keys
this call is made after the netr_ServerReqChallenge call
*/
static void netlogon_creds_init_hmac_sha256 ( struct netlogon_creds_CredentialState * creds ,
const struct netr_Credential * client_challenge ,
const struct netr_Credential * server_challenge ,
const struct samr_Password * machine_password )
{
struct HMACSHA256Context ctx ;
uint8_t digest [ SHA256_DIGEST_LENGTH ] ;
ZERO_STRUCT ( creds - > session_key ) ;
hmac_sha256_init ( machine_password - > hash ,
sizeof ( machine_password - > hash ) ,
& ctx ) ;
hmac_sha256_update ( client_challenge - > data , 8 , & ctx ) ;
hmac_sha256_update ( server_challenge - > data , 8 , & ctx ) ;
hmac_sha256_final ( digest , & ctx ) ;
memcpy ( creds - > session_key , digest , sizeof ( creds - > session_key ) ) ;
ZERO_STRUCT ( digest ) ;
ZERO_STRUCT ( ctx ) ;
}
2009-08-25 13:25:47 +04:00
static void netlogon_creds_first_step ( struct netlogon_creds_CredentialState * creds ,
const struct netr_Credential * client_challenge ,
const struct netr_Credential * server_challenge )
{
netlogon_creds_step_crypt ( creds , client_challenge , & creds - > client ) ;
netlogon_creds_step_crypt ( creds , server_challenge , & creds - > server ) ;
2003-12-02 01:13:11 +03:00
2003-12-02 05:15:33 +03:00
creds - > seed = creds - > client ;
}
/*
2003-12-02 06:06:21 +03:00
step the credentials to the next element in the chain , updating the
current client and server credentials and the seed
2003-12-02 05:15:33 +03:00
*/
2009-04-06 16:53:01 +04:00
static void netlogon_creds_step ( struct netlogon_creds_CredentialState * creds )
2003-12-02 05:15:33 +03:00
{
struct netr_Credential time_cred ;
2012-12-07 04:05:00 +04:00
DEBUG ( 5 , ( " \t seed %08x:%08x \n " ,
2003-12-02 05:15:33 +03:00
IVAL ( creds - > seed . data , 0 ) , IVAL ( creds - > seed . data , 4 ) ) ) ;
SIVAL ( time_cred . data , 0 , IVAL ( creds - > seed . data , 0 ) + creds - > sequence ) ;
SIVAL ( time_cred . data , 4 , IVAL ( creds - > seed . data , 4 ) ) ;
DEBUG ( 5 , ( " \t seed+time %08x:%08x \n " , IVAL ( time_cred . data , 0 ) , IVAL ( time_cred . data , 4 ) ) ) ;
2009-08-25 13:25:47 +04:00
netlogon_creds_step_crypt ( creds , & time_cred , & creds - > client ) ;
2003-12-02 05:15:33 +03:00
2012-12-07 04:05:00 +04:00
DEBUG ( 5 , ( " \t CLIENT %08x:%08x \n " ,
2003-12-02 05:15:33 +03:00
IVAL ( creds - > client . data , 0 ) , IVAL ( creds - > client . data , 4 ) ) ) ;
SIVAL ( time_cred . data , 0 , IVAL ( creds - > seed . data , 0 ) + creds - > sequence + 1 ) ;
SIVAL ( time_cred . data , 4 , IVAL ( creds - > seed . data , 4 ) ) ;
2012-12-07 04:05:00 +04:00
DEBUG ( 5 , ( " \t seed+time+1 %08x:%08x \n " ,
2003-12-02 05:15:33 +03:00
IVAL ( time_cred . data , 0 ) , IVAL ( time_cred . data , 4 ) ) ) ;
2009-08-25 13:25:47 +04:00
netlogon_creds_step_crypt ( creds , & time_cred , & creds - > server ) ;
2003-12-01 07:13:43 +03:00
2012-12-07 04:05:00 +04:00
DEBUG ( 5 , ( " \t SERVER %08x:%08x \n " ,
2003-12-02 05:15:33 +03:00
IVAL ( creds - > server . data , 0 ) , IVAL ( creds - > server . data , 4 ) ) ) ;
creds - > seed = time_cred ;
2003-12-01 07:13:43 +03:00
}
2004-05-17 01:30:48 +04:00
2004-11-11 07:32:01 +03:00
/*
DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
*/
2009-04-06 16:53:01 +04:00
void netlogon_creds_des_encrypt_LMKey ( struct netlogon_creds_CredentialState * creds , struct netr_LMSessionKey * key )
2004-11-11 07:32:01 +03:00
{
struct netr_LMSessionKey tmp ;
des_crypt56 ( tmp . key , key - > key , creds - > session_key , 1 ) ;
* key = tmp ;
}
/*
DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
*/
2009-04-06 16:53:01 +04:00
void netlogon_creds_des_decrypt_LMKey ( struct netlogon_creds_CredentialState * creds , struct netr_LMSessionKey * key )
2004-11-11 07:32:01 +03:00
{
struct netr_LMSessionKey tmp ;
des_crypt56 ( tmp . key , key - > key , creds - > session_key , 0 ) ;
* key = tmp ;
}
2004-05-09 16:42:18 +04:00
/*
DES encrypt a 16 byte password buffer using the session key
*/
2009-04-06 16:53:01 +04:00
void netlogon_creds_des_encrypt ( struct netlogon_creds_CredentialState * creds , struct samr_Password * pass )
2004-05-09 16:42:18 +04:00
{
2004-06-04 15:58:46 +04:00
struct samr_Password tmp ;
des_crypt112_16 ( tmp . hash , pass - > hash , creds - > session_key , 1 ) ;
2004-05-09 16:42:18 +04:00
* pass = tmp ;
}
2004-05-17 01:30:48 +04:00
/*
DES decrypt a 16 byte password buffer using the session key
*/
2009-04-06 16:53:01 +04:00
void netlogon_creds_des_decrypt ( struct netlogon_creds_CredentialState * creds , struct samr_Password * pass )
2004-05-17 01:30:48 +04:00
{
2004-06-04 15:58:46 +04:00
struct samr_Password tmp ;
des_crypt112_16 ( tmp . hash , pass - > hash , creds - > session_key , 0 ) ;
2004-05-17 01:30:48 +04:00
* pass = tmp ;
}
2004-05-09 16:42:18 +04:00
/*
ARCFOUR encrypt / decrypt a password buffer using the session key
*/
2009-04-06 16:53:01 +04:00
void netlogon_creds_arcfour_crypt ( struct netlogon_creds_CredentialState * creds , uint8_t * data , size_t len )
2004-05-09 16:42:18 +04:00
{
2004-06-04 03:15:16 +04:00
DATA_BLOB session_key = data_blob ( creds - > session_key , 16 ) ;
2004-05-09 16:42:18 +04:00
2004-06-04 03:15:16 +04:00
arcfour_crypt_blob ( data , len , & session_key ) ;
2003-12-02 01:13:11 +03:00
2004-05-09 16:42:18 +04:00
data_blob_free ( & session_key ) ;
}
2003-12-02 06:06:21 +03:00
2012-11-30 00:23:30 +04:00
/*
AES encrypt a password buffer using the session key
*/
void netlogon_creds_aes_encrypt ( struct netlogon_creds_CredentialState * creds , uint8_t * data , size_t len )
{
AES_KEY key ;
uint8_t iv [ AES_BLOCK_SIZE ] ;
AES_set_encrypt_key ( creds - > session_key , 128 , & key ) ;
ZERO_STRUCT ( iv ) ;
aes_cfb8_encrypt ( data , data , len , & key , iv , AES_ENCRYPT ) ;
}
/*
AES decrypt a password buffer using the session key
*/
void netlogon_creds_aes_decrypt ( struct netlogon_creds_CredentialState * creds , uint8_t * data , size_t len )
{
AES_KEY key ;
uint8_t iv [ AES_BLOCK_SIZE ] ;
AES_set_encrypt_key ( creds - > session_key , 128 , & key ) ;
ZERO_STRUCT ( iv ) ;
aes_cfb8_encrypt ( data , data , len , & key , iv , AES_DECRYPT ) ;
}
2003-12-02 06:06:21 +03:00
/*****************************************************************
The above functions are common to the client and server interface
next comes the client specific functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-12-01 15:41:54 +03:00
/*
2003-12-02 05:15:33 +03:00
initialise the credentials chain and return the first client
credentials
2003-12-01 15:41:54 +03:00
*/
2012-12-07 04:05:00 +04:00
struct netlogon_creds_CredentialState * netlogon_creds_client_init ( TALLOC_CTX * mem_ctx ,
2009-04-06 16:53:01 +04:00
const char * client_account ,
2012-12-07 04:05:00 +04:00
const char * client_computer_name ,
2012-12-19 16:53:23 +04:00
uint16_t secure_channel_type ,
2009-04-06 16:53:01 +04:00
const struct netr_Credential * client_challenge ,
const struct netr_Credential * server_challenge ,
const struct samr_Password * machine_password ,
struct netr_Credential * initial_credential ,
uint32_t negotiate_flags )
2003-12-01 07:13:43 +03:00
{
2010-08-23 18:02:23 +04:00
struct netlogon_creds_CredentialState * creds = talloc_zero ( mem_ctx , struct netlogon_creds_CredentialState ) ;
2012-12-07 04:05:00 +04:00
2009-04-06 16:53:01 +04:00
if ( ! creds ) {
return NULL ;
}
2012-12-07 04:05:00 +04:00
2004-05-15 11:51:38 +04:00
creds - > sequence = time ( NULL ) ;
2004-06-04 03:15:16 +04:00
creds - > negotiate_flags = negotiate_flags ;
2012-12-19 16:53:23 +04:00
creds - > secure_channel_type = secure_channel_type ;
2004-06-04 03:15:16 +04:00
2009-04-06 16:53:01 +04:00
creds - > computer_name = talloc_strdup ( creds , client_computer_name ) ;
if ( ! creds - > computer_name ) {
talloc_free ( creds ) ;
return NULL ;
}
creds - > account_name = talloc_strdup ( creds , client_account ) ;
if ( ! creds - > account_name ) {
talloc_free ( creds ) ;
return NULL ;
}
2004-06-04 03:15:16 +04:00
dump_data_pw ( " Client chall " , client_challenge - > data , sizeof ( client_challenge - > data ) ) ;
dump_data_pw ( " Server chall " , server_challenge - > data , sizeof ( server_challenge - > data ) ) ;
2004-06-05 07:14:59 +04:00
dump_data_pw ( " Machine Pass " , machine_password - > hash , sizeof ( machine_password - > hash ) ) ;
2004-06-04 03:15:16 +04:00
2009-08-27 19:28:35 +04:00
if ( negotiate_flags & NETLOGON_NEG_SUPPORTS_AES ) {
netlogon_creds_init_hmac_sha256 ( creds ,
client_challenge ,
server_challenge ,
machine_password ) ;
} else if ( negotiate_flags & NETLOGON_NEG_STRONG_KEYS ) {
2009-04-06 16:53:01 +04:00
netlogon_creds_init_128bit ( creds , client_challenge , server_challenge , machine_password ) ;
2004-06-04 03:15:16 +04:00
} else {
2009-04-06 16:53:01 +04:00
netlogon_creds_init_64bit ( creds , client_challenge , server_challenge , machine_password ) ;
2004-06-04 03:15:16 +04:00
}
2009-08-25 13:25:47 +04:00
netlogon_creds_first_step ( creds , client_challenge , server_challenge ) ;
2004-06-04 03:15:16 +04:00
dump_data_pw ( " Session key " , creds - > session_key , 16 ) ;
dump_data_pw ( " Credential " , creds - > client . data , 8 ) ;
2003-12-02 05:15:33 +03:00
* initial_credential = creds - > client ;
2009-04-06 16:53:01 +04:00
return creds ;
}
/*
initialise the credentials structure with only a session key . The caller better know what they are doing !
*/
2012-12-07 04:05:00 +04:00
struct netlogon_creds_CredentialState * netlogon_creds_client_init_session_key ( TALLOC_CTX * mem_ctx ,
2009-04-06 16:53:01 +04:00
const uint8_t session_key [ 16 ] )
{
2009-10-23 19:26:58 +04:00
struct netlogon_creds_CredentialState * creds ;
creds = talloc_zero ( mem_ctx , struct netlogon_creds_CredentialState ) ;
2009-04-06 16:53:01 +04:00
if ( ! creds ) {
return NULL ;
}
2012-12-07 04:05:00 +04:00
2009-04-06 16:53:01 +04:00
memcpy ( creds - > session_key , session_key , 16 ) ;
return creds ;
2003-12-02 05:15:33 +03:00
}
2003-12-01 07:13:43 +03:00
2004-05-17 01:30:48 +04:00
/*
step the credentials to the next element in the chain , updating the
current client and server credentials and the seed
2012-12-07 04:05:00 +04:00
produce the next authenticator in the sequence ready to send to
2004-05-17 01:30:48 +04:00
the server
*/
2009-04-06 16:53:01 +04:00
void netlogon_creds_client_authenticator ( struct netlogon_creds_CredentialState * creds ,
2004-05-17 01:30:48 +04:00
struct netr_Authenticator * next )
2012-12-07 04:05:00 +04:00
{
2013-12-17 22:55:12 +04:00
uint32_t t32n = ( uint32_t ) time ( NULL ) ;
/*
* we always increment and ignore an overflow here
*/
2004-05-17 01:30:48 +04:00
creds - > sequence + = 2 ;
2013-12-17 22:55:12 +04:00
if ( t32n > creds - > sequence ) {
/*
* we may increment more
*/
creds - > sequence = t32n ;
} else {
uint32_t d = creds - > sequence - t32n ;
if ( d > = INT32_MAX ) {
/*
* got an overflow of time_t vs . uint32_t
*/
creds - > sequence = t32n ;
}
}
2009-04-06 16:53:01 +04:00
netlogon_creds_step ( creds ) ;
2004-05-17 01:30:48 +04:00
next - > cred = creds - > client ;
next - > timestamp = creds - > sequence ;
}
2003-12-02 05:15:33 +03:00
/*
check that a credentials reply from a server is correct
*/
2009-04-06 16:53:01 +04:00
bool netlogon_creds_client_check ( struct netlogon_creds_CredentialState * creds ,
2003-12-02 05:15:33 +03:00
const struct netr_Credential * received_credentials )
{
2012-12-07 04:05:00 +04:00
if ( ! received_credentials | |
2004-05-15 11:51:38 +04:00
memcmp ( received_credentials - > data , creds - > server . data , 8 ) ! = 0 ) {
2003-12-01 15:41:54 +03:00
DEBUG ( 2 , ( " credentials check failed \n " ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2003-12-01 07:13:43 +03:00
}
2007-10-07 02:28:14 +04:00
return true ;
2003-12-02 01:13:11 +03:00
}
2003-12-01 07:13:43 +03:00
2003-12-02 03:31:54 +03:00
2004-05-15 11:51:38 +04:00
/*****************************************************************
The above functions are common to the client and server interface
next comes the server specific functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
check that a credentials reply from a server is correct
*/
2009-04-06 16:53:01 +04:00
static bool netlogon_creds_server_check_internal ( const struct netlogon_creds_CredentialState * creds ,
const struct netr_Credential * received_credentials )
2004-05-15 11:51:38 +04:00
{
if ( memcmp ( received_credentials - > data , creds - > client . data , 8 ) ! = 0 ) {
DEBUG ( 2 , ( " credentials check failed \n " ) ) ;
dump_data_pw ( " client creds " , creds - > client . data , 8 ) ;
dump_data_pw ( " calc creds " , received_credentials - > data , 8 ) ;
2007-10-07 02:28:14 +04:00
return false ;
2004-05-15 11:51:38 +04:00
}
2007-10-07 02:28:14 +04:00
return true ;
2004-05-15 11:51:38 +04:00
}
2009-04-06 16:53:01 +04:00
/*
initialise the credentials chain and return the first server
credentials
*/
2012-12-07 04:05:00 +04:00
struct netlogon_creds_CredentialState * netlogon_creds_server_init ( TALLOC_CTX * mem_ctx ,
2009-04-06 16:53:01 +04:00
const char * client_account ,
2012-12-07 04:05:00 +04:00
const char * client_computer_name ,
2009-04-06 16:53:01 +04:00
uint16_t secure_channel_type ,
const struct netr_Credential * client_challenge ,
const struct netr_Credential * server_challenge ,
const struct samr_Password * machine_password ,
2015-03-19 18:26:03 +03:00
const struct netr_Credential * credentials_in ,
2009-04-06 16:53:01 +04:00
struct netr_Credential * credentials_out ,
uint32_t negotiate_flags )
{
2012-12-07 04:05:00 +04:00
2009-04-06 16:53:01 +04:00
struct netlogon_creds_CredentialState * creds = talloc_zero ( mem_ctx , struct netlogon_creds_CredentialState ) ;
2012-12-07 04:05:00 +04:00
2009-04-06 16:53:01 +04:00
if ( ! creds ) {
return NULL ;
}
2012-12-07 04:05:00 +04:00
2009-04-06 16:53:01 +04:00
creds - > negotiate_flags = negotiate_flags ;
2009-08-25 14:02:38 +04:00
creds - > secure_channel_type = secure_channel_type ;
2009-04-06 16:53:01 +04:00
2009-08-27 19:28:35 +04:00
dump_data_pw ( " Client chall " , client_challenge - > data , sizeof ( client_challenge - > data ) ) ;
dump_data_pw ( " Server chall " , server_challenge - > data , sizeof ( server_challenge - > data ) ) ;
dump_data_pw ( " Machine Pass " , machine_password - > hash , sizeof ( machine_password - > hash ) ) ;
2009-04-06 16:53:01 +04:00
creds - > computer_name = talloc_strdup ( creds , client_computer_name ) ;
if ( ! creds - > computer_name ) {
talloc_free ( creds ) ;
return NULL ;
}
creds - > account_name = talloc_strdup ( creds , client_account ) ;
if ( ! creds - > account_name ) {
talloc_free ( creds ) ;
return NULL ;
}
2009-08-27 19:28:35 +04:00
if ( negotiate_flags & NETLOGON_NEG_SUPPORTS_AES ) {
netlogon_creds_init_hmac_sha256 ( creds ,
client_challenge ,
server_challenge ,
machine_password ) ;
} else if ( negotiate_flags & NETLOGON_NEG_STRONG_KEYS ) {
2012-12-07 04:05:00 +04:00
netlogon_creds_init_128bit ( creds , client_challenge , server_challenge ,
2009-04-06 16:53:01 +04:00
machine_password ) ;
} else {
2012-12-07 04:05:00 +04:00
netlogon_creds_init_64bit ( creds , client_challenge , server_challenge ,
2009-04-06 16:53:01 +04:00
machine_password ) ;
}
2009-08-25 13:25:47 +04:00
netlogon_creds_first_step ( creds , client_challenge , server_challenge ) ;
2009-08-27 19:28:35 +04:00
dump_data_pw ( " Session key " , creds - > session_key , 16 ) ;
dump_data_pw ( " Client Credential " , creds - > client . data , 8 ) ;
dump_data_pw ( " Server Credential " , creds - > server . data , 8 ) ;
dump_data_pw ( " Credentials in " , credentials_in - > data , sizeof ( credentials_in - > data ) ) ;
2009-04-06 16:53:01 +04:00
/* And before we leak information about the machine account
* password , check that they got the first go right */
if ( ! netlogon_creds_server_check_internal ( creds , credentials_in ) ) {
talloc_free ( creds ) ;
return NULL ;
}
* credentials_out = creds - > server ;
2009-08-27 19:28:35 +04:00
dump_data_pw ( " Credentials out " , credentials_out - > data , sizeof ( credentials_out - > data ) ) ;
2009-04-06 16:53:01 +04:00
return creds ;
}
NTSTATUS netlogon_creds_server_step_check ( struct netlogon_creds_CredentialState * creds ,
2015-03-19 18:26:03 +03:00
const struct netr_Authenticator * received_authenticator ,
2012-12-07 04:05:00 +04:00
struct netr_Authenticator * return_authenticator )
2004-05-17 01:30:48 +04:00
{
2005-01-03 09:23:02 +03:00
if ( ! received_authenticator | | ! return_authenticator ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2005-01-10 15:30:13 +03:00
if ( ! creds ) {
return NT_STATUS_ACCESS_DENIED ;
}
2004-05-17 01:30:48 +04:00
creds - > sequence = received_authenticator - > timestamp ;
2009-04-06 16:53:01 +04:00
netlogon_creds_step ( creds ) ;
if ( netlogon_creds_server_check_internal ( creds , & received_authenticator - > cred ) ) {
2004-05-17 01:30:48 +04:00
return_authenticator - > cred = creds - > server ;
2013-12-17 22:35:37 +04:00
return_authenticator - > timestamp = 0 ;
2005-01-03 09:23:02 +03:00
return NT_STATUS_OK ;
2004-05-17 01:30:48 +04:00
} else {
ZERO_STRUCTP ( return_authenticator ) ;
2005-01-03 09:23:02 +03:00
return NT_STATUS_ACCESS_DENIED ;
2004-05-17 01:30:48 +04:00
}
}
2005-10-09 16:38:23 +04:00
2012-12-14 17:18:40 +04:00
static void netlogon_creds_crypt_samlogon_validation ( struct netlogon_creds_CredentialState * creds ,
uint16_t validation_level ,
union netr_Validation * validation ,
2013-06-14 11:47:50 +04:00
bool do_encrypt )
2005-10-09 16:38:23 +04:00
{
static const char zeros [ 16 ] ;
2005-10-09 17:03:52 +04:00
struct netr_SamBaseInfo * base = NULL ;
2013-04-24 14:36:04 +04:00
if ( validation = = NULL ) {
return ;
}
2005-10-09 16:38:23 +04:00
switch ( validation_level ) {
case 2 :
2005-10-09 17:03:52 +04:00
if ( validation - > sam2 ) {
base = & validation - > sam2 - > base ;
}
2005-10-09 16:38:23 +04:00
break ;
case 3 :
2005-10-09 17:03:52 +04:00
if ( validation - > sam3 ) {
base = & validation - > sam3 - > base ;
}
2005-10-09 16:38:23 +04:00
break ;
case 6 :
2005-10-09 17:03:52 +04:00
if ( validation - > sam6 ) {
base = & validation - > sam6 - > base ;
}
2005-10-09 16:38:23 +04:00
break ;
2005-10-09 17:03:52 +04:00
default :
/* If we can't find it, we can't very well decrypt it */
return ;
2005-10-09 16:38:23 +04:00
}
2005-10-09 17:03:52 +04:00
if ( ! base ) {
return ;
}
2005-10-09 16:38:23 +04:00
/* find and decyrpt the session keys, return in parameters above */
if ( validation_level = = 6 ) {
/* they aren't encrypted! */
2012-12-07 15:38:16 +04:00
} else if ( creds - > negotiate_flags & NETLOGON_NEG_SUPPORTS_AES ) {
2012-12-14 17:17:22 +04:00
/* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
2012-12-07 15:38:16 +04:00
if ( memcmp ( base - > key . key , zeros ,
sizeof ( base - > key . key ) ) ! = 0 ) {
2013-06-14 11:47:50 +04:00
if ( do_encrypt ) {
2012-12-14 17:18:40 +04:00
netlogon_creds_aes_encrypt ( creds ,
base - > key . key ,
sizeof ( base - > key . key ) ) ;
} else {
netlogon_creds_aes_decrypt ( creds ,
2012-12-07 15:38:16 +04:00
base - > key . key ,
sizeof ( base - > key . key ) ) ;
2012-12-14 17:18:40 +04:00
}
2012-12-07 15:38:16 +04:00
}
if ( memcmp ( base - > LMSessKey . key , zeros ,
sizeof ( base - > LMSessKey . key ) ) ! = 0 ) {
2013-06-14 11:47:50 +04:00
if ( do_encrypt ) {
2012-12-14 17:18:40 +04:00
netlogon_creds_aes_encrypt ( creds ,
2012-12-07 15:38:16 +04:00
base - > LMSessKey . key ,
sizeof ( base - > LMSessKey . key ) ) ;
2012-12-14 17:18:40 +04:00
} else {
netlogon_creds_aes_decrypt ( creds ,
base - > LMSessKey . key ,
sizeof ( base - > LMSessKey . key ) ) ;
}
2012-12-07 15:38:16 +04:00
}
2005-10-09 16:38:23 +04:00
} else if ( creds - > negotiate_flags & NETLOGON_NEG_ARCFOUR ) {
2012-12-14 17:17:22 +04:00
/* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
2012-12-07 04:05:00 +04:00
if ( memcmp ( base - > key . key , zeros ,
2005-10-09 16:38:23 +04:00
sizeof ( base - > key . key ) ) ! = 0 ) {
2012-12-07 04:05:00 +04:00
netlogon_creds_arcfour_crypt ( creds ,
base - > key . key ,
2005-10-09 16:38:23 +04:00
sizeof ( base - > key . key ) ) ;
}
2012-12-07 04:05:00 +04:00
if ( memcmp ( base - > LMSessKey . key , zeros ,
2005-10-09 16:38:23 +04:00
sizeof ( base - > LMSessKey . key ) ) ! = 0 ) {
2012-12-07 04:05:00 +04:00
netlogon_creds_arcfour_crypt ( creds ,
base - > LMSessKey . key ,
2005-10-09 16:38:23 +04:00
sizeof ( base - > LMSessKey . key ) ) ;
}
} else {
2012-12-14 17:17:22 +04:00
/* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
2012-12-07 04:05:00 +04:00
if ( memcmp ( base - > LMSessKey . key , zeros ,
2005-10-09 16:38:23 +04:00
sizeof ( base - > LMSessKey . key ) ) ! = 0 ) {
2013-06-14 11:47:50 +04:00
if ( do_encrypt ) {
2012-12-14 17:18:40 +04:00
netlogon_creds_des_encrypt_LMKey ( creds ,
2005-10-09 16:38:23 +04:00
& base - > LMSessKey ) ;
2012-12-14 17:18:40 +04:00
} else {
netlogon_creds_des_decrypt_LMKey ( creds ,
& base - > LMSessKey ) ;
}
2005-10-09 16:38:23 +04:00
}
}
2012-12-07 04:05:00 +04:00
}
2009-04-06 16:53:01 +04:00
2012-12-14 17:18:40 +04:00
void netlogon_creds_decrypt_samlogon_validation ( struct netlogon_creds_CredentialState * creds ,
uint16_t validation_level ,
union netr_Validation * validation )
{
2013-01-21 03:45:10 +04:00
netlogon_creds_crypt_samlogon_validation ( creds , validation_level ,
2012-12-14 17:18:40 +04:00
validation , false ) ;
}
void netlogon_creds_encrypt_samlogon_validation ( struct netlogon_creds_CredentialState * creds ,
uint16_t validation_level ,
union netr_Validation * validation )
{
2013-01-21 03:45:10 +04:00
netlogon_creds_crypt_samlogon_validation ( creds , validation_level ,
2012-12-14 17:18:40 +04:00
validation , true ) ;
}
2013-04-25 19:01:00 +04:00
static void netlogon_creds_crypt_samlogon_logon ( struct netlogon_creds_CredentialState * creds ,
enum netr_LogonInfoClass level ,
union netr_LogonLevel * logon ,
2014-02-27 12:40:03 +04:00
bool do_encrypt )
2013-04-25 19:01:00 +04:00
{
static const char zeros [ 16 ] ;
if ( logon = = NULL ) {
return ;
}
switch ( level ) {
case NetlogonInteractiveInformation :
case NetlogonInteractiveTransitiveInformation :
case NetlogonServiceInformation :
case NetlogonServiceTransitiveInformation :
if ( logon - > password = = NULL ) {
return ;
}
if ( creds - > negotiate_flags & NETLOGON_NEG_SUPPORTS_AES ) {
uint8_t * h ;
h = logon - > password - > lmpassword . hash ;
if ( memcmp ( h , zeros , 16 ) ! = 0 ) {
2014-02-27 12:40:03 +04:00
if ( do_encrypt ) {
2013-04-25 19:01:00 +04:00
netlogon_creds_aes_encrypt ( creds , h , 16 ) ;
} else {
netlogon_creds_aes_decrypt ( creds , h , 16 ) ;
}
}
h = logon - > password - > ntpassword . hash ;
if ( memcmp ( h , zeros , 16 ) ! = 0 ) {
2014-02-27 12:40:03 +04:00
if ( do_encrypt ) {
2013-04-25 19:01:00 +04:00
netlogon_creds_aes_encrypt ( creds , h , 16 ) ;
} else {
netlogon_creds_aes_decrypt ( creds , h , 16 ) ;
}
}
} else if ( creds - > negotiate_flags & NETLOGON_NEG_ARCFOUR ) {
uint8_t * h ;
h = logon - > password - > lmpassword . hash ;
if ( memcmp ( h , zeros , 16 ) ! = 0 ) {
netlogon_creds_arcfour_crypt ( creds , h , 16 ) ;
}
h = logon - > password - > ntpassword . hash ;
if ( memcmp ( h , zeros , 16 ) ! = 0 ) {
netlogon_creds_arcfour_crypt ( creds , h , 16 ) ;
}
} else {
struct samr_Password * p ;
p = & logon - > password - > lmpassword ;
if ( memcmp ( p - > hash , zeros , 16 ) ! = 0 ) {
2014-02-27 12:40:03 +04:00
if ( do_encrypt ) {
2013-04-25 19:01:00 +04:00
netlogon_creds_des_encrypt ( creds , p ) ;
} else {
netlogon_creds_des_decrypt ( creds , p ) ;
}
}
p = & logon - > password - > ntpassword ;
if ( memcmp ( p - > hash , zeros , 16 ) ! = 0 ) {
2014-02-27 12:40:03 +04:00
if ( do_encrypt ) {
2013-04-25 19:01:00 +04:00
netlogon_creds_des_encrypt ( creds , p ) ;
} else {
netlogon_creds_des_decrypt ( creds , p ) ;
}
}
}
break ;
case NetlogonNetworkInformation :
case NetlogonNetworkTransitiveInformation :
break ;
case NetlogonGenericInformation :
if ( logon - > generic = = NULL ) {
return ;
}
if ( creds - > negotiate_flags & NETLOGON_NEG_SUPPORTS_AES ) {
2014-02-27 12:40:03 +04:00
if ( do_encrypt ) {
2013-04-25 19:01:00 +04:00
netlogon_creds_aes_encrypt ( creds ,
logon - > generic - > data ,
logon - > generic - > length ) ;
} else {
netlogon_creds_aes_decrypt ( creds ,
logon - > generic - > data ,
logon - > generic - > length ) ;
}
} else if ( creds - > negotiate_flags & NETLOGON_NEG_ARCFOUR ) {
netlogon_creds_arcfour_crypt ( creds ,
logon - > generic - > data ,
logon - > generic - > length ) ;
} else {
/* Using DES to verify kerberos tickets makes no sense */
}
break ;
}
}
void netlogon_creds_decrypt_samlogon_logon ( struct netlogon_creds_CredentialState * creds ,
enum netr_LogonInfoClass level ,
union netr_LogonLevel * logon )
{
netlogon_creds_crypt_samlogon_logon ( creds , level , logon , false ) ;
}
void netlogon_creds_encrypt_samlogon_logon ( struct netlogon_creds_CredentialState * creds ,
enum netr_LogonInfoClass level ,
union netr_LogonLevel * logon )
{
netlogon_creds_crypt_samlogon_logon ( creds , level , logon , true ) ;
}
2013-04-24 14:53:27 +04:00
union netr_LogonLevel * netlogon_creds_shallow_copy_logon ( TALLOC_CTX * mem_ctx ,
enum netr_LogonInfoClass level ,
const union netr_LogonLevel * in )
{
union netr_LogonLevel * out ;
if ( in = = NULL ) {
return NULL ;
}
out = talloc ( mem_ctx , union netr_LogonLevel ) ;
if ( out = = NULL ) {
return NULL ;
}
* out = * in ;
switch ( level ) {
case NetlogonInteractiveInformation :
case NetlogonInteractiveTransitiveInformation :
case NetlogonServiceInformation :
case NetlogonServiceTransitiveInformation :
if ( in - > password = = NULL ) {
return out ;
}
out - > password = talloc ( out , struct netr_PasswordInfo ) ;
if ( out - > password = = NULL ) {
talloc_free ( out ) ;
return NULL ;
}
* out - > password = * in - > password ;
return out ;
case NetlogonNetworkInformation :
case NetlogonNetworkTransitiveInformation :
break ;
case NetlogonGenericInformation :
if ( in - > generic = = NULL ) {
return out ;
}
out - > generic = talloc ( out , struct netr_GenericInfo ) ;
if ( out - > generic = = NULL ) {
talloc_free ( out ) ;
return NULL ;
}
* out - > generic = * in - > generic ;
if ( in - > generic - > data = = NULL ) {
return out ;
}
if ( in - > generic - > length = = 0 ) {
return out ;
}
out - > generic - > data = talloc_memdup ( out - > generic ,
in - > generic - > data ,
in - > generic - > length ) ;
if ( out - > generic - > data = = NULL ) {
talloc_free ( out ) ;
return NULL ;
}
return out ;
}
return out ;
}
2010-08-23 18:02:23 +04:00
/*
copy a netlogon_creds_CredentialState struct
*/
struct netlogon_creds_CredentialState * netlogon_creds_copy ( TALLOC_CTX * mem_ctx ,
struct netlogon_creds_CredentialState * creds_in )
{
struct netlogon_creds_CredentialState * creds = talloc_zero ( mem_ctx , struct netlogon_creds_CredentialState ) ;
if ( ! creds ) {
return NULL ;
}
creds - > sequence = creds_in - > sequence ;
creds - > negotiate_flags = creds_in - > negotiate_flags ;
creds - > secure_channel_type = creds_in - > secure_channel_type ;
creds - > computer_name = talloc_strdup ( creds , creds_in - > computer_name ) ;
if ( ! creds - > computer_name ) {
talloc_free ( creds ) ;
return NULL ;
}
creds - > account_name = talloc_strdup ( creds , creds_in - > account_name ) ;
if ( ! creds - > account_name ) {
talloc_free ( creds ) ;
return NULL ;
}
if ( creds_in - > sid ) {
creds - > sid = dom_sid_dup ( creds , creds_in - > sid ) ;
if ( ! creds - > sid ) {
talloc_free ( creds ) ;
return NULL ;
}
}
memcpy ( creds - > session_key , creds_in - > session_key , sizeof ( creds - > session_key ) ) ;
memcpy ( creds - > seed . data , creds_in - > seed . data , sizeof ( creds - > seed . data ) ) ;
memcpy ( creds - > client . data , creds_in - > client . data , sizeof ( creds - > client . data ) ) ;
memcpy ( creds - > server . data , creds_in - > server . data , sizeof ( creds - > server . data ) ) ;
return creds ;
}