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>
2016-11-04 02:47:37 +03:00
# include <crypto/aead.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 )
{
2018-02-16 21:19:27 +03:00
return cifs_alloc_hash ( " hmac(sha256) " ,
& server - > secmech . hmacsha256 ,
& server - > secmech . sdeschmacsha256 ) ;
2013-07-04 19:35:21 +04:00
}
static int
smb3_crypto_shash_allocate ( struct TCP_Server_Info * server )
{
2018-02-16 21:19:27 +03:00
struct cifs_secmech * p = & server - > secmech ;
2013-07-04 19:35:21 +04:00
int rc ;
2018-02-16 21:19:27 +03:00
rc = cifs_alloc_hash ( " hmac(sha256) " ,
& p - > hmacsha256 ,
& p - > sdeschmacsha256 ) ;
2013-07-04 19:35:21 +04:00
if ( rc )
2018-02-16 21:19:27 +03:00
goto err ;
2013-07-04 19:35:21 +04:00
2018-02-16 21:19:27 +03:00
rc = cifs_alloc_hash ( " cmac(aes) " , & p - > cmacaes , & p - > sdesccmacaes ) ;
if ( rc )
goto err ;
2013-07-04 19:35:21 +04:00
return 0 ;
2018-02-16 21:19:27 +03:00
err :
cifs_free_hash ( & p - > hmacsha256 , & p - > sdeschmacsha256 ) ;
return rc ;
2013-07-04 19:35:21 +04:00
}
2018-02-16 21:19:28 +03:00
# ifdef CONFIG_CIFS_SMB311
int
smb311_crypto_shash_allocate ( struct TCP_Server_Info * server )
{
struct cifs_secmech * p = & server - > secmech ;
int rc = 0 ;
rc = cifs_alloc_hash ( " hmac(sha256) " ,
& p - > hmacsha256 ,
& p - > sdeschmacsha256 ) ;
if ( rc )
return rc ;
rc = cifs_alloc_hash ( " cmac(aes) " , & p - > cmacaes , & p - > sdesccmacaes ) ;
if ( rc )
goto err ;
rc = cifs_alloc_hash ( " sha512 " , & p - > sha512 , & p - > sdescsha512 ) ;
if ( rc )
goto err ;
return 0 ;
err :
cifs_free_hash ( & p - > cmacaes , & p - > sdesccmacaes ) ;
cifs_free_hash ( & p - > hmacsha256 , & p - > sdeschmacsha256 ) ;
return rc ;
}
# endif
2017-03-04 02:41:38 +03:00
static struct cifs_ses *
smb2_find_smb_ses_unlocked ( struct TCP_Server_Info * server , __u64 ses_id )
2013-08-29 17:35:11 +04:00
{
struct cifs_ses * ses ;
list_for_each_entry ( ses , & server - > smb_ses_list , smb_ses_list ) {
2016-11-04 02:47:37 +03:00
if ( ses - > Suid ! = ses_id )
2013-08-29 17:35:11 +04:00
continue ;
return ses ;
}
2017-03-04 02:41:38 +03:00
return NULL ;
}
struct cifs_ses *
smb2_find_smb_ses ( struct TCP_Server_Info * server , __u64 ses_id )
{
struct cifs_ses * ses ;
spin_lock ( & cifs_tcp_ses_lock ) ;
ses = smb2_find_smb_ses_unlocked ( server , ses_id ) ;
2013-08-29 17:35:11 +04:00
spin_unlock ( & cifs_tcp_ses_lock ) ;
2017-03-04 02:41:38 +03:00
return ses ;
}
static struct cifs_tcon *
smb2_find_smb_sess_tcon_unlocked ( struct cifs_ses * ses , __u32 tid )
{
struct cifs_tcon * tcon ;
list_for_each_entry ( tcon , & ses - > tcon_list , tcon_list ) {
if ( tcon - > tid ! = tid )
continue ;
+ + tcon - > tc_count ;
return tcon ;
}
2013-08-29 17:35:11 +04:00
return NULL ;
}
2017-03-04 02:41:38 +03:00
/*
* Obtain tcon corresponding to the tid in the given
* cifs_ses
*/
struct cifs_tcon *
smb2_find_smb_tcon ( struct TCP_Server_Info * server , __u64 ses_id , __u32 tid )
{
struct cifs_ses * ses ;
struct cifs_tcon * tcon ;
spin_lock ( & cifs_tcp_ses_lock ) ;
ses = smb2_find_smb_ses_unlocked ( server , ses_id ) ;
if ( ! ses ) {
spin_unlock ( & cifs_tcp_ses_lock ) ;
return NULL ;
}
tcon = smb2_find_smb_sess_tcon_unlocked ( ses , tid ) ;
spin_unlock ( & cifs_tcp_ses_lock ) ;
return tcon ;
}
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
{
2015-11-13 06:46:49 +03:00
int rc ;
2012-09-19 03:20:30 +04:00
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 ;
2018-06-12 01:00:58 +03:00
struct smb2_sync_hdr * shdr = ( struct smb2_sync_hdr * ) iov [ 0 ] . iov_base ;
2013-08-29 17:35:11 +04:00
struct cifs_ses * ses ;
2016-11-04 02:47:37 +03:00
ses = smb2_find_smb_ses ( server , shdr - > SessionId ) ;
2013-08-29 17:35:11 +04:00
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 ) ;
2016-10-25 01:33:04 +03:00
memset ( shdr - > Signature , 0x0 , SMB2_SIGNATURE_SIZE ) ;
2012-09-19 03:20:30 +04:00
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 ;
}
2018-06-12 01:00:58 +03:00
rc = __cifs_calc_signature ( rqst , server , sigptr ,
2015-11-13 06:46:49 +03:00
& server - > secmech . sdeschmacsha256 - > shash ) ;
2012-09-19 03:20:30 +04:00
2015-11-13 06:46:49 +03:00
if ( ! rc )
2016-10-25 01:33:04 +03:00
memcpy ( shdr - > Signature , sigptr , SMB2_SIGNATURE_SIZE ) ;
2012-09-19 03:20:30 +04:00
return rc ;
}
2015-12-18 22:05:30 +03:00
static int generate_key ( struct cifs_ses * ses , struct kvec label ,
struct kvec context , __u8 * key , unsigned int key_size )
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 ) ;
2015-12-18 22:05:30 +03:00
memset ( key , 0x0 , key_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 ,
2015-12-18 22:05:30 +03:00
label . iov_base , label . iov_len ) ;
2013-06-27 08:45:05 +04:00
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 ,
2015-12-18 22:05:30 +03:00
context . iov_base , context . iov_len ) ;
2013-06-27 08:45:05 +04:00
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 ;
}
2015-12-18 22:05:30 +03:00
memcpy ( key , hashptr , key_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
}
2015-12-18 22:05:30 +03:00
struct derivation {
struct kvec label ;
struct kvec context ;
} ;
struct derivation_triplet {
struct derivation signing ;
struct derivation encryption ;
struct derivation decryption ;
} ;
static int
generate_smb3signingkey ( struct cifs_ses * ses ,
const struct derivation_triplet * ptriplet )
{
int rc ;
rc = generate_key ( ses , ptriplet - > signing . label ,
ptriplet - > signing . context , ses - > smb3signingkey ,
SMB3_SIGN_KEY_SIZE ) ;
if ( rc )
return rc ;
rc = generate_key ( ses , ptriplet - > encryption . label ,
ptriplet - > encryption . context , ses - > smb3encryptionkey ,
SMB3_SIGN_KEY_SIZE ) ;
if ( rc )
return rc ;
2017-05-24 17:13:25 +03:00
rc = generate_key ( ses , ptriplet - > decryption . label ,
ptriplet - > decryption . context ,
ses - > smb3decryptionkey , SMB3_SIGN_KEY_SIZE ) ;
if ( rc )
return rc ;
# ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS
cifs_dbg ( VFS , " %s: dumping generated AES session keys \n " , __func__ ) ;
/*
* The session id is opaque in terms of endianness , so we can ' t
* print it as a long long . we dump it as we got it on the wire
*/
cifs_dbg ( VFS , " Session Id %*ph \n " , ( int ) sizeof ( ses - > Suid ) ,
& ses - > Suid ) ;
cifs_dbg ( VFS , " Session Key %*ph \n " ,
SMB2_NTLMV2_SESSKEY_SIZE , ses - > auth_key . response ) ;
cifs_dbg ( VFS , " Signing Key %*ph \n " ,
SMB3_SIGN_KEY_SIZE , ses - > smb3signingkey ) ;
cifs_dbg ( VFS , " ServerIn Key %*ph \n " ,
SMB3_SIGN_KEY_SIZE , ses - > smb3encryptionkey ) ;
cifs_dbg ( VFS , " ServerOut Key %*ph \n " ,
SMB3_SIGN_KEY_SIZE , ses - > smb3decryptionkey ) ;
# endif
return rc ;
2015-12-18 22:05:30 +03:00
}
int
generate_smb30signingkey ( struct cifs_ses * ses )
{
struct derivation_triplet triplet ;
struct derivation * d ;
d = & triplet . signing ;
d - > label . iov_base = " SMB2AESCMAC " ;
d - > label . iov_len = 12 ;
d - > context . iov_base = " SmbSign " ;
d - > context . iov_len = 8 ;
d = & triplet . encryption ;
d - > label . iov_base = " SMB2AESCCM " ;
d - > label . iov_len = 11 ;
d - > context . iov_base = " ServerIn " ;
d - > context . iov_len = 10 ;
d = & triplet . decryption ;
d - > label . iov_base = " SMB2AESCCM " ;
d - > label . iov_len = 11 ;
d - > context . iov_base = " ServerOut " ;
d - > context . iov_len = 10 ;
return generate_smb3signingkey ( ses , & triplet ) ;
}
2017-09-26 04:11:58 +03:00
# ifdef CONFIG_CIFS_SMB311
2015-12-18 22:05:30 +03:00
int
generate_smb311signingkey ( struct cifs_ses * ses )
{
struct derivation_triplet triplet ;
struct derivation * d ;
d = & triplet . signing ;
2017-09-26 04:11:58 +03:00
d - > label . iov_base = " SMBSigningKey " ;
d - > label . iov_len = 14 ;
d - > context . iov_base = ses - > preauth_sha_hash ;
d - > context . iov_len = 64 ;
2015-12-18 22:05:30 +03:00
d = & triplet . encryption ;
2017-09-26 04:11:58 +03:00
d - > label . iov_base = " SMBC2SCipherKey " ;
d - > label . iov_len = 16 ;
d - > context . iov_base = ses - > preauth_sha_hash ;
d - > context . iov_len = 64 ;
2015-12-18 22:05:30 +03:00
d = & triplet . decryption ;
2017-09-26 04:11:58 +03:00
d - > label . iov_base = " SMBS2CCipherKey " ;
d - > label . iov_len = 16 ;
d - > context . iov_base = ses - > preauth_sha_hash ;
d - > context . iov_len = 64 ;
2015-12-18 22:05:30 +03:00
return generate_smb3signingkey ( ses , & triplet ) ;
}
2017-09-26 04:11:58 +03:00
# endif /* 311 */
2015-12-18 22:05:30 +03: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 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 ;
2018-06-12 01:00:58 +03:00
struct smb2_sync_hdr * shdr = ( struct smb2_sync_hdr * ) iov [ 0 ] . iov_base ;
2013-08-29 17:35:11 +04:00
struct cifs_ses * ses ;
2016-11-04 02:47:37 +03:00
ses = smb2_find_smb_ses ( server , shdr - > SessionId ) ;
2013-08-29 17:35:11 +04:00
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 ) ;
2016-10-25 01:33:04 +03:00
memset ( shdr - > Signature , 0x0 , SMB2_SIGNATURE_SIZE ) ;
2013-06-27 08:45:05 +04:00
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 ;
}
2018-02-16 21:19:27 +03:00
2018-06-12 01:00:58 +03:00
rc = __cifs_calc_signature ( rqst , server , sigptr ,
2015-11-13 06:46:49 +03:00
& server - > secmech . sdesccmacaes - > shash ) ;
2013-06-27 08:45:05 +04:00
2015-11-13 06:46:49 +03:00
if ( ! rc )
2016-10-25 01:33:04 +03:00
memcpy ( shdr - > Signature , sigptr , SMB2_SIGNATURE_SIZE ) ;
2013-06-27 08:45:05 +04:00
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 ;
2016-11-24 02:14:57 +03:00
struct smb2_sync_hdr * shdr =
2018-06-12 01:00:58 +03:00
( struct smb2_sync_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2012-09-19 03:20:30 +04:00
2016-10-25 01:33:04 +03:00
if ( ! ( shdr - > Flags & SMB2_FLAGS_SIGNED ) | |
2012-09-19 03:20:30 +04:00
server - > tcpStatus = = CifsNeedNegotiate )
return rc ;
if ( ! server - > session_estab ) {
2016-10-25 01:33:04 +03:00
strncpy ( shdr - > Signature , " BSRSPYL " , 8 ) ;
2012-09-19 03:20:30 +04:00
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 ] ;
2016-11-24 02:14:57 +03:00
struct smb2_sync_hdr * shdr =
2018-06-01 03:53:02 +03:00
( struct smb2_sync_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2012-09-19 03:20:30 +04:00
2016-10-25 01:33:04 +03:00
if ( ( shdr - > Command = = SMB2_NEGOTIATE ) | |
( shdr - > Command = = SMB2_SESSION_SETUP ) | |
( shdr - > Command = = SMB2_OPLOCK_BREAK ) | |
2012-09-19 03:20:30 +04:00
( ! 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 " */
2016-10-25 01:33:04 +03:00
if ( memcmp ( shdr - > Signature , " BSRSPYL " , 8 ) = = 0 )
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " dummy signature received for smb command 0x%x \n " ,
2016-10-25 01:33:04 +03:00
shdr - > 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 .
*/
2016-10-25 01:33:04 +03:00
memcpy ( server_response_sig , shdr - > Signature , SMB2_SIGNATURE_SIZE ) ;
2012-09-19 03:20:30 +04:00
2016-10-25 01:33:04 +03:00
memset ( shdr - > Signature , 0 , SMB2_SIGNATURE_SIZE ) ;
2012-09-19 03:20:30 +04:00
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 ;
2016-10-25 01:33:04 +03:00
if ( memcmp ( server_response_sig , shdr - > Signature , SMB2_SIGNATURE_SIZE ) )
2012-09-19 03:20:30 +04:00
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
2016-10-25 01:33:04 +03:00
smb2_seq_num_into_buf ( struct TCP_Server_Info * server ,
struct smb2_sync_hdr * shdr )
2011-12-26 22:53:34 +04:00
{
2016-10-25 01:33:04 +03:00
unsigned int i , num = le16_to_cpu ( shdr - > CreditCharge ) ;
2014-06-05 19:03:27 +04:00
2016-10-25 01:33:04 +03:00
shdr - > 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 *
2016-10-25 01:33:04 +03:00
smb2_mid_entry_alloc ( const struct smb2_sync_hdr * shdr ,
2011-12-26 22:53:34 +04:00
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 ) ;
2017-04-10 05:08:53 +03:00
memset ( temp , 0 , sizeof ( struct mid_q_entry ) ) ;
temp - > mid = le64_to_cpu ( shdr - > MessageId ) ;
temp - > pid = current - > pid ;
temp - > command = shdr - > 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 ;
2011-12-26 22:53:34 +04:00
atomic_inc ( & midCount ) ;
temp - > mid_state = MID_REQUEST_ALLOCATED ;
return temp ;
}
static int
2016-10-25 01:33:04 +03:00
smb2_get_mid_entry ( struct cifs_ses * ses , struct smb2_sync_hdr * shdr ,
2011-12-26 22:53:34 +04:00
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 ) {
2016-10-25 01:33:04 +03:00
if ( ( shdr - > Command ! = SMB2_SESSION_SETUP ) & &
( shdr - > Command ! = SMB2_NEGOTIATE ) )
2011-12-26 22:53:34 +04:00
return - EAGAIN ;
/* else ok - we are setting up session */
}
2013-10-12 19:06:03 +04:00
if ( ses - > status = = CifsExiting ) {
2016-10-25 01:33:04 +03:00
if ( shdr - > Command ! = SMB2_LOGOFF )
2013-10-12 19:06:03 +04:00
return - EAGAIN ;
/* else ok - we are shutting down the session */
}
2016-10-25 01:33:04 +03:00
* mid = smb2_mid_entry_alloc ( shdr , ses - > server ) ;
2011-12-26 22:53:34 +04:00
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 )
{
2018-04-09 11:06:28 +03:00
unsigned int len = mid - > resp_buf_size ;
2018-06-01 03:53:02 +03:00
struct kvec iov [ 1 ] ;
2016-11-24 02:14:57 +03:00
struct smb_rqst rqst = { . rq_iov = iov ,
2018-06-01 03:53:02 +03:00
. rq_nvec = 1 } ;
2012-09-19 03:20:34 +04:00
2016-11-24 02:14:57 +03:00
iov [ 0 ] . iov_base = ( char * ) mid - > resp_buf ;
2018-06-01 03:53:02 +03:00
iov [ 0 ] . iov_len = len ;
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 */
2016-11-18 02:24:46 +03:00
if ( len > 24 & & server - > sign & & ! mid - > decrypted ) {
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 ;
2016-11-24 02:14:57 +03:00
struct smb2_sync_hdr * shdr =
2018-06-12 01:00:58 +03:00
( struct smb2_sync_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2011-12-26 22:53:34 +04:00
struct mid_q_entry * mid ;
2016-10-25 01:33:04 +03:00
smb2_seq_num_into_buf ( ses - > server , shdr ) ;
2011-12-26 22:53:34 +04:00
2016-10-25 01:33:04 +03:00
rc = smb2_get_mid_entry ( ses , shdr , & mid ) ;
2011-12-26 22:53:34 +04:00
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 ;
2016-11-24 02:14:57 +03:00
struct smb2_sync_hdr * shdr =
2018-06-12 01:00:58 +03:00
( struct smb2_sync_hdr * ) rqst - > rq_iov [ 0 ] . iov_base ;
2012-07-11 14:45:28 +04:00
struct mid_q_entry * mid ;
2016-10-25 01:33:04 +03:00
smb2_seq_num_into_buf ( server , shdr ) ;
2012-07-11 14:45:28 +04:00
2016-10-25 01:33:04 +03:00
mid = smb2_mid_entry_alloc ( shdr , server ) ;
2012-07-11 14:45:28 +04:00
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
}
2016-11-04 02:47:37 +03:00
int
smb3_crypto_aead_allocate ( struct TCP_Server_Info * server )
{
struct crypto_aead * tfm ;
if ( ! server - > secmech . ccmaesencrypt ) {
tfm = crypto_alloc_aead ( " ccm(aes) " , 0 , 0 ) ;
if ( IS_ERR ( tfm ) ) {
cifs_dbg ( VFS , " %s: Failed to alloc encrypt aead \n " ,
__func__ ) ;
return PTR_ERR ( tfm ) ;
}
server - > secmech . ccmaesencrypt = tfm ;
}
if ( ! server - > secmech . ccmaesdecrypt ) {
tfm = crypto_alloc_aead ( " ccm(aes) " , 0 , 0 ) ;
if ( IS_ERR ( tfm ) ) {
crypto_free_aead ( server - > secmech . ccmaesencrypt ) ;
server - > secmech . ccmaesencrypt = NULL ;
cifs_dbg ( VFS , " %s: Failed to alloc decrypt aead \n " ,
__func__ ) ;
return PTR_ERR ( tfm ) ;
}
server - > secmech . ccmaesdecrypt = tfm ;
}
return 0 ;
}