2005-04-17 02:20:36 +04:00
/*
* fs / cifs / connect . c
*
2007-06-24 22:30:48 +04:00
* Copyright ( C ) International Business Machines Corp . , 2002 , 2007
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
2007-07-10 05:16:18 +04:00
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2005-04-17 02:20:36 +04:00
*/
# include <linux/fs.h>
# include <linux/net.h>
# include <linux/string.h>
# include <linux/list.h>
# include <linux/wait.h>
# include <linux/ipv6.h>
# include <linux/pagemap.h>
# include <linux/ctype.h>
# include <linux/utsname.h>
# include <linux/mempool.h>
2005-04-29 09:41:07 +04:00
# include <linux/delay.h>
2005-08-18 20:37:34 +04:00
# include <linux/completion.h>
2007-04-03 23:16:43 +04:00
# include <linux/kthread.h>
2005-10-10 21:57:19 +04:00
# include <linux/pagevec.h>
2006-12-07 07:34:23 +03:00
# include <linux/freezer.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <asm/processor.h>
# include "cifspdu.h"
# include "cifsglob.h"
# include "cifsproto.h"
# include "cifs_unicode.h"
# include "cifs_debug.h"
# include "cifs_fs_sb.h"
# include "ntlmssp.h"
# include "nterr.h"
# include "rfc1002pdu.h"
2005-11-11 02:33:38 +03:00
# include "cn_cifs.h"
2005-04-17 02:20:36 +04:00
# define CIFS_PORT 445
# define RFC1001_PORT 139
2005-08-18 20:37:34 +04:00
static DECLARE_COMPLETION ( cifsd_complete ) ;
2005-04-17 02:20:36 +04:00
extern void SMBNTencrypt ( unsigned char * passwd , unsigned char * c8 ,
unsigned char * p24 ) ;
extern mempool_t * cifs_req_poolp ;
struct smb_vol {
char * username ;
char * password ;
char * domainname ;
char * UNC ;
char * UNCip ;
char * in6_addr ; /* ipv6 address as human readable form of in6_addr */
char * iocharset ; /* local code page for mapping to and from Unicode */
char source_rfc1001_name [ 16 ] ; /* netbios name of client */
2005-08-23 08:38:31 +04:00
char target_rfc1001_name [ 16 ] ; /* netbios name of server for Win9x/ME */
2005-04-17 02:20:36 +04:00
uid_t linux_uid ;
gid_t linux_gid ;
mode_t file_mode ;
mode_t dir_mode ;
2006-06-23 06:33:48 +04:00
unsigned secFlg ;
2005-04-17 02:20:36 +04:00
unsigned rw : 1 ;
unsigned retry : 1 ;
unsigned intr : 1 ;
unsigned setuids : 1 ;
2007-05-01 00:13:06 +04:00
unsigned override_uid : 1 ;
unsigned override_gid : 1 ;
2005-04-17 02:20:36 +04:00
unsigned noperm : 1 ;
unsigned no_psx_acl : 1 ; /* set if posix acl support should be disabled */
2006-01-13 02:44:21 +03:00
unsigned cifs_acl : 1 ;
2005-04-17 02:20:36 +04:00
unsigned no_xattr : 1 ; /* set if xattr (EA) support should be disabled*/
unsigned server_ino : 1 ; /* use inode numbers from server ie UniqueId */
unsigned direct_io : 1 ;
2005-04-29 09:41:05 +04:00
unsigned remap : 1 ; /* set to remap seven reserved chars in filenames */
2005-06-23 04:26:35 +04:00
unsigned posix_paths : 1 ; /* unset to not ask for posix pathnames. */
2007-07-19 03:21:09 +04:00
unsigned no_linux_ext : 1 ;
2005-07-15 03:25:12 +04:00
unsigned sfu_emul : 1 ;
2005-12-02 09:32:42 +03:00
unsigned nullauth : 1 ; /* attempt to authenticate with null user */
2005-08-19 07:49:57 +04:00
unsigned nocase ; /* request case insensitive filenames */
unsigned nobrl ; /* disable sending byte range locks to srv */
2005-04-17 02:20:36 +04:00
unsigned int rsize ;
unsigned int wsize ;
unsigned int sockopt ;
unsigned short int port ;
2007-07-10 05:16:18 +04:00
char * prepath ;
2005-04-17 02:20:36 +04:00
} ;
2007-07-10 05:16:18 +04:00
static int ipv4_connect ( struct sockaddr_in * psin_server ,
2005-04-17 02:20:36 +04:00
struct socket * * csocket ,
2007-07-10 05:16:18 +04:00
char * netb_name ,
char * server_netb_name ) ;
static int ipv6_connect ( struct sockaddr_in6 * psin_server ,
2005-04-17 02:20:36 +04:00
struct socket * * csocket ) ;
2007-07-10 05:16:18 +04:00
/*
2005-04-17 02:20:36 +04:00
* cifs tcp session reconnection
2007-07-10 05:16:18 +04:00
*
2005-04-17 02:20:36 +04:00
* mark tcp session as reconnecting so temporarily locked
* mark all smb sessions as reconnecting for tcp session
* reconnect tcp session
* wake up waiters on reconnection ? - ( not needed currently )
*/
2006-09-28 23:43:08 +04:00
static int
2005-04-17 02:20:36 +04:00
cifs_reconnect ( struct TCP_Server_Info * server )
{
int rc = 0 ;
struct list_head * tmp ;
struct cifsSesInfo * ses ;
struct cifsTconInfo * tcon ;
2007-07-10 05:16:18 +04:00
struct mid_q_entry * mid_entry ;
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
spin_lock ( & GlobalMid_Lock ) ;
2007-08-31 02:09:15 +04:00
if ( kthread_should_stop ( ) ) {
2007-07-10 05:16:18 +04:00
/* the demux thread will exit normally
2005-04-17 02:20:36 +04:00
next time through the loop */
spin_unlock ( & GlobalMid_Lock ) ;
return rc ;
} else
server - > tcpStatus = CifsNeedReconnect ;
spin_unlock ( & GlobalMid_Lock ) ;
server - > maxBuf = 0 ;
2005-04-29 09:41:09 +04:00
cFYI ( 1 , ( " Reconnecting tcp session " ) ) ;
2005-04-17 02:20:36 +04:00
/* before reconnecting the tcp session, mark the smb session (uid)
and the tid bad so they are not used until reconnected */
read_lock ( & GlobalSMBSeslock ) ;
list_for_each ( tmp , & GlobalSMBSessionList ) {
ses = list_entry ( tmp , struct cifsSesInfo , cifsSessionList ) ;
if ( ses - > server ) {
if ( ses - > server = = server ) {
ses - > status = CifsNeedReconnect ;
ses - > ipc_tid = 0 ;
}
}
/* else tcp and smb sessions need reconnection */
}
list_for_each ( tmp , & GlobalTreeConnectionList ) {
tcon = list_entry ( tmp , struct cifsTconInfo , cifsConnectionList ) ;
2007-08-31 02:09:15 +04:00
if ( ( tcon ) & & ( tcon - > ses ) & & ( tcon - > ses - > server = = server ) )
2005-04-17 02:20:36 +04:00
tcon - > tidStatus = CifsNeedReconnect ;
}
read_unlock ( & GlobalSMBSeslock ) ;
/* do not want to be sending data on a socket we are freeing */
2007-07-10 05:16:18 +04:00
down ( & server - > tcpSem ) ;
if ( server - > ssocket ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " State: 0x%x Flags: 0x%lx " , server - > ssocket - > state ,
2005-04-17 02:20:36 +04:00
server - > ssocket - > flags ) ) ;
2007-07-10 05:16:18 +04:00
server - > ssocket - > ops - > shutdown ( server - > ssocket , SEND_SHUTDOWN ) ;
cFYI ( 1 , ( " Post shutdown state: 0x%x Flags: 0x%lx " ,
2007-06-28 02:41:32 +04:00
server - > ssocket - > state ,
2005-04-17 02:20:36 +04:00
server - > ssocket - > flags ) ) ;
sock_release ( server - > ssocket ) ;
server - > ssocket = NULL ;
}
spin_lock ( & GlobalMid_Lock ) ;
list_for_each ( tmp , & server - > pending_mid_q ) {
mid_entry = list_entry ( tmp , struct
mid_q_entry ,
qhead ) ;
2007-07-10 05:16:18 +04:00
if ( mid_entry ) {
if ( mid_entry - > midState = = MID_REQUEST_SUBMITTED ) {
2005-04-29 09:41:08 +04:00
/* Mark other intransit requests as needing
retry so we do not immediately mark the
session bad again ( ie after we reconnect
below ) as they timeout too */
2005-04-17 02:20:36 +04:00
mid_entry - > midState = MID_RETRY_NEEDED ;
}
}
}
spin_unlock ( & GlobalMid_Lock ) ;
2007-07-10 05:16:18 +04:00
up ( & server - > tcpSem ) ;
2005-04-17 02:20:36 +04:00
2007-08-31 02:09:15 +04:00
while ( ( ! kthread_should_stop ( ) ) & & ( server - > tcpStatus ! = CifsGood ) ) {
2006-08-01 02:46:20 +04:00
try_to_freeze ( ) ;
2007-07-10 05:16:18 +04:00
if ( server - > protocolType = = IPV6 ) {
rc = ipv6_connect ( & server - > addr . sockAddr6 ,
& server - > ssocket ) ;
2005-04-17 02:20:36 +04:00
} else {
2007-07-10 05:16:18 +04:00
rc = ipv4_connect ( & server - > addr . sockAddr ,
2005-04-17 02:20:36 +04:00
& server - > ssocket ,
2005-08-23 08:38:31 +04:00
server - > workstation_RFC1001_name ,
server - > server_RFC1001_name ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-10 05:16:18 +04:00
if ( rc ) {
cFYI ( 1 , ( " reconnect error %d " , rc ) ) ;
2005-04-29 09:41:11 +04:00
msleep ( 3000 ) ;
2005-04-17 02:20:36 +04:00
} else {
atomic_inc ( & tcpSesReconnectCount ) ;
spin_lock ( & GlobalMid_Lock ) ;
2007-08-31 02:09:15 +04:00
if ( ! kthread_should_stop ( ) )
2005-04-17 02:20:36 +04:00
server - > tcpStatus = CifsGood ;
2005-04-29 09:41:05 +04:00
server - > sequence_number = 0 ;
2007-07-10 05:16:18 +04:00
spin_unlock ( & GlobalMid_Lock ) ;
2005-04-17 02:20:36 +04:00
/* atomic_set(&server->inFlight,0);*/
wake_up ( & server - > response_q ) ;
}
}
return rc ;
}
2007-07-10 05:16:18 +04:00
/*
2005-04-29 09:41:09 +04:00
return codes :
0 not a transact2 , or all data present
> 0 transact2 with that much data missing
- EINVAL = invalid transact2
*/
2007-07-10 05:16:18 +04:00
static int check2ndT2 ( struct smb_hdr * pSMB , unsigned int maxBufSize )
2005-04-29 09:41:09 +04:00
{
2007-07-10 05:16:18 +04:00
struct smb_t2_rsp * pSMBt ;
int total_data_size ;
2005-04-29 09:41:09 +04:00
int data_in_this_rsp ;
int remaining ;
2007-07-10 05:16:18 +04:00
if ( pSMB - > Command ! = SMB_COM_TRANSACTION2 )
2005-04-29 09:41:09 +04:00
return 0 ;
2007-07-10 05:16:18 +04:00
/* check for plausible wct, bcc and t2 data and parm sizes */
/* check for parm and data offset going beyond end of smb */
if ( pSMB - > WordCount ! = 10 ) { /* coalesce_t2 depends on this */
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " invalid transact2 word count " ) ) ;
2005-04-29 09:41:09 +04:00
return - EINVAL ;
}
pSMBt = ( struct smb_t2_rsp * ) pSMB ;
total_data_size = le16_to_cpu ( pSMBt - > t2_rsp . TotalDataCount ) ;
data_in_this_rsp = le16_to_cpu ( pSMBt - > t2_rsp . DataCount ) ;
remaining = total_data_size - data_in_this_rsp ;
2007-07-10 05:16:18 +04:00
if ( remaining = = 0 )
2005-04-29 09:41:09 +04:00
return 0 ;
2007-07-10 05:16:18 +04:00
else if ( remaining < 0 ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " total data %d smaller than data in frame %d " ,
2005-04-29 09:41:09 +04:00
total_data_size , data_in_this_rsp ) ) ;
return - EINVAL ;
} else {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " missing %d bytes from transact2, check next response " ,
2005-04-29 09:41:09 +04:00
remaining ) ) ;
2007-07-10 05:16:18 +04:00
if ( total_data_size > maxBufSize ) {
cERROR ( 1 , ( " TotalDataSize %d is over maximum buffer %d " ,
total_data_size , maxBufSize ) ) ;
return - EINVAL ;
2005-04-29 09:41:09 +04:00
}
return remaining ;
}
}
2007-07-10 05:16:18 +04:00
static int coalesce_t2 ( struct smb_hdr * psecond , struct smb_hdr * pTargetSMB )
2005-04-29 09:41:09 +04:00
{
struct smb_t2_rsp * pSMB2 = ( struct smb_t2_rsp * ) psecond ;
struct smb_t2_rsp * pSMBt = ( struct smb_t2_rsp * ) pTargetSMB ;
int total_data_size ;
int total_in_buf ;
int remaining ;
int total_in_buf2 ;
2007-07-10 05:16:18 +04:00
char * data_area_of_target ;
char * data_area_of_buf2 ;
2005-04-29 09:41:09 +04:00
__u16 byte_count ;
total_data_size = le16_to_cpu ( pSMBt - > t2_rsp . TotalDataCount ) ;
2007-07-10 05:16:18 +04:00
if ( total_data_size ! = le16_to_cpu ( pSMB2 - > t2_rsp . TotalDataCount ) ) {
2007-07-17 21:34:02 +04:00
cFYI ( 1 , ( " total data size of primary and secondary t2 differ " ) ) ;
2005-04-29 09:41:09 +04:00
}
total_in_buf = le16_to_cpu ( pSMBt - > t2_rsp . DataCount ) ;
remaining = total_data_size - total_in_buf ;
2007-07-13 04:33:32 +04:00
2007-07-10 05:16:18 +04:00
if ( remaining < 0 )
2005-04-29 09:41:09 +04:00
return - EINVAL ;
2007-07-10 05:16:18 +04:00
if ( remaining = = 0 ) /* nothing to do, ignore */
2005-04-29 09:41:09 +04:00
return 0 ;
2007-07-13 04:33:32 +04:00
2005-04-29 09:41:09 +04:00
total_in_buf2 = le16_to_cpu ( pSMB2 - > t2_rsp . DataCount ) ;
2007-07-10 05:16:18 +04:00
if ( remaining < total_in_buf2 ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " transact2 2nd response contains too much data " ) ) ;
2005-04-29 09:41:09 +04:00
}
/* find end of first SMB data area */
2007-07-10 05:16:18 +04:00
data_area_of_target = ( char * ) & pSMBt - > hdr . Protocol +
2005-04-29 09:41:09 +04:00
le16_to_cpu ( pSMBt - > t2_rsp . DataOffset ) ;
/* validate target area */
data_area_of_buf2 = ( char * ) & pSMB2 - > hdr . Protocol +
2007-07-10 05:16:18 +04:00
le16_to_cpu ( pSMB2 - > t2_rsp . DataOffset ) ;
2005-04-29 09:41:09 +04:00
data_area_of_target + = total_in_buf ;
/* copy second buffer into end of first buffer */
2007-07-10 05:16:18 +04:00
memcpy ( data_area_of_target , data_area_of_buf2 , total_in_buf2 ) ;
2005-04-29 09:41:09 +04:00
total_in_buf + = total_in_buf2 ;
pSMBt - > t2_rsp . DataCount = cpu_to_le16 ( total_in_buf ) ;
byte_count = le16_to_cpu ( BCC_LE ( pTargetSMB ) ) ;
byte_count + = total_in_buf2 ;
BCC_LE ( pTargetSMB ) = cpu_to_le16 ( byte_count ) ;
2005-09-23 03:32:06 +04:00
byte_count = pTargetSMB - > smb_buf_length ;
2005-04-29 09:41:09 +04:00
byte_count + = total_in_buf2 ;
/* BB also add check that we are not beyond maximum buffer size */
2007-07-13 04:33:32 +04:00
2005-09-23 03:32:06 +04:00
pTargetSMB - > smb_buf_length = byte_count ;
2005-04-29 09:41:09 +04:00
2007-07-10 05:16:18 +04:00
if ( remaining = = total_in_buf2 ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " found the last secondary response " ) ) ;
2005-04-29 09:41:09 +04:00
return 0 ; /* we are done */
} else /* more responses to go */
return 1 ;
}
2005-04-17 02:20:36 +04:00
static int
cifs_demultiplex_thread ( struct TCP_Server_Info * server )
{
int length ;
unsigned int pdu_length , total_read ;
struct smb_hdr * smb_buffer = NULL ;
2005-04-29 09:41:07 +04:00
struct smb_hdr * bigbuf = NULL ;
struct smb_hdr * smallbuf = NULL ;
2005-04-17 02:20:36 +04:00
struct msghdr smb_msg ;
struct kvec iov ;
struct socket * csocket = server - > ssocket ;
struct list_head * tmp ;
struct cifsSesInfo * ses ;
struct task_struct * task_to_wake = NULL ;
struct mid_q_entry * mid_entry ;
2005-09-23 03:32:06 +04:00
char temp ;
2005-04-29 09:41:07 +04:00
int isLargeBuf = FALSE ;
2005-04-29 09:41:09 +04:00
int isMultiRsp ;
int reconnect ;
2005-04-17 02:20:36 +04:00
current - > flags | = PF_MEMALLOC ;
server - > tsk = current ; /* save process info to wake at shutdown */
cFYI ( 1 , ( " Demultiplex PID: %d " , current - > pid ) ) ;
2007-07-10 05:16:18 +04:00
write_lock ( & GlobalSMBSeslock ) ;
2005-04-17 02:20:36 +04:00
atomic_inc ( & tcpSesAllocCount ) ;
length = tcpSesAllocCount . counter ;
write_unlock ( & GlobalSMBSeslock ) ;
2005-08-18 20:37:34 +04:00
complete ( & cifsd_complete ) ;
2007-08-31 02:09:15 +04:00
if ( length > 1 )
mempool_resize ( cifs_req_poolp , length + cifs_min_rcv ,
GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
2007-07-17 15:03:35 +04:00
set_freezable ( ) ;
2007-04-03 23:16:43 +04:00
while ( ! kthread_should_stop ( ) ) {
2005-08-31 07:10:14 +04:00
if ( try_to_freeze ( ) )
continue ;
2005-04-29 09:41:07 +04:00
if ( bigbuf = = NULL ) {
bigbuf = cifs_buf_get ( ) ;
2006-06-14 01:31:39 +04:00
if ( ! bigbuf ) {
cERROR ( 1 , ( " No memory for large SMB response " ) ) ;
2005-04-29 09:41:07 +04:00
msleep ( 3000 ) ;
/* retry will check if exiting */
continue ;
}
2006-06-14 01:31:39 +04:00
} else if ( isLargeBuf ) {
/* we are reusing a dirty large buf, clear its start */
2007-08-31 02:09:15 +04:00
memset ( bigbuf , 0 , sizeof ( struct smb_hdr ) ) ;
2005-04-17 02:20:36 +04:00
}
2005-04-29 09:41:07 +04:00
if ( smallbuf = = NULL ) {
smallbuf = cifs_small_buf_get ( ) ;
2006-06-14 01:31:39 +04:00
if ( ! smallbuf ) {
cERROR ( 1 , ( " No memory for SMB response " ) ) ;
2005-04-29 09:41:07 +04:00
msleep ( 1000 ) ;
/* retry will check if exiting */
continue ;
}
/* beginning of smb buffer is cleared in our buf_get */
} else /* if existing small buf clear beginning */
2007-08-31 02:09:15 +04:00
memset ( smallbuf , 0 , sizeof ( struct smb_hdr ) ) ;
2005-04-29 09:41:07 +04:00
isLargeBuf = FALSE ;
2005-04-29 09:41:09 +04:00
isMultiRsp = FALSE ;
2005-04-29 09:41:07 +04:00
smb_buffer = smallbuf ;
2005-04-17 02:20:36 +04:00
iov . iov_base = smb_buffer ;
iov . iov_len = 4 ;
smb_msg . msg_control = NULL ;
smb_msg . msg_controllen = 0 ;
2007-08-31 01:13:31 +04:00
pdu_length = 4 ; /* enough to get RFC1001 header */
incomplete_rcv :
2005-04-17 02:20:36 +04:00
length =
kernel_recvmsg ( csocket , & smb_msg ,
2007-08-31 01:13:31 +04:00
& iov , 1 , pdu_length , 0 /* BB other flags? */ ) ;
2005-04-17 02:20:36 +04:00
2007-08-31 02:09:15 +04:00
if ( kthread_should_stop ( ) ) {
2005-04-17 02:20:36 +04:00
break ;
} else if ( server - > tcpStatus = = CifsNeedReconnect ) {
2006-06-14 01:31:39 +04:00
cFYI ( 1 , ( " Reconnect after server stopped responding " ) ) ;
2005-04-17 02:20:36 +04:00
cifs_reconnect ( server ) ;
2006-06-14 01:31:39 +04:00
cFYI ( 1 , ( " call to reconnect done " ) ) ;
2005-04-17 02:20:36 +04:00
csocket = server - > ssocket ;
continue ;
} else if ( ( length = = - ERESTARTSYS ) | | ( length = = - EAGAIN ) ) {
2005-04-29 09:41:07 +04:00
msleep ( 1 ) ; /* minimum sleep to prevent looping
2005-04-17 02:20:36 +04:00
allowing socket to clear and app threads to set
tcpStatus CifsNeedReconnect if server hung */
continue ;
} else if ( length < = 0 ) {
2006-06-14 01:31:39 +04:00
if ( server - > tcpStatus = = CifsNew ) {
cFYI ( 1 , ( " tcp session abend after SMBnegprot " ) ) ;
2005-04-29 09:41:08 +04:00
/* some servers kill the TCP session rather than
returning an SMB negprot error , in which
case reconnecting here is not going to help ,
and so simply return error to mount */
2005-04-17 02:20:36 +04:00
break ;
}
2006-06-14 01:31:39 +04:00
if ( ! try_to_freeze ( ) & & ( length = = - EINTR ) ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " cifsd thread killed " ) ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " Reconnect after unexpected peek error %d " ,
2005-04-29 09:41:10 +04:00
length ) ) ;
2005-04-17 02:20:36 +04:00
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
wake_up ( & server - > response_q ) ;
continue ;
2005-04-29 09:41:09 +04:00
} else if ( length < 4 ) {
2007-08-31 01:13:31 +04:00
cFYI ( 1 , ( " less than four bytes received (%d bytes) " ,
2005-04-29 09:41:09 +04:00
length ) ) ;
2007-08-31 01:13:31 +04:00
pdu_length - = length ;
msleep ( 1 ) ;
goto incomplete_rcv ;
2005-04-29 09:41:09 +04:00
}
2005-04-17 02:20:36 +04:00
2005-09-23 03:32:06 +04:00
/* The right amount was read from socket - 4 bytes */
/* so we can now interpret the length field */
2005-04-29 09:41:09 +04:00
2005-09-23 03:32:06 +04:00
/* the first byte big endian of the length field,
is actually not part of the length but the type
with the most common , zero , as regular data */
temp = * ( ( char * ) smb_buffer ) ;
2005-04-29 09:41:09 +04:00
2007-07-10 05:16:18 +04:00
/* Note that FC 1001 length is big endian on the wire,
2005-09-23 03:32:06 +04:00
but we convert it here so it is always manipulated
as host byte order */
2005-04-29 09:41:09 +04:00
pdu_length = ntohl ( smb_buffer - > smb_buf_length ) ;
2005-09-23 03:32:06 +04:00
smb_buffer - > smb_buf_length = pdu_length ;
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " rfc1002 length 0x%x " , pdu_length + 4 ) ) ;
2005-04-29 09:41:09 +04:00
2005-09-23 03:32:06 +04:00
if ( temp = = ( char ) RFC1002_SESSION_KEEP_ALIVE ) {
2007-07-10 05:16:18 +04:00
continue ;
2005-09-23 03:32:06 +04:00
} else if ( temp = = ( char ) RFC1002_POSITIVE_SESSION_RESPONSE ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " Good RFC 1002 session rsp " ) ) ;
2005-04-29 09:41:09 +04:00
continue ;
2005-09-23 03:32:06 +04:00
} else if ( temp = = ( char ) RFC1002_NEGATIVE_SESSION_RESPONSE ) {
2007-07-10 05:16:18 +04:00
/* we get this from Windows 98 instead of
2005-04-29 09:41:09 +04:00
an error on SMB negprot response */
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " Negative RFC1002 Session Response Error 0x%x) " ,
2005-09-23 03:32:06 +04:00
pdu_length ) ) ;
2007-07-10 05:16:18 +04:00
if ( server - > tcpStatus = = CifsNew ) {
/* if nack on negprot (rather than
2005-04-29 09:41:09 +04:00
ret of smb negprot error ) reconnecting
not going to help , ret error to mount */
break ;
} else {
/* give server a second to
clean up before reconnect attempt */
msleep ( 1000 ) ;
/* always try 445 first on reconnect
since we get NACK on some if we ever
2007-07-10 05:16:18 +04:00
connected to port 139 ( the NACK is
2005-04-29 09:41:09 +04:00
since we do not begin with RFC1001
session initialize frame ) */
2007-07-10 05:16:18 +04:00
server - > addr . sockAddr . sin_port =
2005-04-29 09:41:09 +04:00
htons ( CIFS_PORT ) ;
2005-04-17 02:20:36 +04:00
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
2005-04-29 09:41:09 +04:00
wake_up ( & server - > response_q ) ;
2005-04-17 02:20:36 +04:00
continue ;
2005-04-29 09:41:09 +04:00
}
2005-09-23 03:32:06 +04:00
} else if ( temp ! = ( char ) 0 ) {
2007-07-10 05:16:18 +04:00
cERROR ( 1 , ( " Unknown RFC 1002 frame " ) ) ;
2005-09-23 03:32:06 +04:00
cifs_dump_mem ( " Received Data: " , ( char * ) smb_buffer ,
length ) ;
2005-04-29 09:41:09 +04:00
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
continue ;
2005-04-29 09:41:09 +04:00
}
/* else we have an SMB response */
2007-07-10 05:16:18 +04:00
if ( ( pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4 ) | |
2007-08-31 02:09:15 +04:00
( pdu_length < sizeof ( struct smb_hdr ) - 1 - 4 ) ) {
2005-04-29 09:41:09 +04:00
cERROR ( 1 , ( " Invalid size SMB length %d pdu_length %d " ,
2005-04-29 09:41:09 +04:00
length , pdu_length + 4 ) ) ;
2005-04-29 09:41:09 +04:00
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
wake_up ( & server - > response_q ) ;
continue ;
2007-07-10 05:16:18 +04:00
}
2005-04-29 09:41:09 +04:00
/* else length ok */
reconnect = 0 ;
2007-07-10 05:16:18 +04:00
if ( pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4 ) {
2005-04-29 09:41:09 +04:00
isLargeBuf = TRUE ;
memcpy ( bigbuf , smallbuf , 4 ) ;
smb_buffer = bigbuf ;
}
length = 0 ;
iov . iov_base = 4 + ( char * ) smb_buffer ;
iov . iov_len = pdu_length ;
2007-07-10 05:16:18 +04:00
for ( total_read = 0 ; total_read < pdu_length ;
2005-04-29 09:41:09 +04:00
total_read + = length ) {
length = kernel_recvmsg ( csocket , & smb_msg , & iov , 1 ,
pdu_length - total_read , 0 ) ;
2007-08-31 02:09:15 +04:00
if ( kthread_should_stop ( ) | |
2005-04-29 09:41:09 +04:00
( length = = - EINTR ) ) {
/* then will exit */
reconnect = 2 ;
break ;
} else if ( server - > tcpStatus = = CifsNeedReconnect ) {
2005-04-29 09:41:09 +04:00
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
2007-07-10 05:16:18 +04:00
/* Reconnect wakes up rspns q */
2005-04-29 09:41:09 +04:00
/* Now we will reread sock */
reconnect = 1 ;
break ;
2007-07-10 05:16:18 +04:00
} else if ( ( length = = - ERESTARTSYS ) | |
2005-04-29 09:41:09 +04:00
( length = = - EAGAIN ) ) {
msleep ( 1 ) ; /* minimum sleep to prevent looping,
2007-07-10 05:16:18 +04:00
allowing socket to clear and app
2005-04-29 09:41:09 +04:00
threads to set tcpStatus
CifsNeedReconnect if server hung */
2005-04-29 09:41:09 +04:00
continue ;
2005-04-29 09:41:09 +04:00
} else if ( length < = 0 ) {
2007-07-10 05:16:18 +04:00
cERROR ( 1 , ( " Received no data, expecting %d " ,
2005-04-29 09:41:09 +04:00
pdu_length - total_read ) ) ;
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
reconnect = 1 ;
break ;
2005-04-29 09:41:09 +04:00
}
2005-04-29 09:41:09 +04:00
}
2007-07-10 05:16:18 +04:00
if ( reconnect = = 2 )
2005-04-29 09:41:09 +04:00
break ;
2007-07-10 05:16:18 +04:00
else if ( reconnect = = 1 )
2005-04-29 09:41:09 +04:00
continue ;
2005-04-17 02:20:36 +04:00
2005-04-29 09:41:09 +04:00
length + = 4 ; /* account for rfc1002 hdr */
2007-07-13 04:33:32 +04:00
2005-04-29 09:41:08 +04:00
2005-04-29 09:41:09 +04:00
dump_smb ( smb_buffer , length ) ;
2006-02-24 09:15:11 +03:00
if ( checkSMB ( smb_buffer , smb_buffer - > Mid , total_read + 4 ) ) {
2005-10-11 01:21:15 +04:00
cifs_dump_mem ( " Bad SMB: " , smb_buffer , 48 ) ;
2005-04-29 09:41:09 +04:00
continue ;
}
2005-04-17 02:20:36 +04:00
2005-04-29 09:41:09 +04:00
task_to_wake = NULL ;
spin_lock ( & GlobalMid_Lock ) ;
list_for_each ( tmp , & server - > pending_mid_q ) {
mid_entry = list_entry ( tmp , struct mid_q_entry , qhead ) ;
2007-07-13 04:33:32 +04:00
if ( ( mid_entry - > mid = = smb_buffer - > Mid ) & &
2005-04-29 09:41:09 +04:00
( mid_entry - > midState = = MID_REQUEST_SUBMITTED ) & &
( mid_entry - > command = = smb_buffer - > Command ) ) {
2007-07-10 05:16:18 +04:00
if ( check2ndT2 ( smb_buffer , server - > maxBuf ) > 0 ) {
2005-04-29 09:41:09 +04:00
/* We have a multipart transact2 resp */
2005-04-29 09:41:10 +04:00
isMultiRsp = TRUE ;
2007-07-10 05:16:18 +04:00
if ( mid_entry - > resp_buf ) {
2005-04-29 09:41:09 +04:00
/* merge response - fix up 1st*/
2007-07-13 04:33:32 +04:00
if ( coalesce_t2 ( smb_buffer ,
2005-04-29 09:41:09 +04:00
mid_entry - > resp_buf ) ) {
2006-06-01 02:40:51 +04:00
mid_entry - > multiRsp = 1 ;
2005-04-29 09:41:09 +04:00
break ;
} else {
/* all parts received */
2006-06-01 02:40:51 +04:00
mid_entry - > multiEnd = 1 ;
2007-07-13 04:33:32 +04:00
goto multi_t2_fnd ;
2005-04-29 09:41:09 +04:00
}
} else {
2007-07-10 05:16:18 +04:00
if ( ! isLargeBuf ) {
2005-04-29 09:41:09 +04:00
cERROR ( 1 , ( " 1st trans2 resp needs bigbuf " ) ) ;
/* BB maybe we can fix this up, switch
2007-07-13 04:33:32 +04:00
to already allocated large buffer ? */
2005-04-29 09:41:09 +04:00
} else {
2005-04-29 09:41:10 +04:00
/* Have first buffer */
2005-04-29 09:41:09 +04:00
mid_entry - > resp_buf =
smb_buffer ;
mid_entry - > largeBuf = 1 ;
bigbuf = NULL ;
}
}
break ;
2007-07-13 04:33:32 +04:00
}
2005-04-29 09:41:09 +04:00
mid_entry - > resp_buf = smb_buffer ;
2007-07-10 05:16:18 +04:00
if ( isLargeBuf )
2005-04-29 09:41:09 +04:00
mid_entry - > largeBuf = 1 ;
2005-04-29 09:41:09 +04:00
else
2005-04-29 09:41:09 +04:00
mid_entry - > largeBuf = 0 ;
multi_t2_fnd :
task_to_wake = mid_entry - > tsk ;
mid_entry - > midState = MID_RESPONSE_RECEIVED ;
2005-10-12 06:58:06 +04:00
# ifdef CONFIG_CIFS_STATS2
mid_entry - > when_received = jiffies ;
# endif
2006-07-15 02:37:11 +04:00
/* so we do not time out requests to server
which is still responding ( since server could
be busy but not dead ) */
server - > lstrp = jiffies ;
2005-04-29 09:41:09 +04:00
break ;
2005-04-29 09:41:09 +04:00
}
2005-04-17 02:20:36 +04:00
}
2005-04-29 09:41:09 +04:00
spin_unlock ( & GlobalMid_Lock ) ;
if ( task_to_wake ) {
2005-04-29 09:41:10 +04:00
/* Was previous buf put in mpx struct for multi-rsp? */
2007-07-10 05:16:18 +04:00
if ( ! isMultiRsp ) {
2005-04-29 09:41:10 +04:00
/* smb buffer will be freed by user thread */
2007-08-31 02:09:15 +04:00
if ( isLargeBuf )
2005-04-29 09:41:10 +04:00
bigbuf = NULL ;
2007-08-31 02:09:15 +04:00
else
2005-04-29 09:41:10 +04:00
smallbuf = NULL ;
}
2005-04-29 09:41:09 +04:00
wake_up_process ( task_to_wake ) ;
2006-03-03 13:43:49 +03:00
} else if ( ( is_valid_oplock_break ( smb_buffer , server ) = = FALSE )
2007-07-13 04:33:32 +04:00
& & ( isMultiRsp = = FALSE ) ) {
cERROR ( 1 , ( " No task to wake, unknown frame received! "
" NumMids %d " , midCount . counter ) ) ;
cifs_dump_mem ( " Received Data is: " , ( char * ) smb_buffer ,
2005-09-23 03:32:06 +04:00
sizeof ( struct smb_hdr ) ) ;
2006-06-01 02:40:51 +04:00
# ifdef CONFIG_CIFS_DEBUG2
cifs_dump_detail ( smb_buffer ) ;
cifs_dump_mids ( server ) ;
# endif /* CIFS_DEBUG2 */
2007-07-13 04:33:32 +04:00
2005-04-29 09:41:09 +04:00
}
} /* end while !EXITING */
2005-04-17 02:20:36 +04:00
spin_lock ( & GlobalMid_Lock ) ;
server - > tcpStatus = CifsExiting ;
server - > tsk = NULL ;
2005-04-29 09:41:11 +04:00
/* check if we have blocked requests that need to free */
/* Note that cifs_max_pending is normally 50, but
can be set at module install time to as little as two */
2007-07-10 05:16:18 +04:00
if ( atomic_read ( & server - > inFlight ) > = cifs_max_pending )
2005-04-29 09:41:11 +04:00
atomic_set ( & server - > inFlight , cifs_max_pending - 1 ) ;
/* We do not want to set the max_pending too low or we
could end up with the counter going negative */
2005-04-17 02:20:36 +04:00
spin_unlock ( & GlobalMid_Lock ) ;
2007-07-13 04:33:32 +04:00
/* Although there should not be any requests blocked on
2005-04-17 02:20:36 +04:00
this queue it can not hurt to be paranoid and try to wake up requests
2005-04-29 09:41:08 +04:00
that may haven been blocked when more than 50 at time were on the wire
2005-04-17 02:20:36 +04:00
to the same server - they now will see the session is in exit state
and get out of SendReceive . */
wake_up_all ( & server - > request_q ) ;
/* give those requests time to exit */
2005-04-29 09:41:07 +04:00
msleep ( 125 ) ;
2007-07-13 04:33:32 +04:00
2007-07-10 05:16:18 +04:00
if ( server - > ssocket ) {
2005-04-17 02:20:36 +04:00
sock_release ( csocket ) ;
server - > ssocket = NULL ;
}
2005-04-29 09:41:07 +04:00
/* buffer usuallly freed in free_mid - need to free it here on exit */
if ( bigbuf ! = NULL )
cifs_buf_release ( bigbuf ) ;
if ( smallbuf ! = NULL )
cifs_small_buf_release ( smallbuf ) ;
2005-04-17 02:20:36 +04:00
read_lock ( & GlobalSMBSeslock ) ;
if ( list_empty ( & server - > pending_mid_q ) ) {
2005-04-29 09:41:08 +04:00
/* loop through server session structures attached to this and
mark them dead */
2005-04-17 02:20:36 +04:00
list_for_each ( tmp , & GlobalSMBSessionList ) {
ses =
list_entry ( tmp , struct cifsSesInfo ,
cifsSessionList ) ;
if ( ses - > server = = server ) {
ses - > status = CifsExiting ;
ses - > server = NULL ;
}
}
read_unlock ( & GlobalSMBSeslock ) ;
} else {
2005-04-29 09:41:11 +04:00
/* although we can not zero the server struct pointer yet,
since there are active requests which may depnd on them ,
mark the corresponding SMB sessions as exiting too */
list_for_each ( tmp , & GlobalSMBSessionList ) {
ses = list_entry ( tmp , struct cifsSesInfo ,
cifsSessionList ) ;
2007-08-31 02:09:15 +04:00
if ( ses - > server = = server )
2005-04-29 09:41:11 +04:00
ses - > status = CifsExiting ;
}
2005-04-17 02:20:36 +04:00
spin_lock ( & GlobalMid_Lock ) ;
list_for_each ( tmp , & server - > pending_mid_q ) {
mid_entry = list_entry ( tmp , struct mid_q_entry , qhead ) ;
if ( mid_entry - > midState = = MID_REQUEST_SUBMITTED ) {
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Clearing Mid 0x%x - waking up " ,
mid_entry - > mid ) ) ;
2005-04-17 02:20:36 +04:00
task_to_wake = mid_entry - > tsk ;
2007-08-31 02:09:15 +04:00
if ( task_to_wake )
2005-04-17 02:20:36 +04:00
wake_up_process ( task_to_wake ) ;
}
}
spin_unlock ( & GlobalMid_Lock ) ;
read_unlock ( & GlobalSMBSeslock ) ;
/* 1/8th of sec is more than enough time for them to exit */
2005-04-29 09:41:07 +04:00
msleep ( 125 ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-18 20:37:34 +04:00
if ( ! list_empty ( & server - > pending_mid_q ) ) {
2007-07-13 04:33:32 +04:00
/* mpx threads have not exited yet give them
2005-04-17 02:20:36 +04:00
at least the smb send timeout time for long ops */
2005-04-29 09:41:11 +04:00
/* due to delays on oplock break requests, we need
to wait at least 45 seconds before giving up
on a request getting a response and going ahead
and killing cifsd */
2005-04-17 02:20:36 +04:00
cFYI ( 1 , ( " Wait for exit from demultiplex thread " ) ) ;
2005-04-29 09:41:11 +04:00
msleep ( 46000 ) ;
2005-04-17 02:20:36 +04:00
/* if threads still have not exited they are probably never
coming home not much else we can do but free the memory */
}
write_lock ( & GlobalSMBSeslock ) ;
atomic_dec ( & tcpSesAllocCount ) ;
length = tcpSesAllocCount . counter ;
2005-04-29 09:41:11 +04:00
/* last chance to mark ses pointers invalid
if there are any pointing to this ( e . g
2007-07-13 04:33:32 +04:00
if a crazy root user tried to kill cifsd
2005-04-29 09:41:11 +04:00
kernel thread explicitly this might happen ) */
list_for_each ( tmp , & GlobalSMBSessionList ) {
ses = list_entry ( tmp , struct cifsSesInfo ,
cifsSessionList ) ;
2007-08-31 02:09:15 +04:00
if ( ses - > server = = server )
2005-04-29 09:41:11 +04:00
ses - > server = NULL ;
}
2005-04-17 02:20:36 +04:00
write_unlock ( & GlobalSMBSeslock ) ;
2005-04-29 09:41:11 +04:00
kfree ( server ) ;
2007-08-31 02:09:15 +04:00
if ( length > 0 )
mempool_resize ( cifs_req_poolp , length + cifs_min_rcv ,
GFP_KERNEL ) ;
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int
2007-07-13 04:33:32 +04:00
cifs_parse_mount_options ( char * options , const char * devname ,
struct smb_vol * vol )
2005-04-17 02:20:36 +04:00
{
char * value ;
char * data ;
unsigned int temp_len , i , j ;
char separator [ 2 ] ;
separator [ 0 ] = ' , ' ;
2007-07-13 04:33:32 +04:00
separator [ 1 ] = 0 ;
2005-04-17 02:20:36 +04:00
2006-10-13 19:09:29 +04:00
if ( Local_System_Name [ 0 ] ! = 0 )
2007-07-13 04:33:32 +04:00
memcpy ( vol - > source_rfc1001_name , Local_System_Name , 15 ) ;
2006-09-28 23:43:08 +04:00
else {
2006-10-13 19:09:29 +04:00
char * nodename = utsname ( ) - > nodename ;
2007-07-13 04:33:32 +04:00
int n = strnlen ( nodename , 15 ) ;
memset ( vol - > source_rfc1001_name , 0x20 , 15 ) ;
for ( i = 0 ; i < n ; i + + ) {
2006-09-28 23:43:08 +04:00
/* does not have to be perfect mapping since field is
informational , only used for servers that do not support
port 445 and it can be overridden at mount time */
2006-10-13 19:09:29 +04:00
vol - > source_rfc1001_name [ i ] = toupper ( nodename [ i ] ) ;
2006-09-28 23:43:08 +04:00
}
2005-04-17 02:20:36 +04:00
}
vol - > source_rfc1001_name [ 15 ] = 0 ;
2005-08-23 08:38:31 +04:00
/* null target name indicates to use *SMBSERVR default called name
if we end up sending RFC1001 session initialize */
vol - > target_rfc1001_name [ 0 ] = 0 ;
2005-04-17 02:20:36 +04:00
vol - > linux_uid = current - > uid ; /* current->euid instead? */
vol - > linux_gid = current - > gid ;
vol - > dir_mode = S_IRWXUGO ;
/* 2767 perms indicate mandatory locking support */
vol - > file_mode = S_IALLUGO & ~ ( S_ISUID | S_IXGRP ) ;
/* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
vol - > rw = TRUE ;
2005-06-23 04:26:35 +04:00
/* default is always to request posix paths. */
vol - > posix_paths = 1 ;
2005-04-17 02:20:36 +04:00
if ( ! options )
return 1 ;
2007-07-13 04:33:32 +04:00
if ( strncmp ( options , " sep= " , 4 ) = = 0 ) {
2007-07-10 05:16:18 +04:00
if ( options [ 4 ] ! = 0 ) {
2005-04-17 02:20:36 +04:00
separator [ 0 ] = options [ 4 ] ;
options + = 5 ;
} else {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " Null separator not allowed " ) ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
while ( ( data = strsep ( & options , separator ) ) ! = NULL ) {
if ( ! * data )
continue ;
if ( ( value = strchr ( data , ' = ' ) ) ! = NULL )
* value + + = ' \0 ' ;
2007-07-13 04:33:32 +04:00
/* Have to parse this before we parse for "user" */
if ( strnicmp ( data , " user_xattr " , 10 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > no_xattr = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " nouser_xattr " , 12 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > no_xattr = 1 ;
} else if ( strnicmp ( data , " user " , 4 ) = = 0 ) {
2006-10-31 00:46:13 +03:00
if ( ! value ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING
" CIFS: invalid or missing username \n " ) ;
return 1 ; /* needs_arg; */
2007-07-10 05:16:18 +04:00
} else if ( ! * value ) {
2006-10-31 00:46:13 +03:00
/* null user, ie anonymous, authentication */
vol - > nullauth = 1 ;
2005-04-17 02:20:36 +04:00
}
if ( strnlen ( value , 200 ) < 200 ) {
vol - > username = value ;
} else {
printk ( KERN_WARNING " CIFS: username too long \n " ) ;
return 1 ;
}
} else if ( strnicmp ( data , " pass " , 4 ) = = 0 ) {
if ( ! value ) {
vol - > password = NULL ;
continue ;
2007-07-10 05:16:18 +04:00
} else if ( value [ 0 ] = = 0 ) {
2005-04-17 02:20:36 +04:00
/* check if string begins with double comma
since that would mean the password really
does start with a comma , and would not
indicate an empty string */
2007-07-10 05:16:18 +04:00
if ( value [ 1 ] ! = separator [ 0 ] ) {
2005-04-17 02:20:36 +04:00
vol - > password = NULL ;
continue ;
}
}
temp_len = strlen ( value ) ;
/* removed password length check, NTLM passwords
can be arbitrarily long */
2007-07-13 04:33:32 +04:00
/* if comma in password, the string will be
2005-04-17 02:20:36 +04:00
prematurely null terminated . Commas in password are
specified across the cifs mount interface by a double
comma ie , , and a comma used as in other cases ie ' , '
as a parameter delimiter / separator is single and due
to the strsep above is temporarily zeroed . */
/* NB: password legally can have multiple commas and
the only illegal character in a password is null */
2007-07-13 04:33:32 +04:00
if ( ( value [ temp_len ] = = 0 ) & &
2005-04-29 09:41:08 +04:00
( value [ temp_len + 1 ] = = separator [ 0 ] ) ) {
2005-04-17 02:20:36 +04:00
/* reinsert comma */
value [ temp_len ] = separator [ 0 ] ;
2007-07-13 04:33:32 +04:00
temp_len + = 2 ; /* move after second comma */
while ( value [ temp_len ] ! = 0 ) {
2005-04-17 02:20:36 +04:00
if ( value [ temp_len ] = = separator [ 0 ] ) {
2007-07-13 04:33:32 +04:00
if ( value [ temp_len + 1 ] = =
2005-04-29 09:41:08 +04:00
separator [ 0 ] ) {
/* skip second comma */
temp_len + + ;
2007-07-13 04:33:32 +04:00
} else {
2005-04-17 02:20:36 +04:00
/* single comma indicating start
of next parm */
break ;
}
}
temp_len + + ;
}
2007-07-10 05:16:18 +04:00
if ( value [ temp_len ] = = 0 ) {
2005-04-17 02:20:36 +04:00
options = NULL ;
} else {
value [ temp_len ] = 0 ;
/* point option to start of next parm */
options = value + temp_len + 1 ;
}
2007-07-13 04:33:32 +04:00
/* go from value to value + temp_len condensing
2005-04-17 02:20:36 +04:00
double commas to singles . Note that this ends up
allocating a few bytes too many , which is ok */
2005-09-07 02:18:35 +04:00
vol - > password = kzalloc ( temp_len , GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( vol - > password = = NULL ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: no memory "
" for password \n " ) ;
2005-04-29 09:41:08 +04:00
return 1 ;
}
2007-07-13 04:33:32 +04:00
for ( i = 0 , j = 0 ; i < temp_len ; i + + , j + + ) {
2005-04-17 02:20:36 +04:00
vol - > password [ j ] = value [ i ] ;
2007-07-10 05:16:18 +04:00
if ( value [ i ] = = separator [ 0 ]
2005-04-29 09:41:08 +04:00
& & value [ i + 1 ] = = separator [ 0 ] ) {
2005-04-17 02:20:36 +04:00
/* skip second comma */
i + + ;
}
}
vol - > password [ j ] = 0 ;
} else {
2005-09-07 02:18:35 +04:00
vol - > password = kzalloc ( temp_len + 1 , GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( vol - > password = = NULL ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: no memory "
" for password \n " ) ;
2005-04-29 09:41:08 +04:00
return 1 ;
}
2005-04-17 02:20:36 +04:00
strcpy ( vol - > password , value ) ;
}
} else if ( strnicmp ( data , " ip " , 2 ) = = 0 ) {
if ( ! value | | ! * value ) {
vol - > UNCip = NULL ;
} else if ( strnlen ( value , 35 ) < 35 ) {
vol - > UNCip = value ;
} else {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: ip address "
" too long \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " sec " , 3 ) = = 0 ) {
if ( ! value | | ! * value ) {
cERROR ( 1 , ( " no security value specified " ) ) ;
continue ;
} else if ( strnicmp ( value , " krb5i " , 5 ) = = 0 ) {
vol - > secFlg | = CIFSSEC_MAY_KRB5 |
2006-06-23 06:33:48 +04:00
CIFSSEC_MUST_SIGN ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " krb5p " , 5 ) = = 0 ) {
2007-07-13 04:33:32 +04:00
/* vol->secFlg |= CIFSSEC_MUST_SEAL |
CIFSSEC_MAY_KRB5 ; */
cERROR ( 1 , ( " Krb5 cifs privacy not supported " ) ) ;
2005-12-02 09:32:42 +03:00
return 1 ;
} else if ( strnicmp ( value , " krb5 " , 4 ) = = 0 ) {
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_KRB5 ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " ntlmv2i " , 7 ) = = 0 ) {
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_NTLMV2 |
2006-06-23 06:33:48 +04:00
CIFSSEC_MUST_SIGN ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " ntlmv2 " , 6 ) = = 0 ) {
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_NTLMV2 ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " ntlmi " , 5 ) = = 0 ) {
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_NTLM |
2006-06-23 06:33:48 +04:00
CIFSSEC_MUST_SIGN ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " ntlm " , 4 ) = = 0 ) {
/* ntlm is default so can be turned off too */
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_NTLM ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " nontlm " , 6 ) = = 0 ) {
2006-06-23 06:33:48 +04:00
/* BB is there a better way to do this? */
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_NTLMV2 ;
2006-06-23 06:33:48 +04:00
# ifdef CONFIG_CIFS_WEAK_PW_HASH
} else if ( strnicmp ( value , " lanman " , 6 ) = = 0 ) {
2007-07-13 04:33:32 +04:00
vol - > secFlg | = CIFSSEC_MAY_LANMAN ;
2006-06-23 06:33:48 +04:00
# endif
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " none " , 4 ) = = 0 ) {
2006-06-23 06:33:48 +04:00
vol - > nullauth = 1 ;
2007-07-13 04:33:32 +04:00
} else {
cERROR ( 1 , ( " bad security option: %s " , value ) ) ;
return 1 ;
}
2005-04-17 02:20:36 +04:00
} else if ( ( strnicmp ( data , " unc " , 3 ) = = 0 )
| | ( strnicmp ( data , " target " , 6 ) = = 0 )
| | ( strnicmp ( data , " path " , 4 ) = = 0 ) ) {
if ( ! value | | ! * value ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: invalid path to "
" network resource \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ; /* needs_arg; */
}
if ( ( temp_len = strnlen ( value , 300 ) ) < 300 ) {
2007-07-13 04:33:32 +04:00
vol - > UNC = kmalloc ( temp_len + 1 , GFP_KERNEL ) ;
2007-05-01 00:13:06 +04:00
if ( vol - > UNC = = NULL )
2005-04-17 02:20:36 +04:00
return 1 ;
2007-07-13 04:33:32 +04:00
strcpy ( vol - > UNC , value ) ;
2005-04-17 02:20:36 +04:00
if ( strncmp ( vol - > UNC , " // " , 2 ) = = 0 ) {
vol - > UNC [ 0 ] = ' \\ ' ;
vol - > UNC [ 1 ] = ' \\ ' ;
2007-07-13 04:33:32 +04:00
} else if ( strncmp ( vol - > UNC , " \\ \\ " , 2 ) ! = 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING
2007-07-13 04:33:32 +04:00
" CIFS: UNC Path does not begin "
" with // or \\ \\ \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
} else {
printk ( KERN_WARNING " CIFS: UNC name too long \n " ) ;
return 1 ;
}
} else if ( ( strnicmp ( data , " domain " , 3 ) = = 0 )
| | ( strnicmp ( data , " workgroup " , 5 ) = = 0 ) ) {
if ( ! value | | ! * value ) {
printk ( KERN_WARNING " CIFS: invalid domain name \n " ) ;
return 1 ; /* needs_arg; */
}
/* BB are there cases in which a comma can be valid in
a domain name and need special handling ? */
2006-06-01 02:40:51 +04:00
if ( strnlen ( value , 256 ) < 256 ) {
2005-04-17 02:20:36 +04:00
vol - > domainname = value ;
cFYI ( 1 , ( " Domain name set " ) ) ;
} else {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: domain name too "
" long \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " prefixpath " , 10 ) = = 0 ) {
if ( ! value | | ! * value ) {
printk ( KERN_WARNING
" CIFS: invalid path prefix \n " ) ;
return 1 ; /* needs_argument */
}
if ( ( temp_len = strnlen ( value , 1024 ) ) < 1024 ) {
2007-05-01 00:13:06 +04:00
if ( value [ 0 ] ! = ' / ' )
2006-09-21 11:02:52 +04:00
temp_len + + ; /* missing leading slash */
2007-07-13 04:33:32 +04:00
vol - > prepath = kmalloc ( temp_len + 1 , GFP_KERNEL ) ;
if ( vol - > prepath = = NULL )
return 1 ;
2007-05-01 00:13:06 +04:00
if ( value [ 0 ] ! = ' / ' ) {
2006-09-21 11:02:52 +04:00
vol - > prepath [ 0 ] = ' / ' ;
2007-07-13 04:33:32 +04:00
strcpy ( vol - > prepath + 1 , value ) ;
2006-09-21 11:02:52 +04:00
} else
2007-07-13 04:33:32 +04:00
strcpy ( vol - > prepath , value ) ;
cFYI ( 1 , ( " prefix path %s " , vol - > prepath ) ) ;
} else {
printk ( KERN_WARNING " CIFS: prefix too long \n " ) ;
return 1 ;
}
2005-04-17 02:20:36 +04:00
} else if ( strnicmp ( data , " iocharset " , 9 ) = = 0 ) {
if ( ! value | | ! * value ) {
2007-07-17 21:34:02 +04:00
printk ( KERN_WARNING " CIFS: invalid iocharset "
" specified \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ; /* needs_arg; */
}
if ( strnlen ( value , 65 ) < 65 ) {
2007-07-13 04:33:32 +04:00
if ( strnicmp ( value , " default " , 7 ) )
2005-04-17 02:20:36 +04:00
vol - > iocharset = value ;
2007-07-13 04:33:32 +04:00
/* if iocharset not set then load_nls_default
is used by caller */
cFYI ( 1 , ( " iocharset set to %s " , value ) ) ;
2005-04-17 02:20:36 +04:00
} else {
2007-07-17 21:34:02 +04:00
printk ( KERN_WARNING " CIFS: iocharset name "
" too long. \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
} else if ( strnicmp ( data , " uid " , 3 ) = = 0 ) {
if ( value & & * value ) {
vol - > linux_uid =
simple_strtoul ( value , & value , 0 ) ;
2007-05-01 00:13:06 +04:00
vol - > override_uid = 1 ;
2005-04-17 02:20:36 +04:00
}
} else if ( strnicmp ( data , " gid " , 3 ) = = 0 ) {
if ( value & & * value ) {
vol - > linux_gid =
simple_strtoul ( value , & value , 0 ) ;
2007-05-01 00:13:06 +04:00
vol - > override_gid = 1 ;
2005-04-17 02:20:36 +04:00
}
} else if ( strnicmp ( data , " file_mode " , 4 ) = = 0 ) {
if ( value & & * value ) {
vol - > file_mode =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " dir_mode " , 4 ) = = 0 ) {
if ( value & & * value ) {
vol - > dir_mode =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " dirmode " , 4 ) = = 0 ) {
if ( value & & * value ) {
vol - > dir_mode =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " port " , 4 ) = = 0 ) {
if ( value & & * value ) {
vol - > port =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " rsize " , 5 ) = = 0 ) {
if ( value & & * value ) {
vol - > rsize =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " wsize " , 5 ) = = 0 ) {
if ( value & & * value ) {
vol - > wsize =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " sockopt " , 5 ) = = 0 ) {
if ( value & & * value ) {
vol - > sockopt =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " netbiosname " , 4 ) = = 0 ) {
if ( ! value | | ! * value | | ( * value = = ' ' ) ) {
2007-07-17 21:34:02 +04:00
cFYI ( 1 , ( " invalid (empty) netbiosname " ) ) ;
2005-04-17 02:20:36 +04:00
} else {
2007-07-13 04:33:32 +04:00
memset ( vol - > source_rfc1001_name , 0x20 , 15 ) ;
for ( i = 0 ; i < 15 ; i + + ) {
/* BB are there cases in which a comma can be
2005-04-17 02:20:36 +04:00
valid in this workstation netbios name ( and need
special handling ) ? */
/* We do not uppercase netbiosname for user */
2007-07-13 04:33:32 +04:00
if ( value [ i ] = = 0 )
2005-04-17 02:20:36 +04:00
break ;
2007-07-13 04:33:32 +04:00
else
vol - > source_rfc1001_name [ i ] =
value [ i ] ;
2005-04-17 02:20:36 +04:00
}
/* The string has 16th byte zero still from
set at top of the function */
2007-07-13 04:33:32 +04:00
if ( ( i = = 15 ) & & ( value [ i ] ! = 0 ) )
printk ( KERN_WARNING " CIFS: netbiosname "
" longer than 15 truncated. \n " ) ;
2005-08-23 08:38:31 +04:00
}
} else if ( strnicmp ( data , " servern " , 7 ) = = 0 ) {
/* servernetbiosname specified override *SMBSERVER */
if ( ! value | | ! * value | | ( * value = = ' ' ) ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " empty server netbiosname specified " ) ) ;
2005-08-23 08:38:31 +04:00
} else {
/* last byte, type, is 0x20 for servr type */
2007-07-13 04:33:32 +04:00
memset ( vol - > target_rfc1001_name , 0x20 , 16 ) ;
2005-08-23 08:38:31 +04:00
2007-07-13 04:33:32 +04:00
for ( i = 0 ; i < 15 ; i + + ) {
2005-08-23 08:38:31 +04:00
/* BB are there cases in which a comma can be
2007-07-13 04:33:32 +04:00
valid in this workstation netbios name
( and need special handling ) ? */
2005-08-23 08:38:31 +04:00
2007-07-13 04:33:32 +04:00
/* user or mount helper must uppercase
the netbiosname */
if ( value [ i ] = = 0 )
2005-08-23 08:38:31 +04:00
break ;
else
2007-07-13 04:33:32 +04:00
vol - > target_rfc1001_name [ i ] =
value [ i ] ;
2005-08-23 08:38:31 +04:00
}
/* The string has 16th byte zero still from
set at top of the function */
2007-07-13 04:33:32 +04:00
if ( ( i = = 15 ) & & ( value [ i ] ! = 0 ) )
printk ( KERN_WARNING " CIFS: server net "
" biosname longer than 15 truncated. \n " ) ;
2005-04-17 02:20:36 +04:00
}
} else if ( strnicmp ( data , " credentials " , 4 ) = = 0 ) {
/* ignore */
} else if ( strnicmp ( data , " version " , 3 ) = = 0 ) {
/* ignore */
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " guest " , 5 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
/* ignore */
} else if ( strnicmp ( data , " rw " , 2 ) = = 0 ) {
vol - > rw = TRUE ;
} else if ( ( strnicmp ( data , " suid " , 4 ) = = 0 ) | |
( strnicmp ( data , " nosuid " , 6 ) = = 0 ) | |
( strnicmp ( data , " exec " , 4 ) = = 0 ) | |
( strnicmp ( data , " noexec " , 6 ) = = 0 ) | |
( strnicmp ( data , " nodev " , 5 ) = = 0 ) | |
( strnicmp ( data , " noauto " , 6 ) = = 0 ) | |
( strnicmp ( data , " dev " , 3 ) = = 0 ) ) {
/* The mount tool or mount.cifs helper (if present)
2007-07-13 04:33:32 +04:00
uses these opts to set flags , and the flags are read
by the kernel vfs layer before we get here ( ie
before read super ) so there is no point trying to
parse these options again and set anything and it
is ok to just ignore them */
2005-04-17 02:20:36 +04:00
continue ;
} else if ( strnicmp ( data , " ro " , 2 ) = = 0 ) {
vol - > rw = FALSE ;
} else if ( strnicmp ( data , " hard " , 4 ) = = 0 ) {
vol - > retry = 1 ;
} else if ( strnicmp ( data , " soft " , 4 ) = = 0 ) {
vol - > retry = 0 ;
} else if ( strnicmp ( data , " perm " , 4 ) = = 0 ) {
vol - > noperm = 0 ;
} else if ( strnicmp ( data , " noperm " , 6 ) = = 0 ) {
vol - > noperm = 1 ;
2005-04-29 09:41:05 +04:00
} else if ( strnicmp ( data , " mapchars " , 8 ) = = 0 ) {
vol - > remap = 1 ;
} else if ( strnicmp ( data , " nomapchars " , 10 ) = = 0 ) {
vol - > remap = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " sfu " , 3 ) = = 0 ) {
vol - > sfu_emul = 1 ;
} else if ( strnicmp ( data , " nosfu " , 5 ) = = 0 ) {
vol - > sfu_emul = 0 ;
2005-06-23 04:26:35 +04:00
} else if ( strnicmp ( data , " posixpaths " , 10 ) = = 0 ) {
vol - > posix_paths = 1 ;
} else if ( strnicmp ( data , " noposixpaths " , 12 ) = = 0 ) {
vol - > posix_paths = 0 ;
2007-07-19 03:21:09 +04:00
} else if ( strnicmp ( data , " nounix " , 6 ) = = 0 ) {
vol - > no_linux_ext = 1 ;
} else if ( strnicmp ( data , " nolinux " , 7 ) = = 0 ) {
vol - > no_linux_ext = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( ( strnicmp ( data , " nocase " , 6 ) = = 0 ) | |
2005-08-23 08:38:31 +04:00
( strnicmp ( data , " ignorecase " , 10 ) = = 0 ) ) {
2007-07-13 04:33:32 +04:00
vol - > nocase = 1 ;
2005-08-19 07:49:57 +04:00
} else if ( strnicmp ( data , " brl " , 3 ) = = 0 ) {
vol - > nobrl = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( ( strnicmp ( data , " nobrl " , 5 ) = = 0 ) | |
2005-08-31 07:58:07 +04:00
( strnicmp ( data , " nolock " , 6 ) = = 0 ) ) {
2005-08-19 07:49:57 +04:00
vol - > nobrl = 1 ;
2005-08-19 22:04:29 +04:00
/* turn off mandatory locking in mode
if remote locking is turned off since the
local vfs will do advisory */
2007-07-13 04:33:32 +04:00
if ( vol - > file_mode = =
( S_IALLUGO & ~ ( S_ISUID | S_IXGRP ) ) )
2005-08-19 22:04:29 +04:00
vol - > file_mode = S_IALLUGO ;
2005-04-17 02:20:36 +04:00
} else if ( strnicmp ( data , " setuids " , 7 ) = = 0 ) {
vol - > setuids = 1 ;
} else if ( strnicmp ( data , " nosetuids " , 9 ) = = 0 ) {
vol - > setuids = 0 ;
} else if ( strnicmp ( data , " nohard " , 6 ) = = 0 ) {
vol - > retry = 0 ;
} else if ( strnicmp ( data , " nosoft " , 6 ) = = 0 ) {
vol - > retry = 1 ;
} else if ( strnicmp ( data , " nointr " , 6 ) = = 0 ) {
vol - > intr = 0 ;
} else if ( strnicmp ( data , " intr " , 4 ) = = 0 ) {
vol - > intr = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " serverino " , 7 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > server_ino = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " noserverino " , 9 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > server_ino = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " cifsacl " , 7 ) = = 0 ) {
2006-01-13 02:44:21 +03:00
vol - > cifs_acl = 1 ;
} else if ( strnicmp ( data , " nocifsacl " , 9 ) = = 0 ) {
vol - > cifs_acl = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " acl " , 3 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > no_psx_acl = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " noacl " , 5 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > no_psx_acl = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " sign " , 4 ) = = 0 ) {
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MUST_SIGN ;
/* } else if (strnicmp(data, "seal",4) == 0) {
vol - > secFlg | = CIFSSEC_MUST_SEAL ; */
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " direct " , 6 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > direct_io = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " forcedirectio " , 13 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > direct_io = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " in6_addr " , 8 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
if ( ! value | | ! * value ) {
vol - > in6_addr = NULL ;
} else if ( strnlen ( value , 49 ) = = 48 ) {
vol - > in6_addr = value ;
} else {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: ip v6 address not "
" 48 characters long \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
} else if ( strnicmp ( data , " noac " , 4 ) = = 0 ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: Mount option noac not "
" supported. Instead set "
" /proc/fs/cifs/LookupCacheEnabled to 0 \n " ) ;
2005-04-17 02:20:36 +04:00
} else
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: Unknown mount option %s \n " ,
data ) ;
2005-04-17 02:20:36 +04:00
}
if ( vol - > UNC = = NULL ) {
2007-05-01 00:13:06 +04:00
if ( devname = = NULL ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: Missing UNC name for mount "
" target \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
if ( ( temp_len = strnlen ( devname , 300 ) ) < 300 ) {
2007-07-13 04:33:32 +04:00
vol - > UNC = kmalloc ( temp_len + 1 , GFP_KERNEL ) ;
2007-05-01 00:13:06 +04:00
if ( vol - > UNC = = NULL )
2005-04-17 02:20:36 +04:00
return 1 ;
2007-07-13 04:33:32 +04:00
strcpy ( vol - > UNC , devname ) ;
2005-04-17 02:20:36 +04:00
if ( strncmp ( vol - > UNC , " // " , 2 ) = = 0 ) {
vol - > UNC [ 0 ] = ' \\ ' ;
vol - > UNC [ 1 ] = ' \\ ' ;
} else if ( strncmp ( vol - > UNC , " \\ \\ " , 2 ) ! = 0 ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: UNC Path does not "
" begin with // or \\ \\ \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
} else {
printk ( KERN_WARNING " CIFS: UNC name too long \n " ) ;
return 1 ;
}
}
2007-07-10 05:16:18 +04:00
if ( vol - > UNCip = = NULL )
2005-04-17 02:20:36 +04:00
vol - > UNCip = & vol - > UNC [ 2 ] ;
return 0 ;
}
static struct cifsSesInfo *
2007-07-13 04:33:32 +04:00
cifs_find_tcp_session ( struct in_addr * target_ip_addr ,
2005-04-17 02:20:36 +04:00
struct in6_addr * target_ip6_addr ,
char * userName , struct TCP_Server_Info * * psrvTcp )
{
struct list_head * tmp ;
struct cifsSesInfo * ses ;
* psrvTcp = NULL ;
read_lock ( & GlobalSMBSeslock ) ;
list_for_each ( tmp , & GlobalSMBSessionList ) {
ses = list_entry ( tmp , struct cifsSesInfo , cifsSessionList ) ;
if ( ses - > server ) {
2007-07-13 04:33:32 +04:00
if ( ( target_ip_addr & &
2005-04-17 02:20:36 +04:00
( ses - > server - > addr . sockAddr . sin_addr . s_addr
= = target_ip_addr - > s_addr ) ) | | ( target_ip6_addr
& & memcmp ( & ses - > server - > addr . sockAddr6 . sin6_addr ,
2007-07-13 04:33:32 +04:00
target_ip6_addr , sizeof ( * target_ip6_addr ) ) ) ) {
/* BB lock server and tcp session and increment
use count here ? ? */
/* found a match on the TCP session */
* psrvTcp = ses - > server ;
2005-04-17 02:20:36 +04:00
/* BB check if reconnection needed */
if ( strncmp
( ses - > userName , userName ,
MAX_USERNAME_SIZE ) = = 0 ) {
read_unlock ( & GlobalSMBSeslock ) ;
2007-07-13 04:33:32 +04:00
/* Found exact match on both TCP and
SMB sessions */
return ses ;
2005-04-17 02:20:36 +04:00
}
}
}
/* else tcp and smb sessions need reconnection */
}
read_unlock ( & GlobalSMBSeslock ) ;
return NULL ;
}
static struct cifsTconInfo *
find_unc ( __be32 new_target_ip_addr , char * uncName , char * userName )
{
struct list_head * tmp ;
struct cifsTconInfo * tcon ;
read_lock ( & GlobalSMBSeslock ) ;
list_for_each ( tmp , & GlobalTreeConnectionList ) {
2006-08-15 17:07:18 +04:00
cFYI ( 1 , ( " Next tcon " ) ) ;
2005-04-17 02:20:36 +04:00
tcon = list_entry ( tmp , struct cifsTconInfo , cifsConnectionList ) ;
if ( tcon - > ses ) {
if ( tcon - > ses - > server ) {
cFYI ( 1 ,
2006-08-15 17:07:18 +04:00
( " old ip addr: %x == new ip %x ? " ,
2005-04-17 02:20:36 +04:00
tcon - > ses - > server - > addr . sockAddr . sin_addr .
s_addr , new_target_ip_addr ) ) ;
if ( tcon - > ses - > server - > addr . sockAddr . sin_addr .
s_addr = = new_target_ip_addr ) {
2006-08-15 17:07:18 +04:00
/* BB lock tcon, server and tcp session and increment use count here? */
2005-04-17 02:20:36 +04:00
/* found a match on the TCP session */
/* BB check if reconnection needed */
2007-07-13 04:33:32 +04:00
cFYI ( 1 ,
( " IP match, old UNC: %s new: %s " ,
2005-04-17 02:20:36 +04:00
tcon - > treeName , uncName ) ) ;
if ( strncmp
( tcon - > treeName , uncName ,
MAX_TREE_SIZE ) = = 0 ) {
cFYI ( 1 ,
2006-08-15 17:07:18 +04:00
( " and old usr: %s new: %s " ,
2005-04-17 02:20:36 +04:00
tcon - > treeName , uncName ) ) ;
if ( strncmp
( tcon - > ses - > userName ,
userName ,
MAX_USERNAME_SIZE ) = = 0 ) {
read_unlock ( & GlobalSMBSeslock ) ;
2006-08-15 17:07:18 +04:00
/* matched smb session
( user name */
return tcon ;
2005-04-17 02:20:36 +04:00
}
}
}
}
}
}
read_unlock ( & GlobalSMBSeslock ) ;
return NULL ;
}
int
connect_to_dfs_path ( int xid , struct cifsSesInfo * pSesInfo ,
2005-04-29 09:41:06 +04:00
const char * old_path , const struct nls_table * nls_codepage ,
int remap )
2005-04-17 02:20:36 +04:00
{
unsigned char * referrals = NULL ;
unsigned int num_referrals ;
int rc = 0 ;
2007-07-13 04:33:32 +04:00
rc = get_dfs_path ( xid , pSesInfo , old_path , nls_codepage ,
2005-04-29 09:41:06 +04:00
& num_referrals , & referrals , remap ) ;
2005-04-17 02:20:36 +04:00
/* BB Add in code to: if valid refrl, if not ip address contact
2007-07-13 04:33:32 +04:00
the helper that resolves tcp names , mount to it , try to
2005-04-17 02:20:36 +04:00
tcon to it unmount it if fail */
2005-11-07 12:01:34 +03:00
kfree ( referrals ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
int
2007-07-13 04:33:32 +04:00
get_dfs_path ( int xid , struct cifsSesInfo * pSesInfo , const char * old_path ,
const struct nls_table * nls_codepage , unsigned int * pnum_referrals ,
unsigned char * * preferrals , int remap )
2005-04-17 02:20:36 +04:00
{
char * temp_unc ;
int rc = 0 ;
* pnum_referrals = 0 ;
if ( pSesInfo - > ipc_tid = = 0 ) {
temp_unc = kmalloc ( 2 /* for slashes */ +
2007-07-13 04:33:32 +04:00
strnlen ( pSesInfo - > serverName ,
SERVER_NAME_LEN_WITH_NULL * 2 )
2005-04-17 02:20:36 +04:00
+ 1 + 4 /* slash IPC$ */ + 2 ,
GFP_KERNEL ) ;
if ( temp_unc = = NULL )
return - ENOMEM ;
temp_unc [ 0 ] = ' \\ ' ;
temp_unc [ 1 ] = ' \\ ' ;
strcpy ( temp_unc + 2 , pSesInfo - > serverName ) ;
strcpy ( temp_unc + 2 + strlen ( pSesInfo - > serverName ) , " \\ IPC$ " ) ;
rc = CIFSTCon ( xid , pSesInfo , temp_unc , NULL , nls_codepage ) ;
cFYI ( 1 ,
2007-07-13 04:33:32 +04:00
( " CIFS Tcon rc = %d ipc_tid = %d " , rc , pSesInfo - > ipc_tid ) ) ;
2005-04-17 02:20:36 +04:00
kfree ( temp_unc ) ;
}
if ( rc = = 0 )
rc = CIFSGetDFSRefer ( xid , pSesInfo , old_path , preferrals ,
2005-04-29 09:41:06 +04:00
pnum_referrals , nls_codepage , remap ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
/* See RFC1001 section 14 on representation of Netbios names */
2007-07-13 04:33:32 +04:00
static void rfc1002mangle ( char * target , char * source , unsigned int length )
2005-04-17 02:20:36 +04:00
{
2007-07-13 04:33:32 +04:00
unsigned int i , j ;
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
for ( i = 0 , j = 0 ; i < ( length ) ; i + + ) {
2005-04-17 02:20:36 +04:00
/* mask a nibble at a time and encode */
target [ j ] = ' A ' + ( 0x0F & ( source [ i ] > > 4 ) ) ;
target [ j + 1 ] = ' A ' + ( 0x0F & source [ i ] ) ;
2007-07-13 04:33:32 +04:00
j + = 2 ;
2005-04-17 02:20:36 +04:00
}
}
static int
2007-07-13 04:33:32 +04:00
ipv4_connect ( struct sockaddr_in * psin_server , struct socket * * csocket ,
char * netbios_name , char * target_name )
2005-04-17 02:20:36 +04:00
{
int rc = 0 ;
int connected = 0 ;
__be16 orig_port = 0 ;
2007-07-10 05:16:18 +04:00
if ( * csocket = = NULL ) {
2007-07-13 04:33:32 +04:00
rc = sock_create_kern ( PF_INET , SOCK_STREAM ,
IPPROTO_TCP , csocket ) ;
2005-04-17 02:20:36 +04:00
if ( rc < 0 ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " Error %d creating socket " , rc ) ) ;
2005-04-17 02:20:36 +04:00
* csocket = NULL ;
return rc ;
} else {
/* BB other socket options to set KEEPALIVE, NODELAY? */
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " Socket created " ) ) ;
2007-07-13 04:33:32 +04:00
( * csocket ) - > sk - > sk_allocation = GFP_NOFS ;
2005-04-17 02:20:36 +04:00
}
}
psin_server - > sin_family = AF_INET ;
2007-07-10 05:16:18 +04:00
if ( psin_server - > sin_port ) { /* user overrode default port */
2005-04-17 02:20:36 +04:00
rc = ( * csocket ) - > ops - > connect ( * csocket ,
( struct sockaddr * ) psin_server ,
2007-07-13 04:33:32 +04:00
sizeof ( struct sockaddr_in ) , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( rc > = 0 )
connected = 1 ;
2007-07-13 04:33:32 +04:00
}
2005-04-17 02:20:36 +04:00
2007-07-10 05:16:18 +04:00
if ( ! connected ) {
2007-07-13 04:33:32 +04:00
/* save original port so we can retry user specified port
2005-04-17 02:20:36 +04:00
later if fall back ports fail this time */
orig_port = psin_server - > sin_port ;
/* do not retry on the same port we just failed on */
2007-07-10 05:16:18 +04:00
if ( psin_server - > sin_port ! = htons ( CIFS_PORT ) ) {
2005-04-17 02:20:36 +04:00
psin_server - > sin_port = htons ( CIFS_PORT ) ;
rc = ( * csocket ) - > ops - > connect ( * csocket ,
( struct sockaddr * ) psin_server ,
2007-07-13 04:33:32 +04:00
sizeof ( struct sockaddr_in ) , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( rc > = 0 )
connected = 1 ;
}
}
if ( ! connected ) {
psin_server - > sin_port = htons ( RFC1001_PORT ) ;
rc = ( * csocket ) - > ops - > connect ( * csocket , ( struct sockaddr * )
2007-07-13 04:33:32 +04:00
psin_server ,
sizeof ( struct sockaddr_in ) , 0 ) ;
if ( rc > = 0 )
2005-04-17 02:20:36 +04:00
connected = 1 ;
}
/* give up here - unless we want to retry on different
protocol families some day */
if ( ! connected ) {
2007-07-10 05:16:18 +04:00
if ( orig_port )
2005-04-17 02:20:36 +04:00
psin_server - > sin_port = orig_port ;
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Error %d connecting to server via ipv4 " , rc ) ) ;
2005-04-17 02:20:36 +04:00
sock_release ( * csocket ) ;
* csocket = NULL ;
return rc ;
}
2007-07-13 04:33:32 +04:00
/* Eventually check for other socket options to change from
the default . sock_setsockopt not used because it expects
2005-04-17 02:20:36 +04:00
user space buffer */
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " sndbuf %d rcvbuf %d rcvtimeo 0x%lx " ,
( * csocket ) - > sk - > sk_sndbuf ,
2005-10-11 01:21:15 +04:00
( * csocket ) - > sk - > sk_rcvbuf , ( * csocket ) - > sk - > sk_rcvtimeo ) ) ;
2005-04-17 02:20:36 +04:00
( * csocket ) - > sk - > sk_rcvtimeo = 7 * HZ ;
2005-10-11 01:21:15 +04:00
/* make the bufsizes depend on wsize/rsize and max requests */
2007-07-10 05:16:18 +04:00
if ( ( * csocket ) - > sk - > sk_sndbuf < ( 200 * 1024 ) )
2005-10-11 01:21:15 +04:00
( * csocket ) - > sk - > sk_sndbuf = 200 * 1024 ;
2007-07-10 05:16:18 +04:00
if ( ( * csocket ) - > sk - > sk_rcvbuf < ( 140 * 1024 ) )
2005-10-11 01:21:15 +04:00
( * csocket ) - > sk - > sk_rcvbuf = 140 * 1024 ;
2005-04-17 02:20:36 +04:00
/* send RFC1001 sessinit */
2007-07-10 05:16:18 +04:00
if ( psin_server - > sin_port = = htons ( RFC1001_PORT ) ) {
2005-04-17 02:20:36 +04:00
/* some servers require RFC1001 sessinit before sending
2007-07-13 04:33:32 +04:00
negprot - BB check reconnection in case where second
2005-04-17 02:20:36 +04:00
sessinit is sent but no second negprot */
2007-07-13 04:33:32 +04:00
struct rfc1002_session_packet * ses_init_buf ;
struct smb_hdr * smb_buf ;
ses_init_buf = kzalloc ( sizeof ( struct rfc1002_session_packet ) ,
GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( ses_init_buf ) {
2005-04-17 02:20:36 +04:00
ses_init_buf - > trailer . session_req . called_len = 32 ;
2007-07-10 05:16:18 +04:00
if ( target_name & & ( target_name [ 0 ] ! = 0 ) ) {
2005-08-23 08:38:31 +04:00
rfc1002mangle ( ses_init_buf - > trailer . session_req . called_name ,
target_name , 16 ) ;
} else {
rfc1002mangle ( ses_init_buf - > trailer . session_req . called_name ,
2007-07-13 04:33:32 +04:00
DEFAULT_CIFS_CALLED_NAME , 16 ) ;
2005-08-23 08:38:31 +04:00
}
2005-04-17 02:20:36 +04:00
ses_init_buf - > trailer . session_req . calling_len = 32 ;
/* calling name ends in null (byte 16) from old smb
convention . */
2007-07-13 04:33:32 +04:00
if ( netbios_name & & ( netbios_name [ 0 ] ! = 0 ) ) {
2005-04-17 02:20:36 +04:00
rfc1002mangle ( ses_init_buf - > trailer . session_req . calling_name ,
2007-07-13 04:33:32 +04:00
netbios_name , 16 ) ;
2005-04-17 02:20:36 +04:00
} else {
rfc1002mangle ( ses_init_buf - > trailer . session_req . calling_name ,
2007-07-13 04:33:32 +04:00
" LINUX_CIFS_CLNT " , 16 ) ;
2005-04-17 02:20:36 +04:00
}
ses_init_buf - > trailer . session_req . scope1 = 0 ;
ses_init_buf - > trailer . session_req . scope2 = 0 ;
smb_buf = ( struct smb_hdr * ) ses_init_buf ;
/* sizeof RFC1002_SESSION_REQUEST with no scope */
smb_buf - > smb_buf_length = 0x81000044 ;
rc = smb_send ( * csocket , smb_buf , 0x44 ,
( struct sockaddr * ) psin_server ) ;
kfree ( ses_init_buf ) ;
2007-07-13 04:33:32 +04:00
msleep ( 1 ) ; /* RFC1001 layer in at least one server
2006-03-03 12:53:36 +03:00
requires very short break before negprot
presumably because not expecting negprot
to follow so fast . This is a simple
2007-07-13 04:33:32 +04:00
solution that works without
2006-03-03 12:53:36 +03:00
complicating the code and causes no
significant slowing down on mount
for everyone else */
2005-04-17 02:20:36 +04:00
}
2007-07-13 04:33:32 +04:00
/* else the negprot may still work without this
2005-04-17 02:20:36 +04:00
even though malloc failed */
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
}
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
return rc ;
}
static int
ipv6_connect ( struct sockaddr_in6 * psin_server , struct socket * * csocket )
{
int rc = 0 ;
int connected = 0 ;
__be16 orig_port = 0 ;
2007-07-10 05:16:18 +04:00
if ( * csocket = = NULL ) {
2007-07-13 04:33:32 +04:00
rc = sock_create_kern ( PF_INET6 , SOCK_STREAM ,
IPPROTO_TCP , csocket ) ;
2005-04-17 02:20:36 +04:00
if ( rc < 0 ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " Error %d creating ipv6 socket " , rc ) ) ;
2005-04-17 02:20:36 +04:00
* csocket = NULL ;
return rc ;
} else {
/* BB other socket options to set KEEPALIVE, NODELAY? */
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " ipv6 Socket created " ) ) ;
2005-04-17 02:20:36 +04:00
( * csocket ) - > sk - > sk_allocation = GFP_NOFS ;
}
}
psin_server - > sin6_family = AF_INET6 ;
2007-07-10 05:16:18 +04:00
if ( psin_server - > sin6_port ) { /* user overrode default port */
2005-04-17 02:20:36 +04:00
rc = ( * csocket ) - > ops - > connect ( * csocket ,
( struct sockaddr * ) psin_server ,
2007-07-13 04:33:32 +04:00
sizeof ( struct sockaddr_in6 ) , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( rc > = 0 )
connected = 1 ;
2007-07-13 04:33:32 +04:00
}
2005-04-17 02:20:36 +04:00
2007-07-10 05:16:18 +04:00
if ( ! connected ) {
2007-07-13 04:33:32 +04:00
/* save original port so we can retry user specified port
2005-04-17 02:20:36 +04:00
later if fall back ports fail this time */
orig_port = psin_server - > sin6_port ;
/* do not retry on the same port we just failed on */
2007-07-10 05:16:18 +04:00
if ( psin_server - > sin6_port ! = htons ( CIFS_PORT ) ) {
2005-04-17 02:20:36 +04:00
psin_server - > sin6_port = htons ( CIFS_PORT ) ;
rc = ( * csocket ) - > ops - > connect ( * csocket ,
( struct sockaddr * ) psin_server ,
2007-07-13 04:33:32 +04:00
sizeof ( struct sockaddr_in6 ) , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( rc > = 0 )
connected = 1 ;
}
}
if ( ! connected ) {
psin_server - > sin6_port = htons ( RFC1001_PORT ) ;
rc = ( * csocket ) - > ops - > connect ( * csocket , ( struct sockaddr * )
2007-07-13 04:33:32 +04:00
psin_server , sizeof ( struct sockaddr_in6 ) , 0 ) ;
if ( rc > = 0 )
2005-04-17 02:20:36 +04:00
connected = 1 ;
}
/* give up here - unless we want to retry on different
protocol families some day */
if ( ! connected ) {
2007-07-10 05:16:18 +04:00
if ( orig_port )
2005-04-17 02:20:36 +04:00
psin_server - > sin6_port = orig_port ;
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Error %d connecting to server via ipv6 " , rc ) ) ;
2005-04-17 02:20:36 +04:00
sock_release ( * csocket ) ;
* csocket = NULL ;
return rc ;
}
2007-07-13 04:33:32 +04:00
/* Eventually check for other socket options to change from
the default . sock_setsockopt not used because it expects
2005-04-17 02:20:36 +04:00
user space buffer */
( * csocket ) - > sk - > sk_rcvtimeo = 7 * HZ ;
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
return rc ;
}
2007-07-13 04:33:32 +04:00
void reset_cifs_unix_caps ( int xid , struct cifsTconInfo * tcon ,
struct super_block * sb , struct smb_vol * vol_info )
2007-02-14 07:42:51 +03:00
{
/* if we are reconnecting then should we check to see if
* any requested capabilities changed locally e . g . via
* remount but we can not do much about it here
* if they have ( even if we could detect it by the following )
* Perhaps we could add a backpointer to array of sb from tcon
* or if we change to make all sb to same share the same
* sb as NFS - then we only have one backpointer to sb .
* What if we wanted to mount the server share twice once with
* and once without posixacls or posix paths ? */
__u64 saved_cap = le64_to_cpu ( tcon - > fsUnixInfo . Capability ) ;
2007-07-13 04:33:32 +04:00
2007-07-19 03:21:09 +04:00
if ( vol_info & & vol_info - > no_linux_ext ) {
tcon - > fsUnixInfo . Capability = 0 ;
tcon - > unix_ext = 0 ; /* Unix Extensions disabled */
cFYI ( 1 , ( " Linux protocol extensions disabled " ) ) ;
return ;
} else if ( vol_info )
tcon - > unix_ext = 1 ; /* Unix Extensions supported */
if ( tcon - > unix_ext = = 0 ) {
cFYI ( 1 , ( " Unix extensions disabled so not set on reconnect " ) ) ;
return ;
}
2007-07-13 04:33:32 +04:00
2007-07-10 05:16:18 +04:00
if ( ! CIFSSMBQFSUnixInfo ( xid , tcon ) ) {
2007-02-14 07:42:51 +03:00
__u64 cap = le64_to_cpu ( tcon - > fsUnixInfo . Capability ) ;
2007-07-13 04:33:32 +04:00
2007-02-14 07:42:51 +03:00
/* check for reconnect case in which we do not
want to change the mount behavior if we can avoid it */
2007-07-10 05:16:18 +04:00
if ( vol_info = = NULL ) {
2007-07-13 04:33:32 +04:00
/* turn off POSIX ACL and PATHNAMES if not set
2007-02-14 07:42:51 +03:00
originally at mount time */
if ( ( saved_cap & CIFS_UNIX_POSIX_ACL_CAP ) = = 0 )
cap & = ~ CIFS_UNIX_POSIX_ACL_CAP ;
if ( ( saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP ) = = 0 )
cap & = ~ CIFS_UNIX_POSIX_PATHNAMES_CAP ;
}
2007-07-13 04:33:32 +04:00
2007-02-14 07:42:51 +03:00
cap & = CIFS_UNIX_CAP_MASK ;
2007-06-24 22:30:48 +04:00
if ( vol_info & & vol_info - > no_psx_acl )
2007-02-14 07:42:51 +03:00
cap & = ~ CIFS_UNIX_POSIX_ACL_CAP ;
2007-06-24 22:30:48 +04:00
else if ( CIFS_UNIX_POSIX_ACL_CAP & cap ) {
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " negotiated posix acl support " ) ) ;
if ( sb )
2007-02-14 07:42:51 +03:00
sb - > s_flags | = MS_POSIXACL ;
}
2007-06-24 22:30:48 +04:00
if ( vol_info & & vol_info - > posix_paths = = 0 )
2007-02-14 07:42:51 +03:00
cap & = ~ CIFS_UNIX_POSIX_PATHNAMES_CAP ;
2007-06-24 22:30:48 +04:00
else if ( cap & CIFS_UNIX_POSIX_PATHNAMES_CAP ) {
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " negotiate posix pathnames " ) ) ;
2007-06-24 22:30:48 +04:00
if ( sb )
2007-07-13 04:33:32 +04:00
CIFS_SB ( sb ) - > mnt_cifs_flags | =
2007-02-14 07:42:51 +03:00
CIFS_MOUNT_POSIX_PATHS ;
}
2007-07-13 04:33:32 +04:00
2007-04-26 20:42:50 +04:00
/* We might be setting the path sep back to a different
form if we are reconnecting and the server switched its
2007-07-13 04:33:32 +04:00
posix path capability for this share */
2007-06-24 22:30:48 +04:00
if ( sb & & ( CIFS_SB ( sb ) - > prepathlen > 0 ) )
2007-04-26 20:42:50 +04:00
CIFS_SB ( sb ) - > prepath [ 0 ] = CIFS_DIR_SEP ( CIFS_SB ( sb ) ) ;
2007-06-24 22:30:48 +04:00
if ( sb & & ( CIFS_SB ( sb ) - > rsize > 127 * 1024 ) ) {
if ( ( cap & CIFS_UNIX_LARGE_READ_CAP ) = = 0 ) {
CIFS_SB ( sb ) - > rsize = 127 * 1024 ;
# ifdef CONFIG_CIFS_DEBUG2
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " larger reads not supported by srv " ) ) ;
2007-06-24 22:30:48 +04:00
# endif
}
}
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Negotiate caps 0x%x " , ( int ) cap ) ) ;
2007-02-14 07:42:51 +03:00
# ifdef CONFIG_CIFS_DEBUG2
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_FCNTL_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " FCNTL cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_EXTATTR_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " EXTATTR cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_POSIX_PATHNAMES_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " POSIX path cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_XATTR_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " XATTR cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_POSIX_ACL_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " POSIX ACL cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_LARGE_READ_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " very large read cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_LARGE_WRITE_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " very large write cap " ) ) ;
2007-02-14 07:42:51 +03:00
# endif /* CIFS_DEBUG2 */
if ( CIFSSMBSetFSUnixInfo ( xid , tcon , cap ) ) {
2007-09-20 19:16:24 +04:00
if ( vol_info = = NULL )
cFYI ( 1 , ( " resetting capabilities failed " ) ) ;
else
cERROR ( 1 , ( " Negotiating Unix capabilities "
" with the server failed. Consider "
" mounting with the Unix Extensions \n "
" disabled, if problems are found, "
" by specifying the nounix mount "
2007-09-20 19:37:29 +04:00
" option. " ) ) ;
2007-09-20 19:16:24 +04:00
2007-02-14 07:42:51 +03:00
}
}
}
2005-04-17 02:20:36 +04:00
int
cifs_mount ( struct super_block * sb , struct cifs_sb_info * cifs_sb ,
char * mount_data , const char * devname )
{
int rc = 0 ;
int xid ;
int address_type = AF_INET ;
struct socket * csocket = NULL ;
struct sockaddr_in sin_server ;
struct sockaddr_in6 sin_server6 ;
struct smb_vol volume_info ;
struct cifsSesInfo * pSesInfo = NULL ;
struct cifsSesInfo * existingCifsSes = NULL ;
struct cifsTconInfo * tcon = NULL ;
struct TCP_Server_Info * srvTcp = NULL ;
xid = GetXid ( ) ;
/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
2007-07-13 04:33:32 +04:00
memset ( & volume_info , 0 , sizeof ( struct smb_vol ) ) ;
2005-04-17 02:20:36 +04:00
if ( cifs_parse_mount_options ( mount_data , devname , & volume_info ) ) {
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
kfree ( volume_info . password ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return - EINVAL ;
}
2007-05-05 07:27:49 +04:00
if ( volume_info . nullauth ) {
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " null user " ) ) ;
2007-05-05 07:27:49 +04:00
volume_info . username = NULL ;
} else if ( volume_info . username ) {
2005-04-17 02:20:36 +04:00
/* BB fixme parse for domain name here */
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " Username: %s " , volume_info . username ) ) ;
2005-04-17 02:20:36 +04:00
} else {
2005-12-02 09:32:42 +03:00
cifserror ( " No username specified " ) ;
2007-07-13 04:33:32 +04:00
/* In userspace mount helper we can get user name from alternate
locations such as env variables and files on disk */
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
kfree ( volume_info . password ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return - EINVAL ;
}
if ( volume_info . UNCip & & volume_info . UNC ) {
2007-07-13 04:33:32 +04:00
rc = cifs_inet_pton ( AF_INET , volume_info . UNCip ,
& sin_server . sin_addr . s_addr ) ;
2005-04-17 02:20:36 +04:00
2007-07-10 05:16:18 +04:00
if ( rc < = 0 ) {
2005-04-17 02:20:36 +04:00
/* not ipv4 address, try ipv6 */
2007-07-13 04:33:32 +04:00
rc = cifs_inet_pton ( AF_INET6 , volume_info . UNCip ,
& sin_server6 . sin6_addr . in6_u ) ;
2007-07-10 05:16:18 +04:00
if ( rc > 0 )
2005-04-17 02:20:36 +04:00
address_type = AF_INET6 ;
} else {
address_type = AF_INET ;
}
2007-07-13 04:33:32 +04:00
2007-07-10 05:16:18 +04:00
if ( rc < = 0 ) {
2005-04-17 02:20:36 +04:00
/* we failed translating address */
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
kfree ( volume_info . password ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return - EINVAL ;
}
cFYI ( 1 , ( " UNC: %s ip: %s " , volume_info . UNC , volume_info . UNCip ) ) ;
/* success */
rc = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( volume_info . UNCip ) {
/* BB using ip addr as server name to connect to the
DFS root below */
cERROR ( 1 , ( " Connecting to DFS root not implemented yet " ) ) ;
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
kfree ( volume_info . password ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return - EINVAL ;
} else /* which servers DFS root would we conect to */ {
cERROR ( 1 ,
2007-07-13 04:33:32 +04:00
( " CIFS mount error: No UNC path (e.g. -o "
" unc=//192.168.1.100/public) specified " ) ) ;
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
kfree ( volume_info . password ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return - EINVAL ;
}
/* this is needed for ASCII cp to Unicode converts */
2007-07-10 05:16:18 +04:00
if ( volume_info . iocharset = = NULL ) {
2005-04-17 02:20:36 +04:00
cifs_sb - > local_nls = load_nls_default ( ) ;
/* load_nls_default can not return null */
} else {
cifs_sb - > local_nls = load_nls ( volume_info . iocharset ) ;
2007-07-10 05:16:18 +04:00
if ( cifs_sb - > local_nls = = NULL ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " CIFS mount error: iocharset %s not found " ,
volume_info . iocharset ) ) ;
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
kfree ( volume_info . password ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return - ELIBACC ;
}
}
2007-07-10 05:16:18 +04:00
if ( address_type = = AF_INET )
2005-04-17 02:20:36 +04:00
existingCifsSes = cifs_find_tcp_session ( & sin_server . sin_addr ,
NULL /* no ipv6 addr */ ,
volume_info . username , & srvTcp ) ;
2007-07-10 05:16:18 +04:00
else if ( address_type = = AF_INET6 ) {
cFYI ( 1 , ( " looking for ipv6 address " ) ) ;
2005-04-17 02:20:36 +04:00
existingCifsSes = cifs_find_tcp_session ( NULL /* no ipv4 addr */ ,
& sin_server6 . sin6_addr ,
volume_info . username , & srvTcp ) ;
2007-04-25 15:59:10 +04:00
} else {
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
kfree ( volume_info . password ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return - EINVAL ;
}
if ( srvTcp ) {
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Existing tcp session with server found " ) ) ;
2005-04-17 02:20:36 +04:00
} else { /* create socket */
2007-05-01 00:13:06 +04:00
if ( volume_info . port )
2005-04-17 02:20:36 +04:00
sin_server . sin_port = htons ( volume_info . port ) ;
else
sin_server . sin_port = 0 ;
2007-04-25 15:59:10 +04:00
if ( address_type = = AF_INET6 ) {
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " attempting ipv6 connect " ) ) ;
2007-04-25 15:59:10 +04:00
/* BB should we allow ipv6 on port 139? */
/* other OS never observed in Wild doing 139 with v6 */
2007-07-13 04:33:32 +04:00
rc = ipv6_connect ( & sin_server6 , & csocket ) ;
} else
rc = ipv4_connect ( & sin_server , & csocket ,
2005-08-23 08:38:31 +04:00
volume_info . source_rfc1001_name ,
volume_info . target_rfc1001_name ) ;
2005-04-17 02:20:36 +04:00
if ( rc < 0 ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " Error connecting to IPv4 socket. "
" Aborting operation " ) ) ;
2007-05-01 00:13:06 +04:00
if ( csocket ! = NULL )
2005-04-17 02:20:36 +04:00
sock_release ( csocket ) ;
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
kfree ( volume_info . password ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return rc ;
}
srvTcp = kmalloc ( sizeof ( struct TCP_Server_Info ) , GFP_KERNEL ) ;
if ( srvTcp = = NULL ) {
rc = - ENOMEM ;
sock_release ( csocket ) ;
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
kfree ( volume_info . password ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return rc ;
} else {
memset ( srvTcp , 0 , sizeof ( struct TCP_Server_Info ) ) ;
2007-07-13 04:33:32 +04:00
memcpy ( & srvTcp - > addr . sockAddr , & sin_server ,
sizeof ( struct sockaddr_in ) ) ;
atomic_set ( & srvTcp - > inFlight , 0 ) ;
2005-04-17 02:20:36 +04:00
/* BB Add code for ipv6 case too */
srvTcp - > ssocket = csocket ;
srvTcp - > protocolType = IPV4 ;
init_waitqueue_head ( & srvTcp - > response_q ) ;
init_waitqueue_head ( & srvTcp - > request_q ) ;
INIT_LIST_HEAD ( & srvTcp - > pending_mid_q ) ;
/* at this point we are the only ones with the pointer
to the struct since the kernel thread not created yet
so no need to spinlock this init of tcpStatus */
srvTcp - > tcpStatus = CifsNew ;
init_MUTEX ( & srvTcp - > tcpSem ) ;
2007-04-03 23:16:43 +04:00
srvTcp - > tsk = kthread_run ( ( void * ) ( void * ) cifs_demultiplex_thread , srvTcp , " cifsd " ) ;
2007-05-01 00:13:06 +04:00
if ( IS_ERR ( srvTcp - > tsk ) ) {
2007-04-03 23:16:43 +04:00
rc = PTR_ERR ( srvTcp - > tsk ) ;
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " error %d create cifsd thread " , rc ) ) ;
2007-04-03 23:16:43 +04:00
srvTcp - > tsk = NULL ;
2005-04-17 02:20:36 +04:00
sock_release ( csocket ) ;
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
kfree ( volume_info . password ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return rc ;
2005-08-18 20:37:34 +04:00
}
wait_for_completion ( & cifsd_complete ) ;
rc = 0 ;
2007-07-13 04:33:32 +04:00
memcpy ( srvTcp - > workstation_RFC1001_name ,
volume_info . source_rfc1001_name , 16 ) ;
memcpy ( srvTcp - > server_RFC1001_name ,
volume_info . target_rfc1001_name , 16 ) ;
2005-04-29 09:41:05 +04:00
srvTcp - > sequence_number = 0 ;
2005-04-17 02:20:36 +04:00
}
}
if ( existingCifsSes ) {
pSesInfo = existingCifsSes ;
2005-12-02 09:32:42 +03:00
cFYI ( 1 , ( " Existing smb sess found " ) ) ;
2005-11-07 12:01:34 +03:00
kfree ( volume_info . password ) ;
2005-04-17 02:20:36 +04:00
/* volume_info.UNC freed at end of function */
} else if ( ! rc ) {
2005-12-02 09:32:42 +03:00
cFYI ( 1 , ( " Existing smb sess not found " ) ) ;
2005-04-17 02:20:36 +04:00
pSesInfo = sesInfoAlloc ( ) ;
if ( pSesInfo = = NULL )
rc = - ENOMEM ;
else {
pSesInfo - > server = srvTcp ;
sprintf ( pSesInfo - > serverName , " %u.%u.%u.%u " ,
NIPQUAD ( sin_server . sin_addr . s_addr ) ) ;
}
2007-07-13 04:33:32 +04:00
if ( ! rc ) {
/* volume_info.password freed at unmount */
2005-04-17 02:20:36 +04:00
if ( volume_info . password )
pSesInfo - > password = volume_info . password ;
if ( volume_info . username )
strncpy ( pSesInfo - > userName ,
2007-07-13 04:33:32 +04:00
volume_info . username ,
MAX_USERNAME_SIZE ) ;
2006-06-01 02:40:51 +04:00
if ( volume_info . domainname ) {
int len = strlen ( volume_info . domainname ) ;
2007-07-13 04:33:32 +04:00
pSesInfo - > domainName =
2006-06-01 02:40:51 +04:00
kmalloc ( len + 1 , GFP_KERNEL ) ;
2007-05-01 00:13:06 +04:00
if ( pSesInfo - > domainName )
2006-06-01 02:40:51 +04:00
strcpy ( pSesInfo - > domainName ,
volume_info . domainname ) ;
}
2005-04-17 02:20:36 +04:00
pSesInfo - > linux_uid = volume_info . linux_uid ;
2006-06-27 10:28:30 +04:00
pSesInfo - > overrideSecFlg = volume_info . secFlg ;
2005-04-17 02:20:36 +04:00
down ( & pSesInfo - > sesSem ) ;
2006-06-23 06:33:48 +04:00
/* BB FIXME need to pass vol->secFlgs BB */
2007-07-13 04:33:32 +04:00
rc = cifs_setup_session ( xid , pSesInfo ,
cifs_sb - > local_nls ) ;
2005-04-17 02:20:36 +04:00
up ( & pSesInfo - > sesSem ) ;
2007-05-01 00:13:06 +04:00
if ( ! rc )
2005-04-17 02:20:36 +04:00
atomic_inc ( & srvTcp - > socketUseCount ) ;
} else
2005-11-07 12:01:34 +03:00
kfree ( volume_info . password ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
/* search for existing tcon to this server share */
if ( ! rc ) {
2007-05-01 00:13:06 +04:00
if ( volume_info . rsize > CIFSMaxBufSize ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " rsize %d too large, using MaxBufSize " ,
2005-10-10 21:57:19 +04:00
volume_info . rsize ) ) ;
cifs_sb - > rsize = CIFSMaxBufSize ;
2007-06-24 22:30:48 +04:00
} else if ( ( volume_info . rsize ) & &
( volume_info . rsize < = CIFSMaxBufSize ) )
2005-04-17 02:20:36 +04:00
cifs_sb - > rsize = volume_info . rsize ;
2005-10-10 21:57:19 +04:00
else /* default */
cifs_sb - > rsize = CIFSMaxBufSize ;
2007-05-01 00:13:06 +04:00
if ( volume_info . wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " wsize %d too large, using 4096 instead " ,
2005-10-10 21:57:19 +04:00
volume_info . wsize ) ) ;
cifs_sb - > wsize = 4096 ;
2007-05-01 00:13:06 +04:00
} else if ( volume_info . wsize )
2005-04-17 02:20:36 +04:00
cifs_sb - > wsize = volume_info . wsize ;
else
2007-07-13 04:33:32 +04:00
cifs_sb - > wsize =
2006-01-28 05:36:11 +03:00
min_t ( const int , PAGEVEC_SIZE * PAGE_CACHE_SIZE ,
127 * 1024 ) ;
2006-01-25 07:26:48 +03:00
/* old default of CIFSMaxBufSize was too small now
2007-07-13 04:33:32 +04:00
that SMB Write2 can send multiple pages in kvec .
2006-01-25 07:26:48 +03:00
RFC1001 does not describe what happens when frame
bigger than 128 K is sent so use that as max in
conjunction with 52 K kvec constraint on arch with 4 K
page size */
2007-05-01 00:13:06 +04:00
if ( cifs_sb - > rsize < 2048 ) {
2007-07-13 04:33:32 +04:00
cifs_sb - > rsize = 2048 ;
2006-02-23 02:31:52 +03:00
/* Windows ME may prefer this */
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " readsize set to minimum: 2048 " ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-09-21 11:02:52 +04:00
/* calculate prepath */
cifs_sb - > prepath = volume_info . prepath ;
2007-05-01 00:13:06 +04:00
if ( cifs_sb - > prepath ) {
2006-09-21 11:02:52 +04:00
cifs_sb - > prepathlen = strlen ( cifs_sb - > prepath ) ;
cifs_sb - > prepath [ 0 ] = CIFS_DIR_SEP ( cifs_sb ) ;
volume_info . prepath = NULL ;
2007-07-13 04:33:32 +04:00
} else
2006-09-21 11:02:52 +04:00
cifs_sb - > prepathlen = 0 ;
2005-04-17 02:20:36 +04:00
cifs_sb - > mnt_uid = volume_info . linux_uid ;
cifs_sb - > mnt_gid = volume_info . linux_gid ;
cifs_sb - > mnt_file_mode = volume_info . file_mode ;
cifs_sb - > mnt_dir_mode = volume_info . dir_mode ;
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " file mode: 0x%x dir mode: 0x%x " ,
cifs_sb - > mnt_file_mode , cifs_sb - > mnt_dir_mode ) ) ;
2005-04-17 02:20:36 +04:00
2007-05-01 00:13:06 +04:00
if ( volume_info . noperm )
2005-04-17 02:20:36 +04:00
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_NO_PERM ;
2007-05-01 00:13:06 +04:00
if ( volume_info . setuids )
2005-04-17 02:20:36 +04:00
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_SET_UID ;
2007-05-01 00:13:06 +04:00
if ( volume_info . server_ino )
2005-04-17 02:20:36 +04:00
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_SERVER_INUM ;
2007-05-01 00:13:06 +04:00
if ( volume_info . remap )
2005-04-29 09:41:05 +04:00
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_MAP_SPECIAL_CHR ;
2007-05-01 00:13:06 +04:00
if ( volume_info . no_xattr )
2005-04-17 02:20:36 +04:00
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_NO_XATTR ;
2007-05-01 00:13:06 +04:00
if ( volume_info . sfu_emul )
2005-07-15 03:25:12 +04:00
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_UNX_EMUL ;
2007-05-01 00:13:06 +04:00
if ( volume_info . nobrl )
2005-08-19 07:49:57 +04:00
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_NO_BRL ;
2007-05-01 00:13:06 +04:00
if ( volume_info . cifs_acl )
2006-01-13 02:44:21 +03:00
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_CIFS_ACL ;
2007-05-01 00:13:06 +04:00
if ( volume_info . override_uid )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_OVERR_UID ;
if ( volume_info . override_gid )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_OVERR_GID ;
if ( volume_info . direct_io ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " mounting share using direct i/o " ) ) ;
2005-04-17 02:20:36 +04:00
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_DIRECT_IO ;
}
tcon =
find_unc ( sin_server . sin_addr . s_addr , volume_info . UNC ,
volume_info . username ) ;
if ( tcon ) {
2005-12-02 09:32:42 +03:00
cFYI ( 1 , ( " Found match on UNC path " ) ) ;
2005-04-17 02:20:36 +04:00
/* we can have only one retry value for a connection
to a share so for resources mounted more than once
2007-07-13 04:33:32 +04:00
to the same server share the last value passed in
2005-04-17 02:20:36 +04:00
for the retry flag is used */
tcon - > retry = volume_info . retry ;
2005-08-19 22:04:29 +04:00
tcon - > nocase = volume_info . nocase ;
2005-04-17 02:20:36 +04:00
} else {
tcon = tconInfoAlloc ( ) ;
if ( tcon = = NULL )
rc = - ENOMEM ;
else {
2007-07-13 04:33:32 +04:00
/* check for null share name ie connecting to
2007-02-14 07:42:51 +03:00
* dfs root */
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
/* BB check if this works for exactly length
2007-02-14 07:42:51 +03:00
* three strings */
2005-04-17 02:20:36 +04:00
if ( ( strchr ( volume_info . UNC + 3 , ' \\ ' ) = = NULL )
& & ( strchr ( volume_info . UNC + 3 , ' / ' ) = =
NULL ) ) {
2005-04-29 09:41:06 +04:00
rc = connect_to_dfs_path ( xid , pSesInfo ,
2007-02-14 07:42:51 +03:00
" " , cifs_sb - > local_nls ,
2007-07-13 04:33:32 +04:00
cifs_sb - > mnt_cifs_flags &
2007-02-14 07:42:51 +03:00
CIFS_MOUNT_MAP_SPECIAL_CHR ) ;
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return - ENODEV ;
} else {
2007-02-14 07:42:51 +03:00
/* BB Do we need to wrap sesSem around
* this TCon call and Unix SetFS as
* we do on SessSetup and reconnect ? */
2007-07-13 04:33:32 +04:00
rc = CIFSTCon ( xid , pSesInfo ,
2005-04-17 02:20:36 +04:00
volume_info . UNC ,
tcon , cifs_sb - > local_nls ) ;
cFYI ( 1 , ( " CIFS Tcon rc = %d " , rc ) ) ;
}
if ( ! rc ) {
atomic_inc ( & pSesInfo - > inUse ) ;
tcon - > retry = volume_info . retry ;
2005-08-19 22:04:29 +04:00
tcon - > nocase = volume_info . nocase ;
2005-04-17 02:20:36 +04:00
}
}
}
}
2007-05-01 00:13:06 +04:00
if ( pSesInfo ) {
2005-04-17 02:20:36 +04:00
if ( pSesInfo - > capabilities & CAP_LARGE_FILES ) {
sb - > s_maxbytes = ( u64 ) 1 < < 63 ;
} else
sb - > s_maxbytes = ( u64 ) 1 < < 31 ; /* 2 GB */
}
2007-02-14 07:42:51 +03:00
/* BB FIXME fix time_gran to be larger for LANMAN sessions */
2005-04-17 02:20:36 +04:00
sb - > s_time_gran = 100 ;
/* on error free sesinfo and tcon struct if needed */
if ( rc ) {
/* if session setup failed, use count is zero but
we still need to free cifsd thread */
2007-05-01 00:13:06 +04:00
if ( atomic_read ( & srvTcp - > socketUseCount ) = = 0 ) {
2005-04-17 02:20:36 +04:00
spin_lock ( & GlobalMid_Lock ) ;
srvTcp - > tcpStatus = CifsExiting ;
spin_unlock ( & GlobalMid_Lock ) ;
2007-05-01 00:13:06 +04:00
if ( srvTcp - > tsk ) {
2007-05-23 18:45:36 +04:00
struct task_struct * tsk ;
/* If we could verify that kthread_stop would
always wake up processes blocked in
tcp in recv_mesg then we could remove the
send_sig call */
2007-07-13 04:33:32 +04:00
force_sig ( SIGKILL , srvTcp - > tsk ) ;
2007-05-23 18:45:36 +04:00
tsk = srvTcp - > tsk ;
2007-07-10 05:16:18 +04:00
if ( tsk )
2007-05-24 06:29:51 +04:00
kthread_stop ( tsk ) ;
2005-08-18 20:37:34 +04:00
}
2005-04-17 02:20:36 +04:00
}
/* If find_unc succeeded then rc == 0 so we can not end */
if ( tcon ) /* up accidently freeing someone elses tcon struct */
tconInfoFree ( tcon ) ;
if ( existingCifsSes = = NULL ) {
if ( pSesInfo ) {
2007-07-13 04:33:32 +04:00
if ( ( pSesInfo - > server ) & &
2005-04-17 02:20:36 +04:00
( pSesInfo - > status = = CifsGood ) ) {
int temp_rc ;
temp_rc = CIFSSMBLogoff ( xid , pSesInfo ) ;
/* if the socketUseCount is now zero */
2007-05-01 00:13:06 +04:00
if ( ( temp_rc = = - ESHUTDOWN ) & &
2007-07-13 04:33:32 +04:00
( pSesInfo - > server ) & &
2007-06-26 02:16:35 +04:00
( pSesInfo - > server - > tsk ) ) {
2007-05-23 18:45:36 +04:00
struct task_struct * tsk ;
2007-06-26 02:16:35 +04:00
force_sig ( SIGKILL ,
pSesInfo - > server - > tsk ) ;
2007-05-23 18:45:36 +04:00
tsk = pSesInfo - > server - > tsk ;
2007-05-24 06:29:51 +04:00
if ( tsk )
2007-05-23 18:45:36 +04:00
kthread_stop ( tsk ) ;
2005-08-18 20:37:34 +04:00
}
2005-04-17 02:20:36 +04:00
} else
cFYI ( 1 , ( " No session or bad tcon " ) ) ;
sesInfoFree ( pSesInfo ) ;
/* pSesInfo = NULL; */
}
}
} else {
atomic_inc ( & tcon - > useCount ) ;
cifs_sb - > tcon = tcon ;
tcon - > ses = pSesInfo ;
2006-03-02 06:24:57 +03:00
/* do not care if following two calls succeed - informational */
2005-04-29 09:41:06 +04:00
CIFSSMBQFSDeviceInfo ( xid , tcon ) ;
CIFSSMBQFSAttributeInfo ( xid , tcon ) ;
2007-07-13 04:33:32 +04:00
2007-02-14 07:42:51 +03:00
/* tell server which Unix caps we support */
if ( tcon - > ses - > capabilities & CAP_UNIX )
2007-07-19 03:21:09 +04:00
/* reset of caps checks mount to see if unix extensions
disabled for just this mount */
2007-02-14 07:42:51 +03:00
reset_cifs_unix_caps ( xid , tcon , sb , & volume_info ) ;
2007-07-19 03:21:09 +04:00
else
tcon - > unix_ext = 0 ; /* server does not support them */
if ( ( tcon - > unix_ext = = 0 ) & & ( cifs_sb - > rsize > ( 1024 * 127 ) ) ) {
2007-06-24 22:30:48 +04:00
cifs_sb - > rsize = 1024 * 127 ;
# ifdef CONFIG_CIFS_DEBUG2
2007-07-19 03:21:09 +04:00
cFYI ( 1 , ( " no very large read support, rsize now 127K " ) ) ;
2007-06-24 22:30:48 +04:00
# endif
}
2005-10-04 00:37:24 +04:00
if ( ! ( tcon - > ses - > capabilities & CAP_LARGE_WRITE_X ) )
cifs_sb - > wsize = min ( cifs_sb - > wsize ,
( tcon - > ses - > server - > maxBuf -
MAX_CIFS_HDR_SIZE ) ) ;
2005-10-10 21:57:19 +04:00
if ( ! ( tcon - > ses - > capabilities & CAP_LARGE_READ_X ) )
2007-07-13 04:33:32 +04:00
cifs_sb - > rsize = min ( cifs_sb - > rsize ,
( tcon - > ses - > server - > maxBuf -
MAX_CIFS_HDR_SIZE ) ) ;
2005-04-17 02:20:36 +04:00
}
/* volume_info.password is freed above when existing session found
( in which case it is not needed anymore ) but when new sesion is created
the password ptr is put in the new session structure ( in which case the
password will be freed at unmount time ) */
2005-11-07 12:01:34 +03:00
kfree ( volume_info . UNC ) ;
2006-09-21 11:02:52 +04:00
kfree ( volume_info . prepath ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return rc ;
}
static int
CIFSSessSetup ( unsigned int xid , struct cifsSesInfo * ses ,
2006-06-01 23:20:10 +04:00
char session_key [ CIFS_SESS_KEY_SIZE ] ,
2005-04-17 02:20:36 +04:00
const struct nls_table * nls_codepage )
{
struct smb_hdr * smb_buffer ;
struct smb_hdr * smb_buffer_response ;
SESSION_SETUP_ANDX * pSMB ;
SESSION_SETUP_ANDX * pSMBr ;
char * bcc_ptr ;
char * user ;
char * domain ;
int rc = 0 ;
int remaining_words = 0 ;
int bytes_returned = 0 ;
int len ;
__u32 capabilities ;
__u16 count ;
2006-01-14 08:34:58 +03:00
cFYI ( 1 , ( " In sesssetup " ) ) ;
2007-05-01 00:13:06 +04:00
if ( ses = = NULL )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
user = ses - > userName ;
domain = ses - > domainName ;
smb_buffer = cifs_buf_get ( ) ;
if ( smb_buffer = = NULL ) {
return - ENOMEM ;
}
smb_buffer_response = smb_buffer ;
pSMBr = pSMB = ( SESSION_SETUP_ANDX * ) smb_buffer ;
/* send SMBsessionSetup here */
header_assemble ( smb_buffer , SMB_COM_SESSION_SETUP_ANDX ,
NULL /* no tCon exists yet */ , 13 /* wct */ ) ;
2005-08-17 23:38:22 +04:00
smb_buffer - > Mid = GetNextMid ( ses - > server ) ;
2005-04-17 02:20:36 +04:00
pSMB - > req_no_secext . AndXCommand = 0xFF ;
pSMB - > req_no_secext . MaxBufferSize = cpu_to_le16 ( ses - > server - > maxBuf ) ;
pSMB - > req_no_secext . MaxMpxCount = cpu_to_le16 ( ses - > server - > maxReq ) ;
2007-07-13 04:33:32 +04:00
if ( ses - > server - > secMode &
( SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED ) )
2005-04-17 02:20:36 +04:00
smb_buffer - > Flags2 | = SMBFLG2_SECURITY_SIGNATURE ;
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
CAP_LARGE_WRITE_X | CAP_LARGE_READ_X ;
if ( ses - > capabilities & CAP_UNICODE ) {
smb_buffer - > Flags2 | = SMBFLG2_UNICODE ;
capabilities | = CAP_UNICODE ;
}
if ( ses - > capabilities & CAP_STATUS32 ) {
smb_buffer - > Flags2 | = SMBFLG2_ERR_STATUS ;
capabilities | = CAP_STATUS32 ;
}
if ( ses - > capabilities & CAP_DFS ) {
smb_buffer - > Flags2 | = SMBFLG2_DFS ;
capabilities | = CAP_DFS ;
}
pSMB - > req_no_secext . Capabilities = cpu_to_le32 ( capabilities ) ;
2007-07-13 04:33:32 +04:00
pSMB - > req_no_secext . CaseInsensitivePasswordLength =
2006-06-01 23:20:10 +04:00
cpu_to_le16 ( CIFS_SESS_KEY_SIZE ) ;
2005-04-17 02:20:36 +04:00
pSMB - > req_no_secext . CaseSensitivePasswordLength =
2006-06-01 23:20:10 +04:00
cpu_to_le16 ( CIFS_SESS_KEY_SIZE ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr = pByteArea ( smb_buffer ) ;
2006-06-01 23:20:10 +04:00
memcpy ( bcc_ptr , ( char * ) session_key , CIFS_SESS_KEY_SIZE ) ;
bcc_ptr + = CIFS_SESS_KEY_SIZE ;
memcpy ( bcc_ptr , ( char * ) session_key , CIFS_SESS_KEY_SIZE ) ;
bcc_ptr + = CIFS_SESS_KEY_SIZE ;
2005-04-17 02:20:36 +04:00
if ( ses - > capabilities & CAP_UNICODE ) {
if ( ( long ) bcc_ptr % 2 ) { /* must be word aligned for Unicode */
* bcc_ptr = 0 ;
bcc_ptr + + ;
}
2007-05-01 00:13:06 +04:00
if ( user = = NULL )
2006-06-01 02:40:51 +04:00
bytes_returned = 0 ; /* skip null user */
2007-07-13 04:33:32 +04:00
else
2005-04-17 02:20:36 +04:00
bytes_returned =
2007-07-13 04:33:32 +04:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , user , 100 ,
2005-04-17 02:20:36 +04:00
nls_codepage ) ;
/* convert number of 16 bit words to bytes */
bcc_ptr + = 2 * bytes_returned ;
bcc_ptr + = 2 ; /* trailing null */
if ( domain = = NULL )
bytes_returned =
2005-11-12 02:18:19 +03:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr ,
2005-04-17 02:20:36 +04:00
" CIFS_LINUX_DOM " , 32 , nls_codepage ) ;
else
bytes_returned =
2005-11-12 02:18:19 +03:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , domain , 64 ,
2005-04-17 02:20:36 +04:00
nls_codepage ) ;
bcc_ptr + = 2 * bytes_returned ;
bcc_ptr + = 2 ;
bytes_returned =
2005-11-12 02:18:19 +03:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , " Linux version " ,
2005-04-17 02:20:36 +04:00
32 , nls_codepage ) ;
bcc_ptr + = 2 * bytes_returned ;
bytes_returned =
2006-10-02 13:18:11 +04:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , utsname ( ) - > release ,
2005-04-17 02:20:36 +04:00
32 , nls_codepage ) ;
bcc_ptr + = 2 * bytes_returned ;
bcc_ptr + = 2 ;
bytes_returned =
2005-11-12 02:18:19 +03:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , CIFS_NETWORK_OPSYS ,
2005-04-17 02:20:36 +04:00
64 , nls_codepage ) ;
bcc_ptr + = 2 * bytes_returned ;
bcc_ptr + = 2 ;
} else {
2007-07-13 04:33:32 +04:00
if ( user ! = NULL ) {
2005-04-17 02:20:36 +04:00
strncpy ( bcc_ptr , user , 200 ) ;
bcc_ptr + = strnlen ( user , 200 ) ;
}
* bcc_ptr = 0 ;
bcc_ptr + + ;
if ( domain = = NULL ) {
strcpy ( bcc_ptr , " CIFS_LINUX_DOM " ) ;
bcc_ptr + = strlen ( " CIFS_LINUX_DOM " ) + 1 ;
} else {
strncpy ( bcc_ptr , domain , 64 ) ;
bcc_ptr + = strnlen ( domain , 64 ) ;
* bcc_ptr = 0 ;
bcc_ptr + + ;
}
strcpy ( bcc_ptr , " Linux version " ) ;
bcc_ptr + = strlen ( " Linux version " ) ;
2006-10-02 13:18:11 +04:00
strcpy ( bcc_ptr , utsname ( ) - > release ) ;
bcc_ptr + = strlen ( utsname ( ) - > release ) + 1 ;
2005-04-17 02:20:36 +04:00
strcpy ( bcc_ptr , CIFS_NETWORK_OPSYS ) ;
bcc_ptr + = strlen ( CIFS_NETWORK_OPSYS ) + 1 ;
}
count = ( long ) bcc_ptr - ( long ) pByteArea ( smb_buffer ) ;
smb_buffer - > smb_buf_length + = count ;
pSMB - > req_no_secext . ByteCount = cpu_to_le16 ( count ) ;
rc = SendReceive ( xid , ses , smb_buffer , smb_buffer_response ,
& bytes_returned , 1 ) ;
if ( rc ) {
/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
} else if ( ( smb_buffer_response - > WordCount = = 3 )
| | ( smb_buffer_response - > WordCount = = 4 ) ) {
__u16 action = le16_to_cpu ( pSMBr - > resp . Action ) ;
__u16 blob_len = le16_to_cpu ( pSMBr - > resp . SecurityBlobLength ) ;
if ( action & GUEST_LOGIN )
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Guest login " ) ) ; /* BB mark SesInfo struct? */
ses - > Suid = smb_buffer_response - > Uid ; /* UID left in wire format
( little endian ) */
2005-04-17 02:20:36 +04:00
cFYI ( 1 , ( " UID = %d " , ses - > Suid ) ) ;
2007-07-13 04:33:32 +04:00
/* response can have either 3 or 4 word count - Samba sends 3 */
bcc_ptr = pByteArea ( smb_buffer_response ) ;
2005-04-17 02:20:36 +04:00
if ( ( pSMBr - > resp . hdr . WordCount = = 3 )
| | ( ( pSMBr - > resp . hdr . WordCount = = 4 )
& & ( blob_len < pSMBr - > resp . ByteCount ) ) ) {
if ( pSMBr - > resp . hdr . WordCount = = 4 )
bcc_ptr + = blob_len ;
if ( smb_buffer - > Flags2 & SMBFLG2_UNICODE ) {
if ( ( long ) ( bcc_ptr ) % 2 ) {
remaining_words =
2007-07-13 04:33:32 +04:00
( BCC ( smb_buffer_response ) - 1 ) / 2 ;
/* Unicode strings must be word
aligned */
bcc_ptr + + ;
2005-04-17 02:20:36 +04:00
} else {
remaining_words =
BCC ( smb_buffer_response ) / 2 ;
}
len =
UniStrnlen ( ( wchar_t * ) bcc_ptr ,
remaining_words - 1 ) ;
/* 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-10 05:16:18 +04:00
if ( ses - > serverOS )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverOS ) ;
2007-07-13 04:33:32 +04:00
ses - > serverOS = kzalloc ( 2 * ( len + 1 ) ,
GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( ses - > serverOS = = NULL )
2005-04-29 09:41:08 +04:00
goto sesssetup_nomem ;
2005-04-17 02:20:36 +04:00
cifs_strfromUCS_le ( ses - > serverOS ,
2007-07-13 04:33:32 +04:00
( __le16 * ) bcc_ptr ,
len , nls_codepage ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + = 2 * ( len + 1 ) ;
remaining_words - = len + 1 ;
ses - > serverOS [ 2 * len ] = 0 ;
ses - > serverOS [ 1 + ( 2 * len ) ] = 0 ;
if ( remaining_words > 0 ) {
len = UniStrnlen ( ( wchar_t * ) bcc_ptr ,
remaining_words - 1 ) ;
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverNOS ) ;
2007-07-13 04:33:32 +04:00
ses - > serverNOS = kzalloc ( 2 * ( len + 1 ) ,
GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( ses - > serverNOS = = NULL )
2005-04-29 09:41:08 +04:00
goto sesssetup_nomem ;
2005-04-17 02:20:36 +04:00
cifs_strfromUCS_le ( ses - > serverNOS ,
2007-07-13 04:33:32 +04:00
( __le16 * ) bcc_ptr ,
len , nls_codepage ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + = 2 * ( len + 1 ) ;
ses - > serverNOS [ 2 * len ] = 0 ;
ses - > serverNOS [ 1 + ( 2 * len ) ] = 0 ;
2007-07-10 05:16:18 +04:00
if ( strncmp ( ses - > serverNOS ,
2007-07-13 04:33:32 +04:00
" NT LAN Manager 4 " , 16 ) = = 0 ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " NT4 server " ) ) ;
2005-04-17 02:20:36 +04:00
ses - > flags | = CIFS_SES_NT4 ;
}
remaining_words - = len + 1 ;
if ( remaining_words > 0 ) {
2005-04-29 09:41:08 +04:00
len = UniStrnlen ( ( wchar_t * ) bcc_ptr , remaining_words ) ;
2007-07-13 04:33:32 +04:00
/* last string is not always null terminated
( for e . g . for Windows XP & 2000 ) */
2007-07-10 05:16:18 +04:00
if ( ses - > serverDomain )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverDomain ) ;
2005-04-17 02:20:36 +04:00
ses - > serverDomain =
2007-07-13 04:33:32 +04:00
kzalloc ( 2 * ( len + 1 ) ,
GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( ses - > serverDomain = = NULL )
2005-04-29 09:41:08 +04:00
goto sesssetup_nomem ;
2005-04-17 02:20:36 +04:00
cifs_strfromUCS_le ( ses - > serverDomain ,
2007-07-13 04:33:32 +04:00
( __le16 * ) bcc_ptr ,
len , nls_codepage ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + = 2 * ( len + 1 ) ;
ses - > serverDomain [ 2 * len ] = 0 ;
ses - > serverDomain [ 1 + ( 2 * len ) ] = 0 ;
2007-07-13 04:33:32 +04:00
} else { /* else no more room so create
dummy domain string */
2007-07-10 05:16:18 +04:00
if ( ses - > serverDomain )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverDomain ) ;
2007-07-13 04:33:32 +04:00
ses - > serverDomain =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 , GFP_KERNEL ) ;
2006-05-30 22:06:04 +04:00
}
2007-07-13 04:33:32 +04:00
} else { /* no room so create dummy domain
and NOS string */
2005-04-29 09:41:08 +04:00
/* if these kcallocs fail not much we
can do , but better to not fail the
sesssetup itself */
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverDomain ) ;
2005-04-17 02:20:36 +04:00
ses - > serverDomain =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 , GFP_KERNEL ) ;
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverNOS ) ;
2005-04-17 02:20:36 +04:00
ses - > serverNOS =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
}
} else { /* ASCII */
len = strnlen ( bcc_ptr , 1024 ) ;
if ( ( ( long ) bcc_ptr + len ) - ( long )
pByteArea ( smb_buffer_response )
< = BCC ( smb_buffer_response ) ) {
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverOS ) ;
2007-07-13 04:33:32 +04:00
ses - > serverOS = kzalloc ( len + 1 ,
GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( ses - > serverOS = = NULL )
2005-04-29 09:41:08 +04:00
goto sesssetup_nomem ;
2007-07-13 04:33:32 +04:00
strncpy ( ses - > serverOS , bcc_ptr , len ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + = len ;
2007-07-13 04:33:32 +04:00
/* null terminate the string */
bcc_ptr [ 0 ] = 0 ;
2005-04-17 02:20:36 +04:00
bcc_ptr + + ;
len = strnlen ( bcc_ptr , 1024 ) ;
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverNOS ) ;
2007-07-13 04:33:32 +04:00
ses - > serverNOS = kzalloc ( len + 1 ,
GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( ses - > serverNOS = = NULL )
2005-04-29 09:41:08 +04:00
goto sesssetup_nomem ;
2005-04-17 02:20:36 +04:00
strncpy ( ses - > serverNOS , bcc_ptr , len ) ;
bcc_ptr + = len ;
bcc_ptr [ 0 ] = 0 ;
bcc_ptr + + ;
len = strnlen ( bcc_ptr , 1024 ) ;
2007-07-10 05:16:18 +04:00
if ( ses - > serverDomain )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverDomain ) ;
2007-07-13 04:33:32 +04:00
ses - > serverDomain = kzalloc ( len + 1 ,
GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( ses - > serverDomain = = NULL )
2005-04-29 09:41:08 +04:00
goto sesssetup_nomem ;
2007-07-13 04:33:32 +04:00
strncpy ( ses - > serverDomain , bcc_ptr ,
len ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + = len ;
bcc_ptr [ 0 ] = 0 ;
bcc_ptr + + ;
} else
cFYI ( 1 ,
2007-07-13 04:33:32 +04:00
( " Variable field of length %d "
" extends beyond end of smb " ,
2005-04-17 02:20:36 +04:00
len ) ) ;
}
} else {
cERROR ( 1 ,
2007-07-13 04:33:32 +04:00
( " Security Blob Length extends beyond "
" end of SMB " ) ) ;
2005-04-17 02:20:36 +04:00
}
} else {
cERROR ( 1 ,
( " Invalid Word count %d: " ,
smb_buffer_response - > WordCount ) ) ;
rc = - EIO ;
}
2005-04-29 09:41:08 +04:00
sesssetup_nomem : /* do not return an error on nomem for the info strings,
since that could make reconnection harder , and
reconnection might be needed to free memory */
2005-04-17 02:20:36 +04:00
if ( smb_buffer )
cifs_buf_release ( smb_buffer ) ;
return rc ;
}
static int
CIFSNTLMSSPNegotiateSessSetup ( unsigned int xid ,
2007-07-13 04:33:32 +04:00
struct cifsSesInfo * ses , int * pNTLMv2_flag ,
2005-04-17 02:20:36 +04:00
const struct nls_table * nls_codepage )
{
struct smb_hdr * smb_buffer ;
struct smb_hdr * smb_buffer_response ;
SESSION_SETUP_ANDX * pSMB ;
SESSION_SETUP_ANDX * pSMBr ;
char * bcc_ptr ;
char * domain ;
int rc = 0 ;
int remaining_words = 0 ;
int bytes_returned = 0 ;
int len ;
int SecurityBlobLength = sizeof ( NEGOTIATE_MESSAGE ) ;
PNEGOTIATE_MESSAGE SecurityBlob ;
PCHALLENGE_MESSAGE SecurityBlob2 ;
__u32 negotiate_flags , capabilities ;
__u16 count ;
2006-02-10 00:12:47 +03:00
cFYI ( 1 , ( " In NTLMSSP sesssetup (negotiate) " ) ) ;
2007-07-10 05:16:18 +04:00
if ( ses = = NULL )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
domain = ses - > domainName ;
* pNTLMv2_flag = FALSE ;
smb_buffer = cifs_buf_get ( ) ;
if ( smb_buffer = = NULL ) {
return - ENOMEM ;
}
smb_buffer_response = smb_buffer ;
pSMB = ( SESSION_SETUP_ANDX * ) smb_buffer ;
pSMBr = ( SESSION_SETUP_ANDX * ) smb_buffer_response ;
/* send SMBsessionSetup here */
header_assemble ( smb_buffer , SMB_COM_SESSION_SETUP_ANDX ,
NULL /* no tCon exists yet */ , 12 /* wct */ ) ;
2005-08-17 23:38:22 +04:00
smb_buffer - > Mid = GetNextMid ( ses - > server ) ;
2005-04-17 02:20:36 +04:00
pSMB - > req . hdr . Flags2 | = SMBFLG2_EXT_SEC ;
pSMB - > req . hdr . Flags | = ( SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT ) ;
pSMB - > req . AndXCommand = 0xFF ;
pSMB - > req . MaxBufferSize = cpu_to_le16 ( ses - > server - > maxBuf ) ;
pSMB - > req . MaxMpxCount = cpu_to_le16 ( ses - > server - > maxReq ) ;
2007-07-10 05:16:18 +04:00
if ( ses - > server - > secMode & ( SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED ) )
2005-04-17 02:20:36 +04:00
smb_buffer - > Flags2 | = SMBFLG2_SECURITY_SIGNATURE ;
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
CAP_EXTENDED_SECURITY ;
if ( ses - > capabilities & CAP_UNICODE ) {
smb_buffer - > Flags2 | = SMBFLG2_UNICODE ;
capabilities | = CAP_UNICODE ;
}
if ( ses - > capabilities & CAP_STATUS32 ) {
smb_buffer - > Flags2 | = SMBFLG2_ERR_STATUS ;
capabilities | = CAP_STATUS32 ;
}
if ( ses - > capabilities & CAP_DFS ) {
smb_buffer - > Flags2 | = SMBFLG2_DFS ;
capabilities | = CAP_DFS ;
}
pSMB - > req . Capabilities = cpu_to_le32 ( capabilities ) ;
bcc_ptr = ( char * ) & pSMB - > req . SecurityBlob ;
SecurityBlob = ( PNEGOTIATE_MESSAGE ) bcc_ptr ;
strncpy ( SecurityBlob - > Signature , NTLMSSP_SIGNATURE , 8 ) ;
SecurityBlob - > MessageType = NtLmNegotiate ;
negotiate_flags =
NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2006-02-10 00:12:47 +03:00
NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_NEGOTIATE_56 |
2005-04-17 02:20:36 +04:00
/* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128 ;
2007-07-10 05:16:18 +04:00
if ( sign_CIFS_PDUs )
2005-04-17 02:20:36 +04:00
negotiate_flags | = NTLMSSP_NEGOTIATE_SIGN ;
2007-07-10 05:16:18 +04:00
/* if (ntlmv2_support)
2006-06-01 02:40:51 +04:00
negotiate_flags | = NTLMSSP_NEGOTIATE_NTLMV2 ; */
2005-04-17 02:20:36 +04:00
/* setup pointers to domain name and workstation name */
bcc_ptr + = SecurityBlobLength ;
SecurityBlob - > WorkstationName . Buffer = 0 ;
SecurityBlob - > WorkstationName . Length = 0 ;
SecurityBlob - > WorkstationName . MaximumLength = 0 ;
2006-02-10 00:12:47 +03:00
/* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
along with username on auth request ( ie the response to challenge ) */
SecurityBlob - > DomainName . Buffer = 0 ;
SecurityBlob - > DomainName . Length = 0 ;
SecurityBlob - > DomainName . MaximumLength = 0 ;
2005-04-17 02:20:36 +04:00
if ( ses - > capabilities & CAP_UNICODE ) {
if ( ( long ) bcc_ptr % 2 ) {
* bcc_ptr = 0 ;
bcc_ptr + + ;
}
bytes_returned =
2005-11-12 02:18:19 +03:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , " Linux version " ,
2005-04-17 02:20:36 +04:00
32 , nls_codepage ) ;
bcc_ptr + = 2 * bytes_returned ;
bytes_returned =
2006-10-02 13:18:11 +04:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , utsname ( ) - > release , 32 ,
2005-04-17 02:20:36 +04:00
nls_codepage ) ;
bcc_ptr + = 2 * bytes_returned ;
bcc_ptr + = 2 ; /* null terminate Linux version */
bytes_returned =
2005-11-12 02:18:19 +03:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , CIFS_NETWORK_OPSYS ,
2005-04-17 02:20:36 +04:00
64 , nls_codepage ) ;
bcc_ptr + = 2 * bytes_returned ;
* ( bcc_ptr + 1 ) = 0 ;
* ( bcc_ptr + 2 ) = 0 ;
bcc_ptr + = 2 ; /* null terminate network opsys string */
* ( bcc_ptr + 1 ) = 0 ;
* ( bcc_ptr + 2 ) = 0 ;
bcc_ptr + = 2 ; /* null domain */
} else { /* ASCII */
strcpy ( bcc_ptr , " Linux version " ) ;
bcc_ptr + = strlen ( " Linux version " ) ;
2006-10-02 13:18:11 +04:00
strcpy ( bcc_ptr , utsname ( ) - > release ) ;
bcc_ptr + = strlen ( utsname ( ) - > release ) + 1 ;
2005-04-17 02:20:36 +04:00
strcpy ( bcc_ptr , CIFS_NETWORK_OPSYS ) ;
bcc_ptr + = strlen ( CIFS_NETWORK_OPSYS ) + 1 ;
bcc_ptr + + ; /* empty domain field */
* bcc_ptr = 0 ;
}
SecurityBlob - > NegotiateFlags = cpu_to_le32 ( negotiate_flags ) ;
pSMB - > req . SecurityBlobLength = cpu_to_le16 ( SecurityBlobLength ) ;
count = ( long ) bcc_ptr - ( long ) pByteArea ( smb_buffer ) ;
smb_buffer - > smb_buf_length + = count ;
pSMB - > req . ByteCount = cpu_to_le16 ( count ) ;
rc = SendReceive ( xid , ses , smb_buffer , smb_buffer_response ,
& bytes_returned , 1 ) ;
if ( smb_buffer_response - > Status . CifsError = =
cpu_to_le32 ( NT_STATUS_MORE_PROCESSING_REQUIRED ) )
rc = 0 ;
if ( rc ) {
/* rc = map_smb_to_linux_error(smb_buffer_response); */ /* done in SendReceive now */
} else if ( ( smb_buffer_response - > WordCount = = 3 )
| | ( smb_buffer_response - > WordCount = = 4 ) ) {
__u16 action = le16_to_cpu ( pSMBr - > resp . Action ) ;
__u16 blob_len = le16_to_cpu ( pSMBr - > resp . SecurityBlobLength ) ;
if ( action & GUEST_LOGIN )
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Guest login " ) ) ;
/* Do we want to set anything in SesInfo struct when guest login? */
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
bcc_ptr = pByteArea ( smb_buffer_response ) ;
/* response can have either 3 or 4 word count - Samba sends 3 */
2005-04-17 02:20:36 +04:00
SecurityBlob2 = ( PCHALLENGE_MESSAGE ) bcc_ptr ;
if ( SecurityBlob2 - > MessageType ! = NtLmChallenge ) {
cFYI ( 1 ,
( " Unexpected NTLMSSP message type received %d " ,
SecurityBlob2 - > MessageType ) ) ;
} else if ( ses ) {
2007-07-13 04:33:32 +04:00
ses - > Suid = smb_buffer_response - > Uid ; /* UID left in le format */
2006-02-10 00:12:47 +03:00
cFYI ( 1 , ( " UID = %d " , ses - > Suid ) ) ;
2005-04-17 02:20:36 +04:00
if ( ( pSMBr - > resp . hdr . WordCount = = 3 )
| | ( ( pSMBr - > resp . hdr . WordCount = = 4 )
& & ( blob_len <
pSMBr - > resp . ByteCount ) ) ) {
if ( pSMBr - > resp . hdr . WordCount = = 4 ) {
bcc_ptr + = blob_len ;
2006-02-10 00:12:47 +03:00
cFYI ( 1 , ( " Security Blob Length %d " ,
2005-04-17 02:20:36 +04:00
blob_len ) ) ;
}
2006-02-10 00:12:47 +03:00
cFYI ( 1 , ( " NTLMSSP Challenge rcvd " ) ) ;
2005-04-17 02:20:36 +04:00
memcpy ( ses - > server - > cryptKey ,
SecurityBlob2 - > Challenge ,
CIFS_CRYPTO_KEY_SIZE ) ;
2007-07-13 04:33:32 +04:00
if ( SecurityBlob2 - > NegotiateFlags &
2006-02-10 00:12:47 +03:00
cpu_to_le32 ( NTLMSSP_NEGOTIATE_NTLMV2 ) )
2005-04-17 02:20:36 +04:00
* pNTLMv2_flag = TRUE ;
2007-07-13 04:33:32 +04:00
if ( ( SecurityBlob2 - > NegotiateFlags &
cpu_to_le32 ( NTLMSSP_NEGOTIATE_ALWAYS_SIGN ) )
2005-04-17 02:20:36 +04:00
| | ( sign_CIFS_PDUs > 1 ) )
2007-07-13 04:33:32 +04:00
ses - > server - > secMode | =
SECMODE_SIGN_REQUIRED ;
if ( ( SecurityBlob2 - > NegotiateFlags &
2005-04-17 02:20:36 +04:00
cpu_to_le32 ( NTLMSSP_NEGOTIATE_SIGN ) ) & & ( sign_CIFS_PDUs ) )
2007-07-13 04:33:32 +04:00
ses - > server - > secMode | =
2005-04-17 02:20:36 +04:00
SECMODE_SIGN_ENABLED ;
if ( smb_buffer - > Flags2 & SMBFLG2_UNICODE ) {
if ( ( long ) ( bcc_ptr ) % 2 ) {
remaining_words =
( BCC ( smb_buffer_response )
- 1 ) / 2 ;
2007-07-13 04:33:32 +04:00
/* Must word align unicode strings */
bcc_ptr + + ;
2005-04-17 02:20:36 +04:00
} else {
remaining_words =
BCC
( smb_buffer_response ) / 2 ;
}
len =
UniStrnlen ( ( wchar_t * ) bcc_ptr ,
remaining_words - 1 ) ;
/* 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-10 05:16:18 +04:00
if ( ses - > serverOS )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverOS ) ;
2005-04-17 02:20:36 +04:00
ses - > serverOS =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 * ( len + 1 ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
cifs_strfromUCS_le ( ses - > serverOS ,
2005-11-12 02:18:19 +03:00
( __le16 * )
2005-04-17 02:20:36 +04:00
bcc_ptr , len ,
nls_codepage ) ;
bcc_ptr + = 2 * ( len + 1 ) ;
remaining_words - = len + 1 ;
ses - > serverOS [ 2 * len ] = 0 ;
ses - > serverOS [ 1 + ( 2 * len ) ] = 0 ;
if ( remaining_words > 0 ) {
len = UniStrnlen ( ( wchar_t * )
bcc_ptr ,
remaining_words
- 1 ) ;
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverNOS ) ;
2005-04-17 02:20:36 +04:00
ses - > serverNOS =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 * ( len + 1 ) ,
2005-04-17 02:20:36 +04:00
GFP_KERNEL ) ;
cifs_strfromUCS_le ( ses - >
serverNOS ,
2005-11-12 02:18:19 +03:00
( __le16 * )
2005-04-17 02:20:36 +04:00
bcc_ptr ,
len ,
nls_codepage ) ;
bcc_ptr + = 2 * ( len + 1 ) ;
ses - > serverNOS [ 2 * len ] = 0 ;
ses - > serverNOS [ 1 +
( 2 * len ) ] = 0 ;
remaining_words - = len + 1 ;
if ( remaining_words > 0 ) {
2007-07-13 04:33:32 +04:00
len = UniStrnlen ( ( wchar_t * ) bcc_ptr , remaining_words ) ;
/* last string not always null terminated
( for e . g . for Windows XP & 2000 ) */
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverDomain ) ;
2005-04-17 02:20:36 +04:00
ses - > serverDomain =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 *
2005-04-17 02:20:36 +04:00
( len +
1 ) ,
GFP_KERNEL ) ;
cifs_strfromUCS_le
2005-11-12 02:18:19 +03:00
( ses - > serverDomain ,
( __le16 * ) bcc_ptr ,
len , nls_codepage ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + =
2 * ( len + 1 ) ;
2005-11-12 02:18:19 +03:00
ses - > serverDomain [ 2 * len ]
2005-04-17 02:20:36 +04:00
= 0 ;
2005-11-12 02:18:19 +03:00
ses - > serverDomain
[ 1 + ( 2 * len ) ]
2005-04-17 02:20:36 +04:00
= 0 ;
} /* else no more room so create dummy domain string */
2006-05-30 22:06:04 +04:00
else {
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverDomain ) ;
2005-04-17 02:20:36 +04:00
ses - > serverDomain =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 ,
2005-04-17 02:20:36 +04:00
GFP_KERNEL ) ;
2006-05-30 22:06:04 +04:00
}
2005-04-17 02:20:36 +04:00
} else { /* no room so create dummy domain and NOS string */
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverDomain ) ;
2005-04-17 02:20:36 +04:00
ses - > serverDomain =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 , GFP_KERNEL ) ;
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverNOS ) ;
2005-04-17 02:20:36 +04:00
ses - > serverNOS =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
}
} else { /* ASCII */
len = strnlen ( bcc_ptr , 1024 ) ;
if ( ( ( long ) bcc_ptr + len ) - ( long )
pByteArea ( smb_buffer_response )
< = BCC ( smb_buffer_response ) ) {
2007-07-10 05:16:18 +04:00
if ( ses - > serverOS )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverOS ) ;
2005-04-17 02:20:36 +04:00
ses - > serverOS =
2005-09-07 02:18:35 +04:00
kzalloc ( len + 1 ,
2005-04-17 02:20:36 +04:00
GFP_KERNEL ) ;
strncpy ( ses - > serverOS ,
bcc_ptr , len ) ;
bcc_ptr + = len ;
bcc_ptr [ 0 ] = 0 ; /* null terminate string */
bcc_ptr + + ;
len = strnlen ( bcc_ptr , 1024 ) ;
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverNOS ) ;
2005-04-17 02:20:36 +04:00
ses - > serverNOS =
2005-09-07 02:18:35 +04:00
kzalloc ( len + 1 ,
2005-04-17 02:20:36 +04:00
GFP_KERNEL ) ;
strncpy ( ses - > serverNOS , bcc_ptr , len ) ;
bcc_ptr + = len ;
bcc_ptr [ 0 ] = 0 ;
bcc_ptr + + ;
len = strnlen ( bcc_ptr , 1024 ) ;
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverDomain ) ;
2005-04-17 02:20:36 +04:00
ses - > serverDomain =
2005-09-07 02:18:35 +04:00
kzalloc ( len + 1 ,
2005-04-17 02:20:36 +04:00
GFP_KERNEL ) ;
2007-07-13 04:33:32 +04:00
strncpy ( ses - > serverDomain ,
bcc_ptr , len ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + = len ;
bcc_ptr [ 0 ] = 0 ;
bcc_ptr + + ;
} else
cFYI ( 1 ,
2007-07-17 21:34:02 +04:00
( " field of length %d "
" extends beyond end of smb " ,
2005-04-17 02:20:36 +04:00
len ) ) ;
}
} else {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " Security Blob Length extends beyond "
" end of SMB " ) ) ;
2005-04-17 02:20:36 +04:00
}
} else {
cERROR ( 1 , ( " No session structure passed in. " ) ) ;
}
} else {
cERROR ( 1 ,
2006-02-14 04:36:20 +03:00
( " Invalid Word count %d: " ,
2005-04-17 02:20:36 +04:00
smb_buffer_response - > WordCount ) ) ;
rc = - EIO ;
}
if ( smb_buffer )
cifs_buf_release ( smb_buffer ) ;
return rc ;
}
static int
CIFSNTLMSSPAuthSessSetup ( unsigned int xid , struct cifsSesInfo * ses ,
char * ntlm_session_key , int ntlmv2_flag ,
const struct nls_table * nls_codepage )
{
struct smb_hdr * smb_buffer ;
struct smb_hdr * smb_buffer_response ;
SESSION_SETUP_ANDX * pSMB ;
SESSION_SETUP_ANDX * pSMBr ;
char * bcc_ptr ;
char * user ;
char * domain ;
int rc = 0 ;
int remaining_words = 0 ;
int bytes_returned = 0 ;
int len ;
int SecurityBlobLength = sizeof ( AUTHENTICATE_MESSAGE ) ;
PAUTHENTICATE_MESSAGE SecurityBlob ;
__u32 negotiate_flags , capabilities ;
__u16 count ;
cFYI ( 1 , ( " In NTLMSSPSessSetup (Authenticate) " ) ) ;
2007-07-10 05:16:18 +04:00
if ( ses = = NULL )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
user = ses - > userName ;
domain = ses - > domainName ;
smb_buffer = cifs_buf_get ( ) ;
if ( smb_buffer = = NULL ) {
return - ENOMEM ;
}
smb_buffer_response = smb_buffer ;
pSMB = ( SESSION_SETUP_ANDX * ) smb_buffer ;
pSMBr = ( SESSION_SETUP_ANDX * ) smb_buffer_response ;
/* send SMBsessionSetup here */
header_assemble ( smb_buffer , SMB_COM_SESSION_SETUP_ANDX ,
NULL /* no tCon exists yet */ , 12 /* wct */ ) ;
2005-08-17 23:38:22 +04:00
smb_buffer - > Mid = GetNextMid ( ses - > server ) ;
2005-04-17 02:20:36 +04:00
pSMB - > req . hdr . Flags | = ( SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT ) ;
pSMB - > req . hdr . Flags2 | = SMBFLG2_EXT_SEC ;
pSMB - > req . AndXCommand = 0xFF ;
pSMB - > req . MaxBufferSize = cpu_to_le16 ( ses - > server - > maxBuf ) ;
pSMB - > req . MaxMpxCount = cpu_to_le16 ( ses - > server - > maxReq ) ;
pSMB - > req . hdr . Uid = ses - > Suid ;
2007-07-10 05:16:18 +04:00
if ( ses - > server - > secMode & ( SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED ) )
2005-04-17 02:20:36 +04:00
smb_buffer - > Flags2 | = SMBFLG2_SECURITY_SIGNATURE ;
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
CAP_EXTENDED_SECURITY ;
if ( ses - > capabilities & CAP_UNICODE ) {
smb_buffer - > Flags2 | = SMBFLG2_UNICODE ;
capabilities | = CAP_UNICODE ;
}
if ( ses - > capabilities & CAP_STATUS32 ) {
smb_buffer - > Flags2 | = SMBFLG2_ERR_STATUS ;
capabilities | = CAP_STATUS32 ;
}
if ( ses - > capabilities & CAP_DFS ) {
smb_buffer - > Flags2 | = SMBFLG2_DFS ;
capabilities | = CAP_DFS ;
}
pSMB - > req . Capabilities = cpu_to_le32 ( capabilities ) ;
bcc_ptr = ( char * ) & pSMB - > req . SecurityBlob ;
SecurityBlob = ( PAUTHENTICATE_MESSAGE ) bcc_ptr ;
strncpy ( SecurityBlob - > Signature , NTLMSSP_SIGNATURE , 8 ) ;
SecurityBlob - > MessageType = NtLmAuthenticate ;
bcc_ptr + = SecurityBlobLength ;
2007-07-13 04:33:32 +04:00
negotiate_flags =
2005-04-17 02:20:36 +04:00
NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
0x80000000 | NTLMSSP_NEGOTIATE_128 ;
2007-07-10 05:16:18 +04:00
if ( sign_CIFS_PDUs )
2005-04-17 02:20:36 +04:00
negotiate_flags | = /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN ;
2007-07-10 05:16:18 +04:00
if ( ntlmv2_flag )
2005-04-17 02:20:36 +04:00
negotiate_flags | = NTLMSSP_NEGOTIATE_NTLMV2 ;
/* setup pointers to domain name and workstation name */
SecurityBlob - > WorkstationName . Buffer = 0 ;
SecurityBlob - > WorkstationName . Length = 0 ;
SecurityBlob - > WorkstationName . MaximumLength = 0 ;
SecurityBlob - > SessionKey . Length = 0 ;
SecurityBlob - > SessionKey . MaximumLength = 0 ;
SecurityBlob - > SessionKey . Buffer = 0 ;
SecurityBlob - > LmChallengeResponse . Length = 0 ;
SecurityBlob - > LmChallengeResponse . MaximumLength = 0 ;
SecurityBlob - > LmChallengeResponse . Buffer = 0 ;
SecurityBlob - > NtChallengeResponse . Length =
2006-06-01 23:20:10 +04:00
cpu_to_le16 ( CIFS_SESS_KEY_SIZE ) ;
2005-04-17 02:20:36 +04:00
SecurityBlob - > NtChallengeResponse . MaximumLength =
2006-06-01 23:20:10 +04:00
cpu_to_le16 ( CIFS_SESS_KEY_SIZE ) ;
memcpy ( bcc_ptr , ntlm_session_key , CIFS_SESS_KEY_SIZE ) ;
2005-04-17 02:20:36 +04:00
SecurityBlob - > NtChallengeResponse . Buffer =
cpu_to_le32 ( SecurityBlobLength ) ;
2006-06-01 23:20:10 +04:00
SecurityBlobLength + = CIFS_SESS_KEY_SIZE ;
bcc_ptr + = CIFS_SESS_KEY_SIZE ;
2005-04-17 02:20:36 +04:00
if ( ses - > capabilities & CAP_UNICODE ) {
if ( domain = = NULL ) {
SecurityBlob - > DomainName . Buffer = 0 ;
SecurityBlob - > DomainName . Length = 0 ;
SecurityBlob - > DomainName . MaximumLength = 0 ;
} else {
2007-08-31 05:10:17 +04:00
__u16 ln = cifs_strtoUCS ( ( __le16 * ) bcc_ptr , domain , 64 ,
2005-04-17 02:20:36 +04:00
nls_codepage ) ;
2007-08-31 05:10:17 +04:00
ln * = 2 ;
2005-04-17 02:20:36 +04:00
SecurityBlob - > DomainName . MaximumLength =
2007-08-31 05:10:17 +04:00
cpu_to_le16 ( ln ) ;
2005-04-17 02:20:36 +04:00
SecurityBlob - > DomainName . Buffer =
cpu_to_le32 ( SecurityBlobLength ) ;
2007-08-31 05:10:17 +04:00
bcc_ptr + = ln ;
SecurityBlobLength + = ln ;
SecurityBlob - > DomainName . Length = cpu_to_le16 ( ln ) ;
2005-04-17 02:20:36 +04:00
}
if ( user = = NULL ) {
SecurityBlob - > UserName . Buffer = 0 ;
SecurityBlob - > UserName . Length = 0 ;
SecurityBlob - > UserName . MaximumLength = 0 ;
} else {
2007-08-31 05:10:17 +04:00
__u16 ln = cifs_strtoUCS ( ( __le16 * ) bcc_ptr , user , 64 ,
2005-04-17 02:20:36 +04:00
nls_codepage ) ;
2007-08-31 05:10:17 +04:00
ln * = 2 ;
2005-04-17 02:20:36 +04:00
SecurityBlob - > UserName . MaximumLength =
2007-08-31 05:10:17 +04:00
cpu_to_le16 ( ln ) ;
2005-04-17 02:20:36 +04:00
SecurityBlob - > UserName . Buffer =
cpu_to_le32 ( SecurityBlobLength ) ;
2007-08-31 05:10:17 +04:00
bcc_ptr + = ln ;
SecurityBlobLength + = ln ;
SecurityBlob - > UserName . Length = cpu_to_le16 ( ln ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-17 21:34:02 +04:00
/* SecurityBlob->WorkstationName.Length =
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , " AMACHINE " , 64 , nls_codepage ) ;
2005-04-17 02:20:36 +04:00
SecurityBlob - > WorkstationName . Length * = 2 ;
2007-07-17 21:34:02 +04:00
SecurityBlob - > WorkstationName . MaximumLength =
cpu_to_le16 ( SecurityBlob - > WorkstationName . Length ) ;
SecurityBlob - > WorkstationName . Buffer =
cpu_to_le32 ( SecurityBlobLength ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + = SecurityBlob - > WorkstationName . Length ;
SecurityBlobLength + = SecurityBlob - > WorkstationName . Length ;
2007-07-17 21:34:02 +04:00
SecurityBlob - > WorkstationName . Length =
cpu_to_le16 ( SecurityBlob - > WorkstationName . Length ) ; */
2005-04-17 02:20:36 +04:00
if ( ( long ) bcc_ptr % 2 ) {
* bcc_ptr = 0 ;
bcc_ptr + + ;
}
bytes_returned =
2005-11-12 02:18:19 +03:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , " Linux version " ,
2005-04-17 02:20:36 +04:00
32 , nls_codepage ) ;
bcc_ptr + = 2 * bytes_returned ;
bytes_returned =
2006-10-02 13:18:11 +04:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , utsname ( ) - > release , 32 ,
2005-04-17 02:20:36 +04:00
nls_codepage ) ;
bcc_ptr + = 2 * bytes_returned ;
bcc_ptr + = 2 ; /* null term version string */
bytes_returned =
2005-11-12 02:18:19 +03:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , CIFS_NETWORK_OPSYS ,
2005-04-17 02:20:36 +04:00
64 , nls_codepage ) ;
bcc_ptr + = 2 * bytes_returned ;
* ( bcc_ptr + 1 ) = 0 ;
* ( bcc_ptr + 2 ) = 0 ;
bcc_ptr + = 2 ; /* null terminate network opsys string */
* ( bcc_ptr + 1 ) = 0 ;
* ( bcc_ptr + 2 ) = 0 ;
bcc_ptr + = 2 ; /* null domain */
} else { /* ASCII */
if ( domain = = NULL ) {
SecurityBlob - > DomainName . Buffer = 0 ;
SecurityBlob - > DomainName . Length = 0 ;
SecurityBlob - > DomainName . MaximumLength = 0 ;
} else {
2007-08-31 05:10:17 +04:00
__u16 ln ;
2005-04-17 02:20:36 +04:00
negotiate_flags | = NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED ;
strncpy ( bcc_ptr , domain , 63 ) ;
2007-08-31 05:10:17 +04:00
ln = strnlen ( domain , 64 ) ;
2005-04-17 02:20:36 +04:00
SecurityBlob - > DomainName . MaximumLength =
2007-08-31 05:10:17 +04:00
cpu_to_le16 ( ln ) ;
2005-04-17 02:20:36 +04:00
SecurityBlob - > DomainName . Buffer =
cpu_to_le32 ( SecurityBlobLength ) ;
2007-08-31 05:10:17 +04:00
bcc_ptr + = ln ;
SecurityBlobLength + = ln ;
SecurityBlob - > DomainName . Length = cpu_to_le16 ( ln ) ;
2005-04-17 02:20:36 +04:00
}
if ( user = = NULL ) {
SecurityBlob - > UserName . Buffer = 0 ;
SecurityBlob - > UserName . Length = 0 ;
SecurityBlob - > UserName . MaximumLength = 0 ;
} else {
2007-08-31 05:10:17 +04:00
__u16 ln ;
2005-04-17 02:20:36 +04:00
strncpy ( bcc_ptr , user , 63 ) ;
2007-08-31 05:10:17 +04:00
ln = strnlen ( user , 64 ) ;
SecurityBlob - > UserName . MaximumLength = cpu_to_le16 ( ln ) ;
2005-04-17 02:20:36 +04:00
SecurityBlob - > UserName . Buffer =
2007-08-31 05:10:17 +04:00
cpu_to_le32 ( SecurityBlobLength ) ;
bcc_ptr + = ln ;
SecurityBlobLength + = ln ;
SecurityBlob - > UserName . Length = cpu_to_le16 ( ln ) ;
2005-04-17 02:20:36 +04:00
}
/* BB fill in our workstation name if known BB */
strcpy ( bcc_ptr , " Linux version " ) ;
bcc_ptr + = strlen ( " Linux version " ) ;
2006-10-02 13:18:11 +04:00
strcpy ( bcc_ptr , utsname ( ) - > release ) ;
bcc_ptr + = strlen ( utsname ( ) - > release ) + 1 ;
2005-04-17 02:20:36 +04:00
strcpy ( bcc_ptr , CIFS_NETWORK_OPSYS ) ;
bcc_ptr + = strlen ( CIFS_NETWORK_OPSYS ) + 1 ;
bcc_ptr + + ; /* null domain */
* bcc_ptr = 0 ;
}
SecurityBlob - > NegotiateFlags = cpu_to_le32 ( negotiate_flags ) ;
pSMB - > req . SecurityBlobLength = cpu_to_le16 ( SecurityBlobLength ) ;
count = ( long ) bcc_ptr - ( long ) pByteArea ( smb_buffer ) ;
smb_buffer - > smb_buf_length + = count ;
pSMB - > req . ByteCount = cpu_to_le16 ( count ) ;
rc = SendReceive ( xid , ses , smb_buffer , smb_buffer_response ,
& bytes_returned , 1 ) ;
if ( rc ) {
/* rc = map_smb_to_linux_error(smb_buffer_response); */ /* done in SendReceive now */
} else if ( ( smb_buffer_response - > WordCount = = 3 )
| | ( smb_buffer_response - > WordCount = = 4 ) ) {
__u16 action = le16_to_cpu ( pSMBr - > resp . Action ) ;
__u16 blob_len =
le16_to_cpu ( pSMBr - > resp . SecurityBlobLength ) ;
if ( action & GUEST_LOGIN )
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Guest login " ) ) ; /* BB Should we set anything
in SesInfo struct ? */
/* if (SecurityBlob2->MessageType != NtLm??) {
cFYI ( " Unexpected message type on auth response is %d " ) ) ;
} */
2005-04-17 02:20:36 +04:00
if ( ses ) {
cFYI ( 1 ,
2007-07-13 04:33:32 +04:00
( " Check challenge UID %d vs auth response UID %d " ,
2005-04-17 02:20:36 +04:00
ses - > Suid , smb_buffer_response - > Uid ) ) ;
2007-07-13 04:33:32 +04:00
/* UID left in wire format */
ses - > Suid = smb_buffer_response - > Uid ;
bcc_ptr = pByteArea ( smb_buffer_response ) ;
/* response can have either 3 or 4 word count - Samba sends 3 */
2005-04-17 02:20:36 +04:00
if ( ( pSMBr - > resp . hdr . WordCount = = 3 )
| | ( ( pSMBr - > resp . hdr . WordCount = = 4 )
& & ( blob_len <
pSMBr - > resp . ByteCount ) ) ) {
if ( pSMBr - > resp . hdr . WordCount = = 4 ) {
bcc_ptr + =
blob_len ;
cFYI ( 1 ,
( " Security Blob Length %d " ,
blob_len ) ) ;
}
cFYI ( 1 ,
( " NTLMSSP response to Authenticate " ) ) ;
if ( smb_buffer - > Flags2 & SMBFLG2_UNICODE ) {
if ( ( long ) ( bcc_ptr ) % 2 ) {
remaining_words =
( BCC ( smb_buffer_response )
- 1 ) / 2 ;
bcc_ptr + + ; /* Unicode strings must be word aligned */
} else {
remaining_words = BCC ( smb_buffer_response ) / 2 ;
}
2007-08-31 05:10:17 +04:00
len = UniStrnlen ( ( wchar_t * ) bcc_ptr ,
remaining_words - 1 ) ;
2005-04-17 02:20:36 +04:00
/* 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-10 05:16:18 +04:00
if ( ses - > serverOS )
2006-05-30 22:08:26 +04:00
kfree ( ses - > serverOS ) ;
2005-04-17 02:20:36 +04:00
ses - > serverOS =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 * ( len + 1 ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
cifs_strfromUCS_le ( ses - > serverOS ,
2005-11-12 02:18:19 +03:00
( __le16 * )
2005-04-17 02:20:36 +04:00
bcc_ptr , len ,
nls_codepage ) ;
bcc_ptr + = 2 * ( len + 1 ) ;
remaining_words - = len + 1 ;
ses - > serverOS [ 2 * len ] = 0 ;
ses - > serverOS [ 1 + ( 2 * len ) ] = 0 ;
if ( remaining_words > 0 ) {
len = UniStrnlen ( ( wchar_t * )
bcc_ptr ,
remaining_words
- 1 ) ;
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverNOS ) ;
2005-04-17 02:20:36 +04:00
ses - > serverNOS =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 * ( len + 1 ) ,
2005-04-17 02:20:36 +04:00
GFP_KERNEL ) ;
cifs_strfromUCS_le ( ses - >
serverNOS ,
2005-11-12 02:18:19 +03:00
( __le16 * )
2005-04-17 02:20:36 +04:00
bcc_ptr ,
len ,
nls_codepage ) ;
bcc_ptr + = 2 * ( len + 1 ) ;
ses - > serverNOS [ 2 * len ] = 0 ;
ses - > serverNOS [ 1 + ( 2 * len ) ] = 0 ;
remaining_words - = len + 1 ;
if ( remaining_words > 0 ) {
2007-07-13 04:33:32 +04:00
len = UniStrnlen ( ( wchar_t * ) bcc_ptr , remaining_words ) ;
2005-04-17 02:20:36 +04:00
/* last string not always null terminated (e.g. for Windows XP & 2000) */
2007-07-10 05:16:18 +04:00
if ( ses - > serverDomain )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverDomain ) ;
2005-04-17 02:20:36 +04:00
ses - > serverDomain =
2005-09-07 02:18:35 +04:00
kzalloc ( 2 *
2005-04-17 02:20:36 +04:00
( len +
1 ) ,
GFP_KERNEL ) ;
cifs_strfromUCS_le
( ses - >
serverDomain ,
2005-11-12 02:18:19 +03:00
( __le16 * )
2005-04-17 02:20:36 +04:00
bcc_ptr , len ,
nls_codepage ) ;
bcc_ptr + =
2 * ( len + 1 ) ;
ses - >
serverDomain [ 2
* len ]
= 0 ;
ses - >
serverDomain [ 1
+
( 2
*
len ) ]
= 0 ;
} /* else no more room so create dummy domain string */
2006-05-30 22:06:04 +04:00
else {
2007-07-10 05:16:18 +04:00
if ( ses - > serverDomain )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverDomain ) ;
2005-09-07 02:18:35 +04:00
ses - > serverDomain = kzalloc ( 2 , GFP_KERNEL ) ;
2006-05-30 22:06:04 +04:00
}
2005-04-17 02:20:36 +04:00
} else { /* no room so create dummy domain and NOS string */
2007-07-10 05:16:18 +04:00
if ( ses - > serverDomain )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverDomain ) ;
2005-09-07 02:18:35 +04:00
ses - > serverDomain = kzalloc ( 2 , GFP_KERNEL ) ;
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverNOS ) ;
2005-09-07 02:18:35 +04:00
ses - > serverNOS = kzalloc ( 2 , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
}
} else { /* ASCII */
len = strnlen ( bcc_ptr , 1024 ) ;
2007-07-13 04:33:32 +04:00
if ( ( ( long ) bcc_ptr + len ) -
( long ) pByteArea ( smb_buffer_response )
2007-07-17 21:34:02 +04:00
< = BCC ( smb_buffer_response ) ) {
2007-07-10 05:16:18 +04:00
if ( ses - > serverOS )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverOS ) ;
2007-08-31 05:10:17 +04:00
ses - > serverOS = kzalloc ( len + 1 , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
strncpy ( ses - > serverOS , bcc_ptr , len ) ;
bcc_ptr + = len ;
bcc_ptr [ 0 ] = 0 ; /* null terminate the string */
bcc_ptr + + ;
len = strnlen ( bcc_ptr , 1024 ) ;
2006-06-26 08:22:36 +04:00
kfree ( ses - > serverNOS ) ;
2007-07-13 04:33:32 +04:00
ses - > serverNOS = kzalloc ( len + 1 ,
GFP_KERNEL ) ;
2007-07-17 21:34:02 +04:00
strncpy ( ses - > serverNOS ,
bcc_ptr , len ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + = len ;
bcc_ptr [ 0 ] = 0 ;
bcc_ptr + + ;
len = strnlen ( bcc_ptr , 1024 ) ;
2007-07-10 05:16:18 +04:00
if ( ses - > serverDomain )
2006-05-30 22:06:04 +04:00
kfree ( ses - > serverDomain ) ;
2007-07-17 21:34:02 +04:00
ses - > serverDomain =
kzalloc ( len + 1 ,
GFP_KERNEL ) ;
strncpy ( ses - > serverDomain ,
bcc_ptr , len ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + = len ;
bcc_ptr [ 0 ] = 0 ;
bcc_ptr + + ;
} else
cFYI ( 1 ,
2007-07-17 21:34:02 +04:00
( " field of length %d "
" extends beyond end of smb " ,
2005-04-17 02:20:36 +04:00
len ) ) ;
}
} else {
cERROR ( 1 ,
2007-07-17 21:34:02 +04:00
( " Security Blob extends beyond end "
" of SMB " ) ) ;
2005-04-17 02:20:36 +04:00
}
} else {
cERROR ( 1 , ( " No session structure passed in. " ) ) ;
}
} else {
cERROR ( 1 ,
( " Invalid Word count %d: " ,
smb_buffer_response - > WordCount ) ) ;
rc = - EIO ;
}
if ( smb_buffer )
cifs_buf_release ( smb_buffer ) ;
return rc ;
}
int
CIFSTCon ( unsigned int xid , struct cifsSesInfo * ses ,
const char * tree , struct cifsTconInfo * tcon ,
const struct nls_table * nls_codepage )
{
struct smb_hdr * smb_buffer ;
struct smb_hdr * smb_buffer_response ;
TCONX_REQ * pSMB ;
TCONX_RSP * pSMBr ;
unsigned char * bcc_ptr ;
int rc = 0 ;
int length ;
__u16 count ;
if ( ses = = NULL )
return - EIO ;
smb_buffer = cifs_buf_get ( ) ;
if ( smb_buffer = = NULL ) {
return - ENOMEM ;
}
smb_buffer_response = smb_buffer ;
header_assemble ( smb_buffer , SMB_COM_TREE_CONNECT_ANDX ,
NULL /*no tid */ , 4 /*wct */ ) ;
2005-08-17 23:38:22 +04:00
smb_buffer - > Mid = GetNextMid ( ses - > server ) ;
2005-04-17 02:20:36 +04:00
smb_buffer - > Uid = ses - > Suid ;
pSMB = ( TCONX_REQ * ) smb_buffer ;
pSMBr = ( TCONX_RSP * ) smb_buffer_response ;
pSMB - > AndXCommand = 0xFF ;
pSMB - > Flags = cpu_to_le16 ( TCON_EXTENDED_SECINFO ) ;
bcc_ptr = & pSMB - > Password [ 0 ] ;
2007-07-10 05:16:18 +04:00
if ( ( ses - > server - > secMode ) & SECMODE_USER ) {
2006-01-14 08:34:58 +03:00
pSMB - > PasswordLength = cpu_to_le16 ( 1 ) ; /* minimum */
2006-06-01 23:20:10 +04:00
* bcc_ptr = 0 ; /* password is null byte */
2006-01-14 08:34:58 +03:00
bcc_ptr + + ; /* skip password */
2006-06-01 23:20:10 +04:00
/* already aligned so no need to do it below */
2006-01-14 08:34:58 +03:00
} else {
2006-06-01 23:20:10 +04:00
pSMB - > PasswordLength = cpu_to_le16 ( CIFS_SESS_KEY_SIZE ) ;
2006-01-14 08:34:58 +03:00
/* BB FIXME add code to fail this if NTLMv2 or Kerberos
specified as required ( when that support is added to
the vfs in the future ) as only NTLM or the much
2006-06-01 23:20:10 +04:00
weaker LANMAN ( which we do not send by default ) is accepted
2006-01-14 08:34:58 +03:00
by Samba ( not sure whether other servers allow
NTLMv2 password here ) */
2006-06-01 23:20:10 +04:00
# ifdef CONFIG_CIFS_WEAK_PW_HASH
2007-07-13 04:33:32 +04:00
if ( ( extended_security & CIFSSEC_MAY_LANMAN ) & &
2006-06-01 23:20:10 +04:00
( ses - > server - > secType = = LANMAN ) )
calc_lanman_hash ( ses , bcc_ptr ) ;
else
# endif /* CIFS_WEAK_PW_HASH */
2006-01-14 08:34:58 +03:00
SMBNTencrypt ( ses - > password ,
ses - > server - > cryptKey ,
bcc_ptr ) ;
2006-06-01 23:20:10 +04:00
bcc_ptr + = CIFS_SESS_KEY_SIZE ;
2007-07-10 05:16:18 +04:00
if ( ses - > capabilities & CAP_UNICODE ) {
2006-06-01 23:20:10 +04:00
/* must align unicode strings */
* bcc_ptr = 0 ; /* null byte password */
bcc_ptr + + ;
}
2006-01-14 08:34:58 +03:00
}
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
if ( ses - > server - > secMode &
2006-05-30 22:04:19 +04:00
( SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED ) )
2005-04-17 02:20:36 +04:00
smb_buffer - > Flags2 | = SMBFLG2_SECURITY_SIGNATURE ;
if ( ses - > capabilities & CAP_STATUS32 ) {
smb_buffer - > Flags2 | = SMBFLG2_ERR_STATUS ;
}
if ( ses - > capabilities & CAP_DFS ) {
smb_buffer - > Flags2 | = SMBFLG2_DFS ;
}
if ( ses - > capabilities & CAP_UNICODE ) {
smb_buffer - > Flags2 | = SMBFLG2_UNICODE ;
length =
2007-07-13 04:33:32 +04:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , tree ,
6 /* max utf8 char length in bytes */ *
2006-05-30 22:04:19 +04:00
( /* server len*/ + 256 /* share len */ ) , nls_codepage ) ;
bcc_ptr + = 2 * length ; /* convert num 16 bit words to bytes */
2005-04-17 02:20:36 +04:00
bcc_ptr + = 2 ; /* skip trailing null */
} else { /* ASCII */
strcpy ( bcc_ptr , tree ) ;
bcc_ptr + = strlen ( tree ) + 1 ;
}
strcpy ( bcc_ptr , " ????? " ) ;
bcc_ptr + = strlen ( " ????? " ) ;
bcc_ptr + = 1 ;
count = bcc_ptr - & pSMB - > Password [ 0 ] ;
pSMB - > hdr . smb_buf_length + = count ;
pSMB - > ByteCount = cpu_to_le16 ( count ) ;
rc = SendReceive ( xid , ses , smb_buffer , smb_buffer_response , & length , 0 ) ;
/* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
/* above now done in SendReceive */
if ( ( rc = = 0 ) & & ( tcon ! = NULL ) ) {
tcon - > tidStatus = CifsGood ;
tcon - > tid = smb_buffer_response - > Tid ;
bcc_ptr = pByteArea ( smb_buffer_response ) ;
length = strnlen ( bcc_ptr , BCC ( smb_buffer_response ) - 2 ) ;
2007-07-13 04:33:32 +04:00
/* skip service field (NB: this field is always ASCII) */
bcc_ptr + = length + 1 ;
2005-04-17 02:20:36 +04:00
strncpy ( tcon - > treeName , tree , MAX_TREE_SIZE ) ;
if ( smb_buffer - > Flags2 & SMBFLG2_UNICODE ) {
length = UniStrnlen ( ( wchar_t * ) bcc_ptr , 512 ) ;
if ( ( bcc_ptr + ( 2 * length ) ) -
pByteArea ( smb_buffer_response ) < =
BCC ( smb_buffer_response ) ) {
2005-11-07 12:01:34 +03:00
kfree ( tcon - > nativeFileSystem ) ;
2005-04-17 02:20:36 +04:00
tcon - > nativeFileSystem =
2005-09-07 02:18:35 +04:00
kzalloc ( length + 2 , GFP_KERNEL ) ;
2007-09-15 07:01:17 +04:00
if ( tcon - > nativeFileSystem )
cifs_strfromUCS_le (
tcon - > nativeFileSystem ,
( __le16 * ) bcc_ptr ,
length , nls_codepage ) ;
2005-04-17 02:20:36 +04:00
bcc_ptr + = 2 * length ;
bcc_ptr [ 0 ] = 0 ; /* null terminate the string */
bcc_ptr [ 1 ] = 0 ;
bcc_ptr + = 2 ;
}
2007-07-13 04:33:32 +04:00
/* else do not bother copying these information fields*/
2005-04-17 02:20:36 +04:00
} else {
length = strnlen ( bcc_ptr , 1024 ) ;
if ( ( bcc_ptr + length ) -
pByteArea ( smb_buffer_response ) < =
BCC ( smb_buffer_response ) ) {
2005-11-07 12:01:34 +03:00
kfree ( tcon - > nativeFileSystem ) ;
2005-04-17 02:20:36 +04:00
tcon - > nativeFileSystem =
2005-09-07 02:18:35 +04:00
kzalloc ( length + 1 , GFP_KERNEL ) ;
2007-09-15 07:01:17 +04:00
if ( tcon - > nativeFileSystem )
strncpy ( tcon - > nativeFileSystem , bcc_ptr ,
length ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-13 04:33:32 +04:00
/* else do not bother copying these information fields*/
2005-04-17 02:20:36 +04:00
}
2007-07-10 05:16:18 +04:00
if ( ( smb_buffer_response - > WordCount = = 3 ) | |
2006-10-13 01:33:51 +04:00
( smb_buffer_response - > WordCount = = 7 ) )
/* field is in same location */
2006-06-01 02:40:51 +04:00
tcon - > Flags = le16_to_cpu ( pSMBr - > OptionalSupport ) ;
else
tcon - > Flags = 0 ;
2005-04-17 02:20:36 +04:00
cFYI ( 1 , ( " Tcon flags: 0x%x " , tcon - > Flags ) ) ;
} else if ( ( rc = = 0 ) & & tcon = = NULL ) {
2007-07-13 04:33:32 +04:00
/* all we need to save for IPC$ connection */
2005-04-17 02:20:36 +04:00
ses - > ipc_tid = smb_buffer_response - > Tid ;
}
if ( smb_buffer )
cifs_buf_release ( smb_buffer ) ;
return rc ;
}
int
cifs_umount ( struct super_block * sb , struct cifs_sb_info * cifs_sb )
{
int rc = 0 ;
int xid ;
struct cifsSesInfo * ses = NULL ;
struct task_struct * cifsd_task ;
2007-07-13 04:33:32 +04:00
char * tmp ;
2005-04-17 02:20:36 +04:00
xid = GetXid ( ) ;
if ( cifs_sb - > tcon ) {
ses = cifs_sb - > tcon - > ses ; /* save ptr to ses before delete tcon!*/
rc = CIFSSMBTDis ( xid , cifs_sb - > tcon ) ;
if ( rc = = - EBUSY ) {
FreeXid ( xid ) ;
return 0 ;
}
tconInfoFree ( cifs_sb - > tcon ) ;
if ( ( ses ) & & ( ses - > server ) ) {
/* save off task so we do not refer to ses later */
cifsd_task = ses - > server - > tsk ;
cFYI ( 1 , ( " About to do SMBLogoff " ) ) ;
rc = CIFSSMBLogoff ( xid , ses ) ;
if ( rc = = - EBUSY ) {
FreeXid ( xid ) ;
return 0 ;
} else if ( rc = = - ESHUTDOWN ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " Waking up socket by sending signal " ) ) ;
2007-05-24 06:29:51 +04:00
if ( cifsd_task ) {
2007-07-13 04:33:32 +04:00
force_sig ( SIGKILL , cifsd_task ) ;
2007-04-03 23:16:43 +04:00
kthread_stop ( cifsd_task ) ;
2005-08-18 20:37:34 +04:00
}
2005-04-17 02:20:36 +04:00
rc = 0 ;
} /* else - we have an smb session
left on this socket do not kill cifsd */
} else
cFYI ( 1 , ( " No session or bad tcon " ) ) ;
}
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
cifs_sb - > tcon = NULL ;
2006-09-21 11:02:52 +04:00
tmp = cifs_sb - > prepath ;
cifs_sb - > prepathlen = 0 ;
cifs_sb - > prepath = NULL ;
kfree ( tmp ) ;
2005-09-10 11:27:23 +04:00
if ( ses )
schedule_timeout_interruptible ( msecs_to_jiffies ( 500 ) ) ;
2005-04-17 02:20:36 +04:00
if ( ses )
sesInfoFree ( ses ) ;
FreeXid ( xid ) ;
2007-07-13 04:33:32 +04:00
return rc ; /* BB check if we should always return zero here */
}
2005-04-17 02:20:36 +04:00
int cifs_setup_session ( unsigned int xid , struct cifsSesInfo * pSesInfo ,
2007-07-13 04:33:32 +04:00
struct nls_table * nls_info )
2005-04-17 02:20:36 +04:00
{
int rc = 0 ;
2006-06-01 23:20:10 +04:00
char ntlm_session_key [ CIFS_SESS_KEY_SIZE ] ;
2005-04-17 02:20:36 +04:00
int ntlmv2_flag = FALSE ;
2005-04-29 09:41:05 +04:00
int first_time = 0 ;
2005-04-17 02:20:36 +04:00
/* what if server changes its buffer size after dropping the session? */
2007-07-10 05:16:18 +04:00
if ( pSesInfo - > server - > maxBuf = = 0 ) /* no need to send on reconnect */ {
2005-04-17 02:20:36 +04:00
rc = CIFSSMBNegotiate ( xid , pSesInfo ) ;
2007-07-10 05:16:18 +04:00
if ( rc = = - EAGAIN ) /* retry only once on 1st time connection */ {
2005-04-17 02:20:36 +04:00
rc = CIFSSMBNegotiate ( xid , pSesInfo ) ;
2007-07-13 04:33:32 +04:00
if ( rc = = - EAGAIN )
2005-04-17 02:20:36 +04:00
rc = - EHOSTDOWN ;
}
2007-07-10 05:16:18 +04:00
if ( rc = = 0 ) {
2005-04-17 02:20:36 +04:00
spin_lock ( & GlobalMid_Lock ) ;
2007-07-10 05:16:18 +04:00
if ( pSesInfo - > server - > tcpStatus ! = CifsExiting )
2005-04-17 02:20:36 +04:00
pSesInfo - > server - > tcpStatus = CifsGood ;
else
rc = - EHOSTDOWN ;
spin_unlock ( & GlobalMid_Lock ) ;
}
2005-04-29 09:41:05 +04:00
first_time = 1 ;
2005-04-17 02:20:36 +04:00
}
if ( ! rc ) {
2006-09-30 08:13:17 +04:00
pSesInfo - > flags = 0 ;
2005-04-17 02:20:36 +04:00
pSesInfo - > capabilities = pSesInfo - > server - > capabilities ;
2007-07-10 05:16:18 +04:00
if ( linuxExtEnabled = = 0 )
2005-04-17 02:20:36 +04:00
pSesInfo - > capabilities & = ( ~ CAP_UNIX ) ;
2005-04-29 09:41:05 +04:00
/* pSesInfo->sequence_number = 0;*/
2007-07-13 04:33:32 +04:00
cFYI ( 1 ,
( " Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d " ,
2005-04-17 02:20:36 +04:00
pSesInfo - > server - > secMode ,
pSesInfo - > server - > capabilities ,
2006-09-30 05:07:38 +04:00
pSesInfo - > server - > timeAdj ) ) ;
2007-07-10 05:16:18 +04:00
if ( experimEnabled < 2 )
2006-06-01 02:40:51 +04:00
rc = CIFS_SessSetup ( xid , pSesInfo ,
first_time , nls_info ) ;
2006-06-23 06:33:48 +04:00
else if ( extended_security
2007-07-13 04:33:32 +04:00
& & ( pSesInfo - > capabilities
2006-09-30 05:07:38 +04:00
& CAP_EXTENDED_SECURITY )
2005-04-17 02:20:36 +04:00
& & ( pSesInfo - > server - > secType = = NTLMSSP ) ) {
2006-06-23 06:33:48 +04:00
rc = - EOPNOTSUPP ;
2005-04-17 02:20:36 +04:00
} else if ( extended_security
& & ( pSesInfo - > capabilities & CAP_EXTENDED_SECURITY )
& & ( pSesInfo - > server - > secType = = RawNTLMSSP ) ) {
2006-02-14 04:36:20 +03:00
cFYI ( 1 , ( " NTLMSSP sesssetup " ) ) ;
2005-04-17 02:20:36 +04:00
rc = CIFSNTLMSSPNegotiateSessSetup ( xid ,
pSesInfo ,
& ntlmv2_flag ,
nls_info ) ;
if ( ! rc ) {
2007-07-10 05:16:18 +04:00
if ( ntlmv2_flag ) {
2007-07-13 04:33:32 +04:00
char * v2_response ;
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " more secure NTLM ver2 hash " ) ) ;
2007-07-13 04:33:32 +04:00
if ( CalcNTLMv2_partial_mac_key ( pSesInfo ,
2005-04-17 02:20:36 +04:00
nls_info ) ) {
rc = - ENOMEM ;
goto ss_err_exit ;
} else
v2_response = kmalloc ( 16 + 64 /* blob */ , GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( v2_response ) {
2007-07-13 04:33:32 +04:00
CalcNTLMv2_response ( pSesInfo ,
v2_response ) ;
2007-07-10 05:16:18 +04:00
/* if (first_time)
2007-07-13 04:33:32 +04:00
cifs_calculate_ntlmv2_mac_key (
pSesInfo - > server - > mac_signing_key ,
response , ntlm_session_key , */
2005-04-17 02:20:36 +04:00
kfree ( v2_response ) ;
/* BB Put dummy sig in SessSetup PDU? */
} else {
rc = - ENOMEM ;
goto ss_err_exit ;
}
} else {
SMBNTencrypt ( pSesInfo - > password ,
pSesInfo - > server - > cryptKey ,
ntlm_session_key ) ;
2007-07-10 05:16:18 +04:00
if ( first_time )
2005-04-29 09:41:05 +04:00
cifs_calculate_mac_key (
2007-07-09 11:55:14 +04:00
& pSesInfo - > server - > mac_signing_key ,
2005-04-29 09:41:05 +04:00
ntlm_session_key ,
pSesInfo - > password ) ;
2005-04-17 02:20:36 +04:00
}
/* for better security the weaker lanman hash not sent
in AuthSessSetup so we no longer calculate it */
rc = CIFSNTLMSSPAuthSessSetup ( xid ,
pSesInfo ,
ntlm_session_key ,
ntlmv2_flag ,
nls_info ) ;
}
} else { /* old style NTLM 0.12 session setup */
SMBNTencrypt ( pSesInfo - > password ,
pSesInfo - > server - > cryptKey ,
ntlm_session_key ) ;
2007-07-10 05:16:18 +04:00
if ( first_time )
2005-04-29 09:41:05 +04:00
cifs_calculate_mac_key (
2007-07-09 11:55:14 +04:00
& pSesInfo - > server - > mac_signing_key ,
2005-04-29 09:41:05 +04:00
ntlm_session_key , pSesInfo - > password ) ;
2005-04-17 02:20:36 +04:00
rc = CIFSSessSetup ( xid , pSesInfo ,
ntlm_session_key , nls_info ) ;
}
if ( rc ) {
2007-07-10 05:16:18 +04:00
cERROR ( 1 , ( " Send error in SessSetup = %d " , rc ) ) ;
2005-04-17 02:20:36 +04:00
} else {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " CIFS Session Established successfully " ) ) ;
2005-04-17 02:20:36 +04:00
pSesInfo - > status = CifsGood ;
}
}
ss_err_exit :
return rc ;
}