mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (25 commits) [CIFS] Fix authentication choice so we do not force NTLMv2 unless the [CIFS] Fix alignment of unicode strings in previous patch [CIFS] Fix allocation of buffers for new session setup routine to allow [CIFS] Remove calls to to take f_owner.lock [CIFS] remove some redundant null pointer checks [CIFS] Fix compile warning when CONFIG_CIFS_EXPERIMENTAL is off [CIFS] Enable sec flags on mount for cifs (part one) [CIFS] Fix suspend/resume problem which causes EIO on subsequent access to [CIFS] fix minor compile warning when config_cifs_weak_security is off [CIFS] NTLMv2 support part 5 [CIFS] Add support for readdir to legacy servers [CIFS] NTLMv2 support part 4 [CIFS] NTLMv2 support part 3 [CIFS] NTLMv2 support part 2 [CIFS] Fix mask so can set new cifs security flags properly CIFS] Support for older servers which require plaintext passwords - part 2 [CIFS] Support for older servers which require plaintext passwords [CIFS] Fix mapping of old SMB return code Invalid Net Name so it is [CIFS] Missing brace [CIFS] Do not overwrite aops ...
This commit is contained in:
commit
f17a2686b1
28 changed files with 1544 additions and 826 deletions
40
fs/Kconfig
40
fs/Kconfig
|
@ -1722,7 +1722,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
|
||||
|
@ -1735,6 +1735,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
|
||||
|
@ -1763,6 +1789,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
|
||||
|
@ -1778,7 +1814,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
|
||||
|
|
|
@ -1,9 +1,24 @@
|
|||
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.
|
||||
Fix oops on ls to OS/2 servers. Add support for level 1 FindFirst
|
||||
so we can do search (ls etc.) to OS/2. Do not send NTCreateX
|
||||
or recent levels of FindFirst unless server says it supports NT SMBs
|
||||
(instead use legacy equivalents from LANMAN dialect). Fix to allow
|
||||
NTLMv2 authentication support (now can use stronger password hashing
|
||||
on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004).
|
||||
Allow override of global cifs security flags on mount via "sec=" option(s).
|
||||
|
||||
Version 1.43
|
||||
------------
|
||||
POSIX locking to servers which support CIFS POSIX Extensions
|
||||
(disabled by default controlled by proc/fs/cifs/Experimental).
|
||||
Handle conversion of long share names (especially Asian languages)
|
||||
to Unicode during mount.
|
||||
to Unicode during mount. Fix memory leak in sess struct on reconnect.
|
||||
Fix rare oops after acpi suspend. Fix O_TRUNC opens to overwrite on
|
||||
cifs open which helps rare case when setpathinfo fails or server does
|
||||
not support it.
|
||||
|
||||
Version 1.42
|
||||
------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -443,7 +443,10 @@ A partial list of the supported mount options follows:
|
|||
SFU does). In the future the bottom 9 bits of the mode
|
||||
mode also will be emulated using queries of the security
|
||||
descriptor (ACL).
|
||||
sec Security mode. Allowed values are:
|
||||
sign Must use packet signing (helps avoid unwanted data modification
|
||||
by intermediate systems in the route). Note that signing
|
||||
does not work with lanman or plaintext authentication.
|
||||
sec Security mode. Allowed values are:
|
||||
none attempt to connection as a null user (no name)
|
||||
krb5 Use Kerberos version 5 authentication
|
||||
krb5i Use Kerberos authentication and packet signing
|
||||
|
@ -453,6 +456,8 @@ sec Security mode. Allowed values are:
|
|||
server requires signing also can be the default)
|
||||
ntlmv2 Use NTLMv2 password hashing
|
||||
ntlmv2i Use NTLMv2 password hashing with packet signing
|
||||
lanman (if configured in kernel config) use older
|
||||
lanman hash
|
||||
|
||||
The mount.cifs mount helper also accepts a few mount options before -o
|
||||
including:
|
||||
|
@ -485,14 +490,34 @@ PacketSigningEnabled If set to one, cifs packet signing is enabled
|
|||
it. If set to two, cifs packet signing is
|
||||
required even if the server considers packet
|
||||
signing optional. (default 1)
|
||||
SecurityFlags Flags which control security negotiation and
|
||||
also packet signing. Authentication (may/must)
|
||||
flags (e.g. for NTLM and/or NTLMv2) may be combined with
|
||||
the signing flags. Specifying two different password
|
||||
hashing mechanisms (as "must use") on the other hand
|
||||
does not make much sense. Default flags are
|
||||
0x07007
|
||||
(NTLM, NTLMv2 and packet signing allowed). Maximum
|
||||
allowable flags if you want to allow mounts to servers
|
||||
using weaker password hashes is 0x37037 (lanman,
|
||||
plaintext, ntlm, ntlmv2, signing allowed):
|
||||
|
||||
may use packet signing 0x00001
|
||||
must use packet signing 0x01001
|
||||
may use NTLM (most common password hash) 0x00002
|
||||
must use NTLM 0x02002
|
||||
may use NTLMv2 0x00004
|
||||
must use NTLMv2 0x04004
|
||||
may use Kerberos security (not implemented yet) 0x00008
|
||||
must use Kerberos (not implemented yet) 0x08008
|
||||
may use lanman (weak) password hash 0x00010
|
||||
must use lanman password hash 0x10010
|
||||
may use plaintext passwords 0x00020
|
||||
must use plaintext passwords 0x20020
|
||||
(reserved for future packet encryption) 0x00040
|
||||
|
||||
cifsFYI If set to one, additional debug information is
|
||||
logged to the system error log. (default 0)
|
||||
ExtendedSecurity If set to one, SPNEGO session establishment
|
||||
is allowed which enables more advanced
|
||||
secure CIFS session establishment (default 0)
|
||||
NTLMV2Enabled If set to one, more secure password hashes
|
||||
are used when the server supports them and
|
||||
when kerberos is not negotiated (default 0)
|
||||
traceSMB If set to one, debug information is logged to the
|
||||
system error log with the start of smb requests
|
||||
and responses (default 0)
|
||||
|
|
|
@ -467,7 +467,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|
|||
asn1_open(&ctx, security_blob, length);
|
||||
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding negTokenInit header "));
|
||||
cFYI(1, ("Error decoding negTokenInit header"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_APL) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_EOC)) {
|
||||
|
@ -495,7 +495,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|
|||
}
|
||||
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding negTokenInit "));
|
||||
cFYI(1, ("Error decoding negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_EOC)) {
|
||||
|
@ -505,7 +505,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|
|||
}
|
||||
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding negTokenInit "));
|
||||
cFYI(1, ("Error decoding negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_SEQ)) {
|
||||
|
@ -515,7 +515,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|
|||
}
|
||||
|
||||
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding 2nd part of negTokenInit "));
|
||||
cFYI(1, ("Error decoding 2nd part of negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_EOC)) {
|
||||
|
@ -527,7 +527,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
|
|||
|
||||
if (asn1_header_decode
|
||||
(&ctx, &sequence_end, &cls, &con, &tag) == 0) {
|
||||
cFYI(1, ("Error decoding 2nd part of negTokenInit "));
|
||||
cFYI(1, ("Error decoding 2nd part of negTokenInit"));
|
||||
return 0;
|
||||
} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|
||||
|| (tag != ASN1_SEQ)) {
|
||||
|
|
|
@ -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"
|
||||
|
@ -395,12 +445,12 @@ static read_proc_t traceSMB_read;
|
|||
static write_proc_t traceSMB_write;
|
||||
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 security_flags_read;
|
||||
static write_proc_t security_flags_write;
|
||||
/* 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;
|
||||
|
@ -458,10 +508,10 @@ cifs_proc_init(void)
|
|||
pde->write_proc = multiuser_mount_write;
|
||||
|
||||
pde =
|
||||
create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs,
|
||||
extended_security_read, NULL);
|
||||
create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs,
|
||||
security_flags_read, NULL);
|
||||
if (pde)
|
||||
pde->write_proc = extended_security_write;
|
||||
pde->write_proc = security_flags_write;
|
||||
|
||||
pde =
|
||||
create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs,
|
||||
|
@ -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("ExtendedSecurity",proc_fs_cifs);
|
||||
remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
|
||||
/* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
|
||||
remove_proc_entry("SecurityFlags",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);
|
||||
|
@ -782,12 +832,12 @@ multiuser_mount_write(struct file *file, const char __user *buffer,
|
|||
}
|
||||
|
||||
static int
|
||||
extended_security_read(char *page, char **start, off_t off,
|
||||
security_flags_read(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = sprintf(page, "%d\n", extended_security);
|
||||
len = sprintf(page, "0x%x\n", extended_security);
|
||||
|
||||
len -= off;
|
||||
*start = page + off;
|
||||
|
@ -803,24 +853,52 @@ extended_security_read(char *page, char **start, off_t off,
|
|||
return len;
|
||||
}
|
||||
static int
|
||||
extended_security_write(struct file *file, const char __user *buffer,
|
||||
security_flags_write(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
unsigned int flags;
|
||||
char flags_string[12];
|
||||
char c;
|
||||
int rc;
|
||||
|
||||
rc = get_user(c, buffer);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (c == '0' || c == 'n' || c == 'N')
|
||||
extended_security = 0;
|
||||
else if (c == '1' || c == 'y' || c == 'Y')
|
||||
extended_security = 1;
|
||||
if((count < 1) || (count > 11))
|
||||
return -EINVAL;
|
||||
|
||||
memset(flags_string, 0, 12);
|
||||
|
||||
if(copy_from_user(flags_string, buffer, count))
|
||||
return -EFAULT;
|
||||
|
||||
if(count < 3) {
|
||||
/* single char or single char followed by null */
|
||||
c = flags_string[0];
|
||||
if (c == '0' || c == 'n' || c == 'N')
|
||||
extended_security = CIFSSEC_DEF; /* default */
|
||||
else if (c == '1' || c == 'y' || c == 'Y')
|
||||
extended_security = CIFSSEC_MAX;
|
||||
return count;
|
||||
}
|
||||
/* else we have a number */
|
||||
|
||||
flags = simple_strtoul(flags_string, NULL, 0);
|
||||
|
||||
cFYI(1,("sec flags 0x%x", flags));
|
||||
|
||||
if(flags <= 0) {
|
||||
cERROR(1,("invalid security flags %s",flags_string));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(flags & ~CIFSSEC_MASK) {
|
||||
cERROR(1,("attempt to set unsupported security flags 0x%x",
|
||||
flags & ~CIFSSEC_MASK));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* flags look ok - update the global security flags for cifs module */
|
||||
extended_security = flags;
|
||||
return count;
|
||||
}
|
||||
|
||||
static int
|
||||
/* static int
|
||||
ntlmv2_enabled_read(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
|
@ -855,6 +933,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 +978,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer,
|
|||
sign_CIFS_PDUs = 2;
|
||||
|
||||
return count;
|
||||
}
|
||||
} */
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "cifs_unicode.h"
|
||||
#include "cifs_uniupr.h"
|
||||
#include "cifspdu.h"
|
||||
#include "cifsglob.h"
|
||||
#include "cifs_debug.h"
|
||||
|
||||
/*
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "md5.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "cifsproto.h"
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
/* Calculate and return the CIFS signature based on the mac key and the smb pdu */
|
||||
/* the 16 byte signature must be allocated by the caller */
|
||||
|
@ -35,6 +37,8 @@
|
|||
|
||||
extern void mdfour(unsigned char *out, unsigned char *in, int n);
|
||||
extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
|
||||
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu,
|
||||
const char * key, char * signature)
|
||||
|
@ -45,7 +49,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu,
|
|||
return -EINVAL;
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
|
||||
MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
|
||||
MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
|
||||
MD5Final(signature,&context);
|
||||
return 0;
|
||||
|
@ -90,7 +94,7 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
|
|||
return -EINVAL;
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
|
||||
MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
|
||||
for(i=0;i<n_vec;i++) {
|
||||
if(iov[i].iov_base == NULL) {
|
||||
cERROR(1,("null iovec entry"));
|
||||
|
@ -204,11 +208,12 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
|
|||
|
||||
E_md4hash(password, temp_key);
|
||||
mdfour(key,temp_key,16);
|
||||
memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE);
|
||||
memcpy(key+16,rn, CIFS_SESS_KEY_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info)
|
||||
int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses,
|
||||
const struct nls_table * nls_info)
|
||||
{
|
||||
char temp_hash[16];
|
||||
struct HMACMD5Context ctx;
|
||||
|
@ -225,6 +230,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;
|
||||
|
@ -259,16 +266,131 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
|
|||
kfree(unicode_buf);
|
||||
return 0;
|
||||
}
|
||||
void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response)
|
||||
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
|
||||
{
|
||||
int i;
|
||||
char password_with_pad[CIFS_ENCPWD_SIZE];
|
||||
|
||||
if(ses->server == NULL)
|
||||
return;
|
||||
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
|
||||
|
||||
if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
|
||||
if(extended_security & CIFSSEC_MAY_PLNTXT) {
|
||||
memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* calculate old style session key */
|
||||
/* calling toupper is less broken than repeatedly
|
||||
calling nls_toupper would be since that will never
|
||||
work for UTF8, but neither handles multibyte code pages
|
||||
but the only alternative would be converting to UCS-16 (Unicode)
|
||||
(using a routine something like UniStrupr) then
|
||||
uppercasing and then converting back from Unicode - which
|
||||
would only worth doing it if we knew it were utf8. Basically
|
||||
utf8 and other multibyte codepages each need their own strupper
|
||||
function since a byte at a time will ont work. */
|
||||
|
||||
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);
|
||||
/* clear password before we return/free memory */
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
}
|
||||
#endif /* CIFS_WEAK_PW_HASH */
|
||||
|
||||
static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
|
||||
const struct nls_table * nls_cp)
|
||||
{
|
||||
int rc = 0;
|
||||
int len;
|
||||
char nt_hash[16];
|
||||
struct HMACMD5Context * pctxt;
|
||||
wchar_t * user;
|
||||
wchar_t * domain;
|
||||
|
||||
pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);
|
||||
|
||||
if(pctxt == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* calculate md4 hash of password */
|
||||
E_md4hash(ses->password, nt_hash);
|
||||
|
||||
/* convert Domainname to unicode and uppercase */
|
||||
hmac_md5_init_limK_to_64(nt_hash, 16, pctxt);
|
||||
|
||||
/* convert ses->userName to unicode and uppercase */
|
||||
len = strlen(ses->userName);
|
||||
user = kmalloc(2 + (len * 2), GFP_KERNEL);
|
||||
if(user == NULL)
|
||||
goto calc_exit_2;
|
||||
len = cifs_strtoUCS(user, ses->userName, len, nls_cp);
|
||||
UniStrupr(user);
|
||||
hmac_md5_update((char *)user, 2*len, pctxt);
|
||||
|
||||
/* convert ses->domainName to unicode and uppercase */
|
||||
if(ses->domainName) {
|
||||
len = strlen(ses->domainName);
|
||||
|
||||
domain = kmalloc(2 + (len * 2), GFP_KERNEL);
|
||||
if(domain == NULL)
|
||||
goto calc_exit_1;
|
||||
len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp);
|
||||
UniStrupr(domain);
|
||||
|
||||
hmac_md5_update((char *)domain, 2*len, pctxt);
|
||||
|
||||
kfree(domain);
|
||||
}
|
||||
calc_exit_1:
|
||||
kfree(user);
|
||||
calc_exit_2:
|
||||
/* BB FIXME what about bytes 24 through 40 of the signing key?
|
||||
compare with the NTLM example */
|
||||
hmac_md5_final(ses->server->mac_signing_key, pctxt);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf,
|
||||
const struct nls_table * nls_cp)
|
||||
{
|
||||
int rc;
|
||||
struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf;
|
||||
|
||||
buf->blob_signature = cpu_to_le32(0x00000101);
|
||||
buf->reserved = 0;
|
||||
buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
|
||||
get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
|
||||
buf->reserved2 = 0;
|
||||
buf->names[0].type = 0;
|
||||
buf->names[0].length = 0;
|
||||
|
||||
/* calculate buf->ntlmv2_hash */
|
||||
rc = calc_ntlmv2_hash(ses, nls_cp);
|
||||
if(rc)
|
||||
cERROR(1,("could not get v2 hash rc %d",rc));
|
||||
CalcNTLMv2_response(ses, resp_buf);
|
||||
}
|
||||
|
||||
void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response)
|
||||
{
|
||||
struct HMACMD5Context context;
|
||||
/* rest of v2 struct already generated */
|
||||
memcpy(v2_session_response + 8, ses->server->cryptKey,8);
|
||||
/* gen_blob(v2_session_response + 16); */
|
||||
hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
|
||||
|
||||
hmac_md5_update(ses->server->cryptKey,8,&context);
|
||||
/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
|
||||
hmac_md5_update(v2_session_response+8,
|
||||
sizeof(struct ntlmv2_resp) - 8, &context);
|
||||
|
||||
hmac_md5_final(v2_session_response,&context);
|
||||
cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); /* BB removeme BB */
|
||||
/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -908,7 +908,7 @@ static int cifs_dnotify_thread(void * dummyarg)
|
|||
struct cifsSesInfo *ses;
|
||||
|
||||
do {
|
||||
if(try_to_freeze())
|
||||
if (try_to_freeze())
|
||||
continue;
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(15*HZ);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#endif
|
||||
|
||||
extern struct address_space_operations cifs_addr_ops;
|
||||
extern struct address_space_operations cifs_addr_ops_smallbuf;
|
||||
|
||||
/* Functions related to super block operations */
|
||||
extern struct super_operations cifs_super_ops;
|
||||
|
@ -99,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
|
|||
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
|
||||
extern int cifs_ioctl (struct inode * inode, struct file * filep,
|
||||
unsigned int command, unsigned long arg);
|
||||
#define CIFS_VERSION "1.43"
|
||||
#define CIFS_VERSION "1.44"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -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 */
|
||||
|
@ -157,7 +158,7 @@ struct TCP_Server_Info {
|
|||
/* 16th byte of RFC1001 workstation name is always null */
|
||||
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
||||
__u32 sequence_number; /* needed for CIFS PDU signature */
|
||||
char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];
|
||||
char mac_signing_key[CIFS_SESS_KEY_SIZE + 16];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -179,10 +180,13 @@ 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;
|
||||
unsigned overrideSecFlg; /* if non-zero override global sec flags */
|
||||
__u16 ipc_tid; /* special tid for connection to IPC share */
|
||||
__u16 flags;
|
||||
char *serverOS; /* name of operating system underlying server */
|
||||
|
@ -194,7 +198,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 */
|
||||
|
@ -209,12 +213,12 @@ struct cifsTconInfo {
|
|||
struct list_head openFileList;
|
||||
struct semaphore tconSem;
|
||||
struct cifsSesInfo *ses; /* pointer to session associated with */
|
||||
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */
|
||||
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
|
||||
char *nativeFileSystem;
|
||||
__u16 tid; /* The 2 byte tree id */
|
||||
__u16 Flags; /* optional support bits */
|
||||
enum statusEnum tidStatus;
|
||||
atomic_t useCount; /* how many mounts (explicit or implicit) to this share */
|
||||
atomic_t useCount; /* how many explicit/implicit mounts to share */
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
atomic_t num_smbs_sent;
|
||||
atomic_t num_writes;
|
||||
|
@ -254,7 +258,7 @@ struct cifsTconInfo {
|
|||
spinlock_t stat_lock;
|
||||
#endif /* CONFIG_CIFS_STATS */
|
||||
FILE_SYSTEM_DEVICE_INFO fsDevInfo;
|
||||
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */
|
||||
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
|
||||
FILE_SYSTEM_UNIX_INFO fsUnixInfo;
|
||||
unsigned retry:1;
|
||||
unsigned nocase:1;
|
||||
|
@ -305,7 +309,6 @@ struct cifsFileInfo {
|
|||
atomic_t wrtPending; /* handle in use - defer close */
|
||||
struct semaphore fh_sem; /* prevents reopen race after dead ses*/
|
||||
char * search_resume_name; /* BB removeme BB */
|
||||
unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
|
||||
struct cifs_search_info srch_inf;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -500,16 +523,16 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
|
|||
GLOBAL_EXTERN struct list_head GlobalOplock_Q;
|
||||
|
||||
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */
|
||||
GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */
|
||||
GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;/* DirNotify response queue */
|
||||
|
||||
/*
|
||||
* Global transaction id (XID) information
|
||||
*/
|
||||
GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */
|
||||
GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */
|
||||
GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */
|
||||
GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
|
||||
GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */
|
||||
/* on midQ entries */
|
||||
GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */
|
||||
/* on midQ entries */
|
||||
GLOBAL_EXTERN char Local_System_Name[15];
|
||||
|
||||
/*
|
||||
|
@ -531,7 +554,7 @@ GLOBAL_EXTERN atomic_t smBufAllocCount;
|
|||
GLOBAL_EXTERN atomic_t midCount;
|
||||
|
||||
/* Misc globals */
|
||||
GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
|
||||
GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
|
||||
to be established on existing mount if we
|
||||
have the uid/password or Kerberos credential
|
||||
or equivalent for current user */
|
||||
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
@ -110,7 +116,7 @@
|
|||
/*
|
||||
* Size of the session key (crypto key encrypted with the password
|
||||
*/
|
||||
#define CIFS_SESSION_KEY_SIZE (24)
|
||||
#define CIFS_SESS_KEY_SIZE (24)
|
||||
|
||||
/*
|
||||
* Maximum user name length
|
||||
|
@ -400,6 +406,29 @@ 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;
|
||||
|
||||
#define READ_RAW_ENABLE 1
|
||||
#define WRITE_RAW_ENABLE 2
|
||||
#define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE)
|
||||
|
||||
typedef struct negotiate_rsp {
|
||||
struct smb_hdr hdr; /* wct = 17 */
|
||||
__le16 DialectIndex;
|
||||
|
@ -509,7 +538,7 @@ typedef union smb_com_session_setup_andx {
|
|||
/* unsigned char * NativeOS; */
|
||||
/* unsigned char * NativeLanMan; */
|
||||
/* unsigned char * PrimaryDomain; */
|
||||
} __attribute__((packed)) resp; /* NTLM response format (with or without extended security */
|
||||
} __attribute__((packed)) resp; /* NTLM response with or without extended sec*/
|
||||
|
||||
struct { /* request format */
|
||||
struct smb_hdr hdr; /* wct = 10 */
|
||||
|
@ -520,8 +549,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 */
|
||||
|
@ -543,6 +572,26 @@ typedef union smb_com_session_setup_andx {
|
|||
} __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */
|
||||
} __attribute__((packed)) SESSION_SETUP_ANDX;
|
||||
|
||||
/* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */
|
||||
|
||||
struct ntlmssp2_name {
|
||||
__le16 type;
|
||||
__le16 length;
|
||||
/* char name[length]; */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ntlmv2_resp {
|
||||
char ntlmv2_hash[CIFS_ENCPWD_SIZE];
|
||||
__le32 blob_signature;
|
||||
__u32 reserved;
|
||||
__le64 time;
|
||||
__u64 client_chal; /* random */
|
||||
__u32 reserved2;
|
||||
struct ntlmssp2_name names[1];
|
||||
/* array of name entries could follow ending in minimum 4 byte struct */
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
#define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
|
||||
|
||||
/* Capabilities bits (for NTLM SessSetup request) */
|
||||
|
@ -573,7 +622,9 @@ typedef struct smb_com_tconx_req {
|
|||
} __attribute__((packed)) TCONX_REQ;
|
||||
|
||||
typedef struct smb_com_tconx_rsp {
|
||||
struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */
|
||||
struct smb_hdr hdr; /* wct = 3 note that Win2000 has sent wct = 7
|
||||
in some cases on responses. Four unspecified
|
||||
words followed OptionalSupport */
|
||||
__u8 AndXCommand;
|
||||
__u8 AndXReserved;
|
||||
__le16 AndXOffset;
|
||||
|
@ -1323,6 +1374,9 @@ struct smb_t2_rsp {
|
|||
#define SMB_FILE_MAXIMUM_INFO 0x40d
|
||||
|
||||
/* Find File infolevels */
|
||||
#define SMB_FIND_FILE_INFO_STANDARD 0x001
|
||||
#define SMB_FIND_FILE_QUERY_EA_SIZE 0x002
|
||||
#define SMB_FIND_FILE_QUERY_EAS_FROM_LIST 0x003
|
||||
#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
|
||||
#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
|
||||
#define SMB_FIND_FILE_NAMES_INFO 0x103
|
||||
|
@ -1844,13 +1898,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;
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -1947,7 +2001,8 @@ typedef struct {
|
|||
|
||||
struct file_allocation_info {
|
||||
__le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
|
||||
} __attribute__((packed)); /* size used on disk, level 0x103 for set, 0x105 for query */
|
||||
} __attribute__((packed)); /* size used on disk, for level 0x103 for set,
|
||||
0x105 for query */
|
||||
|
||||
struct file_end_of_file_info {
|
||||
__le64 FileSize; /* offset to end of file */
|
||||
|
@ -2054,7 +2109,7 @@ typedef struct {
|
|||
__le32 ExtFileAttributes;
|
||||
__le32 FileNameLength;
|
||||
char FileName[1];
|
||||
} __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */
|
||||
} __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF resp data */
|
||||
|
||||
typedef struct {
|
||||
__le32 NextEntryOffset;
|
||||
|
@ -2069,7 +2124,7 @@ typedef struct {
|
|||
__le32 FileNameLength;
|
||||
__le32 EaSize; /* length of the xattrs */
|
||||
char FileName[1];
|
||||
} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */
|
||||
} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */
|
||||
|
||||
typedef struct {
|
||||
__le32 NextEntryOffset;
|
||||
|
@ -2086,7 +2141,7 @@ typedef struct {
|
|||
__le32 Reserved;
|
||||
__u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
|
||||
char FileName[1];
|
||||
} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */
|
||||
} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */
|
||||
|
||||
typedef struct {
|
||||
__le32 NextEntryOffset;
|
||||
|
@ -2104,7 +2159,22 @@ typedef struct {
|
|||
__u8 Reserved;
|
||||
__u8 ShortName[12];
|
||||
char FileName[1];
|
||||
} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */
|
||||
} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */
|
||||
|
||||
typedef struct {
|
||||
__u32 ResumeKey;
|
||||
__le16 CreationDate; /* SMB Date */
|
||||
__le16 CreationTime; /* SMB Time */
|
||||
__le16 LastAccessDate;
|
||||
__le16 LastAccessTime;
|
||||
__le16 LastWriteDate;
|
||||
__le16 LastWriteTime;
|
||||
__le32 DataSize; /* File Size (EOF) */
|
||||
__le32 AllocationSize;
|
||||
__le16 Attributes; /* verify not u32 */
|
||||
__u8 FileNameLength;
|
||||
char FileName[1];
|
||||
} __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */
|
||||
|
||||
|
||||
struct win_dev {
|
||||
|
|
|
@ -64,14 +64,12 @@ extern int map_smb_to_linux_error(struct smb_hdr *smb);
|
|||
extern void header_assemble(struct smb_hdr *, char /* command */ ,
|
||||
const struct cifsTconInfo *, int /* length of
|
||||
fixed section (word count) in two byte units */);
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
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);
|
||||
extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16,
|
||||
struct cifsTconInfo *);
|
||||
|
@ -285,8 +283,14 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
|
|||
extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
|
||||
__u32 expected_sequence_number);
|
||||
extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
|
||||
extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
|
||||
extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * );
|
||||
extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *,
|
||||
const struct nls_table *);
|
||||
extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * );
|
||||
extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
|
||||
const struct nls_table *);
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key);
|
||||
#endif /* CIFS_WEAK_PW_HASH */
|
||||
extern int CIFSSMBCopy(int xid,
|
||||
struct cifsTconInfo *source_tcon,
|
||||
const char *fromName,
|
||||
|
|
|
@ -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 */
|
||||
|
@ -188,7 +209,6 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
int
|
||||
small_smb_init_no_tc(const int smb_command, const int wct,
|
||||
struct cifsSesInfo *ses, void **request_buf)
|
||||
|
@ -214,7 +234,6 @@ small_smb_init_no_tc(const int smb_command, const int wct,
|
|||
|
||||
return rc;
|
||||
}
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||
|
||||
/* If the return code is zero, this function must fill in request_buf pointer */
|
||||
static int
|
||||
|
@ -322,7 +341,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,8 +393,10 @@ 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;
|
||||
unsigned int secFlags;
|
||||
|
||||
if(ses->server)
|
||||
server = ses->server;
|
||||
|
@ -386,101 +408,200 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
(void **) &pSMB, (void **) &pSMBr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* if any of auth flags (ie not sign or seal) are overriden use them */
|
||||
if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
|
||||
secFlags = ses->overrideSecFlg;
|
||||
else /* if override flags set only sign/seal OR them with global auth */
|
||||
secFlags = extended_security | ses->overrideSecFlg;
|
||||
|
||||
cFYI(1,("secFlags 0x%x",secFlags));
|
||||
|
||||
pSMB->hdr.Mid = GetNextMid(server);
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
|
||||
if (extended_security)
|
||||
if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
|
||||
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 */
|
||||
|
||||
|
||||
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) {
|
||||
server->secMode = pSMBr->SecurityMode;
|
||||
if((server->secMode & SECMODE_USER) == 0)
|
||||
cFYI(1,("share mode security"));
|
||||
server->secType = NTLM; /* BB override default for
|
||||
NTLMv2 or kerberos v5 */
|
||||
/* one byte - no need to convert this or EncryptionKeyLen
|
||||
from little endian */
|
||||
server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
|
||||
/* probably no need to store and check maxvcs */
|
||||
server->maxBuf =
|
||||
min(le32_to_cpu(pSMBr->MaxBufferSize),
|
||||
(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
|
||||
server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
|
||||
cFYI(0, ("Max buf = %d", ses->server->maxBuf));
|
||||
GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
|
||||
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
|
||||
server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
|
||||
/* BB with UTC do we ever need to be using srvr timezone? */
|
||||
if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
|
||||
memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
|
||||
CIFS_CRYPTO_KEY_SIZE);
|
||||
} else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
|
||||
&& (pSMBr->EncryptionKeyLength == 0)) {
|
||||
/* decode security blob */
|
||||
} else
|
||||
rc = -EIO;
|
||||
if (rc != 0)
|
||||
goto neg_err_exit;
|
||||
|
||||
/* BB might be helpful to save off the domain of server here */
|
||||
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
|
||||
small wct just comes when dialect index is -1 indicating we
|
||||
could not negotiate a common dialect */
|
||||
rc = -EOPNOTSUPP;
|
||||
goto neg_err_exit;
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
} else if((pSMBr->hdr.WordCount == 13)
|
||||
&& (pSMBr->DialectIndex == LANMAN_PROT)) {
|
||||
struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
|
||||
|
||||
if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
|
||||
(server->capabilities & CAP_EXTENDED_SECURITY)) {
|
||||
count = pSMBr->ByteCount;
|
||||
if (count < 16)
|
||||
rc = -EIO;
|
||||
else if (count == 16) {
|
||||
server->secType = RawNTLMSSP;
|
||||
if (server->socketUseCount.counter > 1) {
|
||||
if (memcmp
|
||||
(server->server_GUID,
|
||||
pSMBr->u.extended_response.
|
||||
GUID, 16) != 0) {
|
||||
cFYI(1, ("server UID changed"));
|
||||
memcpy(server->
|
||||
server_GUID,
|
||||
pSMBr->u.
|
||||
extended_response.
|
||||
GUID, 16);
|
||||
}
|
||||
} else
|
||||
memcpy(server->server_GUID,
|
||||
pSMBr->u.extended_response.
|
||||
GUID, 16);
|
||||
} else {
|
||||
rc = decode_negTokenInit(pSMBr->u.
|
||||
extended_response.
|
||||
SecurityBlob,
|
||||
count - 16,
|
||||
&server->secType);
|
||||
if(rc == 1) {
|
||||
/* BB Need to fill struct for sessetup here */
|
||||
rc = -EOPNOTSUPP;
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
}
|
||||
}
|
||||
} else
|
||||
server->capabilities &= ~CAP_EXTENDED_SECURITY;
|
||||
if(sign_CIFS_PDUs == FALSE) {
|
||||
if(server->secMode & SECMODE_SIGN_REQUIRED)
|
||||
cERROR(1,
|
||||
("Server requires /proc/fs/cifs/PacketSigningEnabled"));
|
||||
server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
|
||||
} else if(sign_CIFS_PDUs == 1) {
|
||||
if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
|
||||
server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
|
||||
if((secFlags & CIFSSEC_MAY_LANMAN) ||
|
||||
(secFlags & CIFSSEC_MAY_PLNTXT))
|
||||
server->secType = LANMAN;
|
||||
else {
|
||||
cERROR(1, ("mount failed weak security disabled"
|
||||
" in /proc/fs/cifs/SecurityFlags"));
|
||||
rc = -EOPNOTSUPP;
|
||||
goto neg_err_exit;
|
||||
}
|
||||
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);
|
||||
GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
|
||||
/* even though we do not use raw we might as well set this
|
||||
accurately, in case we ever find a need for it */
|
||||
if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
|
||||
server->maxRw = 0xFF00;
|
||||
server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
|
||||
} else {
|
||||
server->maxRw = 0;/* we do not need to use raw anyway */
|
||||
server->capabilities = CAP_MPX_MODE;
|
||||
}
|
||||
|
||||
server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
|
||||
|
||||
/* BB 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 if (server->secMode & SECMODE_PW_ENCRYPT) {
|
||||
rc = -EIO; /* need cryptkey unless plain text */
|
||||
goto neg_err_exit;
|
||||
}
|
||||
|
||||
cFYI(1,("LANMAN negotiated"));
|
||||
/* we will not end up setting signing flags - as no signing
|
||||
was in LANMAN and server did not return the flags on */
|
||||
goto signing_check;
|
||||
#else /* weak security disabled */
|
||||
} else if(pSMBr->hdr.WordCount == 13) {
|
||||
cERROR(1,("mount failed, cifs module not built "
|
||||
"with CIFS_WEAK_PW_HASH support"));
|
||||
rc = -EOPNOTSUPP;
|
||||
#endif /* WEAK_PW_HASH */
|
||||
goto neg_err_exit;
|
||||
} else if(pSMBr->hdr.WordCount != 17) {
|
||||
/* unknown wct */
|
||||
rc = -EOPNOTSUPP;
|
||||
goto neg_err_exit;
|
||||
}
|
||||
|
||||
/* else wct == 17 NTLM */
|
||||
server->secMode = pSMBr->SecurityMode;
|
||||
if((server->secMode & SECMODE_USER) == 0)
|
||||
cFYI(1,("share mode security"));
|
||||
|
||||
if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
|
||||
#endif /* CIFS_WEAK_PW_HASH */
|
||||
cERROR(1,("Server requests plain text password"
|
||||
" but client support disabled"));
|
||||
|
||||
if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
|
||||
server->secType = NTLMv2;
|
||||
else if(secFlags & CIFSSEC_MAY_NTLM)
|
||||
server->secType = NTLM;
|
||||
else if(secFlags & CIFSSEC_MAY_NTLMV2)
|
||||
server->secType = NTLMv2;
|
||||
/* else krb5 ... any others ... */
|
||||
|
||||
/* one byte, so no need to convert this or EncryptionKeyLen from
|
||||
little endian */
|
||||
server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
|
||||
/* probably no need to store and check maxvcs */
|
||||
server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
|
||||
(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
|
||||
server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
|
||||
cFYI(0, ("Max buf = %d", ses->server->maxBuf));
|
||||
GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
|
||||
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
|
||||
server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
|
||||
if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
|
||||
memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
|
||||
CIFS_CRYPTO_KEY_SIZE);
|
||||
} else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
|
||||
&& (pSMBr->EncryptionKeyLength == 0)) {
|
||||
/* decode security blob */
|
||||
} else if (server->secMode & SECMODE_PW_ENCRYPT) {
|
||||
rc = -EIO; /* no crypt key only if plain text pwd */
|
||||
goto neg_err_exit;
|
||||
}
|
||||
|
||||
/* BB might be helpful to save off the domain of server here */
|
||||
|
||||
if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
|
||||
(server->capabilities & CAP_EXTENDED_SECURITY)) {
|
||||
count = pSMBr->ByteCount;
|
||||
if (count < 16)
|
||||
rc = -EIO;
|
||||
else if (count == 16) {
|
||||
server->secType = RawNTLMSSP;
|
||||
if (server->socketUseCount.counter > 1) {
|
||||
if (memcmp(server->server_GUID,
|
||||
pSMBr->u.extended_response.
|
||||
GUID, 16) != 0) {
|
||||
cFYI(1, ("server UID changed"));
|
||||
memcpy(server->server_GUID,
|
||||
pSMBr->u.extended_response.GUID,
|
||||
16);
|
||||
}
|
||||
} else
|
||||
memcpy(server->server_GUID,
|
||||
pSMBr->u.extended_response.GUID, 16);
|
||||
} else {
|
||||
rc = decode_negTokenInit(pSMBr->u.extended_response.
|
||||
SecurityBlob,
|
||||
count - 16,
|
||||
&server->secType);
|
||||
if(rc == 1) {
|
||||
/* BB Need to fill struct for sessetup here */
|
||||
rc = -EOPNOTSUPP;
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
}
|
||||
}
|
||||
} else
|
||||
server->capabilities &= ~CAP_EXTENDED_SECURITY;
|
||||
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
signing_check:
|
||||
#endif
|
||||
if(sign_CIFS_PDUs == FALSE) {
|
||||
if(server->secMode & SECMODE_SIGN_REQUIRED)
|
||||
cERROR(1,("Server requires "
|
||||
"/proc/fs/cifs/PacketSigningEnabled to be on"));
|
||||
server->secMode &=
|
||||
~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
|
||||
} else if(sign_CIFS_PDUs == 1) {
|
||||
if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
|
||||
server->secMode &=
|
||||
~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
|
||||
} else if(sign_CIFS_PDUs == 2) {
|
||||
if((server->secMode &
|
||||
(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
|
||||
cERROR(1,("signing required but server lacks support"));
|
||||
}
|
||||
}
|
||||
neg_err_exit:
|
||||
cifs_buf_release(pSMB);
|
||||
|
||||
cFYI(1,("negprot rc %d",rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -2239,7 +2360,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
|
|||
}
|
||||
symlinkinfo[buflen] = 0; /* just in case so the caller
|
||||
does not go off the end of the buffer */
|
||||
cFYI(1,("readlink result - %s ",symlinkinfo));
|
||||
cFYI(1,("readlink result - %s",symlinkinfo));
|
||||
}
|
||||
}
|
||||
qreparse_out:
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -70,6 +68,7 @@ struct smb_vol {
|
|||
gid_t linux_gid;
|
||||
mode_t file_mode;
|
||||
mode_t dir_mode;
|
||||
unsigned secFlg;
|
||||
unsigned rw:1;
|
||||
unsigned retry:1;
|
||||
unsigned intr:1;
|
||||
|
@ -83,12 +82,7 @@ struct smb_vol {
|
|||
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 krb5:1;
|
||||
unsigned ntlm:1;
|
||||
unsigned ntlmv2:1;
|
||||
unsigned nullauth:1; /* attempt to authenticate with null user */
|
||||
unsigned sign:1;
|
||||
unsigned seal:1; /* encrypt */
|
||||
unsigned nocase; /* request case insensitive filenames */
|
||||
unsigned nobrl; /* disable sending byte range locks to srv */
|
||||
unsigned int rsize;
|
||||
|
@ -369,21 +363,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
continue;
|
||||
if (bigbuf == NULL) {
|
||||
bigbuf = cifs_buf_get();
|
||||
if(bigbuf == NULL) {
|
||||
cERROR(1,("No memory for large SMB response"));
|
||||
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 dirtry large buf, clear its start */
|
||||
} 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 == NULL) {
|
||||
cERROR(1,("No memory for SMB response"));
|
||||
if (!smallbuf) {
|
||||
cERROR(1, ("No memory for SMB response"));
|
||||
msleep(1000);
|
||||
/* retry will check if exiting */
|
||||
continue;
|
||||
|
@ -403,12 +397,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
kernel_recvmsg(csocket, &smb_msg,
|
||||
&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,("Reconnect 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)) {
|
||||
|
@ -417,15 +411,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
tcpStatus CifsNeedReconnect if server hung */
|
||||
continue;
|
||||
} else if (length <= 0) {
|
||||
if(server->tcpStatus == CifsNew) {
|
||||
cFYI(1,("tcp session abend after SMBnegprot"));
|
||||
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;
|
||||
}
|
||||
|
@ -585,9 +579,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 +628,14 @@ multi_t2_fnd:
|
|||
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 */
|
||||
|
||||
|
@ -784,7 +785,6 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
|
|||
|
||||
/* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
|
||||
vol->rw = TRUE;
|
||||
vol->ntlm = TRUE;
|
||||
/* default is always to request posix paths. */
|
||||
vol->posix_paths = 1;
|
||||
|
||||
|
@ -915,30 +915,35 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
|
|||
cERROR(1,("no security value specified"));
|
||||
continue;
|
||||
} else if (strnicmp(value, "krb5i", 5) == 0) {
|
||||
vol->sign = 1;
|
||||
vol->krb5 = 1;
|
||||
vol->secFlg |= CIFSSEC_MAY_KRB5 |
|
||||
CIFSSEC_MUST_SIGN;
|
||||
} else if (strnicmp(value, "krb5p", 5) == 0) {
|
||||
/* vol->seal = 1;
|
||||
vol->krb5 = 1; */
|
||||
/* 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->krb5 = 1;
|
||||
vol->secFlg |= CIFSSEC_MAY_KRB5;
|
||||
} else if (strnicmp(value, "ntlmv2i", 7) == 0) {
|
||||
vol->ntlmv2 = 1;
|
||||
vol->sign = 1;
|
||||
vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
|
||||
CIFSSEC_MUST_SIGN;
|
||||
} else if (strnicmp(value, "ntlmv2", 6) == 0) {
|
||||
vol->ntlmv2 = 1;
|
||||
vol->secFlg |= CIFSSEC_MAY_NTLMV2;
|
||||
} else if (strnicmp(value, "ntlmi", 5) == 0) {
|
||||
vol->ntlm = 1;
|
||||
vol->sign = 1;
|
||||
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->ntlm = 1;
|
||||
vol->secFlg |= CIFSSEC_MAY_NTLM;
|
||||
} else if (strnicmp(value, "nontlm", 6) == 0) {
|
||||
vol->ntlm = 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;
|
||||
vol->nullauth = 1;
|
||||
} else {
|
||||
cERROR(1,("bad security option: %s", value));
|
||||
return 1;
|
||||
|
@ -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 {
|
||||
|
@ -1168,6 +1173,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
|
|||
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) {
|
||||
|
@ -1762,11 +1771,18 @@ 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;
|
||||
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)
|
||||
|
@ -1980,7 +1996,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
|
||||
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;
|
||||
|
@ -2038,15 +2054,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
|
||||
|
||||
pSMB->req_no_secext.CaseInsensitivePasswordLength =
|
||||
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
|
||||
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 *) 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 */
|
||||
|
@ -2054,7 +2070,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,
|
||||
|
@ -2162,8 +2178,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
if (remaining_words > 0) {
|
||||
len = UniStrnlen((wchar_t *)bcc_ptr,
|
||||
remaining_words-1);
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
|
||||
if(ses->serverNOS == NULL)
|
||||
goto sesssetup_nomem;
|
||||
|
@ -2203,12 +2218,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
/* if these kcallocs fail not much we
|
||||
can do, but better to not fail the
|
||||
sesssetup itself */
|
||||
if(ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain =
|
||||
kzalloc(2, GFP_KERNEL);
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS =
|
||||
kzalloc(2, GFP_KERNEL);
|
||||
}
|
||||
|
@ -2217,8 +2230,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
if (((long) bcc_ptr + len) - (long)
|
||||
pByteArea(smb_buffer_response)
|
||||
<= BCC(smb_buffer_response)) {
|
||||
if(ses->serverOS)
|
||||
kfree(ses->serverOS);
|
||||
kfree(ses->serverOS);
|
||||
ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
|
||||
if(ses->serverOS == NULL)
|
||||
goto sesssetup_nomem;
|
||||
|
@ -2229,8 +2241,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
bcc_ptr++;
|
||||
|
||||
len = strnlen(bcc_ptr, 1024);
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
|
||||
if(ses->serverNOS == NULL)
|
||||
goto sesssetup_nomem;
|
||||
|
@ -2273,292 +2284,6 @@ sesssetup_nomem: /* do not return an error on nomem for the info strings,
|
|||
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;
|
||||
char *domain;
|
||||
int rc = 0;
|
||||
int remaining_words = 0;
|
||||
int bytes_returned = 0;
|
||||
int len;
|
||||
__u32 capabilities;
|
||||
__u16 count;
|
||||
|
||||
cFYI(1, ("In spnego sesssetup "));
|
||||
if(ses == NULL)
|
||||
return -EINVAL;
|
||||
user = ses->userName;
|
||||
domain = ses->domainName;
|
||||
|
||||
smb_buffer = cifs_buf_get();
|
||||
if (smb_buffer == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
smb_buffer_response = smb_buffer;
|
||||
pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
|
||||
|
||||
/* send SMBsessionSetup here */
|
||||
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
|
||||
NULL /* no tCon exists yet */ , 12 /* wct */ );
|
||||
|
||||
smb_buffer->Mid = GetNextMid(ses->server);
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
pSMB->req.AndXCommand = 0xFF;
|
||||
if(ses->server->maxBuf > 64*1024)
|
||||
ses->server->maxBuf = (64*1023);
|
||||
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;
|
||||
|
||||
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
|
||||
CAP_EXTENDED_SECURITY;
|
||||
if (ses->capabilities & CAP_UNICODE) {
|
||||
smb_buffer->Flags2 |= SMBFLG2_UNICODE;
|
||||
capabilities |= CAP_UNICODE;
|
||||
}
|
||||
if (ses->capabilities & CAP_STATUS32) {
|
||||
smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
|
||||
capabilities |= CAP_STATUS32;
|
||||
}
|
||||
if (ses->capabilities & CAP_DFS) {
|
||||
smb_buffer->Flags2 |= SMBFLG2_DFS;
|
||||
capabilities |= CAP_DFS;
|
||||
}
|
||||
pSMB->req.Capabilities = cpu_to_le32(capabilities);
|
||||
|
||||
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((__le16 *) 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((__le16 *) bcc_ptr,
|
||||
"CIFS_LINUX_DOM", 32, nls_codepage);
|
||||
else
|
||||
bytes_returned =
|
||||
cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
|
||||
nls_codepage);
|
||||
bcc_ptr += 2 * bytes_returned;
|
||||
bcc_ptr += 2;
|
||||
bytes_returned =
|
||||
cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
|
||||
32, nls_codepage);
|
||||
bcc_ptr += 2 * bytes_returned;
|
||||
bytes_returned =
|
||||
cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
|
||||
nls_codepage);
|
||||
bcc_ptr += 2 * bytes_returned;
|
||||
bcc_ptr += 2;
|
||||
bytes_returned =
|
||||
cifs_strtoUCS((__le16 *) 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, system_utsname.release);
|
||||
bcc_ptr += strlen(system_utsname.release) + 1;
|
||||
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
|
||||
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
|
||||
}
|
||||
count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
|
||||
smb_buffer->smb_buf_length += count;
|
||||
pSMB->req.ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
|
||||
&bytes_returned, 1);
|
||||
if (rc) {
|
||||
/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
|
||||
} else if ((smb_buffer_response->WordCount == 3)
|
||||
|| (smb_buffer_response->WordCount == 4)) {
|
||||
__u16 action = le16_to_cpu(pSMBr->resp.Action);
|
||||
__u16 blob_len =
|
||||
le16_to_cpu(pSMBr->resp.SecurityBlobLength);
|
||||
if (action & GUEST_LOGIN)
|
||||
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)
|
||||
&& (blob_len <
|
||||
pSMBr->resp.ByteCount))) {
|
||||
if (pSMBr->resp.hdr.WordCount == 4) {
|
||||
bcc_ptr +=
|
||||
blob_len;
|
||||
cFYI(1,
|
||||
("Security Blob Length %d ",
|
||||
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 */
|
||||
if(ses->serverOS)
|
||||
kfree(ses->serverOS);
|
||||
ses->serverOS =
|
||||
kzalloc(2 * (len + 1), GFP_KERNEL);
|
||||
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);
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS =
|
||||
kzalloc(2 * (len + 1),
|
||||
GFP_KERNEL);
|
||||
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;
|
||||
remaining_words -= len + 1;
|
||||
if (remaining_words > 0) {
|
||||
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
|
||||
/* last string not null terminated (e.g.Windows XP/2000) */
|
||||
if(ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
|
||||
cifs_strfromUCS_le(ses->serverDomain,
|
||||
(__le16 *)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 {
|
||||
if(ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain =
|
||||
kzalloc(2,GFP_KERNEL);
|
||||
}
|
||||
} else {/* no room use dummy domain&NOS */
|
||||
if(ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain = kzalloc(2, GFP_KERNEL);
|
||||
if(ses->serverNOS)
|
||||
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)) {
|
||||
if(ses->serverOS)
|
||||
kfree(ses->serverOS);
|
||||
ses->serverOS = kzalloc(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);
|
||||
if(ses->serverNOS)
|
||||
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);
|
||||
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;
|
||||
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
|
||||
CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
||||
struct cifsSesInfo *ses, int * pNTLMv2_flag,
|
||||
|
@ -2635,8 +2360,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;
|
||||
|
||||
|
@ -2783,8 +2508,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
|||
bcc_ptr,
|
||||
remaining_words
|
||||
- 1);
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS =
|
||||
kzalloc(2 * (len + 1),
|
||||
GFP_KERNEL);
|
||||
|
@ -2802,8 +2526,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
|||
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) */
|
||||
if(ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain =
|
||||
kzalloc(2 *
|
||||
(len +
|
||||
|
@ -2822,19 +2545,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
|||
= 0;
|
||||
} /* else no more room so create dummy domain string */
|
||||
else {
|
||||
if(ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain =
|
||||
kzalloc(2,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
} else { /* no room so create dummy domain and NOS string */
|
||||
if(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain =
|
||||
kzalloc(2, GFP_KERNEL);
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS =
|
||||
kzalloc(2, GFP_KERNEL);
|
||||
}
|
||||
|
@ -2856,8 +2576,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
|||
bcc_ptr++;
|
||||
|
||||
len = strnlen(bcc_ptr, 1024);
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS =
|
||||
kzalloc(len + 1,
|
||||
GFP_KERNEL);
|
||||
|
@ -2867,8 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
|||
bcc_ptr++;
|
||||
|
||||
len = strnlen(bcc_ptr, 1024);
|
||||
if(ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain =
|
||||
kzalloc(len + 1,
|
||||
GFP_KERNEL);
|
||||
|
@ -2994,14 +2712,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
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) {
|
||||
|
@ -3190,8 +2908,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
bcc_ptr,
|
||||
remaining_words
|
||||
- 1);
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS =
|
||||
kzalloc(2 * (len + 1),
|
||||
GFP_KERNEL);
|
||||
|
@ -3244,8 +2961,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
if(ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain = kzalloc(2, GFP_KERNEL);
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS = kzalloc(2, GFP_KERNEL);
|
||||
}
|
||||
} else { /* ASCII */
|
||||
|
@ -3263,8 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
bcc_ptr++;
|
||||
|
||||
len = strnlen(bcc_ptr, 1024);
|
||||
if(ses->serverNOS)
|
||||
kfree(ses->serverNOS);
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
|
||||
strncpy(ses->serverNOS, bcc_ptr, len);
|
||||
bcc_ptr += len;
|
||||
|
@ -3340,22 +3055,33 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
|||
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_SESSION_KEY_SIZE);
|
||||
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) is accepted
|
||||
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_SESSION_KEY_SIZE;
|
||||
*bcc_ptr = 0;
|
||||
bcc_ptr++; /* align */
|
||||
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 &
|
||||
|
@ -3429,7 +3155,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 */
|
||||
|
@ -3494,7 +3223,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
|
|||
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;
|
||||
|
||||
|
@ -3526,20 +3255,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
|
|||
pSesInfo->server->secMode,
|
||||
pSesInfo->server->capabilities,
|
||||
pSesInfo->server->timeZone));
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
if(experimEnabled > 1)
|
||||
rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */,
|
||||
&ntlmv2_flag, nls_info);
|
||||
else
|
||||
#endif
|
||||
if (extended_security
|
||||
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)) {
|
||||
|
|
|
@ -113,7 +113,7 @@ cifs_bp_rename_retry:
|
|||
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,
|
||||
|
@ -178,11 +178,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
FreeXid(xid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
|
||||
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
|
||||
desiredAccess, CREATE_NOT_DIR,
|
||||
&fileHandle, &oplock, buf, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
else
|
||||
rc = -EIO; /* no NT SMB support fall into legacy open below */
|
||||
|
||||
if(rc == -EIO) {
|
||||
/* old server, retry the open legacy style */
|
||||
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
|
||||
|
@ -191,7 +194,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
if (rc) {
|
||||
cFYI(1, ("cifs_create returned 0x%x ", rc));
|
||||
cFYI(1, ("cifs_create returned 0x%x", rc));
|
||||
} else {
|
||||
/* If Open reported that we actually created a file
|
||||
then we now have to set the mode if possible */
|
||||
|
@ -369,6 +372,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
|
|||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
|
||||
/* BB FIXME - add handling for backlevel servers
|
||||
which need legacy open and check for all
|
||||
calls to SMBOpen for fallback to
|
||||
SMBLeagcyOpen */
|
||||
if(!rc) {
|
||||
/* BB Do not bother to decode buf since no
|
||||
local inode yet to put timestamps in,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -110,7 +110,6 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
|
|||
&pCifsInode->openFileList);
|
||||
}
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
write_unlock(&file->f_owner.lock);
|
||||
if (pCifsInode->clientCanCacheRead) {
|
||||
/* we have the inode open somewhere else
|
||||
no need to discard cache data */
|
||||
|
@ -201,7 +200,7 @@ int cifs_open(struct inode *inode, struct file *file)
|
|||
} else {
|
||||
if (file->f_flags & O_EXCL)
|
||||
cERROR(1, ("could not find file instance for "
|
||||
"new file %p ", file));
|
||||
"new file %p", file));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,10 +259,15 @@ int cifs_open(struct inode *inode, struct file *file)
|
|||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
|
||||
CREATE_NOT_DIR, &netfid, &oplock, buf,
|
||||
|
||||
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
|
||||
desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
|
||||
& CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
else
|
||||
rc = -EIO; /* no NT SMB support fall into legacy open below */
|
||||
|
||||
if (rc == -EIO) {
|
||||
/* Old server, try legacy style OpenX */
|
||||
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
|
||||
|
@ -272,7 +276,7 @@ int cifs_open(struct inode *inode, struct file *file)
|
|||
& CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
if (rc) {
|
||||
cFYI(1, ("cifs_open returned 0x%x ", rc));
|
||||
cFYI(1, ("cifs_open returned 0x%x", rc));
|
||||
goto out;
|
||||
}
|
||||
file->private_data =
|
||||
|
@ -282,7 +286,6 @@ int cifs_open(struct inode *inode, struct file *file)
|
|||
goto out;
|
||||
}
|
||||
pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
|
||||
write_lock(&file->f_owner.lock);
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_add(&pCifsFile->tlist, &pTcon->openFileList);
|
||||
|
||||
|
@ -293,7 +296,6 @@ int cifs_open(struct inode *inode, struct file *file)
|
|||
&oplock, buf, full_path, xid);
|
||||
} else {
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
write_unlock(&file->f_owner.lock);
|
||||
}
|
||||
|
||||
if (oplock & CIFS_CREATE_ACTION) {
|
||||
|
@ -409,8 +411,8 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
|
|||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc) {
|
||||
up(&pCifsFile->fh_sem);
|
||||
cFYI(1, ("cifs_open returned 0x%x ", rc));
|
||||
cFYI(1, ("oplock: %d ", oplock));
|
||||
cFYI(1, ("cifs_open returned 0x%x", rc));
|
||||
cFYI(1, ("oplock: %d", oplock));
|
||||
} else {
|
||||
pCifsFile->netfid = netfid;
|
||||
pCifsFile->invalidHandle = FALSE;
|
||||
|
@ -472,7 +474,6 @@ int cifs_close(struct inode *inode, struct file *file)
|
|||
pTcon = cifs_sb->tcon;
|
||||
if (pSMBFile) {
|
||||
pSMBFile->closePend = TRUE;
|
||||
write_lock(&file->f_owner.lock);
|
||||
if (pTcon) {
|
||||
/* no sense reconnecting to close a file that is
|
||||
already closed */
|
||||
|
@ -487,23 +488,18 @@ int cifs_close(struct inode *inode, struct file *file)
|
|||
the struct would be in each open file,
|
||||
but this should give enough time to
|
||||
clear the socket */
|
||||
write_unlock(&file->f_owner.lock);
|
||||
cERROR(1,("close with pending writes"));
|
||||
msleep(timeout);
|
||||
write_lock(&file->f_owner.lock);
|
||||
timeout *= 4;
|
||||
}
|
||||
write_unlock(&file->f_owner.lock);
|
||||
rc = CIFSSMBClose(xid, pTcon,
|
||||
pSMBFile->netfid);
|
||||
write_lock(&file->f_owner.lock);
|
||||
}
|
||||
}
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_del(&pSMBFile->flist);
|
||||
list_del(&pSMBFile->tlist);
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
write_unlock(&file->f_owner.lock);
|
||||
kfree(pSMBFile->search_resume_name);
|
||||
kfree(file->private_data);
|
||||
file->private_data = NULL;
|
||||
|
@ -531,7 +527,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
|
|||
(struct cifsFileInfo *)file->private_data;
|
||||
char *ptmp;
|
||||
|
||||
cFYI(1, ("Closedir inode = 0x%p with ", inode));
|
||||
cFYI(1, ("Closedir inode = 0x%p", inode));
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
|
@ -605,7 +601,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||
}
|
||||
if (pfLock->fl_flags & FL_ACCESS)
|
||||
cFYI(1, ("Process suspended by mandatory locking - "
|
||||
"not implemented yet "));
|
||||
"not implemented yet"));
|
||||
if (pfLock->fl_flags & FL_LEASE)
|
||||
cFYI(1, ("Lease on file - not implemented yet"));
|
||||
if (pfLock->fl_flags &
|
||||
|
@ -1375,7 +1371,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
|||
|
||||
xid = GetXid();
|
||||
|
||||
cFYI(1, ("Sync file - name: %s datasync: 0x%x ",
|
||||
cFYI(1, ("Sync file - name: %s datasync: 0x%x",
|
||||
dentry->d_name.name, datasync));
|
||||
|
||||
rc = filemap_fdatawrite(inode->i_mapping);
|
||||
|
@ -1404,7 +1400,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
|||
/* fill in rpages then
|
||||
result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
|
||||
|
||||
/* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
|
||||
/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
|
||||
|
||||
#if 0
|
||||
if (rc < 0)
|
||||
|
@ -1836,7 +1832,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
|
|||
if (rc < 0)
|
||||
goto io_error;
|
||||
else
|
||||
cFYI(1, ("Bytes read %d ",rc));
|
||||
cFYI(1, ("Bytes read %d",rc));
|
||||
|
||||
file->f_dentry->d_inode->i_atime =
|
||||
current_fs_time(file->f_dentry->d_inode->i_sb);
|
||||
|
@ -1957,3 +1953,19 @@ struct address_space_operations cifs_addr_ops = {
|
|||
/* .sync_page = cifs_sync_page, */
|
||||
/* .direct_IO = */
|
||||
};
|
||||
|
||||
/*
|
||||
* cifs_readpages requires the server to support a buffer large enough to
|
||||
* contain the header plus one complete page of data. Otherwise, we need
|
||||
* to leave cifs_readpages out of the address space operations.
|
||||
*/
|
||||
struct address_space_operations cifs_addr_ops_smallbuf = {
|
||||
.readpage = cifs_readpage,
|
||||
.writepage = cifs_writepage,
|
||||
.writepages = cifs_writepages,
|
||||
.prepare_write = cifs_prepare_write,
|
||||
.commit_write = cifs_commit_write,
|
||||
.set_page_dirty = __set_page_dirty_nobuffers,
|
||||
/* .sync_page = cifs_sync_page, */
|
||||
/* .direct_IO = */
|
||||
};
|
||||
|
|
|
@ -41,7 +41,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|||
char *tmp_path;
|
||||
|
||||
pTcon = cifs_sb->tcon;
|
||||
cFYI(1, ("Getting info on %s ", search_path));
|
||||
cFYI(1, ("Getting info on %s", search_path));
|
||||
/* could have done a find first instead but this returns more info */
|
||||
rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||
|
@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|||
inode = *pinode;
|
||||
cifsInfo = CIFS_I(inode);
|
||||
|
||||
cFYI(1, ("Old time %ld ", cifsInfo->time));
|
||||
cFYI(1, ("Old time %ld", cifsInfo->time));
|
||||
cifsInfo->time = jiffies;
|
||||
cFYI(1, ("New time %ld ", cifsInfo->time));
|
||||
cFYI(1, ("New time %ld", cifsInfo->time));
|
||||
/* this is ok to set on every inode revalidate */
|
||||
atomic_set(&cifsInfo->inUse,1);
|
||||
|
||||
|
@ -180,11 +180,12 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|||
else /* not direct, send byte range locks */
|
||||
inode->i_fop = &cifs_file_ops;
|
||||
|
||||
inode->i_data.a_ops = &cifs_addr_ops;
|
||||
/* check if server can support readpages */
|
||||
if(pTcon->ses->server->maxBuf <
|
||||
4096 + MAX_CIFS_HDR_SIZE)
|
||||
inode->i_data.a_ops->readpages = NULL;
|
||||
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
|
||||
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
||||
else
|
||||
inode->i_data.a_ops = &cifs_addr_ops;
|
||||
} else if (S_ISDIR(inode->i_mode)) {
|
||||
cFYI(1, ("Directory inode"));
|
||||
inode->i_op = &cifs_dir_inode_ops;
|
||||
|
@ -421,23 +422,23 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
inode = *pinode;
|
||||
cifsInfo = CIFS_I(inode);
|
||||
cifsInfo->cifsAttrs = attr;
|
||||
cFYI(1, ("Old time %ld ", cifsInfo->time));
|
||||
cFYI(1, ("Old time %ld", cifsInfo->time));
|
||||
cifsInfo->time = jiffies;
|
||||
cFYI(1, ("New time %ld ", cifsInfo->time));
|
||||
cFYI(1, ("New time %ld", cifsInfo->time));
|
||||
|
||||
/* blksize needs to be multiple of two. So safer to default to
|
||||
blksize and blkbits set in superblock so 2**blkbits and blksize
|
||||
will match rather than setting to:
|
||||
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
|
||||
|
||||
/* Linux can not store file creation time unfortunately so we ignore it */
|
||||
/* Linux can not store file creation time so ignore it */
|
||||
inode->i_atime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
|
||||
inode->i_mtime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
|
||||
inode->i_ctime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
|
||||
cFYI(0, ("Attributes came in as 0x%x ", attr));
|
||||
cFYI(0, ("Attributes came in as 0x%x", attr));
|
||||
|
||||
/* set default mode. will override for dirs below */
|
||||
if (atomic_read(&cifsInfo->inUse) == 0)
|
||||
|
@ -519,10 +520,11 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
else /* not direct, send byte range locks */
|
||||
inode->i_fop = &cifs_file_ops;
|
||||
|
||||
inode->i_data.a_ops = &cifs_addr_ops;
|
||||
if(pTcon->ses->server->maxBuf <
|
||||
4096 + MAX_CIFS_HDR_SIZE)
|
||||
inode->i_data.a_ops->readpages = NULL;
|
||||
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
|
||||
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
||||
else
|
||||
inode->i_data.a_ops = &cifs_addr_ops;
|
||||
} else if (S_ISDIR(inode->i_mode)) {
|
||||
cFYI(1, ("Directory inode"));
|
||||
inode->i_op = &cifs_dir_inode_ops;
|
||||
|
@ -731,7 +733,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|||
rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc) {
|
||||
cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
|
||||
cFYI(1, ("cifs_mkdir returned 0x%x", rc));
|
||||
d_drop(direntry);
|
||||
} else {
|
||||
inode->i_nlink++;
|
||||
|
@ -798,7 +800,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
|
|||
char *full_path = NULL;
|
||||
struct cifsInodeInfo *cifsInode;
|
||||
|
||||
cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode));
|
||||
cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
|
@ -1121,7 +1123,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 +1159,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;
|
||||
|
@ -1289,7 +1292,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
it may be useful to Windows - but we do
|
||||
not want to set ctime unless some other
|
||||
timestamp is changing */
|
||||
cFYI(1, ("CIFS - CTIME changed "));
|
||||
cFYI(1, ("CIFS - CTIME changed"));
|
||||
time_buf.ChangeTime =
|
||||
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
|
||||
} else
|
||||
|
@ -1356,7 +1359,7 @@ cifs_setattr_exit:
|
|||
|
||||
void cifs_delete_inode(struct inode *inode)
|
||||
{
|
||||
cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
|
||||
cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
|
||||
/* may have to add back in if and when safe distributed caching of
|
||||
directories added e.g. via FindNotify */
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cFYI(1, ("Full path: %s ", full_path));
|
||||
cFYI(1, ("Full path: %s", full_path));
|
||||
cFYI(1, ("symname is %s", symname));
|
||||
|
||||
/* BB what if DFS and this volume is on different share? BB */
|
||||
|
@ -186,8 +186,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
|
|||
inode->i_sb,xid);
|
||||
|
||||
if (rc != 0) {
|
||||
cFYI(1,
|
||||
("Create symlink worked but get_inode_info failed with rc = %d ",
|
||||
cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
|
||||
rc));
|
||||
} else {
|
||||
if (pTcon->nocase)
|
||||
|
@ -289,7 +288,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
|
|||
else {
|
||||
cFYI(1,("num referral: %d",num_referrals));
|
||||
if(referrals) {
|
||||
cFYI(1,("referral string: %s ",referrals));
|
||||
cFYI(1,("referral string: %s",referrals));
|
||||
strncpy(tmpbuffer, referrals, len-1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -84,11 +84,11 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
|
|||
|
||||
static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
|
||||
{ERRerror, -EIO},
|
||||
{ERRbadpw, -EPERM},
|
||||
{ERRbadpw, -EACCES}, /* was EPERM */
|
||||
{ERRbadtype, -EREMOTE},
|
||||
{ERRaccess, -EACCES},
|
||||
{ERRinvtid, -ENXIO},
|
||||
{ERRinvnetname, -ENODEV},
|
||||
{ERRinvnetname, -ENXIO},
|
||||
{ERRinvdevice, -ENXIO},
|
||||
{ERRqfull, -ENOSPC},
|
||||
{ERRqtoobig, -ENOSPC},
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* fs/cifs/ntlmssp.h
|
||||
*
|
||||
* 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"
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/* BB check whether to init vcnum BB */
|
||||
return capabilities;
|
||||
}
|
||||
int
|
||||
CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int type,
|
||||
int * pNTLMv2_flg, const struct nls_table *nls_cp)
|
||||
{
|
||||
int rc = 0;
|
||||
int wct;
|
||||
struct smb_hdr *smb_buffer;
|
||||
char *bcc_ptr;
|
||||
SESSION_SETUP_ANDX *pSMB;
|
||||
__u32 capabilities;
|
||||
|
||||
if(ses == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
cFYI(1,("SStp type: %d",type));
|
||||
if(type < CIFS_NTLM) {
|
||||
#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 < CIFS_NTLMSSP_NEG)
|
||||
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_buffer);
|
||||
if(rc)
|
||||
return rc;
|
||||
|
||||
pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
|
||||
|
||||
capabilities = cifs_ssetup_hdr(ses, pSMB);
|
||||
bcc_ptr = pByteArea(smb_buffer);
|
||||
if(type > CIFS_NTLM) {
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
capabilities |= CAP_EXTENDED_SECURITY;
|
||||
pSMB->req.Capabilities = cpu_to_le32(capabilities);
|
||||
/* BB set password lengths */
|
||||
} else if(type < CIFS_NTLM) /* lanman */ {
|
||||
/* no capabilities flags in old lanman negotiation */
|
||||
/* pSMB->old_req.PasswordLength = */ /* BB fixme BB */
|
||||
} else /* type CIFS_NTLM */ {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* copy session key */
|
||||
|
||||
/* if Unicode, align strings to two byte boundary */
|
||||
|
||||
/* copy user name */ /* BB Do we need to special case null user name? */
|
||||
|
||||
/* copy domain name */
|
||||
|
||||
/* copy Linux version */
|
||||
|
||||
/* copy network operating system name */
|
||||
|
||||
/* update bcc and smb buffer length */
|
||||
|
||||
/* rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */
|
||||
/* SMB request buf freed in SendReceive2 */
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
|
@ -21,6 +21,7 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <linux/fs.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include "cifspdu.h"
|
||||
|
@ -31,8 +32,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 +54,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 */
|
||||
|
@ -107,32 +109,52 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void fill_in_inode(struct inode *tmp_inode,
|
||||
FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode)
|
||||
static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
|
||||
char * buf, int *pobject_type, int isNewInode)
|
||||
{
|
||||
loff_t local_size;
|
||||
struct timespec local_mtime;
|
||||
|
||||
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
|
||||
__u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
|
||||
__u64 allocation_size = le64_to_cpu(pfindData->AllocationSize);
|
||||
__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
|
||||
|
||||
cifsInfo->cifsAttrs = attr;
|
||||
cifsInfo->time = jiffies;
|
||||
__u32 attr;
|
||||
__u64 allocation_size;
|
||||
__u64 end_of_file;
|
||||
|
||||
/* save mtime and size */
|
||||
local_mtime = tmp_inode->i_mtime;
|
||||
local_size = tmp_inode->i_size;
|
||||
|
||||
if(new_buf_type) {
|
||||
FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
|
||||
|
||||
attr = le32_to_cpu(pfindData->ExtFileAttributes);
|
||||
allocation_size = le64_to_cpu(pfindData->AllocationSize);
|
||||
end_of_file = le64_to_cpu(pfindData->EndOfFile);
|
||||
tmp_inode->i_atime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
|
||||
tmp_inode->i_mtime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
|
||||
tmp_inode->i_ctime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
|
||||
} else { /* legacy, OS2 and DOS style */
|
||||
FIND_FILE_STANDARD_INFO * pfindData =
|
||||
(FIND_FILE_STANDARD_INFO *)buf;
|
||||
|
||||
attr = le16_to_cpu(pfindData->Attributes);
|
||||
allocation_size = le32_to_cpu(pfindData->AllocationSize);
|
||||
end_of_file = le32_to_cpu(pfindData->DataSize);
|
||||
tmp_inode->i_atime = CURRENT_TIME;
|
||||
/* tmp_inode->i_mtime = BB FIXME - add dos time handling
|
||||
tmp_inode->i_ctime = 0; BB FIXME */
|
||||
|
||||
}
|
||||
|
||||
/* Linux can not store file creation time unfortunately so ignore it */
|
||||
tmp_inode->i_atime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
|
||||
tmp_inode->i_mtime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
|
||||
tmp_inode->i_ctime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
|
||||
|
||||
cifsInfo->cifsAttrs = attr;
|
||||
cifsInfo->time = jiffies;
|
||||
|
||||
/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
|
||||
/* 2767 perms - indicate mandatory locking */
|
||||
/* BB fill in uid and gid here? with help from winbind?
|
||||
|
@ -215,11 +237,13 @@ static void fill_in_inode(struct inode *tmp_inode,
|
|||
else
|
||||
tmp_inode->i_fop = &cifs_file_ops;
|
||||
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops;
|
||||
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
|
||||
(cifs_sb->tcon->ses->server->maxBuf <
|
||||
4096 + MAX_CIFS_HDR_SIZE))
|
||||
tmp_inode->i_data.a_ops->readpages = NULL;
|
||||
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
||||
else
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops;
|
||||
|
||||
if(isNewInode)
|
||||
return; /* No sense invalidating pages for new inode
|
||||
since have not started caching readahead file
|
||||
|
@ -338,11 +362,12 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
|
|||
else
|
||||
tmp_inode->i_fop = &cifs_file_ops;
|
||||
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops;
|
||||
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
|
||||
(cifs_sb->tcon->ses->server->maxBuf <
|
||||
4096 + MAX_CIFS_HDR_SIZE))
|
||||
tmp_inode->i_data.a_ops->readpages = NULL;
|
||||
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
||||
else
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops;
|
||||
|
||||
if(isNewInode)
|
||||
return; /* No sense invalidating pages for new inode since we
|
||||
|
@ -415,7 +440,10 @@ static int initiate_cifs_search(const int xid, struct file *file)
|
|||
ffirst_retry:
|
||||
/* test for Unix extensions */
|
||||
if (pTcon->ses->capabilities & CAP_UNIX) {
|
||||
cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
|
||||
cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
|
||||
} else if ((pTcon->ses->capabilities &
|
||||
(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
|
||||
cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
|
||||
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
||||
cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
|
||||
} else /* not srvinos - BB fixme add check for backlevel? */ {
|
||||
|
@ -451,12 +479,19 @@ static int cifs_unicode_bytelen(char *str)
|
|||
return len << 1;
|
||||
}
|
||||
|
||||
static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
|
||||
static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
|
||||
{
|
||||
char * new_entry;
|
||||
FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
|
||||
|
||||
new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
|
||||
if(level == SMB_FIND_FILE_INFO_STANDARD) {
|
||||
FIND_FILE_STANDARD_INFO * pfData;
|
||||
pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
|
||||
|
||||
new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
|
||||
pfData->FileNameLength;
|
||||
} else
|
||||
new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
|
||||
cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
|
||||
/* validate that new_entry is not past end of SMB */
|
||||
if(new_entry >= end_of_smb) {
|
||||
|
@ -464,7 +499,10 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb)
|
|||
("search entry %p began after end of SMB %p old entry %p",
|
||||
new_entry, end_of_smb, old_entry));
|
||||
return NULL;
|
||||
} else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) {
|
||||
} else if(((level == SMB_FIND_FILE_INFO_STANDARD) &&
|
||||
(new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) ||
|
||||
((level != SMB_FIND_FILE_INFO_STANDARD) &&
|
||||
(new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) {
|
||||
cERROR(1,("search entry %p extends after end of SMB %p",
|
||||
new_entry, end_of_smb));
|
||||
return NULL;
|
||||
|
@ -482,7 +520,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
|
|||
char * filename = NULL;
|
||||
int len = 0;
|
||||
|
||||
if(cfile->srch_inf.info_level == 0x202) {
|
||||
if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
|
||||
FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
if(cfile->srch_inf.unicode) {
|
||||
|
@ -491,26 +529,34 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
|
|||
/* BB should we make this strnlen of PATH_MAX? */
|
||||
len = strnlen(filename, 5);
|
||||
}
|
||||
} else if(cfile->srch_inf.info_level == 0x101) {
|
||||
} else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
|
||||
FILE_DIRECTORY_INFO * pFindData =
|
||||
(FILE_DIRECTORY_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
len = le32_to_cpu(pFindData->FileNameLength);
|
||||
} else if(cfile->srch_inf.info_level == 0x102) {
|
||||
} else if(cfile->srch_inf.info_level ==
|
||||
SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
|
||||
FILE_FULL_DIRECTORY_INFO * pFindData =
|
||||
(FILE_FULL_DIRECTORY_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
len = le32_to_cpu(pFindData->FileNameLength);
|
||||
} else if(cfile->srch_inf.info_level == 0x105) {
|
||||
} else if(cfile->srch_inf.info_level ==
|
||||
SMB_FIND_FILE_ID_FULL_DIR_INFO) {
|
||||
SEARCH_ID_FULL_DIR_INFO * pFindData =
|
||||
(SEARCH_ID_FULL_DIR_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
len = le32_to_cpu(pFindData->FileNameLength);
|
||||
} else if(cfile->srch_inf.info_level == 0x104) {
|
||||
} else if(cfile->srch_inf.info_level ==
|
||||
SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
|
||||
FILE_BOTH_DIRECTORY_INFO * pFindData =
|
||||
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
len = le32_to_cpu(pFindData->FileNameLength);
|
||||
} else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
|
||||
FIND_FILE_STANDARD_INFO * pFindData =
|
||||
(FIND_FILE_STANDARD_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
len = le32_to_cpu(pFindData->FileNameLength);
|
||||
} else {
|
||||
cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
|
||||
}
|
||||
|
@ -597,7 +643,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)) {
|
||||
|
@ -644,10 +692,12 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
|
|||
first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
|
||||
- cifsFile->srch_inf.entries_in_buffer;
|
||||
pos_in_buf = index_to_find - first_entry_in_buffer;
|
||||
cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
|
||||
cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
|
||||
|
||||
for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
|
||||
/* go entry by entry figuring out which is first */
|
||||
current_entry = nxt_dir_entry(current_entry,end_of_smb);
|
||||
current_entry = nxt_dir_entry(current_entry,end_of_smb,
|
||||
cifsFile->srch_inf.info_level);
|
||||
}
|
||||
if((current_entry == NULL) && (i < pos_in_buf)) {
|
||||
/* BB fixme - check if we should flag this error */
|
||||
|
@ -674,7 +724,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
|
|||
/* inode num, inode type and filename returned */
|
||||
static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
||||
char *current_entry, __u16 level, unsigned int unicode,
|
||||
struct cifs_sb_info * cifs_sb, ino_t *pinum)
|
||||
struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int len = 0;
|
||||
|
@ -718,10 +768,22 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
|||
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
len = le32_to_cpu(pFindData->FileNameLength);
|
||||
} else if(level == SMB_FIND_FILE_INFO_STANDARD) {
|
||||
FIND_FILE_STANDARD_INFO * pFindData =
|
||||
(FIND_FILE_STANDARD_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
/* one byte length, no name conversion */
|
||||
len = (unsigned int)pFindData->FileNameLength;
|
||||
} else {
|
||||
cFYI(1,("Unknown findfirst level %d",level));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(len > max_len) {
|
||||
cERROR(1,("bad search response length %d past smb end", len));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(unicode) {
|
||||
/* BB fixme - test with long names */
|
||||
/* Note converted filename can be longer than in unicode */
|
||||
|
@ -741,7 +803,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
|||
}
|
||||
|
||||
static int cifs_filldir(char *pfindEntry, struct file *file,
|
||||
filldir_t filldir, void *direntry, char *scratch_buf)
|
||||
filldir_t filldir, void *direntry, char *scratch_buf, int max_len)
|
||||
{
|
||||
int rc = 0;
|
||||
struct qstr qstring;
|
||||
|
@ -777,6 +839,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
|
|||
rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
|
||||
pCifsF->srch_inf.info_level,
|
||||
pCifsF->srch_inf.unicode,cifs_sb,
|
||||
max_len,
|
||||
&inum /* returned */);
|
||||
|
||||
if(rc)
|
||||
|
@ -798,13 +861,16 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
|
|||
/* we pass in rc below, indicating whether it is a new inode,
|
||||
so we can figure out whether to invalidate the inode cached
|
||||
data if the file has changed */
|
||||
if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
|
||||
if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
|
||||
unix_fill_in_inode(tmp_inode,
|
||||
(FILE_UNIX_INFO *)pfindEntry,&obj_type, rc);
|
||||
} else {
|
||||
fill_in_inode(tmp_inode,
|
||||
(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
|
||||
}
|
||||
(FILE_UNIX_INFO *)pfindEntry,
|
||||
&obj_type, rc);
|
||||
else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
|
||||
fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
|
||||
pfindEntry, &obj_type, rc);
|
||||
else
|
||||
fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
|
||||
|
||||
|
||||
rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
|
||||
tmp_inode->i_ino,obj_type);
|
||||
|
@ -864,6 +930,12 @@ static int cifs_save_resume_key(const char *current_entry,
|
|||
filename = &pFindData->FileName[0];
|
||||
len = le32_to_cpu(pFindData->FileNameLength);
|
||||
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
|
||||
} else if(level == SMB_FIND_FILE_INFO_STANDARD) {
|
||||
FIND_FILE_STANDARD_INFO * pFindData =
|
||||
(FIND_FILE_STANDARD_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
/* one byte length, no name conversion */
|
||||
len = (unsigned int)pFindData->FileNameLength;
|
||||
} else {
|
||||
cFYI(1,("Unknown findfirst level %d",level));
|
||||
return -EINVAL;
|
||||
|
@ -884,6 +956,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
|||
int num_to_fill = 0;
|
||||
char * tmp_buf = NULL;
|
||||
char * end_of_smb;
|
||||
int max_len;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
|
@ -909,7 +982,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
|||
case 1:
|
||||
if (filldir(direntry, "..", 2, file->f_pos,
|
||||
file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
|
||||
cERROR(1, ("Filldir for parent dir failed "));
|
||||
cERROR(1, ("Filldir for parent dir failed"));
|
||||
rc = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
@ -959,10 +1032,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
|||
goto rddir2_exit;
|
||||
}
|
||||
cFYI(1,("loop through %d times filling dir for net buf %p",
|
||||
num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
|
||||
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
|
||||
smbCalcSize((struct smb_hdr *)
|
||||
cifsFile->srch_inf.ntwrk_buf_start);
|
||||
num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
|
||||
max_len = smbCalcSize((struct smb_hdr *)
|
||||
cifsFile->srch_inf.ntwrk_buf_start);
|
||||
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
|
||||
|
||||
/* To be safe - for UCS to UTF-8 with strings loaded
|
||||
with the rare long characters alloc more to account for
|
||||
such multibyte target UTF-8 characters. cifs_unicode.c,
|
||||
|
@ -977,17 +1051,19 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
|||
}
|
||||
/* if buggy server returns . and .. late do
|
||||
we want to check for that here? */
|
||||
rc = cifs_filldir(current_entry, file,
|
||||
filldir, direntry,tmp_buf);
|
||||
rc = cifs_filldir(current_entry, file,
|
||||
filldir, direntry, tmp_buf, max_len);
|
||||
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
|
||||
current_entry = nxt_dir_entry(current_entry,
|
||||
end_of_smb);
|
||||
current_entry =
|
||||
nxt_dir_entry(current_entry, end_of_smb,
|
||||
cifsFile->srch_inf.info_level);
|
||||
}
|
||||
kfree(tmp_buf);
|
||||
break;
|
||||
|
|
538
fs/cifs/sess.c
Normal file
538
fs/cifs/sess.c
Normal file
|
@ -0,0 +1,538 @@
|
|||
/*
|
||||
* 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/utsname.h>
|
||||
|
||||
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static 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 */
|
||||
|
||||
/* unicode strings, must be word aligned before the call */
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static 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, 300);
|
||||
*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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
struct smb_hdr *smb_buf;
|
||||
char *bcc_ptr;
|
||||
char *str_area;
|
||||
SESSION_SETUP_ANDX *pSMB;
|
||||
__u32 capabilities;
|
||||
int count;
|
||||
int resp_buf_type = 0;
|
||||
struct kvec iov[2];
|
||||
enum securityEnum type;
|
||||
__u16 action;
|
||||
int bytes_remaining;
|
||||
|
||||
if(ses == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
type = ses->server->secType;
|
||||
|
||||
cFYI(1,("sess setup type %d",type));
|
||||
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) || (type == NTLMv2)) {
|
||||
/* For NTLMv2 failures eventually may need to 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);
|
||||
|
||||
/* we will send the SMB in two pieces,
|
||||
a fixed length beginning part, and a
|
||||
second part which will include the strings
|
||||
and rest of bcc area, in order to avoid having
|
||||
to do a large buffer 17K allocation */
|
||||
iov[0].iov_base = (char *)pSMB;
|
||||
iov[0].iov_len = smb_buf->smb_buf_length + 4;
|
||||
|
||||
/* 2000 big enough to fit max user, domain, NOS name etc. */
|
||||
str_area = kmalloc(2000, GFP_KERNEL);
|
||||
bcc_ptr = str_area;
|
||||
|
||||
if(type == LANMAN) {
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
char lnm_session_key[CIFS_SESS_KEY_SIZE];
|
||||
|
||||
/* no capabilities flags in old lanman negotiation */
|
||||
|
||||
pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE;
|
||||
/* BB calculate hash with password */
|
||||
/* and copy into bcc */
|
||||
|
||||
calc_lanman_hash(ses, lnm_session_key);
|
||||
|
||||
/* #ifdef CONFIG_CIFS_DEBUG2
|
||||
cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
|
||||
CIFS_SESS_KEY_SIZE);
|
||||
#endif */
|
||||
memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
|
||||
bcc_ptr += CIFS_SESS_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? */
|
||||
|
||||
cFYI(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_SESS_KEY_SIZE];
|
||||
|
||||
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_SESS_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_SESS_KEY_SIZE);
|
||||
bcc_ptr += CIFS_SESS_KEY_SIZE;
|
||||
memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
|
||||
bcc_ptr += CIFS_SESS_KEY_SIZE;
|
||||
if(ses->capabilities & CAP_UNICODE) {
|
||||
/* unicode strings must be word aligned */
|
||||
if (iov[0].iov_len % 2) {
|
||||
*bcc_ptr = 0;
|
||||
bcc_ptr++;
|
||||
}
|
||||
unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
|
||||
} else
|
||||
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
|
||||
} else if (type == NTLMv2) {
|
||||
char * v2_sess_key =
|
||||
kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL);
|
||||
|
||||
/* BB FIXME change all users of v2_sess_key to
|
||||
struct ntlmv2_resp */
|
||||
|
||||
if(v2_sess_key == NULL) {
|
||||
cifs_small_buf_release(smb_buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
|
||||
|
||||
/* LM2 password would be here if we supported it */
|
||||
pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
|
||||
/* cpu_to_le16(LM2_SESS_KEY_SIZE); */
|
||||
|
||||
pSMB->req_no_secext.CaseSensitivePasswordLength =
|
||||
cpu_to_le16(sizeof(struct ntlmv2_resp));
|
||||
|
||||
/* calculate session key */
|
||||
setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
|
||||
if(first_time) /* should this be moved into common code
|
||||
with similar ntlmv2 path? */
|
||||
/* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
|
||||
response BB FIXME, v2_sess_key); */
|
||||
|
||||
/* copy session key */
|
||||
|
||||
/* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
|
||||
bcc_ptr += LM2_SESS_KEY_SIZE; */
|
||||
memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp));
|
||||
bcc_ptr += sizeof(struct ntlmv2_resp);
|
||||
kfree(v2_sess_key);
|
||||
if(ses->capabilities & CAP_UNICODE) {
|
||||
if(iov[0].iov_len % 2) {
|
||||
*bcc_ptr = 0;
|
||||
} bcc_ptr++;
|
||||
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) str_area;
|
||||
smb_buf->smb_buf_length += count;
|
||||
|
||||
BCC_LE(smb_buf) = cpu_to_le16(count);
|
||||
|
||||
iov[1].iov_base = str_area;
|
||||
iov[1].iov_len = count;
|
||||
rc = SendReceive2(xid, ses, iov, 2 /* 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:
|
||||
kfree(str_area);
|
||||
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;
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -654,8 +654,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
|
||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
up(&ses->server->tcpSem);
|
||||
cERROR(1,
|
||||
("Illegal length, greater than maximum frame, %d ",
|
||||
cERROR(1, ("Illegal length, greater than maximum frame, %d",
|
||||
in_buf->smb_buf_length));
|
||||
DeleteMidQEntry(midQ);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
|
|
Loading…
Reference in a new issue