2011-12-26 22:53:34 +04:00
/*
* fs / cifs / smb2transport . c
*
* Copyright ( C ) International Business Machines Corp . , 2002 , 2011
* Etersoft , 2012
* Author ( s ) : Steve French ( sfrench @ us . ibm . com )
* Jeremy Allison ( jra @ samba . org ) 2006
* Pavel Shilovsky ( pshilovsky @ samba . org ) 2012
*
* 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 <linux/list.h>
# include <linux/wait.h>
# include <linux/net.h>
# include <linux/delay.h>
# include <linux/uaccess.h>
# include <asm/processor.h>
# include <linux/mempool.h>
2012-09-19 03:20:35 +04:00
# include <linux/highmem.h>
2011-12-26 22:53:34 +04:00
# include "smb2pdu.h"
# include "cifsglob.h"
# include "cifsproto.h"
# include "smb2proto.h"
# include "cifs_debug.h"
# include "smb2status.h"
2012-09-19 03:20:30 +04:00
# include "smb2glob.h"
2013-07-04 19:35:21 +04:00
static int
smb2_crypto_shash_allocate ( struct TCP_Server_Info * server )
{
2013-07-31 21:48:00 +04:00
int rc ;
2013-07-04 19:35:21 +04:00
unsigned int size ;
if ( server - > secmech . sdeschmacsha256 ! = NULL )
return 0 ; /* already allocated */
server - > secmech . hmacsha256 = crypto_alloc_shash ( " hmac(sha256) " , 0 , 0 ) ;
if ( IS_ERR ( server - > secmech . hmacsha256 ) ) {
cifs_dbg ( VFS , " could not allocate crypto hmacsha256 \n " ) ;
2013-07-31 21:48:00 +04:00
rc = PTR_ERR ( server - > secmech . hmacsha256 ) ;
server - > secmech . hmacsha256 = NULL ;
return rc ;
2013-07-04 19:35:21 +04:00
}
size = sizeof ( struct shash_desc ) +
crypto_shash_descsize ( server - > secmech . hmacsha256 ) ;
server - > secmech . sdeschmacsha256 = kmalloc ( size , GFP_KERNEL ) ;
if ( ! server - > secmech . sdeschmacsha256 ) {
crypto_free_shash ( server - > secmech . hmacsha256 ) ;
server - > secmech . hmacsha256 = NULL ;
return - ENOMEM ;
}
server - > secmech . sdeschmacsha256 - > shash . tfm = server - > secmech . hmacsha256 ;
server - > secmech . sdeschmacsha256 - > shash . flags = 0x0 ;
return 0 ;
}
static int
smb3_crypto_shash_allocate ( struct TCP_Server_Info * server )
{
unsigned int size ;
int rc ;
if ( server - > secmech . sdesccmacaes ! = NULL )
return 0 ; /* already allocated */
rc = smb2_crypto_shash_allocate ( server ) ;
if ( rc )
return rc ;
server - > secmech . cmacaes = crypto_alloc_shash ( " cmac(aes) " , 0 , 0 ) ;
if ( IS_ERR ( server - > secmech . cmacaes ) ) {
cifs_dbg ( VFS , " could not allocate crypto cmac-aes " ) ;
kfree ( server - > secmech . sdeschmacsha256 ) ;
server - > secmech . sdeschmacsha256 = NULL ;
crypto_free_shash ( server - > secmech . hmacsha256 ) ;
server - > secmech . hmacsha256 = NULL ;
2013-07-31 21:48:00 +04:00
rc = PTR_ERR ( server - > secmech . cmacaes ) ;
server - > secmech . cmacaes = NULL ;
return rc ;
2013-07-04 19:35:21 +04:00
}
size = sizeof ( struct shash_desc ) +
crypto_shash_descsize ( server - > secmech . cmacaes ) ;
server - > secmech . sdesccmacaes = kmalloc ( size , GFP_KERNEL ) ;
if ( ! server - > secmech . sdesccmacaes ) {
cifs_dbg ( VFS , " %s: Can't alloc cmacaes \n " , __func__ ) ;
kfree ( server - > secmech . sdeschmacsha256 ) ;
server - > secmech . sdeschmacsha256 = NULL ;
crypto_free_shash ( server - > secmech . hmacsha256 ) ;
crypto_free_shash ( server - > secmech . cmacaes ) ;
server - > secmech . hmacsha256 = NULL ;
server - > secmech . cmacaes = NULL ;
return - ENOMEM ;
}
server - > secmech . sdesccmacaes - > shash . tfm = server - > secmech . cmacaes ;
server - > secmech . sdesccmacaes - > shash . flags = 0x0 ;
return 0 ;
}
2013-08-29 17:35:11 +04:00
static struct cifs_ses *
smb2_find_smb_ses ( struct smb2_hdr * smb2hdr , struct TCP_Server_Info * server )
{
struct cifs_ses * ses ;
spin_lock ( & cifs_tcp_ses_lock ) ;
list_for_each_entry ( ses , & server - > smb_ses_list , smb_ses_list ) {
if ( ses - > Suid ! = smb2hdr - > SessionId )
continue ;
spin_unlock ( & cifs_tcp_ses_lock ) ;
return ses ;
}
spin_unlock ( & cifs_tcp_ses_lock ) ;
return NULL ;
}
2013-07-04 19:35:21 +04:00
2012-12-09 08:08:06 +04:00
int
2012-09-19 03:20:34 +04:00
smb2_calc_signature ( struct smb_rqst * rqst , struct TCP_Server_Info * server )
2012-09-19 03:20:30 +04:00
{
int i , rc ;
unsigned char smb2_signature [ SMB2_HMACSHA256_SIZE ] ;
unsigned char * sigptr = smb2_signature ;
2012-09-19 03:20:34 +04:00
struct kvec * iov = rqst - > rq_iov ;
int n_vec = rqst - > rq_nvec ;
2012-09-19 03:20:30 +04:00
struct smb2_hdr * smb2_pdu = ( struct smb2_hdr * ) iov [ 0 ] . iov_base ;
2013-08-29 17:35:11 +04:00
struct cifs_ses * ses ;
ses = smb2_find_smb_ses ( smb2_pdu , server ) ;
if ( ! ses ) {
cifs_dbg ( VFS , " %s: Could not find session \n " , __func__ ) ;
return 0 ;
}
2012-09-19 03:20:30 +04:00
memset ( smb2_signature , 0x0 , SMB2_HMACSHA256_SIZE ) ;
memset ( smb2_pdu - > Signature , 0x0 , SMB2_SIGNATURE_SIZE ) ;
2013-07-04 19:35:21 +04:00
rc = smb2_crypto_shash_allocate ( server ) ;
if ( rc ) {
cifs_dbg ( VFS , " %s: shah256 alloc failed \n " , __func__ ) ;
return rc ;
}
2012-09-19 03:20:30 +04:00
rc = crypto_shash_setkey ( server - > secmech . hmacsha256 ,
2013-08-29 17:35:11 +04:00
ses - > auth_key . response , SMB2_NTLMV2_SESSKEY_SIZE ) ;
2012-09-19 03:20:30 +04:00
if ( rc ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " %s: Could not update with response \n " , __func__ ) ;
2012-09-19 03:20:30 +04:00
return rc ;
}
rc = crypto_shash_init ( & server - > secmech . sdeschmacsha256 - > shash ) ;
if ( rc ) {
2013-07-04 19:35:21 +04:00
cifs_dbg ( VFS , " %s: Could not init sha256 " , __func__ ) ;
2012-09-19 03:20:30 +04:00
return rc ;
}
for ( i = 0 ; i < n_vec ; i + + ) {
if ( iov [ i ] . iov_len = = 0 )
continue ;
if ( iov [ i ] . iov_base = = NULL ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " null iovec entry \n " ) ;
2012-09-19 03:20:30 +04:00
return - EIO ;
}
/*
* The first entry includes a length field ( which does not get
* signed that occupies the first 4 bytes before the header ) .
*/
if ( i = = 0 ) {
if ( iov [ 0 ] . iov_len < = 8 ) /* cmd field at offset 9 */
break ; /* nothing to sign or corrupt header */
rc =
crypto_shash_update (
& server - > secmech . sdeschmacsha256 - > shash ,
iov [ i ] . iov_base + 4 , iov [ i ] . iov_len - 4 ) ;
} else {
rc =
crypto_shash_update (
& server - > secmech . sdeschmacsha256 - > shash ,
iov [ i ] . iov_base , iov [ i ] . iov_len ) ;
}
if ( rc ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " %s: Could not update with payload \n " ,
__func__ ) ;
2012-09-19 03:20:30 +04:00
return rc ;
}
}
2012-09-19 03:20:35 +04:00
/* now hash over the rq_pages array */
for ( i = 0 ; i < rqst - > rq_npages ; i + + ) {
struct kvec p_iov ;
cifs_rqst_page_to_kvec ( rqst , i , & p_iov ) ;
crypto_shash_update ( & server - > secmech . sdeschmacsha256 - > shash ,
p_iov . iov_base , p_iov . iov_len ) ;
kunmap ( rqst - > rq_pages [ i ] ) ;
}
2012-09-19 03:20:30 +04:00
rc = crypto_shash_final ( & server - > secmech . sdeschmacsha256 - > shash ,
sigptr ) ;
if ( rc )
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " %s: Could not generate sha256 hash \n " , __func__ ) ;
2012-09-19 03:20:30 +04:00
memcpy ( smb2_pdu - > Signature , sigptr , SMB2_SIGNATURE_SIZE ) ;
return rc ;
}
2013-08-29 17:35:11 +04:00
int
generate_smb3signingkey ( struct cifs_ses * ses )
2013-06-27 08:45:05 +04:00
{
unsigned char zero = 0x0 ;
__u8 i [ 4 ] = { 0 , 0 , 0 , 1 } ;
__u8 L [ 4 ] = { 0 , 0 , 0 , 128 } ;
int rc = 0 ;
unsigned char prfhash [ SMB2_HMACSHA256_SIZE ] ;
unsigned char * hashptr = prfhash ;
memset ( prfhash , 0x0 , SMB2_HMACSHA256_SIZE ) ;
2013-08-29 17:35:11 +04:00
memset ( ses - > smb3signingkey , 0x0 , SMB3_SIGNKEY_SIZE ) ;
2013-06-27 08:45:05 +04:00
2013-08-29 17:35:11 +04:00
rc = smb3_crypto_shash_allocate ( ses - > server ) ;
2013-07-04 19:35:21 +04:00
if ( rc ) {
cifs_dbg ( VFS , " %s: crypto alloc failed \n " , __func__ ) ;
goto smb3signkey_ret ;
}
2013-08-29 17:35:11 +04:00
rc = crypto_shash_setkey ( ses - > server - > secmech . hmacsha256 ,
ses - > auth_key . response , SMB2_NTLMV2_SESSKEY_SIZE ) ;
2013-06-27 08:45:05 +04:00
if ( rc ) {
cifs_dbg ( VFS , " %s: Could not set with session key \n " , __func__ ) ;
goto smb3signkey_ret ;
}
2013-08-29 17:35:11 +04:00
rc = crypto_shash_init ( & ses - > server - > secmech . sdeschmacsha256 - > shash ) ;
2013-06-27 08:45:05 +04:00
if ( rc ) {
cifs_dbg ( VFS , " %s: Could not init sign hmac \n " , __func__ ) ;
goto smb3signkey_ret ;
}
2013-08-29 17:35:11 +04:00
rc = crypto_shash_update ( & ses - > server - > secmech . sdeschmacsha256 - > shash ,
2013-06-27 08:45:05 +04:00
i , 4 ) ;
if ( rc ) {
cifs_dbg ( VFS , " %s: Could not update with n \n " , __func__ ) ;
goto smb3signkey_ret ;
}
2013-08-29 17:35:11 +04:00
rc = crypto_shash_update ( & ses - > server - > secmech . sdeschmacsha256 - > shash ,
2013-06-27 08:45:05 +04:00
" SMB2AESCMAC " , 12 ) ;
if ( rc ) {
cifs_dbg ( VFS , " %s: Could not update with label \n " , __func__ ) ;
goto smb3signkey_ret ;
}
2013-08-29 17:35:11 +04:00
rc = crypto_shash_update ( & ses - > server - > secmech . sdeschmacsha256 - > shash ,
2013-06-27 08:45:05 +04:00
& zero , 1 ) ;
if ( rc ) {
cifs_dbg ( VFS , " %s: Could not update with zero \n " , __func__ ) ;
goto smb3signkey_ret ;
}
2013-08-29 17:35:11 +04:00
rc = crypto_shash_update ( & ses - > server - > secmech . sdeschmacsha256 - > shash ,
2013-06-27 08:45:05 +04:00
" SmbSign " , 8 ) ;
if ( rc ) {
cifs_dbg ( VFS , " %s: Could not update with context \n " , __func__ ) ;
goto smb3signkey_ret ;
}
2013-08-29 17:35:11 +04:00
rc = crypto_shash_update ( & ses - > server - > secmech . sdeschmacsha256 - > shash ,
2013-06-27 08:45:05 +04:00
L , 4 ) ;
if ( rc ) {
cifs_dbg ( VFS , " %s: Could not update with L \n " , __func__ ) ;
goto smb3signkey_ret ;
}
2013-08-29 17:35:11 +04:00
rc = crypto_shash_final ( & ses - > server - > secmech . sdeschmacsha256 - > shash ,
2013-06-27 08:45:05 +04:00
hashptr ) ;
if ( rc ) {
cifs_dbg ( VFS , " %s: Could not generate sha256 hash \n " , __func__ ) ;
goto smb3signkey_ret ;
}
2013-08-29 17:35:11 +04:00
memcpy ( ses - > smb3signingkey , hashptr , SMB3_SIGNKEY_SIZE ) ;
2013-06-27 08:45:05 +04:00
smb3signkey_ret :
2013-08-29 17:35:11 +04:00
return rc ;
2013-06-27 08:45:05 +04:00
}
2012-12-09 08:08:06 +04:00
int
smb3_calc_signature ( struct smb_rqst * rqst , struct TCP_Server_Info * server )
{
2013-08-29 17:35:11 +04:00
int i ;
int rc = 0 ;
2013-06-27 08:45:05 +04:00
unsigned char smb3_signature [ SMB2_CMACAES_SIZE ] ;
unsigned char * sigptr = smb3_signature ;
struct kvec * iov = rqst - > rq_iov ;
int n_vec = rqst - > rq_nvec ;
struct smb2_hdr * smb2_pdu = ( struct smb2_hdr * ) iov [ 0 ] . iov_base ;
2013-08-29 17:35:11 +04:00
struct cifs_ses * ses ;
ses = smb2_find_smb_ses ( smb2_pdu , server ) ;
if ( ! ses ) {
cifs_dbg ( VFS , " %s: Could not find session \n " , __func__ ) ;
return 0 ;
}
2013-06-27 08:45:05 +04:00
memset ( smb3_signature , 0x0 , SMB2_CMACAES_SIZE ) ;
memset ( smb2_pdu - > Signature , 0x0 , SMB2_SIGNATURE_SIZE ) ;
rc = crypto_shash_setkey ( server - > secmech . cmacaes ,
2013-08-29 17:35:11 +04:00
ses - > smb3signingkey , SMB2_CMACAES_SIZE ) ;
2013-06-27 08:45:05 +04:00
if ( rc ) {
cifs_dbg ( VFS , " %s: Could not set key for cmac aes \n " , __func__ ) ;
return rc ;
}
2013-07-04 19:35:21 +04:00
/*
* we already allocate sdesccmacaes when we init smb3 signing key ,
* so unlike smb2 case we do not have to check here if secmech are
* initialized
*/
2013-06-27 08:45:05 +04:00
rc = crypto_shash_init ( & server - > secmech . sdesccmacaes - > shash ) ;
if ( rc ) {
cifs_dbg ( VFS , " %s: Could not init cmac aes \n " , __func__ ) ;
return rc ;
}
for ( i = 0 ; i < n_vec ; i + + ) {
if ( iov [ i ] . iov_len = = 0 )
continue ;
if ( iov [ i ] . iov_base = = NULL ) {
cifs_dbg ( VFS , " null iovec entry " ) ;
return - EIO ;
}
/*
* The first entry includes a length field ( which does not get
* signed that occupies the first 4 bytes before the header ) .
*/
if ( i = = 0 ) {
if ( iov [ 0 ] . iov_len < = 8 ) /* cmd field at offset 9 */
break ; /* nothing to sign or corrupt header */
rc =
crypto_shash_update (
& server - > secmech . sdesccmacaes - > shash ,
iov [ i ] . iov_base + 4 , iov [ i ] . iov_len - 4 ) ;
} else {
rc =
crypto_shash_update (
& server - > secmech . sdesccmacaes - > shash ,
iov [ i ] . iov_base , iov [ i ] . iov_len ) ;
}
if ( rc ) {
cifs_dbg ( VFS , " %s: Couldn't update cmac aes with payload \n " ,
__func__ ) ;
return rc ;
}
}
/* now hash over the rq_pages array */
for ( i = 0 ; i < rqst - > rq_npages ; i + + ) {
struct kvec p_iov ;
cifs_rqst_page_to_kvec ( rqst , i , & p_iov ) ;
crypto_shash_update ( & server - > secmech . sdesccmacaes - > shash ,
p_iov . iov_base , p_iov . iov_len ) ;
kunmap ( rqst - > rq_pages [ i ] ) ;
}
rc = crypto_shash_final ( & server - > secmech . sdesccmacaes - > shash ,
sigptr ) ;
if ( rc )
cifs_dbg ( VFS , " %s: Could not generate cmac aes \n " , __func__ ) ;
memcpy ( smb2_pdu - > Signature , sigptr , SMB2_SIGNATURE_SIZE ) ;
return rc ;
2012-12-09 08:08:06 +04:00
}
2012-09-19 03:20:30 +04:00
/* must be called with server->srv_mutex held */
static int
2012-09-19 03:20:34 +04:00
smb2_sign_rqst ( struct smb_rqst * rqst , struct TCP_Server_Info * server )
2012-09-19 03:20:30 +04:00
{
int rc = 0 ;
2012-09-19 03:20:34 +04:00
struct smb2_hdr * smb2_pdu = rqst - > rq_iov [ 0 ] . iov_base ;
2012-09-19 03:20:30 +04:00
if ( ! ( smb2_pdu - > Flags & SMB2_FLAGS_SIGNED ) | |
server - > tcpStatus = = CifsNeedNegotiate )
return rc ;
if ( ! server - > session_estab ) {
strncpy ( smb2_pdu - > Signature , " BSRSPYL " , 8 ) ;
return rc ;
}
2012-12-09 08:08:06 +04:00
rc = server - > ops - > calc_signature ( rqst , server ) ;
2012-09-19 03:20:30 +04:00
return rc ;
}
int
2012-09-19 03:20:34 +04:00
smb2_verify_signature ( struct smb_rqst * rqst , struct TCP_Server_Info * server )
2012-09-19 03:20:30 +04:00
{
unsigned int rc ;
char server_response_sig [ 16 ] ;
2012-09-19 03:20:34 +04:00
struct smb2_hdr * smb2_pdu = ( struct smb2_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2012-09-19 03:20:30 +04:00
if ( ( smb2_pdu - > Command = = SMB2_NEGOTIATE ) | |
2013-08-29 17:35:11 +04:00
( smb2_pdu - > Command = = SMB2_SESSION_SETUP ) | |
2012-09-19 03:20:30 +04:00
( smb2_pdu - > Command = = SMB2_OPLOCK_BREAK ) | |
( ! server - > session_estab ) )
return 0 ;
/*
* BB what if signatures are supposed to be on for session but
* server does not send one ? BB
*/
/* Do not need to verify session setups with signature "BSRSPYL " */
if ( memcmp ( smb2_pdu - > Signature , " BSRSPYL " , 8 ) = = 0 )
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " dummy signature received for smb command 0x%x \n " ,
smb2_pdu - > Command ) ;
2012-09-19 03:20:30 +04:00
/*
* Save off the origiginal signature so we can modify the smb and check
* our calculated signature against what the server sent .
*/
memcpy ( server_response_sig , smb2_pdu - > Signature , SMB2_SIGNATURE_SIZE ) ;
memset ( smb2_pdu - > Signature , 0 , SMB2_SIGNATURE_SIZE ) ;
mutex_lock ( & server - > srv_mutex ) ;
2012-12-09 08:08:06 +04:00
rc = server - > ops - > calc_signature ( rqst , server ) ;
2012-09-19 03:20:30 +04:00
mutex_unlock ( & server - > srv_mutex ) ;
if ( rc )
return rc ;
if ( memcmp ( server_response_sig , smb2_pdu - > Signature ,
SMB2_SIGNATURE_SIZE ) )
return - EACCES ;
else
return 0 ;
}
2011-12-26 22:53:34 +04:00
/*
* Set message id for the request . Should be called after wait_for_free_request
* and when srv_mutex is held .
*/
static inline void
smb2_seq_num_into_buf ( struct TCP_Server_Info * server , struct smb2_hdr * hdr )
{
2014-06-05 19:03:27 +04:00
unsigned int i , num = le16_to_cpu ( hdr - > CreditCharge ) ;
2013-11-02 21:50:34 +04:00
hdr - > MessageId = get_next_mid64 ( server ) ;
2014-06-05 19:03:27 +04:00
/* skip message numbers according to CreditCharge field */
for ( i = 1 ; i < num ; i + + )
get_next_mid ( server ) ;
2011-12-26 22:53:34 +04:00
}
static struct mid_q_entry *
smb2_mid_entry_alloc ( const struct smb2_hdr * smb_buffer ,
struct TCP_Server_Info * server )
{
struct mid_q_entry * temp ;
if ( server = = NULL ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " Null TCP session in smb2_mid_entry_alloc \n " ) ;
2011-12-26 22:53:34 +04:00
return NULL ;
}
temp = mempool_alloc ( cifs_mid_poolp , GFP_NOFS ) ;
if ( temp = = NULL )
return temp ;
else {
memset ( temp , 0 , sizeof ( struct mid_q_entry ) ) ;
temp - > mid = smb_buffer - > MessageId ; /* always LE */
temp - > pid = current - > pid ;
temp - > command = smb_buffer - > Command ; /* Always LE */
temp - > when_alloc = jiffies ;
temp - > server = server ;
/*
* The default is for the mid to be synchronous , so the
* default callback just wakes up the current task .
*/
temp - > callback = cifs_wake_up_task ;
temp - > callback_data = current ;
}
atomic_inc ( & midCount ) ;
temp - > mid_state = MID_REQUEST_ALLOCATED ;
return temp ;
}
static int
smb2_get_mid_entry ( struct cifs_ses * ses , struct smb2_hdr * buf ,
struct mid_q_entry * * mid )
{
if ( ses - > server - > tcpStatus = = CifsExiting )
return - ENOENT ;
if ( ses - > server - > tcpStatus = = CifsNeedReconnect ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " tcp session dead - return to caller to retry \n " ) ;
2011-12-26 22:53:34 +04:00
return - EAGAIN ;
}
2013-10-12 19:06:03 +04:00
if ( ses - > status = = CifsNew ) {
2011-12-26 22:53:34 +04:00
if ( ( buf - > Command ! = SMB2_SESSION_SETUP ) & &
( buf - > Command ! = SMB2_NEGOTIATE ) )
return - EAGAIN ;
/* else ok - we are setting up session */
}
2013-10-12 19:06:03 +04:00
if ( ses - > status = = CifsExiting ) {
if ( buf - > Command ! = SMB2_LOGOFF )
return - EAGAIN ;
/* else ok - we are shutting down the session */
}
2011-12-26 22:53:34 +04:00
* mid = smb2_mid_entry_alloc ( buf , ses - > server ) ;
if ( * mid = = NULL )
return - ENOMEM ;
spin_lock ( & GlobalMid_Lock ) ;
list_add_tail ( & ( * mid ) - > qhead , & ses - > server - > pending_mid_q ) ;
spin_unlock ( & GlobalMid_Lock ) ;
return 0 ;
}
int
smb2_check_receive ( struct mid_q_entry * mid , struct TCP_Server_Info * server ,
bool log_error )
{
unsigned int len = get_rfc1002_length ( mid - > resp_buf ) ;
2012-09-19 03:20:34 +04:00
struct kvec iov ;
struct smb_rqst rqst = { . rq_iov = & iov ,
. rq_nvec = 1 } ;
iov . iov_base = ( char * ) mid - > resp_buf ;
iov . iov_len = get_rfc1002_length ( mid - > resp_buf ) + 4 ;
2011-12-26 22:53:34 +04:00
dump_smb ( mid - > resp_buf , min_t ( u32 , 80 , len ) ) ;
/* convert the length into a more usable form */
2013-05-26 15:01:00 +04:00
if ( len > 24 & & server - > sign ) {
2012-09-19 03:20:30 +04:00
int rc ;
2012-09-19 03:20:34 +04:00
rc = smb2_verify_signature ( & rqst , server ) ;
2012-09-19 03:20:30 +04:00
if ( rc )
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " SMB signature verification returned error = %d \n " ,
rc ) ;
2012-09-19 03:20:30 +04:00
}
2011-12-26 22:53:34 +04:00
return map_smb2_to_linux_error ( mid - > resp_buf , log_error ) ;
}
2012-09-19 03:20:35 +04:00
struct mid_q_entry *
smb2_setup_request ( struct cifs_ses * ses , struct smb_rqst * rqst )
2011-12-26 22:53:34 +04:00
{
int rc ;
2012-09-19 03:20:35 +04:00
struct smb2_hdr * hdr = ( struct smb2_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2011-12-26 22:53:34 +04:00
struct mid_q_entry * mid ;
smb2_seq_num_into_buf ( ses - > server , hdr ) ;
rc = smb2_get_mid_entry ( ses , hdr , & mid ) ;
if ( rc )
2012-09-19 03:20:35 +04:00
return ERR_PTR ( rc ) ;
rc = smb2_sign_rqst ( rqst , ses - > server ) ;
if ( rc ) {
2012-09-19 03:20:30 +04:00
cifs_delete_mid ( mid ) ;
2012-09-19 03:20:35 +04:00
return ERR_PTR ( rc ) ;
}
return mid ;
2011-12-26 22:53:34 +04:00
}
2012-09-19 03:20:35 +04:00
struct mid_q_entry *
smb2_setup_async_request ( struct TCP_Server_Info * server , struct smb_rqst * rqst )
2012-07-11 14:45:28 +04:00
{
2012-09-19 03:20:35 +04:00
int rc ;
struct smb2_hdr * hdr = ( struct smb2_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2012-07-11 14:45:28 +04:00
struct mid_q_entry * mid ;
smb2_seq_num_into_buf ( server , hdr ) ;
mid = smb2_mid_entry_alloc ( hdr , server ) ;
if ( mid = = NULL )
2012-09-19 03:20:35 +04:00
return ERR_PTR ( - ENOMEM ) ;
2012-07-11 14:45:28 +04:00
2012-09-19 03:20:35 +04:00
rc = smb2_sign_rqst ( rqst , server ) ;
2012-07-11 14:45:28 +04:00
if ( rc ) {
DeleteMidQEntry ( mid ) ;
2012-09-19 03:20:35 +04:00
return ERR_PTR ( rc ) ;
2012-09-19 03:20:30 +04:00
}
2012-09-19 03:20:35 +04:00
return mid ;
2012-07-11 14:45:28 +04:00
}