[CIFS] Support for setting up SMB sessions to legacy lanman servers

This commit is contained in:
Steve French 2006-05-31 22:40:51 +00:00
parent 26a21b980b
commit 3979877e56
20 changed files with 836 additions and 75 deletions

View file

@ -1663,7 +1663,7 @@ config CIFS_STATS
mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
config CIFS_STATS2
bool "CIFS extended statistics"
bool "Extended statistics"
depends on CIFS_STATS
help
Enabling this option will allow more detailed statistics on SMB
@ -1676,6 +1676,32 @@ config CIFS_STATS2
Unless you are a developer or are doing network performance analysis
or tuning, say N.
config CIFS_WEAK_PW_HASH
bool "Support legacy servers which use weaker LANMAN security"
depends on CIFS
help
Modern CIFS servers including Samba and most Windows versions
(since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
security mechanisms. These hash the password more securely
than the mechanisms used in the older LANMAN version of the
SMB protocol needed to establish sessions with old SMB servers.
Enabling this option allows the cifs module to mount to older
LANMAN based servers such as OS/2 and Windows 95, but such
mounts may be less secure than mounts using NTLM or more recent
security mechanisms if you are on a public network. Unless you
have a need to access old SMB servers (and are on a private
network) you probably want to say N. Even if this support
is enabled in the kernel build, they will not be used
automatically. At runtime LANMAN mounts are disabled but
can be set to required (or optional) either in
/proc/fs/cifs (see fs/cifs/README for more detail) or via an
option on the mount command. This support is disabled by
default in order to reduce the possibility of a downgrade
attack.
If unsure, say N.
config CIFS_XATTR
bool "CIFS extended attributes"
depends on CIFS
@ -1704,6 +1730,16 @@ config CIFS_POSIX
(such as Samba 3.10 and later) which can negotiate
CIFS POSIX ACL support. If unsure, say N.
config CIFS_DEBUG2
bool "Enable additional CIFS debugging routines
help
Enabling this option adds a few more debugging routines
to the cifs code which slightly increases the size of
the cifs module and can cause additional logging of debug
messages in some error paths, slowing performance. This
option can be turned off unless you are debugging
cifs problems. If unsure, say N.
config CIFS_EXPERIMENTAL
bool "CIFS Experimental Features (EXPERIMENTAL)"
depends on CIFS && EXPERIMENTAL
@ -1719,7 +1755,7 @@ config CIFS_EXPERIMENTAL
If unsure, say N.
config CIFS_UPCALL
bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
depends on CIFS_EXPERIMENTAL
select CONNECTOR
help

View file

@ -1,3 +1,8 @@
Version 1.44
------------
Rewritten sessionsetup support, including support for legacy SMB
session setup needed for OS/2 and older servers such as Windows 95 and 98.
Version 1.43
------------
POSIX locking to servers which support CIFS POSIX Extensions

View file

@ -3,4 +3,4 @@
#
obj-$(CONFIG_CIFS) += cifs.o
cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o ntlmssp.o
cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o

View file

@ -39,7 +39,7 @@ cifs_dump_mem(char *label, void *data, int length)
char *charptr = data;
char buf[10], line[80];
printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n",
printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n",
label, length, data);
for (i = 0; i < length; i += 16) {
line[0] = 0;
@ -57,6 +57,57 @@ cifs_dump_mem(char *label, void *data, int length)
}
}
#ifdef CONFIG_CIFS_DEBUG2
void cifs_dump_detail(struct smb_hdr * smb)
{
cERROR(1,("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
smb->Command, smb->Status.CifsError,
smb->Flags, smb->Flags2, smb->Mid, smb->Pid));
cERROR(1,("smb buf %p len %d", smb, smbCalcSize_LE(smb)));
}
void cifs_dump_mids(struct TCP_Server_Info * server)
{
struct list_head *tmp;
struct mid_q_entry * mid_entry;
if(server == NULL)
return;
cERROR(1,("Dump pending requests:"));
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) {
cERROR(1,("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
mid_entry->midState,
(int)mid_entry->command,
mid_entry->pid,
mid_entry->tsk,
mid_entry->mid));
#ifdef CONFIG_CIFS_STATS2
cERROR(1,("IsLarge: %d buf: %p time rcv: %ld now: %ld",
mid_entry->largeBuf,
mid_entry->resp_buf,
mid_entry->when_received,
jiffies));
#endif /* STATS2 */
cERROR(1,("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
mid_entry->multiEnd));
if(mid_entry->resp_buf) {
cifs_dump_detail(mid_entry->resp_buf);
cifs_dump_mem("existing buf: ",
mid_entry->resp_buf,
62 /* fixme */);
}
}
}
spin_unlock(&GlobalMid_Lock);
}
#endif /* CONFIG_CIFS_DEBUG2 */
#ifdef CONFIG_PROC_FS
static int
cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
@ -73,7 +124,6 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
*beginBuffer = buf + offset;
length =
sprintf(buf,
"Display Internal CIFS Data Structures for Debugging\n"
@ -397,10 +447,10 @@ static read_proc_t multiuser_mount_read;
static write_proc_t multiuser_mount_write;
static read_proc_t extended_security_read;
static write_proc_t extended_security_write;
static read_proc_t ntlmv2_enabled_read;
/* static read_proc_t ntlmv2_enabled_read;
static write_proc_t ntlmv2_enabled_write;
static read_proc_t packet_signing_enabled_read;
static write_proc_t packet_signing_enabled_write;
static write_proc_t packet_signing_enabled_write;*/
static read_proc_t experimEnabled_read;
static write_proc_t experimEnabled_write;
static read_proc_t linuxExtensionsEnabled_read;
@ -469,7 +519,7 @@ cifs_proc_init(void)
if (pde)
pde->write_proc = lookupFlag_write;
pde =
/* pde =
create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
ntlmv2_enabled_read, NULL);
if (pde)
@ -479,7 +529,7 @@ cifs_proc_init(void)
create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
packet_signing_enabled_read, NULL);
if (pde)
pde->write_proc = packet_signing_enabled_write;
pde->write_proc = packet_signing_enabled_write;*/
}
void
@ -496,9 +546,9 @@ cifs_proc_clean(void)
#endif
remove_proc_entry("MultiuserMount", proc_fs_cifs);
remove_proc_entry("OplockEnabled", proc_fs_cifs);
remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
/* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
/* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */
remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
remove_proc_entry("Experimental",proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
@ -787,7 +837,7 @@ extended_security_read(char *page, char **start, off_t off,
{
int len;
len = sprintf(page, "%d\n", extended_security);
len = sprintf(page, "0x%x\n", extended_security);
len -= off;
*start = page + off;
@ -808,19 +858,25 @@ extended_security_write(struct file *file, const char __user *buffer,
{
char c;
int rc;
cERROR(1,("size %ld",count)); /* BB removeme BB */
if((count < 2) || (count > 8))
return -EINVAL;
rc = get_user(c, buffer);
/* BB fixme need to parse more characters in order to handle CIFSSEC flags */
if (rc)
return rc;
if (c == '0' || c == 'n' || c == 'N')
extended_security = 0;
extended_security = CIFSSEC_DEF; /* default */
else if (c == '1' || c == 'y' || c == 'Y')
extended_security = 1;
extended_security = CIFSSEC_MAX;
return count;
}
static int
/* static int
ntlmv2_enabled_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
@ -855,6 +911,8 @@ ntlmv2_enabled_write(struct file *file, const char __user *buffer,
ntlmv2_support = 0;
else if (c == '1' || c == 'y' || c == 'Y')
ntlmv2_support = 1;
else if (c == '2')
ntlmv2_support = 2;
return count;
}
@ -898,7 +956,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer,
sign_CIFS_PDUs = 2;
return count;
}
} */
#endif

View file

@ -24,6 +24,10 @@
#define _H_CIFS_DEBUG
void cifs_dump_mem(char *label, void *data, int length);
#ifdef CONFIG_CIFS_DEBUG2
void cifs_dump_detail(struct smb_hdr *);
void cifs_dump_mids(struct TCP_Server_Info *);
#endif
extern int traceSMB; /* flag which enables the function below */
void dump_smb(struct smb_hdr *, int);
#define CIFS_INFO 0x01

View file

@ -22,6 +22,7 @@
#include "cifs_unicode.h"
#include "cifs_uniupr.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifs_debug.h"
/*

View file

@ -225,6 +225,8 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
user_name_len = strlen(ses->userName);
if(user_name_len > MAX_USERNAME_SIZE)
return -EINVAL;
if(ses->domainName == NULL)
return -EINVAL; /* BB should we use CIFS_LINUX_DOM */
dom_name_len = strlen(ses->domainName);
if(dom_name_len > MAX_USERNAME_SIZE)
return -EINVAL;

View file

@ -56,8 +56,8 @@ unsigned int experimEnabled = 0;
unsigned int linuxExtEnabled = 1;
unsigned int lookupCacheEnabled = 1;
unsigned int multiuser_mount = 0;
unsigned int extended_security = 0;
unsigned int ntlmv2_support = 0;
unsigned int extended_security = CIFSSEC_DEF;
/* unsigned int ntlmv2_support = 0; */
unsigned int sign_CIFS_PDUs = 1;
extern struct task_struct * oplockThread; /* remove sparse warning */
struct task_struct * oplockThread = NULL;

View file

@ -88,7 +88,8 @@ enum statusEnum {
};
enum securityEnum {
NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */
LANMAN = 0, /* Legacy LANMAN auth */
NTLM, /* Legacy NTLM012 auth with NTLM hash */
NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */
RawNTLMSSP, /* NTLMSSP without SPNEGO */
NTLMSSP, /* NTLMSSP via SPNEGO */
@ -179,7 +180,9 @@ struct cifsUidInfo {
struct cifsSesInfo {
struct list_head cifsSessionList;
struct semaphore sesSem;
#if 0
struct cifsUidInfo *uidInfo; /* pointer to user info */
#endif
struct TCP_Server_Info *server; /* pointer to server info */
atomic_t inUse; /* # of mounts (tree connections) on this ses */
enum statusEnum status;
@ -194,7 +197,7 @@ struct cifsSesInfo {
char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
TCP names - will ipv6 and sctp addresses fit? */
char userName[MAX_USERNAME_SIZE + 1];
char domainName[MAX_USERNAME_SIZE + 1];
char * domainName;
char * password;
};
/* session flags */
@ -391,9 +394,9 @@ struct mid_q_entry {
struct smb_hdr *resp_buf; /* response buffer */
int midState; /* wish this were enum but can not pass to wait_event */
__u8 command; /* smb command code */
unsigned multiPart:1; /* multiple responses to one SMB request */
unsigned largeBuf:1; /* if valid response, is pointer to large buf */
unsigned multiResp:1; /* multiple trans2 responses for one request */
unsigned multiRsp:1; /* multiple trans2 responses for one request */
unsigned multiEnd:1; /* both received */
};
struct oplock_q_entry {
@ -430,15 +433,35 @@ struct dir_notify_req {
#define CIFS_LARGE_BUFFER 2
#define CIFS_IOVEC 4 /* array of response buffers */
/* Type of session setup needed */
#define CIFS_PLAINTEXT 0
#define CIFS_LANMAN 1
#define CIFS_NTLM 2
#define CIFS_NTLMSSP_NEG 3
#define CIFS_NTLMSSP_AUTH 4
#define CIFS_SPNEGO_INIT 5
#define CIFS_SPNEGO_TARG 6
/* Security Flags: indicate type of session setup needed */
#define CIFSSEC_MAY_SIGN 0x00001
#define CIFSSEC_MAY_NTLM 0x00002
#define CIFSSEC_MAY_NTLMV2 0x00004
#define CIFSSEC_MAY_KRB5 0x00008
#ifdef CONFIG_CIFS_WEAK_PW_HASH
#define CIFSSEC_MAY_LANMAN 0x00010
#define CIFSSEC_MAY_PLNTXT 0x00020
#endif /* weak passwords */
#define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */
#define CIFSSEC_MUST_SIGN 0x01001
/* note that only one of the following can be set so the
result of setting MUST flags more than once will be to
require use of the stronger protocol */
#define CIFSSEC_MUST_NTLM 0x02002
#define CIFSSEC_MUST_NTLMV2 0x04004
#define CIFSSEC_MUST_KRB5 0x08008
#ifdef CONFIG_CIFS_WEAK_PW_HASH
#define CIFSSEC_MUST_LANMAN 0x10010
#define CIFSSEC_MUST_PLNTXT 0x20020
#define CIFSSEC_MASK 0x37037 /* current flags supported if weak */
#else
#define CIFSSEC_MASK 0x07007 /* flags supported if no weak config */
#endif /* WEAK_PW_HASH */
#define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */
#define CIFSSEC_DEF CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2
#define CIFSSEC_MAX CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2
/*
*****************************************************************
* All constants go here
@ -540,8 +563,8 @@ GLOBAL_EXTERN unsigned int experimEnabled;
GLOBAL_EXTERN unsigned int lookupCacheEnabled;
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */
GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */
GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
GLOBAL_EXTERN unsigned int secFlags;
GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */
GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */

View file

@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CIFSPDU_H
@ -24,8 +24,14 @@
#include <net/sock.h>
#ifdef CONFIG_CIFS_WEAK_PW_HASH
#define LANMAN_PROT 0
#define CIFS_PROT 1
#else
#define CIFS_PROT 0
#define BAD_PROT CIFS_PROT+1
#endif
#define POSIX_PROT CIFS_PROT+1
#define BAD_PROT 0xFFFF
/* SMB command codes */
/* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
@ -400,6 +406,25 @@ typedef struct negotiate_req {
unsigned char DialectsArray[1];
} __attribute__((packed)) NEGOTIATE_REQ;
/* Dialect index is 13 for LANMAN */
typedef struct lanman_neg_rsp {
struct smb_hdr hdr; /* wct = 13 */
__le16 DialectIndex;
__le16 SecurityMode;
__le16 MaxBufSize;
__le16 MaxMpxCount;
__le16 MaxNumberVcs;
__le16 RawMode;
__le32 SessionKey;
__le32 ServerTime;
__le16 ServerTimeZone;
__le16 EncryptionKeyLength;
__le16 Reserved;
__u16 ByteCount;
unsigned char EncryptionKey[1];
} __attribute__((packed)) LANMAN_NEG_RSP;
typedef struct negotiate_rsp {
struct smb_hdr hdr; /* wct = 17 */
__le16 DialectIndex;
@ -520,8 +545,8 @@ typedef union smb_com_session_setup_andx {
__le16 MaxMpxCount;
__le16 VcNumber;
__u32 SessionKey;
__le16 PassswordLength;
__u32 Reserved;
__le16 PasswordLength;
__u32 Reserved; /* encrypt key len and offset */
__le16 ByteCount;
unsigned char AccountPassword[1]; /* followed by */
/* STRING AccountName */
@ -1844,13 +1869,13 @@ typedef struct {
typedef struct {
__le32 DeviceType;
__le32 DeviceCharacteristics;
} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */
} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
typedef struct {
__le32 Attributes;
__le32 MaxPathNameComponentLength;
__le32 FileSystemNameLen;
char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */
char FileSystemName[52]; /* do not have to save this - get subset? */
} __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO;
/******************************************************************************/

View file

@ -69,7 +69,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
struct cifsSesInfo *ses,
void ** request_buf);
extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
const int stage, int * pNTLMv2_flg,
const int stage,
const struct nls_table *nls_cp);
#endif
extern __u16 GetNextMid(struct TCP_Server_Info *server);

View file

@ -44,8 +44,11 @@ static struct {
int index;
char *name;
} protocols[] = {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
{LANMAN_PROT, "\2LM1.2X002"},
#endif /* weak password hashing for legacy clients */
{CIFS_PROT, "\2NT LM 0.12"},
{CIFS_PROT, "\2POSIX 2"},
{POSIX_PROT, "\2POSIX 2"},
{BAD_PROT, "\2"}
};
#else
@ -53,11 +56,29 @@ static struct {
int index;
char *name;
} protocols[] = {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
{LANMAN_PROT, "\2LM1.2X002"},
#endif /* weak password hashing for legacy clients */
{CIFS_PROT, "\2NT LM 0.12"},
{BAD_PROT, "\2"}
};
#endif
/* define the number of elements in the cifs dialect array */
#ifdef CONFIG_CIFS_POSIX
#ifdef CONFIG_CIFS_WEAK_PW_HASH
#define CIFS_NUM_PROT 3
#else
#define CIFS_NUM_PROT 2
#endif /* CIFS_WEAK_PW_HASH */
#else /* not posix */
#ifdef CONFIG_CIFS_WEAK_PW_HASH
#define CIFS_NUM_PROT 2
#else
#define CIFS_NUM_PROT 1
#endif /* CONFIG_CIFS_WEAK_PW_HASH */
#endif /* CIFS_POSIX */
/* Mark as invalid, all open files on tree connections since they
were closed when session to server was lost */
@ -322,7 +343,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* potential retries of smb operations it turns out we can determine */
/* from the mid flags when the request buffer can be resent without */
/* having to use a second distinct buffer for the response */
*response_buf = *request_buf;
if(response_buf)
*response_buf = *request_buf;
header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
wct /*wct */ );
@ -373,6 +395,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
NEGOTIATE_RSP *pSMBr;
int rc = 0;
int bytes_returned;
int i;
struct TCP_Server_Info * server;
u16 count;
@ -388,19 +411,71 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
return rc;
pSMB->hdr.Mid = GetNextMid(server);
pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
if (extended_security)
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
count = strlen(protocols[0].name) + 1;
strncpy(pSMB->DialectsArray, protocols[0].name, 30);
/* null guaranteed to be at end of source and target buffers anyway */
/* if (extended_security)
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/
count = 0;
for(i=0;i<CIFS_NUM_PROT;i++) {
strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
count += strlen(protocols[i].name) + 1;
/* null at end of source and target buffers anyway */
}
pSMB->hdr.smb_buf_length += count;
pSMB->ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc == 0) {
cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
/* Check wct = 1 error case */
if((pSMBr->hdr.WordCount < 13)
|| (pSMBr->DialectIndex == BAD_PROT)) {
/* core returns wct = 1, but we do not ask for
core - otherwise it just comes when dialect
index is -1 indicating we could not negotiate
a common dialect */
rc = -EOPNOTSUPP;
goto neg_err_exit;
} else if((pSMBr->hdr.WordCount == 13) &&
(pSMBr->DialectIndex == LANMAN_PROT)) {
struct lanman_neg_rsp * rsp =
(struct lanman_neg_rsp *)pSMBr;
/* BB Mark ses struct as negotiated lanman level BB */
server->secType = LANMAN;
server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
/* BB what do we do with raw mode? BB */
server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
/* Do we have to set signing flags? no signing
was available LANMAN - default should be ok */
/* BB FIXME set default dummy capabilities since
they are not returned by the server in this dialect */
/* get server time for time conversions and add
code to use it and timezone since this is not UTC */
if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
memcpy(server->cryptKey, rsp->EncryptionKey,
CIFS_CRYPTO_KEY_SIZE);
} else {
rc = -EIO;
goto neg_err_exit;
}
cFYI(1,("LANMAN negotiated")); /* BB removeme BB */
goto neg_err_exit;
} else if(pSMBr->hdr.WordCount != 17) {
/* unknown wct */
rc = -EOPNOTSUPP;
goto neg_err_exit;
}
server->secMode = pSMBr->SecurityMode;
if((server->secMode & SECMODE_USER) == 0)
cFYI(1,("share mode security"));
@ -479,7 +554,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
}
}
neg_err_exit:
cifs_buf_release(pSMB);
return rc;
}

View file

@ -49,8 +49,6 @@
static DECLARE_COMPLETION(cifsd_complete);
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
@ -585,9 +583,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
/* 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 {
@ -632,9 +632,14 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
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!"));
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 */
@ -976,7 +981,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
}
/* 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 {
@ -1762,9 +1767,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
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;
down(&pSesInfo->sesSem);
rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
@ -2054,7 +2064,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr++;
}
if(user == NULL)
bytes_returned = 0; /* skill null user */
bytes_returned = 0; /* skip null user */
else
bytes_returned =
cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
@ -2635,8 +2645,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
/* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
if(sign_CIFS_PDUs)
negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
if(ntlmv2_support)
negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
/* if(ntlmv2_support)
negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
/* setup pointers to domain name and workstation name */
bcc_ptr += SecurityBlobLength;
@ -3429,7 +3439,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
}
/* else do not bother copying these informational fields */
}
tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
if(smb_buffer_response->WordCount == 3)
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 */
@ -3528,8 +3541,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
pSesInfo->server->timeZone));
#ifdef CONFIG_CIFS_EXPERIMENTAL
if(experimEnabled > 1)
rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */,
&ntlmv2_flag, nls_info);
rc = CIFS_SessSetup(xid, pSesInfo,
first_time, nls_info);
else
#endif
if (extended_security

View file

@ -113,7 +113,7 @@ build_path_from_dentry(struct dentry *direntry)
full_path[namelen+2] = 0;
BB remove above eight lines BB */
/* Inode operations in similar order to how they appear in the Linux file fs.h */
/* Inode operations in similar order to how they appear in Linux file fs.h */
int
cifs_create(struct inode *inode, struct dentry *direntry, int mode,

View file

@ -91,14 +91,14 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
if(full_path == NULL) {
rc = -ENOMEM;
} else {
cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */
cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg));
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
&netfid, &oplock,NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
/* BB fixme - add this handle to a notify handle list */
if(rc) {
cERROR(1,("Could not open directory for notify")); /* BB remove BB */
cFYI(1,("Could not open directory for notify"));
} else {
filter = convert_to_cifs_notify_flags(arg);
if(filter != 0) {

View file

@ -1121,7 +1121,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
xid = GetXid();
cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x",
cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
direntry->d_name.name, attrs->ia_valid));
cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
@ -1157,6 +1157,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
when the local oplock break takes longer to flush
writebehind data than the SMB timeout for the SetPathInfo
request would allow */
open_file = find_writable_file(cifsInode);
if (open_file) {
__u16 nfid = open_file->netfid;

View file

@ -101,6 +101,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
kfree(buf_to_free->serverDomain);
kfree(buf_to_free->serverNOS);
kfree(buf_to_free->password);
kfree(buf_to_free->domainName);
kfree(buf_to_free);
}
@ -499,11 +500,12 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
data_offset = le32_to_cpu(pSMBr->DataOffset);
pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol
+ data_offset);
cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName,
pnotify = (struct file_notify_information *)
((char *)&pSMBr->hdr.Protocol + data_offset);
cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName,
pnotify->Action)); /* BB removeme BB */
/* cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */
/* cifs_dump_mem("Rcvd notify Data: ",buf,
sizeof(struct smb_hdr)+60); */
return TRUE;
}
if(pSMBr->hdr.Status.CifsError) {

View file

@ -31,8 +31,8 @@
#include "cifs_fs_sb.h"
#include "cifsfs.h"
/* BB fixme - add debug wrappers around this function to disable it fixme BB */
/* static void dump_cifs_file_struct(struct file *file, char *label)
#ifdef CONFIG_CIFS_DEBUG2
static void dump_cifs_file_struct(struct file *file, char *label)
{
struct cifsFileInfo * cf;
@ -53,7 +53,8 @@
}
}
} */
}
#endif /* DEBUG2 */
/* Returns one if new inode created (which therefore needs to be hashed) */
/* Might check in the future if inode number changed so we can rehash inode */
@ -597,7 +598,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
. and .. for the root of a drive and for those we need
to start two entries earlier */
/* dump_cifs_file_struct(file, "In fce ");*/
#ifdef CONFIG_CIFS_DEBUG2
dump_cifs_file_struct(file, "In fce ");
#endif
if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
is_dir_changed(file)) ||
(index_to_find < first_entry_in_buffer)) {
@ -980,9 +983,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
rc = cifs_filldir(current_entry, file,
filldir, direntry,tmp_buf);
file->f_pos++;
if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) {
if(file->f_pos ==
cifsFile->srch_inf.index_of_last_entry) {
cFYI(1,("last entry in buf at pos %lld %s",
file->f_pos,tmp_buf)); /* BB removeme BB */
file->f_pos,tmp_buf));
cifs_save_resume_key(current_entry,cifsFile);
break;
} else

