/*
* fs/cifs/connect.c
*
- * Copyright (C) International Business Machines Corp., 2002,2004
+ * Copyright (C) International Business Machines Corp., 2002,2006
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
#include <linux/string.h>
#include <linux/list.h>
#include <linux/wait.h>
-#include <linux/version.h>
#include <linux/ipv6.h>
#include <linux/pagemap.h>
#include <linux/ctype.h>
#include <linux/utsname.h>
#include <linux/mempool.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/pagevec.h>
+#include <linux/freezer.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include "cifspdu.h"
#include "ntlmssp.h"
#include "nterr.h"
#include "rfc1002pdu.h"
+#include "cn_cifs.h"
#define CIFS_PORT 445
#define RFC1001_PORT 139
-extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
- unsigned char *p24);
+static DECLARE_COMPLETION(cifsd_complete);
+
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
-extern int cifs_inet_pton(int, const char *, void *dst);
extern mempool_t *cifs_req_poolp;
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 */
+ char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
uid_t linux_uid;
gid_t linux_gid;
mode_t file_mode;
mode_t dir_mode;
- int rw:1;
- int retry:1;
- int intr:1;
- int setuids:1;
- int noperm:1;
+ unsigned secFlg;
+ unsigned rw:1;
+ unsigned retry:1;
+ unsigned intr:1;
+ unsigned setuids:1;
+ unsigned noperm:1;
+ unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
+ unsigned cifs_acl:1;
+ 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;
+ unsigned remap:1; /* set to remap seven reserved chars in filenames */
+ unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
+ unsigned sfu_emul:1;
+ unsigned nullauth:1; /* attempt to authenticate with null user */
+ unsigned nocase; /* request case insensitive filenames */
+ unsigned nobrl; /* disable sending byte range locks to srv */
unsigned int rsize;
unsigned int wsize;
unsigned int sockopt;
unsigned short int port;
+ char * prepath;
};
static int ipv4_connect(struct sockaddr_in *psin_server,
struct socket **csocket,
- char * netb_name);
+ char * netb_name,
+ char * server_netb_name);
static int ipv6_connect(struct sockaddr_in6 *psin_server,
struct socket **csocket);
* wake up waiters on reconnection? - (not needed currently)
*/
-int
+static int
cifs_reconnect(struct TCP_Server_Info *server)
{
int rc = 0;
spin_unlock(&GlobalMid_Lock);
server->maxBuf = 0;
- cFYI(1, ("Reconnecting tcp session "));
+ cFYI(1, ("Reconnecting tcp session"));
/* before reconnecting the tcp session, mark the smb session (uid)
and the tid bad so they are not used until reconnected */
qhead);
if(mid_entry) {
if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
- /* 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 */
+ /* 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 */
mid_entry->midState = MID_RETRY_NEEDED;
}
}
while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
{
+ try_to_freeze();
if(server->protocolType == IPV6) {
rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
} else {
rc = ipv4_connect(&server->addr.sockAddr,
&server->ssocket,
- server->workstation_RFC1001_name);
+ server->workstation_RFC1001_name,
+ server->server_RFC1001_name);
}
if(rc) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(3 * HZ);
+ cFYI(1,("reconnect error %d",rc));
+ msleep(3000);
} else {
atomic_inc(&tcpSesReconnectCount);
spin_lock(&GlobalMid_Lock);
if(server->tcpStatus != CifsExiting)
server->tcpStatus = CifsGood;
- spin_unlock(&GlobalMid_Lock);
+ server->sequence_number = 0;
+ spin_unlock(&GlobalMid_Lock);
/* atomic_set(&server->inFlight,0);*/
wake_up(&server->response_q);
}
return rc;
}
+/*
+ return codes:
+ 0 not a transact2, or all data present
+ >0 transact2 with that much data missing
+ -EINVAL = invalid transact2
+
+ */
+static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
+{
+ struct smb_t2_rsp * pSMBt;
+ int total_data_size;
+ int data_in_this_rsp;
+ int remaining;
+
+ if(pSMB->Command != SMB_COM_TRANSACTION2)
+ return 0;
+
+ /* 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 */
+ cFYI(1,("invalid transact2 word count"));
+ 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;
+
+ if(remaining == 0)
+ return 0;
+ else if(remaining < 0) {
+ cFYI(1,("total data %d smaller than data in frame %d",
+ total_data_size, data_in_this_rsp));
+ return -EINVAL;
+ } else {
+ cFYI(1,("missing %d bytes from transact2, check next response",
+ remaining));
+ if(total_data_size > maxBufSize) {
+ cERROR(1,("TotalDataSize %d is over maximum buffer %d",
+ total_data_size,maxBufSize));
+ return -EINVAL;
+ }
+ return remaining;
+ }
+}
+
+static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
+{
+ 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;
+ char * data_area_of_target;
+ char * data_area_of_buf2;
+ __u16 byte_count;
+
+ total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
+
+ if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
+ cFYI(1,("total data sizes of primary and secondary t2 differ"));
+ }
+
+ total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+
+ remaining = total_data_size - total_in_buf;
+
+ if(remaining < 0)
+ return -EINVAL;
+
+ if(remaining == 0) /* nothing to do, ignore */
+ return 0;
+
+ total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
+ if(remaining < total_in_buf2) {
+ cFYI(1,("transact2 2nd response contains too much data"));
+ }
+
+ /* find end of first SMB data area */
+ data_area_of_target = (char *)&pSMBt->hdr.Protocol +
+ le16_to_cpu(pSMBt->t2_rsp.DataOffset);
+ /* validate target area */
+
+ data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
+ le16_to_cpu(pSMB2->t2_rsp.DataOffset);
+
+ data_area_of_target += total_in_buf;
+
+ /* copy second buffer into end of first buffer */
+ memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
+ 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);
+
+ byte_count = pTargetSMB->smb_buf_length;
+ byte_count += total_in_buf2;
+
+ /* BB also add check that we are not beyond maximum buffer size */
+
+ pTargetSMB->smb_buf_length = byte_count;
+
+ if(remaining == total_in_buf2) {
+ cFYI(1,("found the last secondary response"));
+ return 0; /* we are done */
+ } else /* more responses to go */
+ return 1;
+
+}
+
static int
cifs_demultiplex_thread(struct TCP_Server_Info *server)
{
int length;
unsigned int pdu_length, total_read;
struct smb_hdr *smb_buffer = NULL;
+ struct smb_hdr *bigbuf = NULL;
+ struct smb_hdr *smallbuf = NULL;
struct msghdr smb_msg;
struct kvec iov;
struct socket *csocket = server->ssocket;
struct cifsSesInfo *ses;
struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mid_entry;
- char *temp;
+ char temp;
+ int isLargeBuf = FALSE;
+ int isMultiRsp;
+ int reconnect;
daemonize("cifsd");
allow_signal(SIGKILL);
current->flags |= PF_MEMALLOC;
server->tsk = current; /* save process info to wake at shutdown */
cFYI(1, ("Demultiplex PID: %d", current->pid));
- write_lock(&GlobalSMBSeslock);
+ write_lock(&GlobalSMBSeslock);
atomic_inc(&tcpSesAllocCount);
length = tcpSesAllocCount.counter;
write_unlock(&GlobalSMBSeslock);
+ complete(&cifsd_complete);
if(length > 1) {
mempool_resize(cifs_req_poolp,
- length + CIFS_MIN_RCV_POOL,
+ length + cifs_min_rcv,
GFP_KERNEL);
}
while (server->tcpStatus != CifsExiting) {
- if (smb_buffer == NULL)
- smb_buffer = cifs_buf_get();
- else
- memset(smb_buffer, 0, sizeof (struct smb_hdr));
-
- if (smb_buffer == NULL) {
- cERROR(1,("Can not get memory for SMB response"));
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ * 3); /* give system time to free memory */
+ if (try_to_freeze())
continue;
+ if (bigbuf == NULL) {
+ bigbuf = cifs_buf_get();
+ if (!bigbuf) {
+ cERROR(1, ("No memory for large SMB response"));
+ msleep(3000);
+ /* retry will check if exiting */
+ continue;
+ }
+ } else if (isLargeBuf) {
+ /* we are reusing a dirty large buf, clear its start */
+ memset(bigbuf, 0, sizeof (struct smb_hdr));
}
+
+ if (smallbuf == NULL) {
+ smallbuf = cifs_small_buf_get();
+ if (!smallbuf) {
+ cERROR(1, ("No memory for SMB response"));
+ 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 */
+ memset(smallbuf, 0, sizeof (struct smb_hdr));
+
+ isLargeBuf = FALSE;
+ isMultiRsp = FALSE;
+ smb_buffer = smallbuf;
iov.iov_base = smb_buffer;
- iov.iov_len = sizeof (struct smb_hdr) - 1;
- /* 1 byte less above since wct is not always returned in error cases */
+ iov.iov_len = 4;
smb_msg.msg_control = NULL;
smb_msg.msg_controllen = 0;
-
length =
kernel_recvmsg(csocket, &smb_msg,
- &iov, 1,
- sizeof (struct smb_hdr) -
- 1 /* RFC1001 header and SMB header */ ,
- MSG_PEEK /* flags see socket.h */ );
+ &iov, 1, 4, 0 /* BB see socket.h flags */);
- if(server->tcpStatus == CifsExiting) {
+ if (server->tcpStatus == CifsExiting) {
break;
} else if (server->tcpStatus == CifsNeedReconnect) {
- cFYI(1,("Reconnecting after server stopped responding"));
+ cFYI(1, ("Reconnect after server stopped responding"));
cifs_reconnect(server);
- cFYI(1,("call to reconnect done"));
+ cFYI(1, ("call to reconnect done"));
csocket = server->ssocket;
continue;
} else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1); /* minimum sleep to prevent looping
+ msleep(1); /* minimum sleep to prevent looping
allowing socket to clear and app threads to set
tcpStatus CifsNeedReconnect if server hung */
continue;
} else if (length <= 0) {
- if(server->tcpStatus == CifsNew) {
- cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
- /* some servers kill tcp session rather than returning
- smb negprot error in which case reconnecting here is
- not going to help - return error to mount */
+ if (server->tcpStatus == CifsNew) {
+ cFYI(1, ("tcp session abend after SMBnegprot"));
+ /* 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 */
break;
}
- if(length == -EINTR) {
+ if (!try_to_freeze() && (length == -EINTR)) {
cFYI(1,("cifsd thread killed"));
break;
}
- cFYI(1,("Reconnecting after unexpected peek error %d",length));
+ cFYI(1,("Reconnect after unexpected peek error %d",
+ length));
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ wake_up(&server->response_q);
+ continue;
+ } else if (length < 4) {
+ cFYI(1,
+ ("Frame under four bytes received (%d bytes long)",
+ length));
cifs_reconnect(server);
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
}
- pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
- /* Ony read pdu_length after below checks for too short (due
- to e.g. int overflow) and too long ie beyond end of buf */
- cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length));
-
- temp = (char *) smb_buffer;
- if (length > 3) {
- if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
- iov.iov_base = smb_buffer;
- iov.iov_len = 4;
- length = kernel_recvmsg(csocket, &smb_msg,
- &iov, 1, 4, 0);
- cFYI(0,("Received 4 byte keep alive packet"));
- } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
- iov.iov_base = smb_buffer;
- iov.iov_len = 4;
- length = kernel_recvmsg(csocket, &smb_msg,
- &iov, 1, 4, 0);
- cFYI(1,("Good RFC 1002 session rsp"));
- } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE)
- && (length == 5)) {
- /* we get this from Windows 98 instead of error on SMB negprot response */
- cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
- if(server->tcpStatus == CifsNew) {
- /* if nack on negprot (rather than
- 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 */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
- /* always try 445 first on reconnect
- since we get NACK on some if we ever
- connected to port 139 (the NACK is
- since we do not begin with RFC1001
- session initialize frame) */
- server->addr.sockAddr.sin_port = CIFS_PORT;
- cifs_reconnect(server);
- csocket = server->ssocket;
- wake_up(&server->response_q);
- continue;
- }
- } else if (temp[0] != (char) 0) {
- cERROR(1,("Unknown RFC 1002 frame"));
- cifs_dump_mem(" Received Data: ", temp, length);
+ /* The right amount was read from socket - 4 bytes */
+ /* so we can now interpret the length field */
+
+ /* 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);
+
+ /* Note that FC 1001 length is big endian on the wire,
+ but we convert it here so it is always manipulated
+ as host byte order */
+ pdu_length = ntohl(smb_buffer->smb_buf_length);
+ smb_buffer->smb_buf_length = pdu_length;
+
+ cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
+
+ if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
+ continue;
+ } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
+ cFYI(1,("Good RFC 1002 session rsp"));
+ continue;
+ } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
+ /* we get this from Windows 98 instead of
+ an error on SMB negprot response */
+ cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
+ pdu_length));
+ if(server->tcpStatus == CifsNew) {
+ /* if nack on negprot (rather than
+ 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
+ connected to port 139 (the NACK is
+ since we do not begin with RFC1001
+ session initialize frame) */
+ server->addr.sockAddr.sin_port =
+ htons(CIFS_PORT);
cifs_reconnect(server);
csocket = server->ssocket;
+ wake_up(&server->response_q);
continue;
- } else {
- if ((length != sizeof (struct smb_hdr) - 1)
- || (pdu_length >
- CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)
- || (pdu_length <
- sizeof (struct smb_hdr) - 1)
- ||
- (checkSMBhdr
- (smb_buffer, smb_buffer->Mid))) {
- cERROR(1,
- ("Invalid size or format for SMB found with length %d and pdu_lenght %d",
- length, pdu_length));
- cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
- /* could we fix this network corruption by finding next
- smb header (instead of killing the session) and
- restart reading from next valid SMB found? */
- cifs_reconnect(server);
- csocket = server->ssocket;
- continue;
- } else { /* length ok */
-
- length = 0;
- iov.iov_base = smb_buffer;
- iov.iov_len = pdu_length;
- for (total_read = 0;
- total_read < pdu_length;
- total_read += length) {
- length = kernel_recvmsg(csocket, &smb_msg,
- &iov, 1,
- pdu_length - total_read, 0);
- if (length == 0) {
- cERROR(1,
- ("Zero length receive when expecting %d ",
- pdu_length - total_read));
- cifs_reconnect(server);
- csocket = server->ssocket;
- continue;
- }
- }
- }
+ }
+ } else if (temp != (char) 0) {
+ cERROR(1,("Unknown RFC 1002 frame"));
+ cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
+ length);
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ continue;
+ }
- dump_smb(smb_buffer, length);
- if (checkSMB
- (smb_buffer, smb_buffer->Mid, total_read)) {
- cERROR(1, ("Bad SMB Received "));
- continue;
- }
+ /* else we have an SMB response */
+ if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
+ (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
+ cERROR(1, ("Invalid size SMB length %d pdu_length %d",
+ length, pdu_length+4));
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ wake_up(&server->response_q);
+ continue;
+ }
- 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);
+ /* else length ok */
+ reconnect = 0;
- if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
- cFYI(1,
- (" Mid 0x%x matched - waking up ",mid_entry->mid));
- task_to_wake = mid_entry->tsk;
- mid_entry->resp_buf =
- smb_buffer;
- mid_entry->midState =
- MID_RESPONSE_RECEIVED;
+ if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
+ isLargeBuf = TRUE;
+ memcpy(bigbuf, smallbuf, 4);
+ smb_buffer = bigbuf;
+ }
+ length = 0;
+ iov.iov_base = 4 + (char *)smb_buffer;
+ iov.iov_len = pdu_length;
+ for (total_read = 0; total_read < pdu_length;
+ total_read += length) {
+ length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
+ pdu_length - total_read, 0);
+ if((server->tcpStatus == CifsExiting) ||
+ (length == -EINTR)) {
+ /* then will exit */
+ reconnect = 2;
+ break;
+ } else if (server->tcpStatus == CifsNeedReconnect) {
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ /* Reconnect wakes up rspns q */
+ /* Now we will reread sock */
+ reconnect = 1;
+ break;
+ } else if ((length == -ERESTARTSYS) ||
+ (length == -EAGAIN)) {
+ msleep(1); /* minimum sleep to prevent looping,
+ allowing socket to clear and app
+ threads to set tcpStatus
+ CifsNeedReconnect if server hung*/
+ continue;
+ } else if (length <= 0) {
+ cERROR(1,("Received no data, expecting %d",
+ pdu_length - total_read));
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ reconnect = 1;
+ break;
+ }
+ }
+ if(reconnect == 2)
+ break;
+ else if(reconnect == 1)
+ continue;
+
+ length += 4; /* account for rfc1002 hdr */
+
+
+ dump_smb(smb_buffer, length);
+ if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
+ cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
+ continue;
+ }
+
+
+ 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);
+
+ if ((mid_entry->mid == smb_buffer->Mid) &&
+ (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
+ (mid_entry->command == smb_buffer->Command)) {
+ if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
+ /* We have a multipart transact2 resp */
+ isMultiRsp = TRUE;
+ if(mid_entry->resp_buf) {
+ /* merge response - fix up 1st*/
+ if(coalesce_t2(smb_buffer,
+ mid_entry->resp_buf)) {
+ mid_entry->multiRsp = 1;
+ break;
+ } else {
+ /* all parts received */
+ mid_entry->multiEnd = 1;
+ goto multi_t2_fnd;
+ }
+ } else {
+ if(!isLargeBuf) {
+ cERROR(1,("1st trans2 resp needs bigbuf"));
+ /* BB maybe we can fix this up, switch
+ to already allocated large buffer? */
+ } else {
+ /* Have first buffer */
+ mid_entry->resp_buf =
+ smb_buffer;
+ mid_entry->largeBuf = 1;
+ bigbuf = NULL;
+ }
}
- }
- spin_unlock(&GlobalMid_Lock);
- if (task_to_wake) {
- smb_buffer = NULL; /* will be freed by users thread after he is done */
- wake_up_process(task_to_wake);
- } else if (is_valid_oplock_break(smb_buffer) == FALSE) {
- cERROR(1, ("No task to wake, unknown frame rcvd!"));
- cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
- }
+ break;
+ }
+ mid_entry->resp_buf = smb_buffer;
+ if(isLargeBuf)
+ mid_entry->largeBuf = 1;
+ else
+ mid_entry->largeBuf = 0;
+multi_t2_fnd:
+ task_to_wake = mid_entry->tsk;
+ mid_entry->midState = MID_RESPONSE_RECEIVED;
+#ifdef CONFIG_CIFS_STATS2
+ mid_entry->when_received = jiffies;
+#endif
+ /* so we do not time out requests to server
+ which is still responding (since server could
+ be busy but not dead) */
+ server->lstrp = jiffies;
+ break;
}
- } else {
- cFYI(0,
- ("Frame less than four bytes received %d bytes long.",
- length));
- if (length > 0) {
- length = kernel_recvmsg(csocket, &smb_msg,
- &iov, 1,
- length, 0); /* throw away junk frame */
- cFYI(1,
- (" with junk 0x%x in it ",
- *(__u32 *) smb_buffer));
+ }
+ spin_unlock(&GlobalMid_Lock);
+ if (task_to_wake) {
+ /* Was previous buf put in mpx struct for multi-rsp? */
+ if(!isMultiRsp) {
+ /* smb buffer will be freed by user thread */
+ if(isLargeBuf) {
+ bigbuf = NULL;
+ } else
+ smallbuf = NULL;
}
+ wake_up_process(task_to_wake);
+ } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
+ && (isMultiRsp == FALSE)) {
+ cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
+ cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
+ sizeof(struct smb_hdr));
+#ifdef CONFIG_CIFS_DEBUG2
+ cifs_dump_detail(smb_buffer);
+ cifs_dump_mids(server);
+#endif /* CIFS_DEBUG2 */
+
}
- }
+ } /* end while !EXITING */
+
spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting;
server->tsk = NULL;
- atomic_set(&server->inFlight, 0);
+ /* 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 */
+ if(atomic_read(&server->inFlight) >= cifs_max_pending)
+ 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 */
spin_unlock(&GlobalMid_Lock);
/* Although there should not be any requests blocked on
this queue it can not hurt to be paranoid and try to wake up requests
- that may haven been blocked when more than 50 at time were on the wire
+ that may haven been blocked when more than 50 at time were on the wire
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 */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/8);
-
+ msleep(125);
+
if(server->ssocket) {
sock_release(csocket);
server->ssocket = NULL;
}
- if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
- cifs_buf_release(smb_buffer);
+ /* 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);
read_lock(&GlobalSMBSeslock);
if (list_empty(&server->pending_mid_q)) {
- /* loop through server session structures attached to this and mark them dead */
+ /* loop through server session structures attached to this and
+ mark them dead */
list_for_each(tmp, &GlobalSMBSessionList) {
ses =
list_entry(tmp, struct cifsSesInfo,
}
read_unlock(&GlobalSMBSeslock);
} else {
+ /* 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);
+ if (ses->server == server) {
+ ses->status = CifsExiting;
+ }
+ }
+
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) {
cFYI(1,
- (" Clearing Mid 0x%x - waking up ",mid_entry->mid));
+ ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
task_to_wake = mid_entry->tsk;
if(task_to_wake) {
wake_up_process(task_to_wake);
}
spin_unlock(&GlobalMid_Lock);
read_unlock(&GlobalSMBSeslock);
- set_current_state(TASK_INTERRUPTIBLE);
/* 1/8th of sec is more than enough time for them to exit */
- schedule_timeout(HZ/8);
+ msleep(125);
}
- if (list_empty(&server->pending_mid_q)) {
+ if (!list_empty(&server->pending_mid_q)) {
/* mpx threads have not exited yet give them
at least the smb send timeout time for long ops */
+ /* 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 */
cFYI(1, ("Wait for exit from demultiplex thread"));
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(46 * HZ);
+ msleep(46000);
/* if threads still have not exited they are probably never
coming home not much else we can do but free the memory */
}
- kfree(server);
write_lock(&GlobalSMBSeslock);
atomic_dec(&tcpSesAllocCount);
length = tcpSesAllocCount.counter;
+
+ /* last chance to mark ses pointers invalid
+ if there are any pointing to this (e.g
+ if a crazy root user tried to kill cifsd
+ kernel thread explicitly this might happen) */
+ list_for_each(tmp, &GlobalSMBSessionList) {
+ ses = list_entry(tmp, struct cifsSesInfo,
+ cifsSessionList);
+ if (ses->server == server) {
+ ses->server = NULL;
+ }
+ }
write_unlock(&GlobalSMBSeslock);
+
+ kfree(server);
if(length > 0) {
mempool_resize(cifs_req_poolp,
- length + CIFS_MIN_RCV_POOL,
+ length + cifs_min_rcv,
GFP_KERNEL);
}
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/4);
+
+ complete_and_exit(&cifsd_complete, 0);
return 0;
}
-static void *
-cifs_kcalloc(size_t size, int type)
-{
- void *addr;
- addr = kmalloc(size, type);
- if (addr)
- memset(addr, 0, size);
- return addr;
-}
-
static int
-cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol)
+cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
{
char *value;
char *data;
separator[0] = ',';
separator[1] = 0;
- memset(vol->source_rfc1001_name,0x20,15);
- for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
- /* does not have to be a perfect mapping since the field is
- informational, only used for servers that do not support
- port 445 and it can be overridden at mount time */
- vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]);
+ if (Local_System_Name[0] != 0)
+ memcpy(vol->source_rfc1001_name, Local_System_Name,15);
+ else {
+ char *nodename = utsname()->nodename;
+ int n = strnlen(nodename,15);
+ memset(vol->source_rfc1001_name,0x20,15);
+ for(i=0 ; i < n ; i++) {
+ /* 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 */
+ vol->source_rfc1001_name[i] = toupper(nodename[i]);
+ }
}
vol->source_rfc1001_name[15] = 0;
-
+ /* null target name indicates to use *SMBSERVR default called name
+ if we end up sending RFC1001 session initialize */
+ vol->target_rfc1001_name[0] = 0;
vol->linux_uid = current->uid; /* current->euid instead? */
vol->linux_gid = current->gid;
vol->dir_mode = S_IRWXUGO;
/* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
vol->rw = TRUE;
+ /* default is always to request posix paths. */
+ vol->posix_paths = 1;
if (!options)
return 1;
continue;
if ((value = strchr(data, '=')) != NULL)
*value++ = '\0';
- if (strnicmp(data, "user", 4) == 0) {
- if (!value || !*value) {
+
+ if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
+ vol->no_xattr = 0;
+ } else if (strnicmp(data, "nouser_xattr",12) == 0) {
+ vol->no_xattr = 1;
+ } else if (strnicmp(data, "user", 4) == 0) {
+ if (!value) {
printk(KERN_WARNING
"CIFS: invalid or missing username\n");
return 1; /* needs_arg; */
+ } else if(!*value) {
+ /* null user, ie anonymous, authentication */
+ vol->nullauth = 1;
}
if (strnlen(value, 200) < 200) {
vol->username = value;
return 1;
}
} else if (strnicmp(data, "pass", 4) == 0) {
- if (!value || !*value) {
+ if (!value) {
vol->password = NULL;
continue;
+ } else if(value[0] == 0) {
+ /* 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 */
+ if(value[1] != separator[0]) {
+ vol->password = NULL;
+ continue;
+ }
}
temp_len = strlen(value);
/* removed password length check, NTLM passwords
/* NB: password legally can have multiple commas and
the only illegal character in a password is null */
-
- if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) {
+
+ if ((value[temp_len] == 0) &&
+ (value[temp_len+1] == separator[0])) {
/* reinsert comma */
value[temp_len] = separator[0];
temp_len+=2; /* move after the second comma */
while(value[temp_len] != 0) {
- if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) {
- /* single comma indicating start of next parm */
- break;
+ if (value[temp_len] == separator[0]) {
+ if (value[temp_len+1] ==
+ separator[0]) {
+ /* skip second comma */
+ temp_len++;
+ } else {
+ /* single comma indicating start
+ of next parm */
+ break;
+ }
}
temp_len++;
}
options = NULL;
} else {
value[temp_len] = 0;
- /* move options to point to start of next parm */
+ /* point option to start of next parm */
options = value + temp_len + 1;
}
- /* go from value to (value + temp_len) condensing double commas to singles */
- vol->password = cifs_kcalloc(temp_len, GFP_KERNEL);
+ /* go from value to value + temp_len condensing
+ double commas to singles. Note that this ends up
+ allocating a few bytes too many, which is ok */
+ vol->password = kzalloc(temp_len, GFP_KERNEL);
+ if(vol->password == NULL) {
+ printk("CIFS: no memory for pass\n");
+ return 1;
+ }
for(i=0,j=0;i<temp_len;i++,j++) {
vol->password[j] = value[i];
- if(value[i] == separator[0] && value[i+1] == separator[0]) {
+ if(value[i] == separator[0]
+ && value[i+1] == separator[0]) {
/* skip second comma */
i++;
}
}
- /* value[temp_len] is zeroed above so
- vol->password[temp_len] guaranteed to be null */
+ vol->password[j] = 0;
} else {
- vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL);
+ vol->password = kzalloc(temp_len+1, GFP_KERNEL);
+ if(vol->password == NULL) {
+ printk("CIFS: no memory for pass\n");
+ return 1;
+ }
strcpy(vol->password, value);
}
} else if (strnicmp(data, "ip", 2) == 0) {
printk(KERN_WARNING "CIFS: ip address too long\n");
return 1;
}
+ } 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 |
+ CIFSSEC_MUST_SIGN;
+ } else if (strnicmp(value, "krb5p", 5) == 0) {
+ /* vol->secFlg |= CIFSSEC_MUST_SEAL |
+ CIFSSEC_MAY_KRB5; */
+ cERROR(1,("Krb5 cifs privacy not supported"));
+ return 1;
+ } else if (strnicmp(value, "krb5", 4) == 0) {
+ vol->secFlg |= CIFSSEC_MAY_KRB5;
+ } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
+ vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
+ CIFSSEC_MUST_SIGN;
+ } else if (strnicmp(value, "ntlmv2", 6) == 0) {
+ vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+ } else if (strnicmp(value, "ntlmi", 5) == 0) {
+ vol->secFlg |= CIFSSEC_MAY_NTLM |
+ CIFSSEC_MUST_SIGN;
+ } else if (strnicmp(value, "ntlm", 4) == 0) {
+ /* ntlm is default so can be turned off too */
+ vol->secFlg |= CIFSSEC_MAY_NTLM;
+ } else if (strnicmp(value, "nontlm", 6) == 0) {
+ /* BB is there a better way to do this? */
+ vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+ } else if (strnicmp(value, "lanman", 6) == 0) {
+ vol->secFlg |= CIFSSEC_MAY_LANMAN;
+#endif
+ } else if (strnicmp(value, "none", 4) == 0) {
+ vol->nullauth = 1;
+ } else {
+ cERROR(1,("bad security option: %s", value));
+ return 1;
+ }
} else if ((strnicmp(data, "unc", 3) == 0)
|| (strnicmp(data, "target", 6) == 0)
|| (strnicmp(data, "path", 4) == 0)) {
}
/* BB are there cases in which a comma can be valid in
a domain name and need special handling? */
- if (strnlen(value, 65) < 65) {
+ if (strnlen(value, 256) < 256) {
vol->domainname = value;
cFYI(1, ("Domain name set"));
} else {
printk(KERN_WARNING "CIFS: domain name too long\n");
return 1;
}
+ } else if (strnicmp(data, "prefixpath", 10) == 0) {
+ if (!value || !*value) {
+ printk(KERN_WARNING
+ "CIFS: invalid path prefix\n");
+ return 1; /* needs_arg; */
+ }
+ if ((temp_len = strnlen(value, 1024)) < 1024) {
+ if(value[0] != '/')
+ temp_len++; /* missing leading slash */
+ vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
+ if(vol->prepath == NULL)
+ return 1;
+ if(value[0] != '/') {
+ vol->prepath[0] = '/';
+ strcpy(vol->prepath+1,value);
+ } else
+ strcpy(vol->prepath,value);
+ cFYI(1,("prefix path %s",vol->prepath));
+ } else {
+ printk(KERN_WARNING "CIFS: prefix too long\n");
+ return 1;
+ }
} else if (strnicmp(data, "iocharset", 9) == 0) {
if (!value || !*value) {
printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
vol->file_mode =
simple_strtoul(value, &value, 0);
}
- } else if (strnicmp(data, "dir_mode", 3) == 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);
/* The string has 16th byte zero still from
set at top of the function */
if((i==15) && (value[i] != 0))
- printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
+ printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
+ }
+ } else if (strnicmp(data, "servern", 7) == 0) {
+ /* servernetbiosname specified override *SMBSERVER */
+ if (!value || !*value || (*value == ' ')) {
+ cFYI(1,("empty server netbiosname specified"));
+ } else {
+ /* last byte, type, is 0x20 for servr type */
+ memset(vol->target_rfc1001_name,0x20,16);
+
+ for(i=0;i<15;i++) {
+ /* BB are there cases in which a comma can be
+ valid in this workstation netbios name (and need
+ special handling)? */
+
+ /* user or mount helper must uppercase netbiosname */
+ if (value[i]==0)
+ break;
+ else
+ vol->target_rfc1001_name[i] = value[i];
+ }
+ /* The string has 16th byte zero still from
+ set at top of the function */
+ if((i==15) && (value[i] != 0))
+ printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
}
} else if (strnicmp(data, "credentials", 4) == 0) {
/* ignore */
} else if (strnicmp(data, "version", 3) == 0) {
/* ignore */
+ } else if (strnicmp(data, "guest",5) == 0) {
+ /* ignore */
} else if (strnicmp(data, "rw", 2) == 0) {
vol->rw = TRUE;
} else if ((strnicmp(data, "suid", 4) == 0) ||
vol->noperm = 0;
} else if (strnicmp(data, "noperm", 6) == 0) {
vol->noperm = 1;
+ } else if (strnicmp(data, "mapchars", 8) == 0) {
+ vol->remap = 1;
+ } else if (strnicmp(data, "nomapchars", 10) == 0) {
+ vol->remap = 0;
+ } else if (strnicmp(data, "sfu", 3) == 0) {
+ vol->sfu_emul = 1;
+ } else if (strnicmp(data, "nosfu", 5) == 0) {
+ vol->sfu_emul = 0;
+ } else if (strnicmp(data, "posixpaths", 10) == 0) {
+ vol->posix_paths = 1;
+ } else if (strnicmp(data, "noposixpaths", 12) == 0) {
+ vol->posix_paths = 0;
+ } else if ((strnicmp(data, "nocase", 6) == 0) ||
+ (strnicmp(data, "ignorecase", 10) == 0)) {
+ vol->nocase = 1;
+ } else if (strnicmp(data, "brl", 3) == 0) {
+ vol->nobrl = 0;
+ } else if ((strnicmp(data, "nobrl", 5) == 0) ||
+ (strnicmp(data, "nolock", 6) == 0)) {
+ vol->nobrl = 1;
+ /* turn off mandatory locking in mode
+ if remote locking is turned off since the
+ local vfs will do advisory */
+ if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
+ vol->file_mode = S_IALLUGO;
} else if (strnicmp(data, "setuids", 7) == 0) {
vol->setuids = 1;
} else if (strnicmp(data, "nosetuids", 9) == 0) {
vol->intr = 0;
} else if (strnicmp(data, "intr", 4) == 0) {
vol->intr = 1;
+ } else if (strnicmp(data, "serverino",7) == 0) {
+ vol->server_ino = 1;
+ } else if (strnicmp(data, "noserverino",9) == 0) {
+ vol->server_ino = 0;
+ } else if (strnicmp(data, "cifsacl",7) == 0) {
+ vol->cifs_acl = 1;
+ } else if (strnicmp(data, "nocifsacl", 9) == 0) {
+ vol->cifs_acl = 0;
+ } else if (strnicmp(data, "acl",3) == 0) {
+ vol->no_psx_acl = 0;
+ } else if (strnicmp(data, "noacl",5) == 0) {
+ vol->no_psx_acl = 1;
+ } else if (strnicmp(data, "sign",4) == 0) {
+ vol->secFlg |= CIFSSEC_MUST_SIGN;
+/* } else if (strnicmp(data, "seal",4) == 0) {
+ vol->secFlg |= CIFSSEC_MUST_SEAL; */
+ } else if (strnicmp(data, "direct",6) == 0) {
+ vol->direct_io = 1;
+ } else if (strnicmp(data, "forcedirectio",13) == 0) {
+ vol->direct_io = 1;
+ } else if (strnicmp(data, "in6_addr",8) == 0) {
+ if (!value || !*value) {
+ vol->in6_addr = NULL;
+ } else if (strnlen(value, 49) == 48) {
+ vol->in6_addr = value;
+ } else {
+ printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
+ return 1;
+ }
} else if (strnicmp(data, "noac", 4) == 0) {
printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
} else
return 1;
}
}
- if(vol->UNCip == 0)
+ if(vol->UNCip == NULL)
vol->UNCip = &vol->UNC[2];
return 0;
}
static struct cifsSesInfo *
-cifs_find_tcp_session(__u32 new_target_ip_addr,
+cifs_find_tcp_session(struct in_addr * target_ip_addr,
+ 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) {
- if (ses->server->addr.sockAddr.sin_addr.s_addr ==
- new_target_ip_addr) {
+ if((target_ip_addr &&
+ (ses->server->addr.sockAddr.sin_addr.s_addr
+ == target_ip_addr->s_addr)) || (target_ip6_addr
+ && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
+ target_ip6_addr,sizeof(*target_ip6_addr)))){
/* BB lock server and tcp session and increment use count here?? */
*psrvTcp = ses->server; /* found a match on the TCP session */
/* BB check if reconnection needed */
}
static struct cifsTconInfo *
-find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
+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) {
- cFYI(1, ("Next tcon - "));
+ cFYI(1, ("Next tcon"));
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
if (tcon->ses) {
if (tcon->ses->server) {
cFYI(1,
- (" old ip addr: %x == new ip %x ?",
+ ("old ip addr: %x == new ip %x ?",
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) {
- /* BB lock tcon and server and tcp session and increment use count here? */
+ /* BB lock tcon, server and tcp session and increment use count here? */
/* found a match on the TCP session */
/* BB check if reconnection needed */
- cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
+ cFYI(1,("IP match, old UNC: %s new: %s",
tcon->treeName, uncName));
if (strncmp
(tcon->treeName, uncName,
MAX_TREE_SIZE) == 0) {
cFYI(1,
- ("Matched UNC, old user: %s == new: %s ?",
+ ("and old usr: %s new: %s",
tcon->treeName, uncName));
if (strncmp
(tcon->ses->userName,
userName,
MAX_USERNAME_SIZE) == 0) {
read_unlock(&GlobalSMBSeslock);
- return tcon;/* also matched user (smb session)*/
+ /* matched smb session
+ (user name */
+ return tcon;
}
}
}
int
connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
- const char *old_path, const struct nls_table *nls_codepage)
+ const char *old_path, const struct nls_table *nls_codepage,
+ int remap)
{
unsigned char *referrals = NULL;
unsigned int num_referrals;
int rc = 0;
rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
- &num_referrals, &referrals);
+ &num_referrals, &referrals, remap);
/* BB Add in code to: if valid refrl, if not ip address contact
the helper that resolves tcp names, mount to it, try to
tcon to it unmount it if fail */
- if(referrals)
- kfree(referrals);
+ kfree(referrals);
return rc;
}
int
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)
+ unsigned int *pnum_referrals,
+ unsigned char ** preferrals, int remap)
{
char *temp_unc;
int rc = 0;
}
if (rc == 0)
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
- pnum_referrals, nls_codepage);
+ pnum_referrals, nls_codepage, remap);
return rc;
}
static int
ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
- char * netbios_name)
+ char * netbios_name, char * target_name)
{
int rc = 0;
int connected = 0;
- unsigned short int orig_port = 0;
+ __be16 orig_port = 0;
if(*csocket == NULL) {
rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
/* Eventually check for other socket options to change from
the default. sock_setsockopt not used because it expects
user space buffer */
+ cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
+ (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
+ /* make the bufsizes depend on wsize/rsize and max requests */
+ if((*csocket)->sk->sk_sndbuf < (200 * 1024))
+ (*csocket)->sk->sk_sndbuf = 200 * 1024;
+ if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
+ (*csocket)->sk->sk_rcvbuf = 140 * 1024;
/* send RFC1001 sessinit */
-
- if(psin_server->sin_port == htons(139)) {
+ if(psin_server->sin_port == htons(RFC1001_PORT)) {
/* some servers require RFC1001 sessinit before sending
negprot - BB check reconnection in case where second
sessinit is sent but no second negprot */
struct rfc1002_session_packet * ses_init_buf;
struct smb_hdr * smb_buf;
- ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
+ ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
if(ses_init_buf) {
ses_init_buf->trailer.session_req.called_len = 32;
- rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
- DEFAULT_CIFS_CALLED_NAME,16);
+ if(target_name && (target_name[0] != 0)) {
+ rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+ target_name, 16);
+ } else {
+ rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+ DEFAULT_CIFS_CALLED_NAME,16);
+ }
+
ses_init_buf->trailer.session_req.calling_len = 32;
/* calling name ends in null (byte 16) from old smb
convention. */
rc = smb_send(*csocket, smb_buf, 0x44,
(struct sockaddr *)psin_server);
kfree(ses_init_buf);
+ msleep(1); /* RFC1001 layer in at least one server
+ requires very short break before negprot
+ presumably because not expecting negprot
+ to follow so fast. This is a simple
+ solution that works without
+ complicating the code and causes no
+ significant slowing down on mount
+ for everyone else */
}
/* else the negprot may still work without this
even though malloc failed */
{
int rc = 0;
int connected = 0;
+ __be16 orig_port = 0;
if(*csocket == NULL) {
rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
}
if(!connected) {
+ /* save original port so we can retry user specified port
+ 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 */
if(psin_server->sin6_port != htons(CIFS_PORT)) {
psin_server->sin6_port = htons(CIFS_PORT);
/* give up here - unless we want to retry on different
protocol families some day */
if (!connected) {
+ if(orig_port)
+ psin_server->sin6_port = orig_port;
cFYI(1,("Error %d connecting to server via ipv6",rc));
sock_release(*csocket);
*csocket = NULL;
{
int rc = 0;
int xid;
+ int address_type = AF_INET;
struct socket *csocket = NULL;
struct sockaddr_in sin_server;
struct sockaddr_in6 sin_server6;
memset(&volume_info,0,sizeof(struct smb_vol));
if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
- if(volume_info.UNC)
- kfree(volume_info.UNC);
- if(volume_info.password)
- kfree(volume_info.password);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
}
if (volume_info.username) {
+ /* BB fixme parse for domain name here */
cFYI(1, ("Username: %s ", volume_info.username));
+ } else if (volume_info.nullauth) {
+ cFYI(1,("null user"));
} else {
- cifserror("No username specified ");
+ cifserror("No username specified");
/* In userspace mount helper we can get user name from alternate
locations such as env variables and files on disk */
- if(volume_info.UNC)
- kfree(volume_info.UNC);
- if(volume_info.password)
- kfree(volume_info.password);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
}
if (volume_info.UNCip && volume_info.UNC) {
rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
- if(rc == 0) {
+ if(rc <= 0) {
/* not ipv4 address, try ipv6 */
rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
- }
+ if(rc > 0)
+ address_type = AF_INET6;
+ } else {
+ address_type = AF_INET;
+ }
- if(rc != 1) {
+ if(rc <= 0) {
/* we failed translating address */
- if(volume_info.UNC)
- kfree(volume_info.UNC);
- if(volume_info.password)
- kfree(volume_info.password);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
}
} else if (volume_info.UNCip){
/* BB using ip addr as server name connect to the DFS root below */
cERROR(1,("Connecting to DFS root not implemented yet"));
- if(volume_info.UNC)
- kfree(volume_info.UNC);
- if(volume_info.password)
- kfree(volume_info.password);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
} else /* which servers DFS root would we conect to */ {
cERROR(1,
- ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
- if(volume_info.UNC)
- kfree(volume_info.UNC);
- if(volume_info.password)
- kfree(volume_info.password);
+ ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
}
cifs_sb->local_nls = load_nls(volume_info.iocharset);
if(cifs_sb->local_nls == NULL) {
cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
- if(volume_info.UNC)
- kfree(volume_info.UNC);
- if(volume_info.password)
- kfree(volume_info.password);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return -ELIBACC;
}
}
- existingCifsSes =
- cifs_find_tcp_session(sin_server.sin_addr.s_addr,
- volume_info.username, &srvTcp);
+ if(address_type == AF_INET)
+ existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
+ NULL /* no ipv6 addr */,
+ volume_info.username, &srvTcp);
+ else if(address_type == AF_INET6)
+ existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
+ &sin_server6.sin6_addr,
+ volume_info.username, &srvTcp);
+ else {
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
+ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return -EINVAL;
+ }
+
+
if (srvTcp) {
- cFYI(1, ("Existing tcp session with server found "));
+ cFYI(1, ("Existing tcp session with server found"));
} else { /* create socket */
if(volume_info.port)
sin_server.sin_port = htons(volume_info.port);
else
sin_server.sin_port = 0;
- rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
+ rc = ipv4_connect(&sin_server,&csocket,
+ volume_info.source_rfc1001_name,
+ volume_info.target_rfc1001_name);
if (rc < 0) {
cERROR(1,
("Error connecting to IPv4 socket. Aborting operation"));
if(csocket != NULL)
sock_release(csocket);
- if(volume_info.UNC)
- kfree(volume_info.UNC);
- if(volume_info.password)
- kfree(volume_info.password);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return rc;
}
if (srvTcp == NULL) {
rc = -ENOMEM;
sock_release(csocket);
- if(volume_info.UNC)
- kfree(volume_info.UNC);
- if(volume_info.password)
- kfree(volume_info.password);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
+ kfree(volume_info.prepath);
FreeXid(xid);
return rc;
} else {
so no need to spinlock this init of tcpStatus */
srvTcp->tcpStatus = CifsNew;
init_MUTEX(&srvTcp->tcpSem);
- kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
+ rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
CLONE_FS | CLONE_FILES | CLONE_VM);
+ if(rc < 0) {
+ rc = -ENOMEM;
+ sock_release(csocket);
+ kfree(volume_info.UNC);
+ kfree(volume_info.password);
+ kfree(volume_info.prepath);
+ FreeXid(xid);
+ return rc;
+ }
+ wait_for_completion(&cifsd_complete);
+ rc = 0;
memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
+ memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
+ srvTcp->sequence_number = 0;
}
}
if (existingCifsSes) {
pSesInfo = existingCifsSes;
- cFYI(1, ("Existing smb sess found "));
- if(volume_info.password)
- kfree(volume_info.password);
+ cFYI(1, ("Existing smb sess found"));
+ kfree(volume_info.password);
/* volume_info.UNC freed at end of function */
} else if (!rc) {
- cFYI(1, ("Existing smb sess not found "));
+ cFYI(1, ("Existing smb sess not found"));
pSesInfo = sesInfoAlloc();
if (pSesInfo == NULL)
rc = -ENOMEM;
if (volume_info.username)
strncpy(pSesInfo->userName,
volume_info.username,MAX_USERNAME_SIZE);
- if (volume_info.domainname)
- strncpy(pSesInfo->domainName,
- volume_info.domainname,MAX_USERNAME_SIZE);
+ if (volume_info.domainname) {
+ int len = strlen(volume_info.domainname);
+ pSesInfo->domainName =
+ kmalloc(len + 1, GFP_KERNEL);
+ if(pSesInfo->domainName)
+ strcpy(pSesInfo->domainName,
+ volume_info.domainname);
+ }
pSesInfo->linux_uid = volume_info.linux_uid;
+ pSesInfo->overrideSecFlg = volume_info.secFlg;
down(&pSesInfo->sesSem);
+ /* BB FIXME need to pass vol->secFlgs BB */
rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
up(&pSesInfo->sesSem);
if(!rc)
atomic_inc(&srvTcp->socketUseCount);
} else
- if(volume_info.password)
- kfree(volume_info.password);
+ kfree(volume_info.password);
}
/* search for existing tcon to this server share */
if (!rc) {
- if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+ if(volume_info.rsize > CIFSMaxBufSize) {
+ cERROR(1,("rsize %d too large, using MaxBufSize",
+ volume_info.rsize));
+ cifs_sb->rsize = CIFSMaxBufSize;
+ } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
cifs_sb->rsize = volume_info.rsize;
- else
- cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
- if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
+ else /* default */
+ cifs_sb->rsize = CIFSMaxBufSize;
+
+ if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
+ cERROR(1,("wsize %d too large using 4096 instead",
+ volume_info.wsize));
+ cifs_sb->wsize = 4096;
+ } else if(volume_info.wsize)
cifs_sb->wsize = volume_info.wsize;
else
- cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
- if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
- cifs_sb->rsize = PAGE_CACHE_SIZE;
- cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
+ cifs_sb->wsize =
+ min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
+ 127*1024);
+ /* old default of CIFSMaxBufSize was too small now
+ that SMB Write2 can send multiple pages in kvec.
+ RFC1001 does not describe what happens when frame
+ bigger than 128K is sent so use that as max in
+ conjunction with 52K kvec constraint on arch with 4K
+ page size */
+
+ if(cifs_sb->rsize < 2048) {
+ cifs_sb->rsize = 2048;
+ /* Windows ME may prefer this */
+ cFYI(1,("readsize set to minimum 2048"));
}
+ /* calculate prepath */
+ cifs_sb->prepath = volume_info.prepath;
+ if(cifs_sb->prepath) {
+ cifs_sb->prepathlen = strlen(cifs_sb->prepath);
+ cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
+ volume_info.prepath = NULL;
+ } else
+ cifs_sb->prepathlen = 0;
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;
- cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
+ cFYI(1,("file mode: 0x%x dir mode: 0x%x",
+ cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
if(volume_info.noperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
if(volume_info.setuids)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
+ if(volume_info.server_ino)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
+ if(volume_info.remap)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
+ if(volume_info.no_xattr)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
+ if(volume_info.sfu_emul)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
+ if(volume_info.nobrl)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+ if(volume_info.cifs_acl)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
+
+ if(volume_info.direct_io) {
+ cFYI(1,("mounting share using direct i/o"));
+ 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) {
- cFYI(1, ("Found match on UNC path "));
+ cFYI(1, ("Found match on UNC path"));
/* we can have only one retry value for a connection
to a share so for resources mounted more than once
to the same server share the last value passed in
for the retry flag is used */
tcon->retry = volume_info.retry;
+ tcon->nocase = volume_info.nocase;
} else {
tcon = tconInfoAlloc();
if (tcon == NULL)
if ((strchr(volume_info.UNC + 3, '\\') == NULL)
&& (strchr(volume_info.UNC + 3, '/') ==
NULL)) {
- rc = connect_to_dfs_path(xid,
- pSesInfo,
- "",
- cifs_sb->
- local_nls);
- if(volume_info.UNC)
- kfree(volume_info.UNC);
+ rc = connect_to_dfs_path(xid, pSesInfo,
+ "", cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ kfree(volume_info.UNC);
FreeXid(xid);
return -ENODEV;
} else {
if (!rc) {
atomic_inc(&pSesInfo->inUse);
tcon->retry = volume_info.retry;
+ tcon->nocase = volume_info.nocase;
}
}
}
sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
}
+ 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
spin_lock(&GlobalMid_Lock);
srvTcp->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock);
- if(srvTcp->tsk)
+ if(srvTcp->tsk) {
send_sig(SIGKILL,srvTcp->tsk,1);
+ wait_for_completion(&cifsd_complete);
+ }
}
/* 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 == 0) {
+ if (existingCifsSes == NULL) {
if (pSesInfo) {
if ((pSesInfo->server) &&
(pSesInfo->status == CifsGood)) {
temp_rc = CIFSSMBLogoff(xid, pSesInfo);
/* if the socketUseCount is now zero */
if((temp_rc == -ESHUTDOWN) &&
- (pSesInfo->server->tsk))
+ (pSesInfo->server->tsk)) {
send_sig(SIGKILL,pSesInfo->server->tsk,1);
+ wait_for_completion(&cifsd_complete);
+ }
} else
cFYI(1, ("No session or bad tcon"));
sesInfoFree(pSesInfo);
cifs_sb->tcon = tcon;
tcon->ses = pSesInfo;
- /* do not care if following two calls succeed - informational only */
- CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
- CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
- if (tcon->ses->capabilities & CAP_UNIX)
- CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
- }
+ /* do not care if following two calls succeed - informational */
+ CIFSSMBQFSDeviceInfo(xid, tcon);
+ CIFSSMBQFSAttributeInfo(xid, tcon);
+
+ if (tcon->ses->capabilities & CAP_UNIX) {
+ if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
+ __u64 cap =
+ le64_to_cpu(tcon->fsUnixInfo.Capability);
+ cap &= CIFS_UNIX_CAP_MASK;
+ if(volume_info.no_psx_acl)
+ cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
+ else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
+ cFYI(1,("negotiated posix acl support"));
+ sb->s_flags |= MS_POSIXACL;
+ }
- /* 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
+ if(volume_info.posix_paths == 0)
+ cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+ else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+ cFYI(1,("negotiate posix pathnames"));
+ cifs_sb->mnt_cifs_flags |=
+ CIFS_MOUNT_POSIX_PATHS;
+ }
+
+ cFYI(1,("Negotiate caps 0x%x",(int)cap));
+#ifdef CONFIG_CIFS_DEBUG2
+ if(cap & CIFS_UNIX_FCNTL_CAP)
+ cFYI(1,("FCNTL cap"));
+ if(cap & CIFS_UNIX_EXTATTR_CAP)
+ cFYI(1,("EXTATTR cap"));
+ if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
+ cFYI(1,("POSIX path cap"));
+ if(cap & CIFS_UNIX_XATTR_CAP)
+ cFYI(1,("XATTR cap"));
+ if(cap & CIFS_UNIX_POSIX_ACL_CAP)
+ cFYI(1,("POSIX ACL cap"));
+#endif /* CIFS_DEBUG2 */
+ if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
+ cFYI(1,("setting capabilities failed"));
+ }
+ }
+ }
+ if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
+ cifs_sb->wsize = min(cifs_sb->wsize,
+ (tcon->ses->server->maxBuf -
+ MAX_CIFS_HDR_SIZE));
+ if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
+ cifs_sb->rsize = min(cifs_sb->rsize,
+ (tcon->ses->server->maxBuf -
+ MAX_CIFS_HDR_SIZE));
+ }
+
+ /* 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) */
- if(volume_info.UNC)
- kfree(volume_info.UNC);
+ kfree(volume_info.UNC);
+ kfree(volume_info.prepath);
FreeXid(xid);
return rc;
}
static int
CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
- char session_key[CIFS_SESSION_KEY_SIZE],
+ char session_key[CIFS_SESS_KEY_SIZE],
const struct nls_table *nls_codepage)
{
struct smb_hdr *smb_buffer;
SESSION_SETUP_ANDX *pSMB;
SESSION_SETUP_ANDX *pSMBr;
char *bcc_ptr;
- char *user = ses->userName;
- char *domain = ses->domainName;
+ char *user;
+ char *domain;
int rc = 0;
int remaining_words = 0;
int bytes_returned = 0;
int len;
+ __u32 capabilities;
+ __u16 count;
- cFYI(1, ("In sesssetup "));
-
+ cFYI(1, ("In sesssetup"));
+ if(ses == NULL)
+ return -EINVAL;
+ user = ses->userName;
+ domain = ses->domainName;
smb_buffer = cifs_buf_get();
- if (smb_buffer == 0) {
+ if (smb_buffer == NULL) {
return -ENOMEM;
}
smb_buffer_response = smb_buffer;
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
NULL /* no tCon exists yet */ , 13 /* wct */ );
+ smb_buffer->Mid = GetNextMid(ses->server);
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);
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
- pSMB->req_no_secext.Capabilities =
- CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS;
+ 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;
- pSMB->req_no_secext.Capabilities |= CAP_UNICODE;
+ capabilities |= CAP_UNICODE;
}
if (ses->capabilities & CAP_STATUS32) {
smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
- pSMB->req_no_secext.Capabilities |= CAP_STATUS32;
+ capabilities |= CAP_STATUS32;
}
if (ses->capabilities & CAP_DFS) {
smb_buffer->Flags2 |= SMBFLG2_DFS;
- pSMB->req_no_secext.Capabilities |= CAP_DFS;
+ capabilities |= CAP_DFS;
}
- pSMB->req_no_secext.Capabilities =
- cpu_to_le32(pSMB->req_no_secext.Capabilities);
- /* pSMB->req_no_secext.CaseInsensitivePasswordLength =
- CIFS_SESSION_KEY_SIZE; */
- pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
+ pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+
+ pSMB->req_no_secext.CaseInsensitivePasswordLength =
+ cpu_to_le16(CIFS_SESS_KEY_SIZE);
+
pSMB->req_no_secext.CaseSensitivePasswordLength =
- cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+ cpu_to_le16(CIFS_SESS_KEY_SIZE);
bcc_ptr = pByteArea(smb_buffer);
- /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
- bcc_ptr += CIFS_SESSION_KEY_SIZE; */
- memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
- bcc_ptr += CIFS_SESSION_KEY_SIZE;
+ 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;
if (ses->capabilities & CAP_UNICODE) {
- if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
+ if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
*bcc_ptr = 0;
bcc_ptr++;
}
if(user == NULL)
- bytes_returned = 0; /* skill null user */
+ bytes_returned = 0; /* skip null user */
else
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
+ cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
nls_codepage);
- bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */
+ /* convert number of 16 bit words to bytes */
+ bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2; /* trailing null */
if (domain == NULL)
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr,
+ cifs_strtoUCS((__le16 *) bcc_ptr,
"CIFS_LINUX_DOM", 32, nls_codepage);
else
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+ cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
nls_codepage);
bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2;
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+ cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
- nls_codepage);
+ cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
+ 32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2;
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+ cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
64, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2;
}
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
- strcpy(bcc_ptr, UTS_RELEASE);
- bcc_ptr += strlen(UTS_RELEASE) + 1;
+ strcpy(bcc_ptr, utsname()->release);
+ bcc_ptr += strlen(utsname()->release) + 1;
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
}
- BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
- smb_buffer->smb_buf_length += BCC(smb_buffer);
- BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+ 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);
/* 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)) {
- pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
- if (pSMBr->resp.Action & GUEST_LOGIN)
+ __u16 action = le16_to_cpu(pSMBr->resp.Action);
+ __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
+ if (action & GUEST_LOGIN)
cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
- if (ses) {
- ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
- cFYI(1, ("UID = %d ", ses->Suid));
+ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
+ cFYI(1, ("UID = %d ", ses->Suid));
/* response can have either 3 or 4 word count - Samba sends 3 */
- bcc_ptr = pByteArea(smb_buffer_response);
- if ((pSMBr->resp.hdr.WordCount == 3)
- || ((pSMBr->resp.hdr.WordCount == 4)
- && (pSMBr->resp.SecurityBlobLength <
- pSMBr->resp.ByteCount))) {
- if (pSMBr->resp.hdr.WordCount == 4)
- bcc_ptr +=
- pSMBr->resp.SecurityBlobLength;
-
- 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;
- }
- len =
- UniStrnlen((wchar_t *) bcc_ptr,
- remaining_words - 1);
+ bcc_ptr = pByteArea(smb_buffer_response);
+ 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 =
+ (BCC(smb_buffer_response) - 1) /2;
+ bcc_ptr++; /* Unicode strings must be word aligned */
+ } 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 */
- ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
- cifs_strfromUCS_le(ses->serverOS,
- (wchar_t *)bcc_ptr, len,nls_codepage);
+ if(ses->serverOS)
+ kfree(ses->serverOS);
+ ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
+ if(ses->serverOS == NULL)
+ goto sesssetup_nomem;
+ cifs_strfromUCS_le(ses->serverOS,
+ (__le16 *)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);
+ kfree(ses->serverNOS);
+ ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
+ if(ses->serverNOS == NULL)
+ goto sesssetup_nomem;
+ cifs_strfromUCS_le(ses->serverNOS,
+ (__le16 *)bcc_ptr,len,nls_codepage);
bcc_ptr += 2 * (len + 1);
+ ses->serverNOS[2 * len] = 0;
+ ses->serverNOS[1 + (2 * len)] = 0;
+ if(strncmp(ses->serverNOS,
+ "NT LAN Manager 4",16) == 0) {
+ cFYI(1,("NT4 server"));
+ ses->flags |= CIFS_SES_NT4;
+ }
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);
- ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
- cifs_strfromUCS_le(ses->serverNOS,
- (wchar_t *)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) {
- len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
+ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */
- ses->serverDomain =
- cifs_kcalloc(2*(len+1),GFP_KERNEL);
- cifs_strfromUCS_le(ses->serverDomain,
- (wchar_t *)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 */
- else
- ses->serverDomain =
- cifs_kcalloc(2,
- GFP_KERNEL);
- } else { /* no room so create dummy domain and NOS string */
+ if(ses->serverDomain)
+ kfree(ses->serverDomain);
ses->serverDomain =
- cifs_kcalloc(2, GFP_KERNEL);
- ses->serverNOS =
- cifs_kcalloc(2, GFP_KERNEL);
- }
- } else { /* ASCII */
- len = strnlen(bcc_ptr, 1024);
- if (((long) bcc_ptr + len) - (long)
- pByteArea(smb_buffer_response)
- <= BCC(smb_buffer_response)) {
- ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
- strncpy(ses->serverOS,bcc_ptr, len);
-
- bcc_ptr += len;
- bcc_ptr[0] = 0; /* null terminate the string */
- bcc_ptr++;
-
- len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
- strncpy(ses->serverNOS, bcc_ptr, len);
- bcc_ptr += len;
- bcc_ptr[0] = 0;
- bcc_ptr++;
-
- len = strnlen(bcc_ptr, 1024);
- ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
- strncpy(ses->serverDomain, bcc_ptr, len);
- bcc_ptr += len;
- bcc_ptr[0] = 0;
- bcc_ptr++;
- } else
- cFYI(1,
- ("Variable field of length %d extends beyond end of smb ",
- len));
- }
- } else {
- cERROR(1,
- (" Security Blob Length extends beyond end of SMB"));
- }
- } 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;
-}
-
-static int
-CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
- char *SecurityBlob,int SecurityBlobLength,
- 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 = ses->userName;
- char *domain = ses->domainName;
- int rc = 0;
- int remaining_words = 0;
- int bytes_returned = 0;
- int len;
-
- cFYI(1, ("In spnego sesssetup "));
-
- smb_buffer = cifs_buf_get();
- if (smb_buffer == 0) {
- 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 */ , 12 /* wct */ );
- 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);
-
- if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
- smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
- pSMB->req.Capabilities =
- CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
- CAP_EXTENDED_SECURITY;
- if (ses->capabilities & CAP_UNICODE) {
- smb_buffer->Flags2 |= SMBFLG2_UNICODE;
- pSMB->req.Capabilities |= CAP_UNICODE;
- }
- if (ses->capabilities & CAP_STATUS32) {
- smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
- pSMB->req.Capabilities |= CAP_STATUS32;
- }
- if (ses->capabilities & CAP_DFS) {
- smb_buffer->Flags2 |= SMBFLG2_DFS;
- pSMB->req.Capabilities |= CAP_DFS;
- }
- pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
-
- pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
- bcc_ptr = pByteArea(smb_buffer);
- memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
- bcc_ptr += SecurityBlobLength;
-
- if (ses->capabilities & CAP_UNICODE) {
- if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
- *bcc_ptr = 0;
- bcc_ptr++;
- }
- bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
- bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
- bcc_ptr += 2; /* trailing null */
- if (domain == NULL)
- bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr,
- "CIFS_LINUX_DOM", 32, nls_codepage);
- else
- bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
- nls_codepage);
- bcc_ptr += 2 * bytes_returned;
- bcc_ptr += 2;
- bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
- 32, nls_codepage);
- bcc_ptr += 2 * bytes_returned;
- bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
- nls_codepage);
- bcc_ptr += 2 * bytes_returned;
- bcc_ptr += 2;
- bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
- 64, nls_codepage);
- bcc_ptr += 2 * bytes_returned;
- bcc_ptr += 2;
- } else {
- 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 ");
- strcpy(bcc_ptr, UTS_RELEASE);
- bcc_ptr += strlen(UTS_RELEASE) + 1;
- strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
- bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
- }
- BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
- smb_buffer->smb_buf_length += BCC(smb_buffer);
- BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
-
- 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)) {
- pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
- pSMBr->resp.SecurityBlobLength =
- le16_to_cpu(pSMBr->resp.SecurityBlobLength);
- if (pSMBr->resp.Action & GUEST_LOGIN)
- cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
- if (ses) {
- ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
- cFYI(1, ("UID = %d ", ses->Suid));
- bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
-
- /* BB Fix below to make endian neutral !! */
-
- if ((pSMBr->resp.hdr.WordCount == 3)
- || ((pSMBr->resp.hdr.WordCount == 4)
- && (pSMBr->resp.SecurityBlobLength <
- pSMBr->resp.ByteCount))) {
- if (pSMBr->resp.hdr.WordCount == 4) {
- bcc_ptr +=
- pSMBr->resp.SecurityBlobLength;
- cFYI(1,
- ("Security Blob Length %d ",
- pSMBr->resp.SecurityBlobLength));
- }
-
- 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;
- }
- 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 */
- ses->serverOS =
- cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
- cifs_strfromUCS_le(ses->serverOS,
- (wchar_t *)
- 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);
- ses->serverNOS =
- cifs_kcalloc(2 * (len + 1),
- GFP_KERNEL);
- cifs_strfromUCS_le(ses->serverNOS,
- (wchar_t *)bcc_ptr,
- len,
- nls_codepage);
+ kzalloc(2*(len+1),GFP_KERNEL);
+ if(ses->serverDomain == NULL)
+ goto sesssetup_nomem;
+ cifs_strfromUCS_le(ses->serverDomain,
+ (__le16 *)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) {
- len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
- /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
- ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
- cifs_strfromUCS_le(ses->serverDomain,
- (wchar_t *)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 */
- else
- ses->serverDomain =
- cifs_kcalloc(2,GFP_KERNEL);
- } else { /* no room so create dummy domain and NOS string */
- ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
- ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+ ses->serverDomain[2*len] = 0;
+ ses->serverDomain[1+(2*len)] = 0;
+ } /* else no more room so create dummy domain string */
+ else {
+ if(ses->serverDomain)
+ kfree(ses->serverDomain);
+ ses->serverDomain =
+ kzalloc(2, GFP_KERNEL);
}
- } else { /* ASCII */
-
- len = strnlen(bcc_ptr, 1024);
- if (((long) bcc_ptr + len) - (long)
- pByteArea(smb_buffer_response)
+ } else { /* no room so create dummy domain and NOS string */
+ /* if these kcallocs fail not much we
+ can do, but better to not fail the
+ sesssetup itself */
+ kfree(ses->serverDomain);
+ ses->serverDomain =
+ kzalloc(2, GFP_KERNEL);
+ kfree(ses->serverNOS);
+ ses->serverNOS =
+ kzalloc(2, GFP_KERNEL);
+ }
+ } else { /* ASCII */
+ len = strnlen(bcc_ptr, 1024);
+ if (((long) bcc_ptr + len) - (long)
+ pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
- ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
- strncpy(ses->serverOS, bcc_ptr, len);
+ kfree(ses->serverOS);
+ ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
+ if(ses->serverOS == NULL)
+ goto sesssetup_nomem;
+ strncpy(ses->serverOS,bcc_ptr, len);
- bcc_ptr += len;
- bcc_ptr[0] = 0; /* null terminate the string */
- bcc_ptr++;
+ bcc_ptr += len;
+ bcc_ptr[0] = 0; /* null terminate the string */
+ bcc_ptr++;
- len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
- strncpy(ses->serverNOS, bcc_ptr, len);
- bcc_ptr += len;
- bcc_ptr[0] = 0;
- bcc_ptr++;
+ len = strnlen(bcc_ptr, 1024);
+ kfree(ses->serverNOS);
+ ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
+ if(ses->serverNOS == NULL)
+ goto sesssetup_nomem;
+ strncpy(ses->serverNOS, bcc_ptr, len);
+ bcc_ptr += len;
+ bcc_ptr[0] = 0;
+ bcc_ptr++;
- len = strnlen(bcc_ptr, 1024);
- ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
- strncpy(ses->serverDomain, bcc_ptr, len);
- bcc_ptr += len;
- bcc_ptr[0] = 0;
- bcc_ptr++;
- } else
- cFYI(1,
- ("Variable field of length %d extends beyond end of smb ",
- len));
- }
- } else {
- cERROR(1,
- (" Security Blob Length extends beyond end of SMB"));
+ len = strnlen(bcc_ptr, 1024);
+ if(ses->serverDomain)
+ kfree(ses->serverDomain);
+ ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
+ if(ses->serverDomain == NULL)
+ goto sesssetup_nomem;
+ strncpy(ses->serverDomain, bcc_ptr, len);
+ bcc_ptr += len;
+ bcc_ptr[0] = 0;
+ bcc_ptr++;
+ } else
+ cFYI(1,
+ ("Variable field of length %d extends beyond end of smb ",
+ len));
}
} else {
- cERROR(1, ("No session structure passed in."));
+ cERROR(1,
+ (" Security Blob Length extends beyond end of SMB"));
}
} else {
cERROR(1,
smb_buffer_response->WordCount));
rc = -EIO;
}
-
+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 */
if (smb_buffer)
cifs_buf_release(smb_buffer);
SESSION_SETUP_ANDX *pSMB;
SESSION_SETUP_ANDX *pSMBr;
char *bcc_ptr;
- char *domain = ses->domainName;
+ char *domain;
int rc = 0;
int remaining_words = 0;
int bytes_returned = 0;
int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
PNEGOTIATE_MESSAGE SecurityBlob;
PCHALLENGE_MESSAGE SecurityBlob2;
+ __u32 negotiate_flags, capabilities;
+ __u16 count;
- cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
+ cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
+ if(ses == NULL)
+ return -EINVAL;
+ domain = ses->domainName;
*pNTLMv2_flag = FALSE;
smb_buffer = cifs_buf_get();
- if (smb_buffer == 0) {
+ if (smb_buffer == NULL) {
return -ENOMEM;
}
smb_buffer_response = smb_buffer;
/* send SMBsessionSetup here */
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+ smb_buffer->Mid = GetNextMid(ses->server);
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
- pSMB->req.Capabilities =
- CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+ capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
CAP_EXTENDED_SECURITY;
if (ses->capabilities & CAP_UNICODE) {
smb_buffer->Flags2 |= SMBFLG2_UNICODE;
- pSMB->req.Capabilities |= CAP_UNICODE;
+ capabilities |= CAP_UNICODE;
}
if (ses->capabilities & CAP_STATUS32) {
smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
- pSMB->req.Capabilities |= CAP_STATUS32;
+ capabilities |= CAP_STATUS32;
}
if (ses->capabilities & CAP_DFS) {
smb_buffer->Flags2 |= SMBFLG2_DFS;
- pSMB->req.Capabilities |= CAP_DFS;
+ capabilities |= CAP_DFS;
}
- pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
+ 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;
- SecurityBlob->NegotiateFlags =
+ negotiate_flags =
NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
- NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
+ NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_NEGOTIATE_56 |
/* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
if(sign_CIFS_PDUs)
- SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
- if(ntlmv2_support)
- SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
+ negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
+/* if(ntlmv2_support)
+ negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
/* setup pointers to domain name and workstation name */
bcc_ptr += SecurityBlobLength;
SecurityBlob->WorkstationName.Length = 0;
SecurityBlob->WorkstationName.MaximumLength = 0;
- if (domain == NULL) {
- SecurityBlob->DomainName.Buffer = 0;
- SecurityBlob->DomainName.Length = 0;
- SecurityBlob->DomainName.MaximumLength = 0;
- } else {
- SecurityBlob->NegotiateFlags |=
- NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
- strncpy(bcc_ptr, domain, 63);
- SecurityBlob->DomainName.Length = strnlen(domain, 64);
- SecurityBlob->DomainName.MaximumLength =
- cpu_to_le16(SecurityBlob->DomainName.Length);
- SecurityBlob->DomainName.Buffer =
- cpu_to_le32((long) &SecurityBlob->
- DomainString -
- (long) &SecurityBlob->Signature);
- bcc_ptr += SecurityBlob->DomainName.Length;
- SecurityBlobLength += SecurityBlob->DomainName.Length;
- SecurityBlob->DomainName.Length =
- cpu_to_le16(SecurityBlob->DomainName.Length);
- }
+ /* 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;
if (ses->capabilities & CAP_UNICODE) {
if ((long) bcc_ptr % 2) {
*bcc_ptr = 0;
}
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+ cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+ cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
nls_codepage);
bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2; /* null terminate Linux version */
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+ cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
64, nls_codepage);
bcc_ptr += 2 * bytes_returned;
*(bcc_ptr + 1) = 0;
} else { /* ASCII */
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
- strcpy(bcc_ptr, UTS_RELEASE);
- bcc_ptr += strlen(UTS_RELEASE) + 1;
+ strcpy(bcc_ptr, utsname()->release);
+ bcc_ptr += strlen(utsname()->release) + 1;
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(SecurityBlob->NegotiateFlags);
+ SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
- BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
- smb_buffer->smb_buf_length += BCC(smb_buffer);
- BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+ 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 ==
- (NT_STATUS_MORE_PROCESSING_REQUIRED))
+ 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)) {
- pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
- pSMBr->resp.SecurityBlobLength =
- le16_to_cpu(pSMBr->resp.SecurityBlobLength);
- if (pSMBr->resp.Action & GUEST_LOGIN)
+ __u16 action = le16_to_cpu(pSMBr->resp.Action);
+ __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
+
+ if (action & GUEST_LOGIN)
cFYI(1, (" Guest login"));
/* Do we want to set anything in SesInfo struct when guest login? */
SecurityBlob2->MessageType));
} else if (ses) {
ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
- cFYI(1, ("UID = %d ", ses->Suid));
+ cFYI(1, ("UID = %d", ses->Suid));
if ((pSMBr->resp.hdr.WordCount == 3)
|| ((pSMBr->resp.hdr.WordCount == 4)
- && (pSMBr->resp.SecurityBlobLength <
+ && (blob_len <
pSMBr->resp.ByteCount))) {
+
if (pSMBr->resp.hdr.WordCount == 4) {
- bcc_ptr +=
- pSMBr->resp.SecurityBlobLength;
- cFYI(1,
- ("Security Blob Length %d ",
- pSMBr->resp.SecurityBlobLength));
+ bcc_ptr += blob_len;
+ cFYI(1, ("Security Blob Length %d",
+ blob_len));
}
- cFYI(1, ("NTLMSSP Challenge rcvd "));
+ cFYI(1, ("NTLMSSP Challenge rcvd"));
memcpy(ses->server->cryptKey,
SecurityBlob2->Challenge,
CIFS_CRYPTO_KEY_SIZE);
- if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2)
+ if(SecurityBlob2->NegotiateFlags &
+ cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
*pNTLMv2_flag = TRUE;
if((SecurityBlob2->NegotiateFlags &
- NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
+ cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
|| (sign_CIFS_PDUs > 1))
ses->server->secMode |=
SECMODE_SIGN_REQUIRED;
if ((SecurityBlob2->NegotiateFlags &
- NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs))
+ cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
ses->server->secMode |=
SECMODE_SIGN_ENABLED;
/* 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 */
+ if(ses->serverOS)
+ kfree(ses->serverOS);
ses->serverOS =
- cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ kzalloc(2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
- (wchar_t *)
+ (__le16 *)
bcc_ptr, len,
nls_codepage);
bcc_ptr += 2 * (len + 1);
bcc_ptr,
remaining_words
- 1);
+ kfree(ses->serverNOS);
ses->serverNOS =
- cifs_kcalloc(2 * (len + 1),
+ kzalloc(2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->
serverNOS,
- (wchar_t *)
+ (__le16 *)
bcc_ptr,
len,
nls_codepage);
if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+ kfree(ses->serverDomain);
ses->serverDomain =
- cifs_kcalloc(2 *
+ kzalloc(2 *
(len +
1),
GFP_KERNEL);
cifs_strfromUCS_le
- (ses->
- serverDomain,
- (wchar_t *)
- bcc_ptr, len,
- nls_codepage);
+ (ses->serverDomain,
+ (__le16 *)bcc_ptr,
+ len, nls_codepage);
bcc_ptr +=
2 * (len + 1);
- ses->
- serverDomain[2
- * len]
+ ses->serverDomain[2*len]
= 0;
- ses->
- serverDomain[1
- +
- (2
- *
- len)]
+ ses->serverDomain
+ [1 + (2 * len)]
= 0;
} /* else no more room so create dummy domain string */
- else
+ else {
+ kfree(ses->serverDomain);
ses->serverDomain =
- cifs_kcalloc(2,
+ kzalloc(2,
GFP_KERNEL);
+ }
} else { /* no room so create dummy domain and NOS string */
+ kfree(ses->serverDomain);
ses->serverDomain =
- cifs_kcalloc(2, GFP_KERNEL);
+ kzalloc(2, GFP_KERNEL);
+ kfree(ses->serverNOS);
ses->serverNOS =
- cifs_kcalloc(2, GFP_KERNEL);
+ kzalloc(2, GFP_KERNEL);
}
} else { /* ASCII */
len = strnlen(bcc_ptr, 1024);
if (((long) bcc_ptr + len) - (long)
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
+ if(ses->serverOS)
+ kfree(ses->serverOS);
ses->serverOS =
- cifs_kcalloc(len + 1,
+ kzalloc(len + 1,
GFP_KERNEL);
strncpy(ses->serverOS,
bcc_ptr, len);
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
+ kfree(ses->serverNOS);
ses->serverNOS =
- cifs_kcalloc(len + 1,
+ kzalloc(len + 1,
GFP_KERNEL);
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
+ kfree(ses->serverDomain);
ses->serverDomain =
- cifs_kcalloc(len + 1,
+ kzalloc(len + 1,
GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr++;
} else
cFYI(1,
- ("Variable field of length %d extends beyond end of smb ",
+ ("Variable field of length %d extends beyond end of smb",
len));
}
} else {
}
} else {
cERROR(1,
- (" Invalid Word count %d: ",
+ (" Invalid Word count %d:",
smb_buffer_response->WordCount));
rc = -EIO;
}
return rc;
}
-
static int
CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
char *ntlm_session_key, int ntlmv2_flag,
SESSION_SETUP_ANDX *pSMB;
SESSION_SETUP_ANDX *pSMBr;
char *bcc_ptr;
- char *user = ses->userName;
- char *domain = ses->domainName;
+ 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)"));
-
+ if(ses == NULL)
+ return -EINVAL;
+ user = ses->userName;
+ domain = ses->domainName;
smb_buffer = cifs_buf_get();
- if (smb_buffer == 0) {
+ if (smb_buffer == NULL) {
return -ENOMEM;
}
smb_buffer_response = smb_buffer;
/* send SMBsessionSetup here */
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+ smb_buffer->Mid = GetNextMid(ses->server);
pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
pSMB->req.AndXCommand = 0xFF;
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
- pSMB->req.Capabilities =
- CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+ capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
CAP_EXTENDED_SECURITY;
if (ses->capabilities & CAP_UNICODE) {
smb_buffer->Flags2 |= SMBFLG2_UNICODE;
- pSMB->req.Capabilities |= CAP_UNICODE;
+ capabilities |= CAP_UNICODE;
}
if (ses->capabilities & CAP_STATUS32) {
smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
- pSMB->req.Capabilities |= CAP_STATUS32;
+ capabilities |= CAP_STATUS32;
}
if (ses->capabilities & CAP_DFS) {
smb_buffer->Flags2 |= SMBFLG2_DFS;
- pSMB->req.Capabilities |= CAP_DFS;
+ capabilities |= CAP_DFS;
}
- pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
+ 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;
- SecurityBlob->NegotiateFlags =
+ negotiate_flags =
NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
0x80000000 | NTLMSSP_NEGOTIATE_128;
if(sign_CIFS_PDUs)
- SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
+ negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
if(ntlmv2_flag)
- SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
+ negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
/* setup pointers to domain name and workstation name */
SecurityBlob->LmChallengeResponse.Buffer = 0;
SecurityBlob->NtChallengeResponse.Length =
- cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+ cpu_to_le16(CIFS_SESS_KEY_SIZE);
SecurityBlob->NtChallengeResponse.MaximumLength =
- cpu_to_le16(CIFS_SESSION_KEY_SIZE);
- memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
+ cpu_to_le16(CIFS_SESS_KEY_SIZE);
+ memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
SecurityBlob->NtChallengeResponse.Buffer =
cpu_to_le32(SecurityBlobLength);
- SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
- bcc_ptr += CIFS_SESSION_KEY_SIZE;
+ SecurityBlobLength += CIFS_SESS_KEY_SIZE;
+ bcc_ptr += CIFS_SESS_KEY_SIZE;
if (ses->capabilities & CAP_UNICODE) {
if (domain == NULL) {
SecurityBlob->DomainName.Length = 0;
SecurityBlob->DomainName.MaximumLength = 0;
} else {
- SecurityBlob->DomainName.Length =
- cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+ __u16 len =
+ cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
nls_codepage);
- SecurityBlob->DomainName.Length *= 2;
+ len *= 2;
SecurityBlob->DomainName.MaximumLength =
- cpu_to_le16(SecurityBlob->DomainName.Length);
+ cpu_to_le16(len);
SecurityBlob->DomainName.Buffer =
cpu_to_le32(SecurityBlobLength);
- bcc_ptr += SecurityBlob->DomainName.Length;
- SecurityBlobLength += SecurityBlob->DomainName.Length;
+ bcc_ptr += len;
+ SecurityBlobLength += len;
SecurityBlob->DomainName.Length =
- cpu_to_le16(SecurityBlob->DomainName.Length);
+ cpu_to_le16(len);
}
if (user == NULL) {
SecurityBlob->UserName.Buffer = 0;
SecurityBlob->UserName.Length = 0;
SecurityBlob->UserName.MaximumLength = 0;
} else {
- SecurityBlob->UserName.Length =
- cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
+ __u16 len =
+ cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
nls_codepage);
- SecurityBlob->UserName.Length *= 2;
+ len *= 2;
SecurityBlob->UserName.MaximumLength =
- cpu_to_le16(SecurityBlob->UserName.Length);
+ cpu_to_le16(len);
SecurityBlob->UserName.Buffer =
cpu_to_le32(SecurityBlobLength);
- bcc_ptr += SecurityBlob->UserName.Length;
- SecurityBlobLength += SecurityBlob->UserName.Length;
+ bcc_ptr += len;
+ SecurityBlobLength += len;
SecurityBlob->UserName.Length =
- cpu_to_le16(SecurityBlob->UserName.Length);
+ cpu_to_le16(len);
}
- /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
+ /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
SecurityBlob->WorkstationName.Length *= 2;
SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
bcc_ptr++;
}
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+ cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+ cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
nls_codepage);
bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2; /* null term version string */
bytes_returned =
- cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+ cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
64, nls_codepage);
bcc_ptr += 2 * bytes_returned;
*(bcc_ptr + 1) = 0;
SecurityBlob->DomainName.Length = 0;
SecurityBlob->DomainName.MaximumLength = 0;
} else {
- SecurityBlob->NegotiateFlags |=
- NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
+ __u16 len;
+ negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
strncpy(bcc_ptr, domain, 63);
- SecurityBlob->DomainName.Length = strnlen(domain, 64);
+ len = strnlen(domain, 64);
SecurityBlob->DomainName.MaximumLength =
- cpu_to_le16(SecurityBlob->DomainName.Length);
+ cpu_to_le16(len);
SecurityBlob->DomainName.Buffer =
cpu_to_le32(SecurityBlobLength);
- bcc_ptr += SecurityBlob->DomainName.Length;
- SecurityBlobLength += SecurityBlob->DomainName.Length;
- SecurityBlob->DomainName.Length =
- cpu_to_le16(SecurityBlob->DomainName.Length);
+ bcc_ptr += len;
+ SecurityBlobLength += len;
+ SecurityBlob->DomainName.Length = cpu_to_le16(len);
}
if (user == NULL) {
SecurityBlob->UserName.Buffer = 0;
SecurityBlob->UserName.Length = 0;
SecurityBlob->UserName.MaximumLength = 0;
} else {
+ __u16 len;
strncpy(bcc_ptr, user, 63);
- SecurityBlob->UserName.Length = strnlen(user, 64);
+ len = strnlen(user, 64);
SecurityBlob->UserName.MaximumLength =
- cpu_to_le16(SecurityBlob->UserName.Length);
+ cpu_to_le16(len);
SecurityBlob->UserName.Buffer =
cpu_to_le32(SecurityBlobLength);
- bcc_ptr += SecurityBlob->UserName.Length;
- SecurityBlobLength += SecurityBlob->UserName.Length;
- SecurityBlob->UserName.Length =
- cpu_to_le16(SecurityBlob->UserName.Length);
+ bcc_ptr += len;
+ SecurityBlobLength += len;
+ SecurityBlob->UserName.Length = cpu_to_le16(len);
}
/* BB fill in our workstation name if known BB */
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
- strcpy(bcc_ptr, UTS_RELEASE);
- bcc_ptr += strlen(UTS_RELEASE) + 1;
+ strcpy(bcc_ptr, utsname()->release);
+ bcc_ptr += strlen(utsname()->release) + 1;
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(SecurityBlob->NegotiateFlags);
+ SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
- BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
- smb_buffer->smb_buf_length += BCC(smb_buffer);
- BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+ 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);
/* 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)) {
- pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
- pSMBr->resp.SecurityBlobLength =
+ __u16 action = le16_to_cpu(pSMBr->resp.Action);
+ __u16 blob_len =
le16_to_cpu(pSMBr->resp.SecurityBlobLength);
- if (pSMBr->resp.Action & GUEST_LOGIN)
+ if (action & GUEST_LOGIN)
cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
/* if(SecurityBlob2->MessageType != NtLm??){
cFYI("Unexpected message type on auth response is %d "));
/* response can have either 3 or 4 word count - Samba sends 3 */
if ((pSMBr->resp.hdr.WordCount == 3)
|| ((pSMBr->resp.hdr.WordCount == 4)
- && (pSMBr->resp.SecurityBlobLength <
+ && (blob_len <
pSMBr->resp.ByteCount))) {
if (pSMBr->resp.hdr.WordCount == 4) {
bcc_ptr +=
- pSMBr->resp.SecurityBlobLength;
+ blob_len;
cFYI(1,
("Security Blob Length %d ",
- pSMBr->resp.SecurityBlobLength));
+ blob_len));
}
cFYI(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 */
+ if(ses->serverOS)
+ kfree(ses->serverOS);
ses->serverOS =
- cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
+ kzalloc(2 * (len + 1), GFP_KERNEL);
cifs_strfromUCS_le(ses->serverOS,
- (wchar_t *)
+ (__le16 *)
bcc_ptr, len,
nls_codepage);
bcc_ptr += 2 * (len + 1);
bcc_ptr,
remaining_words
- 1);
+ kfree(ses->serverNOS);
ses->serverNOS =
- cifs_kcalloc(2 * (len + 1),
+ kzalloc(2 * (len + 1),
GFP_KERNEL);
cifs_strfromUCS_le(ses->
serverNOS,
- (wchar_t *)
+ (__le16 *)
bcc_ptr,
len,
nls_codepage);
if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string not always null terminated (e.g. for Windows XP & 2000) */
+ if(ses->serverDomain)
+ kfree(ses->serverDomain);
ses->serverDomain =
- cifs_kcalloc(2 *
+ kzalloc(2 *
(len +
1),
GFP_KERNEL);
cifs_strfromUCS_le
(ses->
serverDomain,
- (wchar_t *)
+ (__le16 *)
bcc_ptr, len,
nls_codepage);
bcc_ptr +=
len)]
= 0;
} /* else no more room so create dummy domain string */
- else
- ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
+ else {
+ if(ses->serverDomain)
+ kfree(ses->serverDomain);
+ ses->serverDomain = kzalloc(2,GFP_KERNEL);
+ }
} else { /* no room so create dummy domain and NOS string */
- ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
- ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
+ if(ses->serverDomain)
+ kfree(ses->serverDomain);
+ ses->serverDomain = kzalloc(2, GFP_KERNEL);
+ kfree(ses->serverNOS);
+ ses->serverNOS = kzalloc(2, GFP_KERNEL);
}
} else { /* ASCII */
len = strnlen(bcc_ptr, 1024);
if (((long) bcc_ptr + len) -
(long) pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
- ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
+ if(ses->serverOS)
+ kfree(ses->serverOS);
+ ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
strncpy(ses->serverOS,bcc_ptr, len);
bcc_ptr += len;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
+ kfree(ses->serverNOS);
+ ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
+ if(ses->serverDomain)
+ kfree(ses->serverDomain);
+ ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
struct smb_hdr *smb_buffer_response;
TCONX_REQ *pSMB;
TCONX_RSP *pSMBr;
- char *bcc_ptr;
+ unsigned char *bcc_ptr;
int rc = 0;
int length;
+ __u16 count;
if (ses == NULL)
return -EIO;
smb_buffer = cifs_buf_get();
- if (smb_buffer == 0) {
+ 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 */ );
+
+ smb_buffer->Mid = GetNextMid(ses->server);
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);
- pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
- bcc_ptr = &(pSMB->Password[0]);
- bcc_ptr++; /* skip password */
+ bcc_ptr = &pSMB->Password[0];
+ if((ses->server->secMode) & SECMODE_USER) {
+ pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
+ *bcc_ptr = 0; /* password is null byte */
+ bcc_ptr++; /* skip password */
+ /* already aligned so no need to do it below */
+ } else {
+ pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
+ /* 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
+ weaker LANMAN (which we do not send by default) is accepted
+ by Samba (not sure whether other servers allow
+ NTLMv2 password here) */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+ if((extended_security & CIFSSEC_MAY_LANMAN) &&
+ (ses->server->secType == LANMAN))
+ calc_lanman_hash(ses, bcc_ptr);
+ else
+#endif /* CIFS_WEAK_PW_HASH */
+ SMBNTencrypt(ses->password,
+ ses->server->cryptKey,
+ bcc_ptr);
+
+ bcc_ptr += CIFS_SESS_KEY_SIZE;
+ if(ses->capabilities & CAP_UNICODE) {
+ /* must align unicode strings */
+ *bcc_ptr = 0; /* null byte password */
+ bcc_ptr++;
+ }
+ }
- if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ if(ses->server->secMode &
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
if (ses->capabilities & CAP_STATUS32) {
if (ses->capabilities & CAP_UNICODE) {
smb_buffer->Flags2 |= SMBFLG2_UNICODE;
length =
- cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
- bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
+ cifs_strtoUCS((__le16 *) bcc_ptr, tree,
+ 6 /* max utf8 char length in bytes */ *
+ (/* server len*/ + 256 /* share len */), nls_codepage);
+ bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
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;
- BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
- smb_buffer->smb_buf_length += BCC(smb_buffer);
- BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+ 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->tidStatus = CifsGood;
tcon->tid = smb_buffer_response->Tid;
bcc_ptr = pByteArea(smb_buffer_response);
length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
length = UniStrnlen((wchar_t *) bcc_ptr, 512);
- if (((long) bcc_ptr + (2 * length)) -
- (long) pByteArea(smb_buffer_response) <=
+ if ((bcc_ptr + (2 * length)) -
+ pByteArea(smb_buffer_response) <=
BCC(smb_buffer_response)) {
- if(tcon->nativeFileSystem)
- kfree(tcon->nativeFileSystem);
+ kfree(tcon->nativeFileSystem);
tcon->nativeFileSystem =
- cifs_kcalloc(length + 2, GFP_KERNEL);
+ kzalloc(length + 2, GFP_KERNEL);
cifs_strfromUCS_le(tcon->nativeFileSystem,
- (wchar_t *) bcc_ptr,
+ (__le16 *) bcc_ptr,
length, nls_codepage);
bcc_ptr += 2 * length;
bcc_ptr[0] = 0; /* null terminate the string */
/* else do not bother copying these informational fields */
} else {
length = strnlen(bcc_ptr, 1024);
- if (((long) bcc_ptr + length) -
- (long) pByteArea(smb_buffer_response) <=
+ if ((bcc_ptr + length) -
+ pByteArea(smb_buffer_response) <=
BCC(smb_buffer_response)) {
- if(tcon->nativeFileSystem)
- kfree(tcon->nativeFileSystem);
+ kfree(tcon->nativeFileSystem);
tcon->nativeFileSystem =
- cifs_kcalloc(length + 1, GFP_KERNEL);
+ kzalloc(length + 1, GFP_KERNEL);
strncpy(tcon->nativeFileSystem, bcc_ptr,
length);
}
/* else do not bother copying these informational fields */
}
- tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+ if((smb_buffer_response->WordCount == 3) ||
+ (smb_buffer_response->WordCount == 7))
+ /* field is in same location */
+ tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+ else
+ tcon->Flags = 0;
cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
} else if ((rc == 0) && tcon == NULL) {
/* all we need to save for IPC$ connection */
int xid;
struct cifsSesInfo *ses = NULL;
struct task_struct *cifsd_task;
+ char * tmp;
xid = GetXid();
return 0;
} else if (rc == -ESHUTDOWN) {
cFYI(1,("Waking up socket by sending it signal"));
- send_sig(SIGKILL,cifsd_task,1);
+ if(cifsd_task) {
+ send_sig(SIGKILL,cifsd_task,1);
+ wait_for_completion(&cifsd_complete);
+ }
rc = 0;
} /* else - we have an smb session
left on this socket do not kill cifsd */
}
cifs_sb->tcon = NULL;
- if (ses) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ / 2);
- }
+ tmp = cifs_sb->prepath;
+ cifs_sb->prepathlen = 0;
+ cifs_sb->prepath = NULL;
+ kfree(tmp);
+ if (ses)
+ schedule_timeout_interruptible(msecs_to_jiffies(500));
if (ses)
sesInfoFree(ses);
struct nls_table * nls_info)
{
int rc = 0;
- char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
+ char ntlm_session_key[CIFS_SESS_KEY_SIZE];
int ntlmv2_flag = FALSE;
+ int first_time = 0;
/* what if server changes its buffer size after dropping the session? */
if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
spin_unlock(&GlobalMid_Lock);
}
+ first_time = 1;
}
if (!rc) {
+ pSesInfo->flags = 0;
pSesInfo->capabilities = pSesInfo->server->capabilities;
if(linuxExtEnabled == 0)
pSesInfo->capabilities &= (~CAP_UNIX);
- pSesInfo->sequence_number = 0;
- cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
+ /* pSesInfo->sequence_number = 0;*/
+ cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
pSesInfo->server->secMode,
pSesInfo->server->capabilities,
- pSesInfo->server->timeZone));
- if (extended_security
- && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+ pSesInfo->server->timeAdj));
+ if(experimEnabled < 2)
+ rc = CIFS_SessSetup(xid, pSesInfo,
+ first_time, nls_info);
+ else if (extended_security
+ && (pSesInfo->capabilities
+ & CAP_EXTENDED_SECURITY)
&& (pSesInfo->server->secType == NTLMSSP)) {
- cFYI(1, ("New style sesssetup "));
- rc = CIFSSpnegoSessSetup(xid, pSesInfo,
- NULL /* security blob */,
- 0 /* blob length */,
- nls_info);
+ rc = -EOPNOTSUPP;
} else if (extended_security
&& (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
&& (pSesInfo->server->secType == RawNTLMSSP)) {
- cFYI(1, ("NTLMSSP sesssetup "));
+ cFYI(1, ("NTLMSSP sesssetup"));
rc = CIFSNTLMSSPNegotiateSessSetup(xid,
pSesInfo,
&ntlmv2_flag,
if (!rc) {
if(ntlmv2_flag) {
char * v2_response;
- cFYI(1,("Can use more secure NTLM version 2 password hash"));
- CalcNTLMv2_partial_mac_key(pSesInfo,
- nls_info);
- v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
+ cFYI(1,("more secure NTLM ver2 hash"));
+ if(CalcNTLMv2_partial_mac_key(pSesInfo,
+ nls_info)) {
+ rc = -ENOMEM;
+ goto ss_err_exit;
+ } else
+ v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
if(v2_response) {
CalcNTLMv2_response(pSesInfo,v2_response);
-/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */
+ /* if(first_time)
+ cifs_calculate_ntlmv2_mac_key(
+ pSesInfo->server->mac_signing_key,
+ response, ntlm_session_key, */
kfree(v2_response);
/* BB Put dummy sig in SessSetup PDU? */
- } else
+ } else {
rc = -ENOMEM;
+ goto ss_err_exit;
+ }
} else {
SMBNTencrypt(pSesInfo->password,
pSesInfo->server->cryptKey,
ntlm_session_key);
- cifs_calculate_mac_key(pSesInfo->mac_signing_key,
- ntlm_session_key,
- pSesInfo->password);
+ if(first_time)
+ cifs_calculate_mac_key(
+ pSesInfo->server->mac_signing_key,
+ ntlm_session_key,
+ pSesInfo->password);
}
/* for better security the weaker lanman hash not sent
in AuthSessSetup so we no longer calculate it */
pSesInfo->server->cryptKey,
ntlm_session_key);
- cifs_calculate_mac_key(pSesInfo->mac_signing_key,
- ntlm_session_key, pSesInfo->password);
+ if(first_time)
+ cifs_calculate_mac_key(
+ pSesInfo->server->mac_signing_key,
+ ntlm_session_key, pSesInfo->password);
+
rc = CIFSSessSetup(xid, pSesInfo,
ntlm_session_key, nls_info);
}
pSesInfo->status = CifsGood;
}
}
+ss_err_exit:
return rc;
}