2005-04-17 02:20:36 +04:00
/*
* fs / cifs / cifsencrypt . c
*
2006-02-10 00:12:47 +03:00
* Copyright ( C ) International Business Machines Corp . , 2005 , 2006
2005-04-17 02:20:36 +04:00
* Author ( s ) : Steve French ( sfrench @ us . ibm . com )
*
* This library is free software ; you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation ; either version 2.1 of the License , or
* ( at your option ) any later version .
*
* This library 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 Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/fs.h>
# include "cifspdu.h"
2007-06-25 01:15:44 +04:00
# include "cifsglob.h"
2005-04-17 02:20:36 +04:00
# include "cifs_debug.h"
# include "md5.h"
# include "cifs_unicode.h"
# include "cifsproto.h"
2006-06-01 23:20:10 +04:00
# include <linux/ctype.h>
2006-06-05 20:26:05 +04:00
# include <linux/random.h>
2005-04-17 02:20:36 +04:00
2007-06-25 01:15:44 +04:00
/* Calculate and return the CIFS signature based on the mac key and SMB PDU */
2005-04-17 02:20:36 +04:00
/* the 16 byte signature must be allocated by the caller */
/* Note we only use the 1st eight bytes */
2007-06-25 01:15:44 +04:00
/* Note that the smb header signature field on input contains the
2005-04-17 02:20:36 +04:00
sequence number before this function is called */
extern void mdfour ( unsigned char * out , unsigned char * in , int n ) ;
extern void E_md4hash ( const unsigned char * passwd , unsigned char * p16 ) ;
2006-06-01 23:20:10 +04:00
extern void SMBencrypt ( unsigned char * passwd , unsigned char * c8 ,
2007-06-25 01:15:44 +04:00
unsigned char * p24 ) ;
2007-07-13 04:33:32 +04:00
2007-06-25 01:15:44 +04:00
static int cifs_calculate_signature ( const struct smb_hdr * cifs_pdu ,
2007-07-09 11:55:14 +04:00
const struct mac_key * key , char * signature )
2005-04-17 02:20:36 +04:00
{
struct MD5Context context ;
2007-07-09 11:55:14 +04:00
if ( ( cifs_pdu = = NULL ) | | ( signature = = NULL ) | | ( key = = NULL ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
MD5Init ( & context ) ;
2007-07-09 11:55:14 +04:00
MD5Update ( & context , ( char * ) & key - > data , key - > len ) ;
2007-06-25 01:15:44 +04:00
MD5Update ( & context , cifs_pdu - > Protocol , cifs_pdu - > smb_buf_length ) ;
2007-07-09 11:55:14 +04:00
2007-06-25 01:15:44 +04:00
MD5Final ( signature , & context ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-06-25 01:15:44 +04:00
int cifs_sign_smb ( struct smb_hdr * cifs_pdu , struct TCP_Server_Info * server ,
__u32 * pexpected_response_sequence_number )
2005-04-17 02:20:36 +04:00
{
int rc = 0 ;
char smb_signature [ 20 ] ;
2007-06-25 01:15:44 +04:00
if ( ( cifs_pdu = = NULL ) | | ( server = = NULL ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-06-25 01:15:44 +04:00
if ( ( cifs_pdu - > Flags2 & SMBFLG2_SECURITY_SIGNATURE ) = = 0 )
2005-04-17 02:20:36 +04:00
return rc ;
spin_lock ( & GlobalMid_Lock ) ;
2007-07-13 04:33:32 +04:00
cifs_pdu - > Signature . Sequence . SequenceNumber =
cpu_to_le32 ( server - > sequence_number ) ;
2005-04-17 02:20:36 +04:00
cifs_pdu - > Signature . Sequence . Reserved = 0 ;
2007-07-13 04:33:32 +04:00
2005-04-29 09:41:05 +04:00
* pexpected_response_sequence_number = server - > sequence_number + + ;
server - > sequence_number + + ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & GlobalMid_Lock ) ;
2007-07-09 11:55:14 +04:00
rc = cifs_calculate_signature ( cifs_pdu , & server - > mac_signing_key ,
2007-06-25 01:15:44 +04:00
smb_signature ) ;
if ( rc )
2005-04-17 02:20:36 +04:00
memset ( cifs_pdu - > Signature . SecuritySignature , 0 , 8 ) ;
else
memcpy ( cifs_pdu - > Signature . SecuritySignature , smb_signature , 8 ) ;
return rc ;
}
2007-06-25 01:15:44 +04:00
static int cifs_calc_signature2 ( const struct kvec * iov , int n_vec ,
2007-07-09 11:55:14 +04:00
const struct mac_key * key , char * signature )
2005-12-03 00:32:45 +03:00
{
2006-04-01 01:22:00 +04:00
struct MD5Context context ;
int i ;
2005-12-03 00:32:45 +03:00
2007-07-09 11:55:14 +04:00
if ( ( iov = = NULL ) | | ( signature = = NULL ) | | ( key = = NULL ) )
2006-04-01 01:22:00 +04:00
return - EINVAL ;
2005-12-03 00:32:45 +03:00
2006-04-01 01:22:00 +04:00
MD5Init ( & context ) ;
2007-07-09 11:55:14 +04:00
MD5Update ( & context , ( char * ) & key - > data , key - > len ) ;
2007-07-13 04:33:32 +04:00
for ( i = 0 ; i < n_vec ; i + + ) {
2007-11-03 07:34:04 +03:00
if ( iov [ i ] . iov_len = = 0 )
continue ;
2007-06-25 01:15:44 +04:00
if ( iov [ i ] . iov_base = = NULL ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " null iovec entry " ) ) ;
2006-04-01 01:22:00 +04:00
return - EIO ;
2007-11-03 07:34:04 +03:00
}
2007-06-25 01:15:44 +04:00
/* The first entry includes a length field (which does not get
2006-04-01 01:22:00 +04:00
signed that occupies the first 4 bytes before the header */
2007-06-25 01:15:44 +04:00
if ( i = = 0 ) {
2007-11-06 00:46:10 +03:00
if ( iov [ 0 ] . iov_len < = 8 ) /* cmd field at offset 9 */
2006-04-01 01:22:00 +04:00
break ; /* nothing to sign or corrupt header */
2007-07-17 21:34:02 +04:00
MD5Update ( & context , iov [ 0 ] . iov_base + 4 ,
iov [ 0 ] . iov_len - 4 ) ;
2006-04-01 01:22:00 +04:00
} else
2007-06-25 01:15:44 +04:00
MD5Update ( & context , iov [ i ] . iov_base , iov [ i ] . iov_len ) ;
2006-04-01 01:22:00 +04:00
}
2005-12-03 00:32:45 +03:00
2007-06-25 01:15:44 +04:00
MD5Final ( signature , & context ) ;
2005-12-03 00:32:45 +03:00
2006-04-01 01:22:00 +04:00
return 0 ;
2005-12-03 00:32:45 +03:00
}
2007-06-25 01:15:44 +04:00
int cifs_sign_smb2 ( struct kvec * iov , int n_vec , struct TCP_Server_Info * server ,
2007-11-06 00:46:10 +03:00
__u32 * pexpected_response_sequence_number )
2005-12-03 00:32:45 +03:00
{
int rc = 0 ;
char smb_signature [ 20 ] ;
2007-06-25 01:15:44 +04:00
struct smb_hdr * cifs_pdu = iov [ 0 ] . iov_base ;
2005-12-03 00:32:45 +03:00
2007-06-25 01:15:44 +04:00
if ( ( cifs_pdu = = NULL ) | | ( server = = NULL ) )
2005-12-03 00:32:45 +03:00
return - EINVAL ;
2007-06-25 01:15:44 +04:00
if ( ( cifs_pdu - > Flags2 & SMBFLG2_SECURITY_SIGNATURE ) = = 0 )
2005-12-03 00:32:45 +03:00
return rc ;
2007-06-25 01:15:44 +04:00
spin_lock ( & GlobalMid_Lock ) ;
cifs_pdu - > Signature . Sequence . SequenceNumber =
2005-12-03 00:32:45 +03:00
cpu_to_le32 ( server - > sequence_number ) ;
2007-06-25 01:15:44 +04:00
cifs_pdu - > Signature . Sequence . Reserved = 0 ;
2005-12-03 00:32:45 +03:00
2007-06-25 01:15:44 +04:00
* pexpected_response_sequence_number = server - > sequence_number + + ;
server - > sequence_number + + ;
spin_unlock ( & GlobalMid_Lock ) ;
2005-12-03 00:32:45 +03:00
2007-07-09 11:55:14 +04:00
rc = cifs_calc_signature2 ( iov , n_vec , & server - > mac_signing_key ,
2005-12-03 00:32:45 +03:00
smb_signature ) ;
2007-06-25 01:15:44 +04:00
if ( rc )
memset ( cifs_pdu - > Signature . SecuritySignature , 0 , 8 ) ;
else
memcpy ( cifs_pdu - > Signature . SecuritySignature , smb_signature , 8 ) ;
2005-12-03 00:32:45 +03:00
2007-06-25 01:15:44 +04:00
return rc ;
2005-12-03 00:32:45 +03:00
}
2007-07-09 11:55:14 +04:00
int cifs_verify_signature ( struct smb_hdr * cifs_pdu ,
const struct mac_key * mac_key ,
2007-06-25 01:15:44 +04:00
__u32 expected_sequence_number )
2005-04-17 02:20:36 +04:00
{
unsigned int rc ;
char server_response_sig [ 8 ] ;
char what_we_think_sig_should_be [ 20 ] ;
2007-06-25 01:15:44 +04:00
if ( ( cifs_pdu = = NULL ) | | ( mac_key = = NULL ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
if ( cifs_pdu - > Command = = SMB_COM_NEGOTIATE )
return 0 ;
if ( cifs_pdu - > Command = = SMB_COM_LOCKING_ANDX ) {
2007-07-13 04:33:32 +04:00
struct smb_com_lock_req * pSMB =
2007-06-25 01:15:44 +04:00
( struct smb_com_lock_req * ) cifs_pdu ;
if ( pSMB - > LockType & LOCKING_ANDX_OPLOCK_RELEASE )
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-13 04:33:32 +04:00
/* BB what if signatures are supposed to be on for session but
server does not send one ? BB */
2005-04-17 02:20:36 +04:00
/* Do not need to verify session setups with signature "BSRSPYL " */
2007-07-13 04:33:32 +04:00
if ( memcmp ( cifs_pdu - > Signature . SecuritySignature , " BSRSPYL " , 8 ) = = 0 )
cFYI ( 1 , ( " dummy signature received for smb command 0x%x " ,
cifs_pdu - > Command ) ) ;
2005-04-17 02:20:36 +04:00
/* save off the origiginal signature so we can modify the smb and check
its signature against what the server sent */
2007-07-13 04:33:32 +04:00
memcpy ( server_response_sig , cifs_pdu - > Signature . SecuritySignature , 8 ) ;
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
cifs_pdu - > Signature . Sequence . SequenceNumber =
cpu_to_le32 ( expected_sequence_number ) ;
2005-04-17 02:20:36 +04:00
cifs_pdu - > Signature . Sequence . Reserved = 0 ;
rc = cifs_calculate_signature ( cifs_pdu , mac_key ,
what_we_think_sig_should_be ) ;
2007-07-13 04:33:32 +04:00
if ( rc )
2005-04-17 02:20:36 +04:00
return rc ;
2007-07-13 04:33:32 +04:00
/* cifs_dump_mem("what we think it should be: ",
what_we_think_sig_should_be , 16 ) ; */
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
if ( memcmp ( server_response_sig , what_we_think_sig_should_be , 8 ) )
2005-04-17 02:20:36 +04:00
return - EACCES ;
else
return 0 ;
}
/* We fill in key by putting in 40 byte array which was allocated by caller */
2007-07-09 11:55:14 +04:00
int cifs_calculate_mac_key ( struct mac_key * key , const char * rn ,
const char * password )
2005-04-17 02:20:36 +04:00
{
char temp_key [ 16 ] ;
if ( ( key = = NULL ) | | ( rn = = NULL ) )
return - EINVAL ;
E_md4hash ( password , temp_key ) ;
2007-07-09 11:55:14 +04:00
mdfour ( key - > data . ntlm , temp_key , 16 ) ;
memcpy ( key - > data . ntlm + 16 , rn , CIFS_SESS_KEY_SIZE ) ;
key - > len = 40 ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-13 04:33:32 +04:00
int CalcNTLMv2_partial_mac_key ( struct cifsSesInfo * ses ,
const struct nls_table * nls_info )
2005-04-17 02:20:36 +04:00
{
char temp_hash [ 16 ] ;
struct HMACMD5Context ctx ;
2007-07-13 04:33:32 +04:00
char * ucase_buf ;
__le16 * unicode_buf ;
unsigned int i , user_name_len , dom_name_len ;
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
if ( ses = = NULL )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
E_md4hash ( ses - > password , temp_hash ) ;
hmac_md5_init_limK_to_64 ( temp_hash , 16 , & ctx ) ;
user_name_len = strlen ( ses - > userName ) ;
2007-07-13 04:33:32 +04:00
if ( user_name_len > MAX_USERNAME_SIZE )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-07-13 04:33:32 +04:00
if ( ses - > domainName = = NULL )
2006-06-01 02:40:51 +04:00
return - EINVAL ; /* BB should we use CIFS_LINUX_DOM */
2005-04-17 02:20:36 +04:00
dom_name_len = strlen ( ses - > domainName ) ;
2007-07-09 11:55:14 +04:00
if ( dom_name_len > MAX_USERNAME_SIZE )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
ucase_buf = kmalloc ( ( MAX_USERNAME_SIZE + 1 ) , GFP_KERNEL ) ;
2007-07-09 11:55:14 +04:00
if ( ucase_buf = = NULL )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
unicode_buf = kmalloc ( ( MAX_USERNAME_SIZE + 1 ) * 4 , GFP_KERNEL ) ;
2007-07-09 11:55:14 +04:00
if ( unicode_buf = = NULL ) {
2005-04-17 02:20:36 +04:00
kfree ( ucase_buf ) ;
return - ENOMEM ;
}
2007-07-13 04:33:32 +04:00
for ( i = 0 ; i < user_name_len ; i + + )
2005-04-17 02:20:36 +04:00
ucase_buf [ i ] = nls_info - > charset2upper [ ( int ) ses - > userName [ i ] ] ;
ucase_buf [ i ] = 0 ;
2007-07-13 04:33:32 +04:00
user_name_len = cifs_strtoUCS ( unicode_buf , ucase_buf ,
MAX_USERNAME_SIZE * 2 , nls_info ) ;
2005-04-17 02:20:36 +04:00
unicode_buf [ user_name_len ] = 0 ;
user_name_len + + ;
2007-07-09 11:55:14 +04:00
for ( i = 0 ; i < dom_name_len ; i + + )
2005-04-17 02:20:36 +04:00
ucase_buf [ i ] = nls_info - > charset2upper [ ( int ) ses - > domainName [ i ] ] ;
ucase_buf [ i ] = 0 ;
2007-07-13 04:33:32 +04:00
dom_name_len = cifs_strtoUCS ( unicode_buf + user_name_len , ucase_buf ,
MAX_USERNAME_SIZE * 2 , nls_info ) ;
2005-04-17 02:20:36 +04:00
unicode_buf [ user_name_len + dom_name_len ] = 0 ;
hmac_md5_update ( ( const unsigned char * ) unicode_buf ,
2007-07-09 11:55:14 +04:00
( user_name_len + dom_name_len ) * 2 , & ctx ) ;
2005-04-17 02:20:36 +04:00
2007-07-09 11:55:14 +04:00
hmac_md5_final ( ses - > server - > ntlmv2_hash , & ctx ) ;
2005-04-17 02:20:36 +04:00
kfree ( ucase_buf ) ;
kfree ( unicode_buf ) ;
return 0 ;
}
2006-06-01 23:20:10 +04:00
# ifdef CONFIG_CIFS_WEAK_PW_HASH
2007-07-13 04:33:32 +04:00
void calc_lanman_hash ( struct cifsSesInfo * ses , char * lnm_session_key )
2006-06-01 23:20:10 +04:00
{
int i ;
char password_with_pad [ CIFS_ENCPWD_SIZE ] ;
2007-07-13 04:33:32 +04:00
if ( ses - > server = = NULL )
2006-06-03 02:57:13 +04:00
return ;
2006-06-01 23:20:10 +04:00
memset ( password_with_pad , 0 , CIFS_ENCPWD_SIZE ) ;
2007-07-13 04:33:32 +04:00
if ( ses - > password )
2006-08-11 20:52:09 +04:00
strncpy ( password_with_pad , ses - > password , CIFS_ENCPWD_SIZE ) ;
2006-06-01 23:20:10 +04:00
2007-07-13 04:33:32 +04:00
if ( ( ses - > server - > secMode & SECMODE_PW_ENCRYPT ) = = 0 )
if ( extended_security & CIFSSEC_MAY_PLNTXT ) {
2008-08-28 01:30:22 +04:00
memset ( lnm_session_key , 0 , CIFS_SESS_KEY_SIZE ) ;
2007-07-13 04:33:32 +04:00
memcpy ( lnm_session_key , password_with_pad ,
CIFS_ENCPWD_SIZE ) ;
2006-06-03 02:57:13 +04:00
return ;
}
2006-06-01 23:20:10 +04:00
/* calculate old style session key */
/* calling toupper is less broken than repeatedly
calling nls_toupper would be since that will never
work for UTF8 , but neither handles multibyte code pages
but the only alternative would be converting to UCS - 16 ( Unicode )
( using a routine something like UniStrupr ) then
uppercasing and then converting back from Unicode - which
would only worth doing it if we knew it were utf8 . Basically
utf8 and other multibyte codepages each need their own strupper
function since a byte at a time will ont work . */
2008-07-24 19:56:05 +04:00
for ( i = 0 ; i < CIFS_ENCPWD_SIZE ; i + + )
2006-06-01 23:20:10 +04:00
password_with_pad [ i ] = toupper ( password_with_pad [ i ] ) ;
SMBencrypt ( password_with_pad , ses - > server - > cryptKey , lnm_session_key ) ;
/* clear password before we return/free memory */
memset ( password_with_pad , 0 , CIFS_ENCPWD_SIZE ) ;
}
# endif /* CIFS_WEAK_PW_HASH */
2007-07-13 04:33:32 +04:00
static int calc_ntlmv2_hash ( struct cifsSesInfo * ses ,
const struct nls_table * nls_cp )
2006-06-06 03:34:19 +04:00
{
int rc = 0 ;
int len ;
char nt_hash [ 16 ] ;
2007-07-13 04:33:32 +04:00
struct HMACMD5Context * pctxt ;
wchar_t * user ;
wchar_t * domain ;
2006-06-06 03:34:19 +04:00
pctxt = kmalloc ( sizeof ( struct HMACMD5Context ) , GFP_KERNEL ) ;
2007-07-13 04:33:32 +04:00
if ( pctxt = = NULL )
2006-06-06 03:34:19 +04:00
return - ENOMEM ;
/* calculate md4 hash of password */
E_md4hash ( ses - > password , nt_hash ) ;
2006-06-08 09:41:32 +04:00
/* convert Domainname to unicode and uppercase */
2006-06-06 03:34:19 +04:00
hmac_md5_init_limK_to_64 ( nt_hash , 16 , pctxt ) ;
/* convert ses->userName to unicode and uppercase */
2006-06-08 09:41:32 +04:00
len = strlen ( ses - > userName ) ;
user = kmalloc ( 2 + ( len * 2 ) , GFP_KERNEL ) ;
2007-07-13 04:33:32 +04:00
if ( user = = NULL )
2006-06-08 09:41:32 +04:00
goto calc_exit_2 ;
2007-10-14 21:58:43 +04:00
len = cifs_strtoUCS ( ( __le16 * ) user , ses - > userName , len , nls_cp ) ;
2006-06-08 09:41:32 +04:00
UniStrupr ( user ) ;
hmac_md5_update ( ( char * ) user , 2 * len , pctxt ) ;
2006-06-06 03:34:19 +04:00
/* convert ses->domainName to unicode and uppercase */
2007-07-13 04:33:32 +04:00
if ( ses - > domainName ) {
2006-06-08 09:41:32 +04:00
len = strlen ( ses - > domainName ) ;
2006-06-06 03:34:19 +04:00
2007-07-13 04:33:32 +04:00
domain = kmalloc ( 2 + ( len * 2 ) , GFP_KERNEL ) ;
if ( domain = = NULL )
2006-06-08 09:41:32 +04:00
goto calc_exit_1 ;
2007-10-14 21:58:43 +04:00
len = cifs_strtoUCS ( ( __le16 * ) domain , ses - > domainName , len ,
nls_cp ) ;
2007-07-09 11:55:14 +04:00
/* the following line was removed since it didn't work well
with lower cased domain name that passed as an option .
Maybe converting the domain name earlier makes sense */
/* UniStrupr(domain); */
2006-06-06 03:34:19 +04:00
2006-06-08 09:41:32 +04:00
hmac_md5_update ( ( char * ) domain , 2 * len , pctxt ) ;
2007-07-13 04:33:32 +04:00
2006-06-08 09:41:32 +04:00
kfree ( domain ) ;
}
calc_exit_1 :
kfree ( user ) ;
calc_exit_2 :
2007-07-13 04:33:32 +04:00
/* BB FIXME what about bytes 24 through 40 of the signing key?
2006-06-08 09:41:32 +04:00
compare with the NTLM example */
2007-07-09 11:55:14 +04:00
hmac_md5_final ( ses - > server - > ntlmv2_hash , pctxt ) ;
2006-06-06 03:34:19 +04:00
return rc ;
}
2007-07-13 04:33:32 +04:00
void setup_ntlmv2_rsp ( struct cifsSesInfo * ses , char * resp_buf ,
const struct nls_table * nls_cp )
2006-06-05 20:26:05 +04:00
{
2006-06-06 03:34:19 +04:00
int rc ;
2007-07-13 04:33:32 +04:00
struct ntlmv2_resp * buf = ( struct ntlmv2_resp * ) resp_buf ;
2007-07-09 11:55:14 +04:00
struct HMACMD5Context context ;
2006-06-05 20:26:05 +04:00
buf - > blob_signature = cpu_to_le32 ( 0x00000101 ) ;
buf - > reserved = 0 ;
buf - > time = cpu_to_le64 ( cifs_UnixTimeToNT ( CURRENT_TIME ) ) ;
2006-06-08 09:41:32 +04:00
get_random_bytes ( & buf - > client_chal , sizeof ( buf - > client_chal ) ) ;
2006-06-05 20:26:05 +04:00
buf - > reserved2 = 0 ;
2006-12-08 07:14:28 +03:00
buf - > names [ 0 ] . type = cpu_to_le16 ( NTLMSSP_DOMAIN_TYPE ) ;
2006-06-05 20:26:05 +04:00
buf - > names [ 0 ] . length = 0 ;
2006-12-08 07:14:28 +03:00
buf - > names [ 1 ] . type = 0 ;
buf - > names [ 1 ] . length = 0 ;
2006-06-06 03:34:19 +04:00
2006-06-05 20:26:05 +04:00
/* calculate buf->ntlmv2_hash */
2006-06-08 09:41:32 +04:00
rc = calc_ntlmv2_hash ( ses , nls_cp ) ;
2007-07-13 04:33:32 +04:00
if ( rc )
cERROR ( 1 , ( " could not get v2 hash rc %d " , rc ) ) ;
2006-06-08 09:41:32 +04:00
CalcNTLMv2_response ( ses , resp_buf ) ;
2007-07-09 11:55:14 +04:00
/* now calculate the MAC key for NTLMv2 */
hmac_md5_init_limK_to_64 ( ses - > server - > ntlmv2_hash , 16 , & context ) ;
hmac_md5_update ( resp_buf , 16 , & context ) ;
hmac_md5_final ( ses - > server - > mac_signing_key . data . ntlmv2 . key , & context ) ;
memcpy ( & ses - > server - > mac_signing_key . data . ntlmv2 . resp , resp_buf ,
sizeof ( struct ntlmv2_resp ) ) ;
ses - > server - > mac_signing_key . len = 16 + sizeof ( struct ntlmv2_resp ) ;
2006-06-05 20:26:05 +04:00
}
2007-07-13 04:33:32 +04:00
void CalcNTLMv2_response ( const struct cifsSesInfo * ses ,
char * v2_session_response )
2005-04-17 02:20:36 +04:00
{
struct HMACMD5Context context ;
2006-06-08 09:41:32 +04:00
/* rest of v2 struct already generated */
2007-07-13 04:33:32 +04:00
memcpy ( v2_session_response + 8 , ses - > server - > cryptKey , 8 ) ;
2007-07-09 11:55:14 +04:00
hmac_md5_init_limK_to_64 ( ses - > server - > ntlmv2_hash , 16 , & context ) ;
2005-04-17 02:20:36 +04:00
2007-07-09 11:55:14 +04:00
hmac_md5_update ( v2_session_response + 8 ,
2006-06-08 09:41:32 +04:00
sizeof ( struct ntlmv2_resp ) - 8 , & context ) ;
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
hmac_md5_final ( v2_session_response , & context ) ;
2006-06-08 09:41:32 +04:00
/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
2005-04-17 02:20:36 +04:00
}