511
fs/cifs/sess.c Normal file
View file

@ -0,0 +1,511 @@
/*
* fs/cifs/sess.c
*
* SMB/CIFS session setup handling routines
*
* Copyright (c) International Business Machines Corp., 2006
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "ntlmssp.h"
#include "nterr.h"
#include <linux/ctype.h>
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
#ifdef CONFIG_CIFS_EXPERIMENTAL
static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
{
__u32 capabilities = 0;
/* init fields common to all four types of SessSetup */
/* note that header is initialized to zero in header_assemble */
pSMB->req.AndXCommand = 0xFF;
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
/* BB verify whether signing required on neg or just on auth frame
(and NTLM case) */
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
if (ses->capabilities & CAP_UNICODE) {
pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
capabilities |= CAP_UNICODE;
}
if (ses->capabilities & CAP_STATUS32) {
pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
capabilities |= CAP_STATUS32;
}
if (ses->capabilities & CAP_DFS) {
pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
capabilities |= CAP_DFS;
}
if (ses->capabilities & CAP_UNIX) {
capabilities |= CAP_UNIX;
}
/* BB check whether to init vcnum BB */
return capabilities;
}
void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
const struct nls_table * nls_cp)
{
char * bcc_ptr = *pbcc_area;
int bytes_ret = 0;
/* BB FIXME add check that strings total less
than 335 or will need to send them as arrays */
/* align unicode strings, must be word aligned */
if ((long) bcc_ptr % 2) {
*bcc_ptr = 0;
bcc_ptr++;
}
/* copy user */
if(ses->userName == NULL) {
/* BB what about null user mounts - check that we do this BB */
} else { /* 300 should be long enough for any conceivable user name */
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName,
300, nls_cp);
}
bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* account for null termination */
/* copy domain */
if(ses->domainName == NULL)
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr,
"CIFS_LINUX_DOM", 32, nls_cp);
else
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName,
256, nls_cp);
bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* account for null terminator */
/* Copy OS version */
bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
nls_cp);
bcc_ptr += 2 * bytes_ret;
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
32, nls_cp);
bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* trailing null */
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
32, nls_cp);
bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* trailing null */
*pbcc_area = bcc_ptr;
}
void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
const struct nls_table * nls_cp)
{
char * bcc_ptr = *pbcc_area;
/* copy user */
/* BB what about null user mounts - check that we do this BB */
/* copy user */
if(ses->userName == NULL) {
/* BB what about null user mounts - check that we do this BB */
} else { /* 300 should be long enough for any conceivable user name */
strncpy(bcc_ptr, ses->userName, 300);
}
/* BB improve check for overflow */
bcc_ptr += strnlen(ses->userName, 200);
*bcc_ptr = 0;
bcc_ptr++; /* account for null termination */
/* copy domain */
if(ses->domainName == NULL) {
strcpy(bcc_ptr, "CIFS_LINUX_DOM");
bcc_ptr += 14; /* strlen(CIFS_LINUX_DOM) */
} else {
strncpy(bcc_ptr, ses->domainName, 256);
bcc_ptr += strnlen(ses->domainName, 256);
}
*bcc_ptr = 0;
bcc_ptr++;
/* BB check for overflow here */
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
strcpy(bcc_ptr, system_utsname.release);
bcc_ptr += strlen(system_utsname.release) + 1;
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
*pbcc_area = bcc_ptr;
}
int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
const struct nls_table * nls_cp)
{
int rc = 0;
int words_left, len;
char * data = *pbcc_area;
cFYI(1,("bleft %d",bleft));
/* word align, if bytes remaining is not even */
if(bleft % 2) {
bleft--;
data++;
}
words_left = bleft / 2;
/* save off server operating system */
len = UniStrnlen((wchar_t *) data, words_left);
/* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
if(len >= words_left)
return rc;
if(ses->serverOS)
kfree(ses->serverOS);
/* UTF-8 string will not grow more than four times as big as UCS-16 */
ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
if(ses->serverOS != NULL) {
cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len,
nls_cp);
}
data += 2 * (len + 1);
words_left -= len + 1;
/* save off server network operating system */
len = UniStrnlen((wchar_t *) data, words_left);
if(len >= words_left)
return rc;
if(ses->serverNOS)
kfree(ses->serverNOS);
ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
if(ses->serverNOS != NULL) {
cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
nls_cp);
if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) {
cFYI(1,("NT4 server"));
ses->flags |= CIFS_SES_NT4;
}
}
data += 2 * (len + 1);
words_left -= len + 1;
/* save off server domain */
len = UniStrnlen((wchar_t *) data, words_left);
if(len > words_left)
return rc;
if(ses->serverDomain)
kfree(ses->serverDomain);
ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
if(ses->serverDomain != NULL) {
cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
nls_cp);
ses->serverDomain[2*len] = 0;
ses->serverDomain[(2*len) + 1] = 0;
}
data += 2 * (len + 1);
words_left -= len + 1;
cFYI(1,("words left: %d",words_left));
return rc;
}
int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
const struct nls_table * nls_cp)
{
int rc = 0;
int len;
char * bcc_ptr = *pbcc_area;
cFYI(1,("decode sessetup ascii. bleft %d", bleft));
len = strnlen(bcc_ptr, bleft);
if(len >= bleft)
return rc;
if(ses->serverOS)
kfree(ses->serverOS);
ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
if(ses->serverOS)
strncpy(ses->serverOS, bcc_ptr, len);
bcc_ptr += len + 1;
bleft -= len + 1;
len = strnlen(bcc_ptr, bleft);
if(len >= bleft)
return rc;
if(ses->serverNOS)
kfree(ses->serverNOS);
ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
if(ses->serverNOS)
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len + 1;
bleft -= len + 1;
len = strnlen(bcc_ptr, bleft);
if(len > bleft)
return rc;
if(ses->serverDomain)
kfree(ses->serverDomain);
ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
if(ses->serverOS)
strncpy(ses->serverOS, bcc_ptr, len);
bcc_ptr += len + 1;
bleft -= len + 1;
cFYI(1,("ascii: bytes left %d",bleft));
return rc;
}
int
CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
const struct nls_table *nls_cp)
{
int rc = 0;
int wct;
int i;
struct smb_hdr *smb_buf;
char *bcc_ptr;
SESSION_SETUP_ANDX *pSMB;
__u32 capabilities;
int count;
int resp_buf_type = 0;
struct kvec iov[1];
enum securityEnum type;
__u16 action;
int bytes_remaining;
if(ses == NULL)
return -EINVAL;
type = ses->server->secType;
if(type == LANMAN) {
#ifndef CONFIG_CIFS_WEAK_PW_HASH
/* LANMAN and plaintext are less secure and off by default.
So we make this explicitly be turned on in kconfig (in the
build) and turned on at runtime (changed from the default)
in proc/fs/cifs or via mount parm. Unfortunately this is
needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
return -EOPNOTSUPP;
#endif
wct = 10; /* lanman 2 style sessionsetup */
} else if(type == NTLM) /* NTLMv2 may retry NTLM */
wct = 13; /* old style NTLM sessionsetup */
else /* same size for negotiate or auth, NTLMSSP or extended security */
wct = 12;
rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
(void **)&smb_buf);
if(rc)
return rc;
pSMB = (SESSION_SETUP_ANDX *)smb_buf;
capabilities = cifs_ssetup_hdr(ses, pSMB);
bcc_ptr = pByteArea(smb_buf);
if(type == LANMAN) {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
char lnm_session_key[CIFS_SESSION_KEY_SIZE];
char password_with_pad[CIFS_ENCPWD_SIZE];
/* no capabilities flags in old lanman negotiation */
pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE;
/* BB calculate hash with password */
/* and copy into bcc */
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
/* calculate old style session key */
/* toupper may be less broken then repeatedly calling
nls_toupper would be, but neither handles multibyte code pages
but the only alternative would be converting to UCS-16 (Unicode)
uppercasing and converting back which is only worth doing if
we knew it were utf8. utf8 code page needs its own
toupper and tolower and strnicmp functions */
for(i = 0; i< CIFS_ENCPWD_SIZE; i++) {
password_with_pad[i] = toupper(password_with_pad[i]);
}
SMBencrypt(password_with_pad, ses->server->cryptKey,
lnm_session_key);
#ifdef CONFIG_CIFS_DEBUG2
cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
CIFS_SESSION_KEY_SIZE);
#endif
/* clear password before we return/free memory */
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE;
/* can not sign if LANMAN negotiated so no need
to calculate signing key? but what if server
changed to do higher than lanman dialect and
we reconnected would we ever calc signing_key? */
cERROR(1,("Negotiating LANMAN setting up strings"));
/* Unicode not allowed for LANMAN dialects */
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
#endif
} else if (type == NTLM) {
char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
pSMB->req_no_secext.CaseInsensitivePasswordLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
pSMB->req_no_secext.CaseSensitivePasswordLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
/* calculate session key */
SMBNTencrypt(ses->password, ses->server->cryptKey,
ntlm_session_key);
if(first_time) /* should this be moved into common code
with similar ntlmv2 path? */
cifs_calculate_mac_key(
ses->server->mac_signing_key,
ntlm_session_key, ses->password);
/* copy session key */
memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE;
memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE;
if(ses->capabilities & CAP_UNICODE)
unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
else
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
} else /* NTLMSSP or SPNEGO */ {
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
capabilities |= CAP_EXTENDED_SECURITY;
pSMB->req.Capabilities = cpu_to_le32(capabilities);
/* BB set password lengths */
}
count = (long) bcc_ptr - (long) pByteArea(smb_buf);
smb_buf->smb_buf_length += count;
/* if we switch to small buffers, count will need to be fewer
than 383 (strings less than 335 bytes) */
BCC_LE(smb_buf) = cpu_to_le16(count);
/* BB FIXME check for other non ntlm code paths */
/* BB check is this too big for a small smb? */
iov[0].iov_base = (char *)pSMB;
iov[0].iov_len = smb_buf->smb_buf_length + 4;
rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0);
/* SMB request buf freed in SendReceive2 */
cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
if(rc)
goto ssetup_exit;
pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
smb_buf = (struct smb_hdr *)iov[0].iov_base;
if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
rc = -EIO;
cERROR(1,("bad word count %d", smb_buf->WordCount));
goto ssetup_exit;
}
action = le16_to_cpu(pSMB->resp.Action);
if (action & GUEST_LOGIN)
cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
cFYI(1, ("UID = %d ", ses->Suid));
/* response can have either 3 or 4 word count - Samba sends 3 */
/* and lanman response is 3 */
bytes_remaining = BCC(smb_buf);
bcc_ptr = pByteArea(smb_buf);
if(smb_buf->WordCount == 4) {
__u16 blob_len;
blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
bcc_ptr += blob_len;
if(blob_len > bytes_remaining) {
cERROR(1,("bad security blob length %d", blob_len));
rc = -EINVAL;
goto ssetup_exit;
}
bytes_remaining -= blob_len;
}
/* BB check if Unicode and decode strings */
if(smb_buf->Flags2 & SMBFLG2_UNICODE)
rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
ses, nls_cp);
else
rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
ssetup_exit:
if(resp_buf_type == CIFS_SMALL_BUFFER) {
cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
cifs_small_buf_release(iov[0].iov_base);
} else if(resp_buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(iov[0].iov_base);
return rc;
}
#endif /* CONFIG_CIFS_EXPERIMENTAL */

View file

@ -30,6 +30,7 @@
#include <linux/random.h>
#include "cifs_unicode.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "md5.h"
#include "cifs_debug.h"
#include "cifsencrypt.h"