2006-06-01 02:40:51 +04:00
/*
* fs / cifs / sess . c
*
* SMB / CIFS session setup handling routines
*
2007-07-07 23:25:05 +04:00
* Copyright ( c ) International Business Machines Corp . , 2006 , 2007
2006-06-01 02:40:51 +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 "cifspdu.h"
# include "cifsglob.h"
# include "cifsproto.h"
# include "cifs_unicode.h"
# include "cifs_debug.h"
# include "ntlmssp.h"
# include "nterr.h"
2006-06-01 09:09:10 +04:00
# include <linux/utsname.h>
2006-06-01 02:40:51 +04:00
extern void SMBNTencrypt ( unsigned char * passwd , unsigned char * c8 ,
2007-07-07 23:25:05 +04:00
unsigned char * p24 ) ;
2006-06-01 02:40:51 +04:00
static __u32 cifs_ssetup_hdr ( struct cifsSesInfo * ses , SESSION_SETUP_ANDX * pSMB )
{
__u32 capabilities = 0 ;
/* init fields common to all four types of SessSetup */
/* note that header is initialized to zero in header_assemble */
pSMB - > req . AndXCommand = 0xFF ;
pSMB - > req . MaxBufferSize = cpu_to_le16 ( ses - > server - > maxBuf ) ;
pSMB - > req . MaxMpxCount = cpu_to_le16 ( ses - > server - > maxReq ) ;
/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
2007-07-07 23:25:05 +04:00
/* BB verify whether signing required on neg or just on auth frame
2006-06-01 02:40:51 +04:00
( and NTLM case ) */
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
CAP_LARGE_WRITE_X | CAP_LARGE_READ_X ;
2007-07-07 23:25:05 +04:00
if ( ses - > server - > secMode &
( SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED ) )
2006-06-01 02:40:51 +04:00
pSMB - > req . hdr . Flags2 | = SMBFLG2_SECURITY_SIGNATURE ;
if ( ses - > capabilities & CAP_UNICODE ) {
pSMB - > req . hdr . Flags2 | = SMBFLG2_UNICODE ;
capabilities | = CAP_UNICODE ;
}
if ( ses - > capabilities & CAP_STATUS32 ) {
pSMB - > req . hdr . Flags2 | = SMBFLG2_ERR_STATUS ;
capabilities | = CAP_STATUS32 ;
}
if ( ses - > capabilities & CAP_DFS ) {
pSMB - > req . hdr . Flags2 | = SMBFLG2_DFS ;
capabilities | = CAP_DFS ;
}
if ( ses - > capabilities & CAP_UNIX ) {
capabilities | = CAP_UNIX ;
}
/* BB check whether to init vcnum BB */
return capabilities ;
}
2006-06-01 23:20:10 +04:00
static void unicode_ssetup_strings ( char * * pbcc_area , struct cifsSesInfo * ses ,
2007-07-07 23:25:05 +04:00
const struct nls_table * nls_cp )
2006-06-01 02:40:51 +04:00
{
2007-07-07 23:25:05 +04:00
char * bcc_ptr = * pbcc_area ;
2006-06-01 02:40:51 +04:00
int bytes_ret = 0 ;
/* BB FIXME add check that strings total less
than 335 or will need to send them as arrays */
2006-06-27 23:50:57 +04:00
/* unicode strings, must be word aligned before the call */
/* if ((long) bcc_ptr % 2) {
2006-06-01 02:40:51 +04:00
* bcc_ptr = 0 ;
bcc_ptr + + ;
2006-06-27 23:50:57 +04:00
} */
2006-06-01 02:40:51 +04:00
/* copy user */
2007-07-07 23:25:05 +04:00
if ( ses - > userName = = NULL ) {
2006-11-09 02:10:46 +03:00
/* null user mount */
* bcc_ptr = 0 ;
* ( bcc_ptr + 1 ) = 0 ;
2006-06-01 02:40:51 +04:00
} else { /* 300 should be long enough for any conceivable user name */
bytes_ret = cifs_strtoUCS ( ( __le16 * ) bcc_ptr , ses - > userName ,
300 , nls_cp ) ;
}
bcc_ptr + = 2 * bytes_ret ;
bcc_ptr + = 2 ; /* account for null termination */
/* copy domain */
2007-07-07 23:25:05 +04:00
if ( ses - > domainName = = NULL ) {
2006-11-09 02:10:46 +03:00
/* Sending null domain better than using a bogus domain name (as
we did briefly in 2.6 .18 ) since server will use its default */
* bcc_ptr = 0 ;
* ( bcc_ptr + 1 ) = 0 ;
bytes_ret = 0 ;
} else
2006-06-01 02:40:51 +04:00
bytes_ret = cifs_strtoUCS ( ( __le16 * ) bcc_ptr , ses - > domainName ,
256 , nls_cp ) ;
bcc_ptr + = 2 * bytes_ret ;
bcc_ptr + = 2 ; /* account for null terminator */
/* Copy OS version */
bytes_ret = cifs_strtoUCS ( ( __le16 * ) bcc_ptr , " Linux version " , 32 ,
nls_cp ) ;
bcc_ptr + = 2 * bytes_ret ;
2006-10-02 13:18:13 +04:00
bytes_ret = cifs_strtoUCS ( ( __le16 * ) bcc_ptr , init_utsname ( ) - > release ,
2006-06-01 02:40:51 +04:00
32 , nls_cp ) ;
bcc_ptr + = 2 * bytes_ret ;
bcc_ptr + = 2 ; /* trailing null */
bytes_ret = cifs_strtoUCS ( ( __le16 * ) bcc_ptr , CIFS_NETWORK_OPSYS ,
2007-07-07 23:25:05 +04:00
32 , nls_cp ) ;
2006-06-01 02:40:51 +04:00
bcc_ptr + = 2 * bytes_ret ;
bcc_ptr + = 2 ; /* trailing null */
* pbcc_area = bcc_ptr ;
}
2006-06-01 23:20:10 +04:00
static void ascii_ssetup_strings ( char * * pbcc_area , struct cifsSesInfo * ses ,
2007-07-07 23:25:05 +04:00
const struct nls_table * nls_cp )
2006-06-01 02:40:51 +04:00
{
2007-07-07 23:25:05 +04:00
char * bcc_ptr = * pbcc_area ;
2006-06-01 02:40:51 +04:00
/* copy user */
/* BB what about null user mounts - check that we do this BB */
2007-07-07 23:25:05 +04:00
/* copy user */
if ( ses - > userName = = NULL ) {
/* BB what about null user mounts - check that we do this BB */
} else { /* 300 should be long enough for any conceivable user name */
strncpy ( bcc_ptr , ses - > userName , 300 ) ;
}
2006-06-01 02:40:51 +04:00
/* BB improve check for overflow */
2007-07-07 23:25:05 +04:00
bcc_ptr + = strnlen ( ses - > userName , 300 ) ;
2006-06-01 02:40:51 +04:00
* bcc_ptr = 0 ;
2007-07-07 23:25:05 +04:00
bcc_ptr + + ; /* account for null termination */
2006-06-01 02:40:51 +04:00
2007-07-07 23:25:05 +04:00
/* copy domain */
if ( ses - > domainName ! = NULL ) {
strncpy ( bcc_ptr , ses - > domainName , 256 ) ;
2006-06-01 02:40:51 +04:00
bcc_ptr + = strnlen ( ses - > domainName , 256 ) ;
2007-07-07 23:25:05 +04:00
} /* else we will send a null domain name
2006-11-09 02:10:46 +03:00
so the server will default to its own domain */
2006-06-01 02:40:51 +04:00
* bcc_ptr = 0 ;
bcc_ptr + + ;
/* BB check for overflow here */
strcpy ( bcc_ptr , " Linux version " ) ;
bcc_ptr + = strlen ( " Linux version " ) ;
2006-10-02 13:18:13 +04:00
strcpy ( bcc_ptr , init_utsname ( ) - > release ) ;
bcc_ptr + = strlen ( init_utsname ( ) - > release ) + 1 ;
2006-06-01 02:40:51 +04:00
strcpy ( bcc_ptr , CIFS_NETWORK_OPSYS ) ;
bcc_ptr + = strlen ( CIFS_NETWORK_OPSYS ) + 1 ;
2007-07-07 23:25:05 +04:00
* pbcc_area = bcc_ptr ;
2006-06-01 02:40:51 +04:00
}
2007-07-07 23:25:05 +04:00
static int decode_unicode_ssetup ( char * * pbcc_area , int bleft ,
struct cifsSesInfo * ses ,
const struct nls_table * nls_cp )
2006-06-01 02:40:51 +04:00
{
int rc = 0 ;
int words_left , len ;
2007-07-07 23:25:05 +04:00
char * data = * pbcc_area ;
2006-06-01 02:40:51 +04:00
2007-07-07 23:25:05 +04:00
cFYI ( 1 , ( " bleft %d " , bleft ) ) ;
2006-06-01 02:40:51 +04:00
2007-01-22 04:19:30 +03:00
/* SMB header is unaligned, so cifs servers word align start of
Unicode strings */
data + + ;
bleft - - ; /* Windows servers do not always double null terminate
their final Unicode string - in which case we
now will not attempt to decode the byte of junk
which follows it */
2006-06-01 02:40:51 +04:00
words_left = bleft / 2 ;
/* save off server operating system */
len = UniStrnlen ( ( wchar_t * ) data , words_left ) ;
/* We look for obvious messed up bcc or strings in response so we do not go off
the end since ( at least ) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
2007-07-07 23:25:05 +04:00
if ( len > = words_left )
2006-06-01 02:40:51 +04:00
return rc ;
2007-07-07 23:25:05 +04:00
if ( ses - > serverOS )
2006-06-01 02:40:51 +04:00
kfree ( ses - > serverOS ) ;
/* UTF-8 string will not grow more than four times as big as UCS-16 */
ses - > serverOS = kzalloc ( 4 * len , GFP_KERNEL ) ;
2007-07-07 23:25:05 +04:00
if ( ses - > serverOS ! = NULL ) {
2006-06-01 02:40:51 +04:00
cifs_strfromUCS_le ( ses - > serverOS , ( __le16 * ) data , len ,
nls_cp ) ;
}
data + = 2 * ( len + 1 ) ;
words_left - = len + 1 ;
/* save off server network operating system */
len = UniStrnlen ( ( wchar_t * ) data , words_left ) ;
2007-07-07 23:25:05 +04:00
if ( len > = words_left )
2006-06-01 02:40:51 +04:00
return rc ;
2007-07-07 23:25:05 +04:00
if ( ses - > serverNOS )
2006-06-01 02:40:51 +04:00
kfree ( ses - > serverNOS ) ;
ses - > serverNOS = kzalloc ( 4 * len , GFP_KERNEL ) ; /* BB this is wrong length FIXME BB */
2007-07-07 23:25:05 +04:00
if ( ses - > serverNOS ! = NULL ) {
2006-06-01 02:40:51 +04:00
cifs_strfromUCS_le ( ses - > serverNOS , ( __le16 * ) data , len ,
nls_cp ) ;
2007-07-07 23:25:05 +04:00
if ( strncmp ( ses - > serverNOS , " NT LAN Manager 4 " , 16 ) = = 0 ) {
cFYI ( 1 , ( " NT4 server " ) ) ;
2006-06-01 02:40:51 +04:00
ses - > flags | = CIFS_SES_NT4 ;
}
}
data + = 2 * ( len + 1 ) ;
words_left - = len + 1 ;
2007-07-07 23:25:05 +04:00
/* save off server domain */
len = UniStrnlen ( ( wchar_t * ) data , words_left ) ;
if ( len > words_left )
return rc ;
if ( ses - > serverDomain )
kfree ( ses - > serverDomain ) ;
ses - > serverDomain = kzalloc ( 2 * ( len + 1 ) , GFP_KERNEL ) ; /* BB FIXME wrong length */
if ( ses - > serverDomain ! = NULL ) {
cifs_strfromUCS_le ( ses - > serverDomain , ( __le16 * ) data , len ,
nls_cp ) ;
ses - > serverDomain [ 2 * len ] = 0 ;
ses - > serverDomain [ ( 2 * len ) + 1 ] = 0 ;
}
data + = 2 * ( len + 1 ) ;
words_left - = len + 1 ;
cFYI ( 1 , ( " words left: %d " , words_left ) ) ;
2006-06-01 02:40:51 +04:00
return rc ;
}
2007-07-07 23:25:05 +04:00
static int decode_ascii_ssetup ( char * * pbcc_area , int bleft ,
struct cifsSesInfo * ses ,
const struct nls_table * nls_cp )
2006-06-01 02:40:51 +04:00
{
int rc = 0 ;
int len ;
2007-07-07 23:25:05 +04:00
char * bcc_ptr = * pbcc_area ;
2006-06-01 02:40:51 +04:00
2007-07-07 23:25:05 +04:00
cFYI ( 1 , ( " decode sessetup ascii. bleft %d " , bleft ) ) ;
2006-06-01 02:40:51 +04:00
len = strnlen ( bcc_ptr , bleft ) ;
2007-07-07 23:25:05 +04:00
if ( len > = bleft )
2006-06-01 02:40:51 +04:00
return rc ;
2007-07-07 23:25:05 +04:00
if ( ses - > serverOS )
2006-06-01 02:40:51 +04:00
kfree ( ses - > serverOS ) ;
ses - > serverOS = kzalloc ( len + 1 , GFP_KERNEL ) ;
2007-07-07 23:25:05 +04:00
if ( ses - > serverOS )
2006-06-01 02:40:51 +04:00
strncpy ( ses - > serverOS , bcc_ptr , len ) ;
2007-07-07 23:25:05 +04:00
if ( strncmp ( ses - > serverOS , " OS/2 " , 4 ) = = 0 ) {
cFYI ( 1 , ( " OS/2 server " ) ) ;
2006-09-30 08:13:17 +04:00
ses - > flags | = CIFS_SES_OS2 ;
}
2006-06-01 02:40:51 +04:00
bcc_ptr + = len + 1 ;
bleft - = len + 1 ;
len = strnlen ( bcc_ptr , bleft ) ;
2007-07-07 23:25:05 +04:00
if ( len > = bleft )
2006-06-01 02:40:51 +04:00
return rc ;
2007-07-07 23:25:05 +04:00
if ( ses - > serverNOS )
2006-06-01 02:40:51 +04:00
kfree ( ses - > serverNOS ) ;
ses - > serverNOS = kzalloc ( len + 1 , GFP_KERNEL ) ;
2007-07-07 23:25:05 +04:00
if ( ses - > serverNOS )
2006-06-01 02:40:51 +04:00
strncpy ( ses - > serverNOS , bcc_ptr , len ) ;
bcc_ptr + = len + 1 ;
bleft - = len + 1 ;
2007-07-07 23:25:05 +04:00
len = strnlen ( bcc_ptr , bleft ) ;
if ( len > bleft )
return rc ;
2006-06-01 02:40:51 +04:00
2006-09-30 08:13:17 +04:00
/* No domain field in LANMAN case. Domain is
returned by old servers in the SMB negprot response */
/* BB For newer servers which do not support Unicode,
but thus do return domain here we could add parsing
for it later , but it is not very important */
2007-07-07 23:25:05 +04:00
cFYI ( 1 , ( " ascii: bytes left %d " , bleft ) ) ;
2006-06-01 02:40:51 +04:00
return rc ;
}
2007-07-07 23:25:05 +04:00
int
2006-06-01 02:40:51 +04:00
CIFS_SessSetup ( unsigned int xid , struct cifsSesInfo * ses , int first_time ,
const struct nls_table * nls_cp )
{
int rc = 0 ;
int wct ;
struct smb_hdr * smb_buf ;
char * bcc_ptr ;
2006-06-27 10:28:30 +04:00
char * str_area ;
2006-06-01 02:40:51 +04:00
SESSION_SETUP_ANDX * pSMB ;
__u32 capabilities ;
int count ;
int resp_buf_type = 0 ;
2006-06-27 10:28:30 +04:00
struct kvec iov [ 2 ] ;
2006-06-01 02:40:51 +04:00
enum securityEnum type ;
__u16 action ;
int bytes_remaining ;
2006-06-04 09:53:15 +04:00
2007-07-07 23:25:05 +04:00
if ( ses = = NULL )
2006-06-01 02:40:51 +04:00
return - EINVAL ;
type = ses - > server - > secType ;
2006-06-28 04:13:38 +04:00
2007-07-07 23:25:05 +04:00
cFYI ( 1 , ( " sess setup type %d " , type ) ) ;
if ( type = = LANMAN ) {
2006-06-01 02:40:51 +04:00
# ifndef CONFIG_CIFS_WEAK_PW_HASH
/* LANMAN and plaintext are less secure and off by default.
So we make this explicitly be turned on in kconfig ( in the
build ) and turned on at runtime ( changed from the default )
in proc / fs / cifs or via mount parm . Unfortunately this is
needed for old Win ( e . g . Win95 ) , some obscure NAS and OS / 2 */
return - EOPNOTSUPP ;
# endif
wct = 10 ; /* lanman 2 style sessionsetup */
2007-07-07 23:25:05 +04:00
} else if ( ( type = = NTLM ) | | ( type = = NTLMv2 ) ) {
2006-06-05 02:21:07 +04:00
/* For NTLMv2 failures eventually may need to retry NTLM */
2006-06-01 02:40:51 +04:00
wct = 13 ; /* old style NTLM sessionsetup */
2007-07-07 23:25:05 +04:00
} else /* same size: negotiate or auth, NTLMSSP or extended security */
2006-06-01 02:40:51 +04:00
wct = 12 ;
rc = small_smb_init_no_tc ( SMB_COM_SESSION_SETUP_ANDX , wct , ses ,
( void * * ) & smb_buf ) ;
2007-07-07 23:25:05 +04:00
if ( rc )
2006-06-01 02:40:51 +04:00
return rc ;
pSMB = ( SESSION_SETUP_ANDX * ) smb_buf ;
capabilities = cifs_ssetup_hdr ( ses , pSMB ) ;
2006-06-27 10:28:30 +04:00
/* we will send the SMB in two pieces,
a fixed length beginning part , and a
second part which will include the strings
and rest of bcc area , in order to avoid having
to do a large buffer 17 K allocation */
2007-07-07 23:25:05 +04:00
iov [ 0 ] . iov_base = ( char * ) pSMB ;
iov [ 0 ] . iov_len = smb_buf - > smb_buf_length + 4 ;
2006-06-27 10:28:30 +04:00
/* 2000 big enough to fit max user, domain, NOS name etc. */
str_area = kmalloc ( 2000 , GFP_KERNEL ) ;
bcc_ptr = str_area ;
2006-06-01 02:40:51 +04:00
2006-09-30 08:13:17 +04:00
ses - > flags & = ~ CIFS_SES_LANMAN ;
2007-07-07 23:25:05 +04:00
if ( type = = LANMAN ) {
2006-06-01 02:40:51 +04:00
# ifdef CONFIG_CIFS_WEAK_PW_HASH
2006-06-01 23:20:10 +04:00
char lnm_session_key [ CIFS_SESS_KEY_SIZE ] ;
2006-06-01 02:40:51 +04:00
/* no capabilities flags in old lanman negotiation */
2007-07-07 23:25:05 +04:00
pSMB - > old_req . PasswordLength = cpu_to_le16 ( CIFS_SESS_KEY_SIZE ) ;
2006-06-01 02:40:51 +04:00
/* BB calculate hash with password */
/* and copy into bcc */
2006-06-01 23:20:10 +04:00
calc_lanman_hash ( ses , lnm_session_key ) ;
2007-07-07 23:25:05 +04:00
ses - > flags | = CIFS_SES_LANMAN ;
2006-06-27 10:28:30 +04:00
/* #ifdef CONFIG_CIFS_DEBUG2
2006-06-01 02:40:51 +04:00
cifs_dump_mem ( " cryptkey: " , ses - > server - > cryptKey ,
2006-06-01 23:20:10 +04:00
CIFS_SESS_KEY_SIZE ) ;
2006-06-27 10:28:30 +04:00
# endif * /
2006-06-01 23:20:10 +04:00
memcpy ( bcc_ptr , ( char * ) lnm_session_key , CIFS_SESS_KEY_SIZE ) ;
bcc_ptr + = CIFS_SESS_KEY_SIZE ;
2006-06-01 02:40:51 +04:00
/* can not sign if LANMAN negotiated so no need
to calculate signing key ? but what if server
changed to do higher than lanman dialect and
we reconnected would we ever calc signing_key ? */
2007-07-07 23:25:05 +04:00
cFYI ( 1 , ( " Negotiating LANMAN setting up strings " ) ) ;
2006-06-01 02:40:51 +04:00
/* Unicode not allowed for LANMAN dialects */
ascii_ssetup_strings ( & bcc_ptr , ses , nls_cp ) ;
2007-07-07 23:25:05 +04:00
# endif
2006-06-01 02:40:51 +04:00
} else if ( type = = NTLM ) {
2006-06-01 23:20:10 +04:00
char ntlm_session_key [ CIFS_SESS_KEY_SIZE ] ;
2006-06-01 02:40:51 +04:00
pSMB - > req_no_secext . Capabilities = cpu_to_le32 ( capabilities ) ;
pSMB - > req_no_secext . CaseInsensitivePasswordLength =
2006-06-01 23:20:10 +04:00
cpu_to_le16 ( CIFS_SESS_KEY_SIZE ) ;
2006-06-01 02:40:51 +04:00
pSMB - > req_no_secext . CaseSensitivePasswordLength =
2006-06-01 23:20:10 +04:00
cpu_to_le16 ( CIFS_SESS_KEY_SIZE ) ;
2006-06-01 02:40:51 +04:00
/* calculate session key */
SMBNTencrypt ( ses - > password , ses - > server - > cryptKey ,
ntlm_session_key ) ;
2007-07-07 23:25:05 +04:00
if ( first_time ) /* should this be moved into common code
2006-06-01 02:40:51 +04:00
with similar ntlmv2 path ? */
2006-06-27 10:28:30 +04:00
cifs_calculate_mac_key ( ses - > server - > mac_signing_key ,
2006-06-01 02:40:51 +04:00
ntlm_session_key , ses - > password ) ;
/* copy session key */
2007-07-07 23:25:05 +04:00
memcpy ( bcc_ptr , ( char * ) ntlm_session_key , CIFS_SESS_KEY_SIZE ) ;
2006-06-01 23:20:10 +04:00
bcc_ptr + = CIFS_SESS_KEY_SIZE ;
2007-07-07 23:25:05 +04:00
memcpy ( bcc_ptr , ( char * ) ntlm_session_key , CIFS_SESS_KEY_SIZE ) ;
2006-06-01 23:20:10 +04:00
bcc_ptr + = CIFS_SESS_KEY_SIZE ;
2007-07-07 23:25:05 +04:00
if ( ses - > capabilities & CAP_UNICODE ) {
2006-06-27 23:50:57 +04:00
/* unicode strings must be word aligned */
if ( iov [ 0 ] . iov_len % 2 ) {
* bcc_ptr = 0 ;
2007-07-07 23:25:05 +04:00
bcc_ptr + + ;
}
2006-06-01 23:20:10 +04:00
unicode_ssetup_strings ( & bcc_ptr , ses , nls_cp ) ;
2006-06-27 23:50:57 +04:00
} else
2006-06-01 23:20:10 +04:00
ascii_ssetup_strings ( & bcc_ptr , ses , nls_cp ) ;
} else if ( type = = NTLMv2 ) {
2007-07-07 23:25:05 +04:00
char * v2_sess_key =
2006-06-05 20:26:05 +04:00
kmalloc ( sizeof ( struct ntlmv2_resp ) , GFP_KERNEL ) ;
2006-06-05 09:27:37 +04:00
/* BB FIXME change all users of v2_sess_key to
struct ntlmv2_resp */
2006-06-01 23:20:10 +04:00
2007-07-07 23:25:05 +04:00
if ( v2_sess_key = = NULL ) {
2006-06-01 23:20:10 +04:00
cifs_small_buf_release ( smb_buf ) ;
return - ENOMEM ;
}
pSMB - > req_no_secext . Capabilities = cpu_to_le32 ( capabilities ) ;
/* LM2 password would be here if we supported it */
pSMB - > req_no_secext . CaseInsensitivePasswordLength = 0 ;
/* cpu_to_le16(LM2_SESS_KEY_SIZE); */
pSMB - > req_no_secext . CaseSensitivePasswordLength =
2006-06-05 09:27:37 +04:00
cpu_to_le16 ( sizeof ( struct ntlmv2_resp ) ) ;
2006-06-01 23:20:10 +04:00
/* calculate session key */
2006-06-08 09:41:32 +04:00
setup_ntlmv2_rsp ( ses , v2_sess_key , nls_cp ) ;
2007-07-07 23:25:05 +04:00
if ( first_time ) /* should this be moved into common code
with similar ntlmv2 path ? */
2006-06-01 23:20:10 +04:00
/* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
response BB FIXME , v2_sess_key ) ; */
/* copy session key */
/* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
bcc_ptr + = LM2_SESS_KEY_SIZE ; */
2006-06-05 09:27:37 +04:00
memcpy ( bcc_ptr , ( char * ) v2_sess_key , sizeof ( struct ntlmv2_resp ) ) ;
bcc_ptr + = sizeof ( struct ntlmv2_resp ) ;
kfree ( v2_sess_key ) ;
2007-07-07 23:25:05 +04:00
if ( ses - > capabilities & CAP_UNICODE ) {
if ( iov [ 0 ] . iov_len % 2 ) {
2006-06-27 23:50:57 +04:00
* bcc_ptr = 0 ;
} bcc_ptr + + ;
2006-06-01 02:40:51 +04:00
unicode_ssetup_strings ( & bcc_ptr , ses , nls_cp ) ;
2006-06-27 23:50:57 +04:00
} else
2006-06-01 02:40:51 +04:00
ascii_ssetup_strings ( & bcc_ptr , ses , nls_cp ) ;
} else /* NTLMSSP or SPNEGO */ {
pSMB - > req . hdr . Flags2 | = SMBFLG2_EXT_SEC ;
capabilities | = CAP_EXTENDED_SECURITY ;
pSMB - > req . Capabilities = cpu_to_le32 ( capabilities ) ;
/* BB set password lengths */
}
2006-06-27 10:28:30 +04:00
count = ( long ) bcc_ptr - ( long ) str_area ;
2006-06-01 02:40:51 +04:00
smb_buf - > smb_buf_length + = count ;
BCC_LE ( smb_buf ) = cpu_to_le16 ( count ) ;
2006-06-27 10:28:30 +04:00
iov [ 1 ] . iov_base = str_area ;
2007-07-07 23:25:05 +04:00
iov [ 1 ] . iov_len = count ;
2006-06-27 10:28:30 +04:00
rc = SendReceive2 ( xid , ses , iov , 2 /* num_iovecs */ , & resp_buf_type , 0 ) ;
2006-06-01 02:40:51 +04:00
/* SMB request buf freed in SendReceive2 */
2007-07-07 23:25:05 +04:00
cFYI ( 1 , ( " ssetup rc from sendrecv2 is %d " , rc ) ) ;
if ( rc )
2006-06-01 02:40:51 +04:00
goto ssetup_exit ;
pSMB = ( SESSION_SETUP_ANDX * ) iov [ 0 ] . iov_base ;
smb_buf = ( struct smb_hdr * ) iov [ 0 ] . iov_base ;
2007-07-07 23:25:05 +04:00
if ( ( smb_buf - > WordCount ! = 3 ) & & ( smb_buf - > WordCount ! = 4 ) ) {
2006-06-01 02:40:51 +04:00
rc = - EIO ;
2007-07-07 23:25:05 +04:00
cERROR ( 1 , ( " bad word count %d " , smb_buf - > WordCount ) ) ;
2006-06-01 02:40:51 +04:00
goto ssetup_exit ;
}
action = le16_to_cpu ( pSMB - > resp . Action ) ;
if ( action & GUEST_LOGIN )
2006-06-23 06:33:48 +04:00
cFYI ( 1 , ( " Guest login " ) ) ; /* BB mark SesInfo struct? */
2006-06-01 02:40:51 +04:00
ses - > Suid = smb_buf - > Uid ; /* UID left in wire format (le) */
cFYI ( 1 , ( " UID = %d " , ses - > Suid ) ) ;
/* response can have either 3 or 4 word count - Samba sends 3 */
/* and lanman response is 3 */
bytes_remaining = BCC ( smb_buf ) ;
bcc_ptr = pByteArea ( smb_buf ) ;
2007-07-07 23:25:05 +04:00
if ( smb_buf - > WordCount = = 4 ) {
2006-06-01 02:40:51 +04:00
__u16 blob_len ;
blob_len = le16_to_cpu ( pSMB - > resp . SecurityBlobLength ) ;
bcc_ptr + = blob_len ;
2007-07-07 23:25:05 +04:00
if ( blob_len > bytes_remaining ) {
cERROR ( 1 , ( " bad security blob length %d " , blob_len ) ) ;
2006-06-01 02:40:51 +04:00
rc = - EINVAL ;
goto ssetup_exit ;
}
bytes_remaining - = blob_len ;
2007-07-07 23:25:05 +04:00
}
2006-06-01 02:40:51 +04:00
/* BB check if Unicode and decode strings */
2007-07-07 23:25:05 +04:00
if ( smb_buf - > Flags2 & SMBFLG2_UNICODE )
2006-06-01 02:40:51 +04:00
rc = decode_unicode_ssetup ( & bcc_ptr , bytes_remaining ,
ses , nls_cp ) ;
else
rc = decode_ascii_ssetup ( & bcc_ptr , bytes_remaining , ses , nls_cp ) ;
ssetup_exit :
2006-06-27 10:28:30 +04:00
kfree ( str_area ) ;
2007-07-07 23:25:05 +04:00
if ( resp_buf_type = = CIFS_SMALL_BUFFER ) {
cFYI ( 1 , ( " ssetup freeing small buf %p " , iov [ 0 ] . iov_base ) ) ;
2006-06-01 02:40:51 +04:00
cifs_small_buf_release ( iov [ 0 ] . iov_base ) ;
2007-07-07 23:25:05 +04:00
} else if ( resp_buf_type = = CIFS_LARGE_BUFFER )
2006-06-01 02:40:51 +04:00
cifs_buf_release ( iov [ 0 ] . iov_base ) ;
return rc ;
}