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:
Linus Torvalds 2006-06-27 18:31:57 -07:00
Родитель 01f7e67367 f40c562855
Коммит f17a2686b1
28 изменённых файлов: 1544 добавлений и 826 удалений

Просмотреть файл

@ -1722,7 +1722,7 @@ config CIFS_STATS
mounted by the cifs client to be displayed in /proc/fs/cifs/Stats mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
config CIFS_STATS2 config CIFS_STATS2
bool "CIFS extended statistics" bool "Extended statistics"
depends on CIFS_STATS depends on CIFS_STATS
help help
Enabling this option will allow more detailed statistics on SMB 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 Unless you are a developer or are doing network performance analysis
or tuning, say N. 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 config CIFS_XATTR
bool "CIFS extended attributes" bool "CIFS extended attributes"
depends on CIFS depends on CIFS
@ -1763,6 +1789,16 @@ config CIFS_POSIX
(such as Samba 3.10 and later) which can negotiate (such as Samba 3.10 and later) which can negotiate
CIFS POSIX ACL support. If unsure, say N. 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 config CIFS_EXPERIMENTAL
bool "CIFS Experimental Features (EXPERIMENTAL)" bool "CIFS Experimental Features (EXPERIMENTAL)"
depends on CIFS && EXPERIMENTAL depends on CIFS && EXPERIMENTAL
@ -1778,7 +1814,7 @@ config CIFS_EXPERIMENTAL
If unsure, say N. If unsure, say N.
config CIFS_UPCALL config CIFS_UPCALL
bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
depends on CIFS_EXPERIMENTAL depends on CIFS_EXPERIMENTAL
select CONNECTOR select CONNECTOR
help 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 Version 1.43
------------ ------------
POSIX locking to servers which support CIFS POSIX Extensions POSIX locking to servers which support CIFS POSIX Extensions
(disabled by default controlled by proc/fs/cifs/Experimental). (disabled by default controlled by proc/fs/cifs/Experimental).
Handle conversion of long share names (especially Asian languages) 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 Version 1.42
------------ ------------

Просмотреть файл

@ -3,4 +3,4 @@
# #
obj-$(CONFIG_CIFS) += cifs.o 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 SFU does). In the future the bottom 9 bits of the mode
mode also will be emulated using queries of the security mode also will be emulated using queries of the security
descriptor (ACL). 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) none attempt to connection as a null user (no name)
krb5 Use Kerberos version 5 authentication krb5 Use Kerberos version 5 authentication
krb5i Use Kerberos authentication and packet signing 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) server requires signing also can be the default)
ntlmv2 Use NTLMv2 password hashing ntlmv2 Use NTLMv2 password hashing
ntlmv2i Use NTLMv2 password hashing with packet signing 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 The mount.cifs mount helper also accepts a few mount options before -o
including: including:
@ -485,14 +490,34 @@ PacketSigningEnabled If set to one, cifs packet signing is enabled
it. If set to two, cifs packet signing is it. If set to two, cifs packet signing is
required even if the server considers packet required even if the server considers packet
signing optional. (default 1) 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 cifsFYI If set to one, additional debug information is
logged to the system error log. (default 0) 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 traceSMB If set to one, debug information is logged to the
system error log with the start of smb requests system error log with the start of smb requests
and responses (default 0) and responses (default 0)

Просмотреть файл

@ -467,7 +467,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
asn1_open(&ctx, security_blob, length); asn1_open(&ctx, security_blob, length);
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, ("Error decoding negTokenInit header ")); cFYI(1, ("Error decoding negTokenInit header"));
return 0; return 0;
} else if ((cls != ASN1_APL) || (con != ASN1_CON) } else if ((cls != ASN1_APL) || (con != ASN1_CON)
|| (tag != ASN1_EOC)) { || (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) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, ("Error decoding negTokenInit ")); cFYI(1, ("Error decoding negTokenInit"));
return 0; return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON) } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|| (tag != ASN1_EOC)) { || (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) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, ("Error decoding negTokenInit ")); cFYI(1, ("Error decoding negTokenInit"));
return 0; return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_CON) } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|| (tag != ASN1_SEQ)) { || (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) { 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; return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON) } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|| (tag != ASN1_EOC)) { || (tag != ASN1_EOC)) {
@ -527,7 +527,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
if (asn1_header_decode if (asn1_header_decode
(&ctx, &sequence_end, &cls, &con, &tag) == 0) { (&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; return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_CON) } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|| (tag != ASN1_SEQ)) { || (tag != ASN1_SEQ)) {

Просмотреть файл

@ -39,7 +39,7 @@ cifs_dump_mem(char *label, void *data, int length)
char *charptr = data; char *charptr = data;
char buf[10], line[80]; 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); label, length, data);
for (i = 0; i < length; i += 16) { for (i = 0; i < length; i += 16) {
line[0] = 0; 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 #ifdef CONFIG_PROC_FS
static int static int
cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, 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; *beginBuffer = buf + offset;
length = length =
sprintf(buf, sprintf(buf,
"Display Internal CIFS Data Structures for Debugging\n" "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 write_proc_t traceSMB_write;
static read_proc_t multiuser_mount_read; static read_proc_t multiuser_mount_read;
static write_proc_t multiuser_mount_write; static write_proc_t multiuser_mount_write;
static read_proc_t extended_security_read; static read_proc_t security_flags_read;
static write_proc_t extended_security_write; static write_proc_t security_flags_write;
static read_proc_t ntlmv2_enabled_read; /* static read_proc_t ntlmv2_enabled_read;
static write_proc_t ntlmv2_enabled_write; static write_proc_t ntlmv2_enabled_write;
static read_proc_t packet_signing_enabled_read; 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 read_proc_t experimEnabled_read;
static write_proc_t experimEnabled_write; static write_proc_t experimEnabled_write;
static read_proc_t linuxExtensionsEnabled_read; static read_proc_t linuxExtensionsEnabled_read;
@ -458,10 +508,10 @@ cifs_proc_init(void)
pde->write_proc = multiuser_mount_write; pde->write_proc = multiuser_mount_write;
pde = pde =
create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs,
extended_security_read, NULL); security_flags_read, NULL);
if (pde) if (pde)
pde->write_proc = extended_security_write; pde->write_proc = security_flags_write;
pde = pde =
create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs,
@ -469,7 +519,7 @@ cifs_proc_init(void)
if (pde) if (pde)
pde->write_proc = lookupFlag_write; pde->write_proc = lookupFlag_write;
pde = /* pde =
create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
ntlmv2_enabled_read, NULL); ntlmv2_enabled_read, NULL);
if (pde) if (pde)
@ -479,7 +529,7 @@ cifs_proc_init(void)
create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
packet_signing_enabled_read, NULL); packet_signing_enabled_read, NULL);
if (pde) if (pde)
pde->write_proc = packet_signing_enabled_write; pde->write_proc = packet_signing_enabled_write;*/
} }
void void
@ -496,9 +546,9 @@ cifs_proc_clean(void)
#endif #endif
remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("MultiuserMount", proc_fs_cifs);
remove_proc_entry("OplockEnabled", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs);
remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); /* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
remove_proc_entry("ExtendedSecurity",proc_fs_cifs); remove_proc_entry("SecurityFlags",proc_fs_cifs);
remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); /* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */
remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
remove_proc_entry("Experimental",proc_fs_cifs); remove_proc_entry("Experimental",proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled",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 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 count, int *eof, void *data)
{ {
int len; int len;
len = sprintf(page, "%d\n", extended_security); len = sprintf(page, "0x%x\n", extended_security);
len -= off; len -= off;
*start = page + off; *start = page + off;
@ -803,24 +853,52 @@ extended_security_read(char *page, char **start, off_t off,
return len; return len;
} }
static int 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 long count, void *data)
{ {
unsigned int flags;
char flags_string[12];
char c; char c;
int rc;
rc = get_user(c, buffer); if((count < 1) || (count > 11))
if (rc) return -EINVAL;
return rc;
if (c == '0' || c == 'n' || c == 'N')
extended_security = 0;
else if (c == '1' || c == 'y' || c == 'Y')
extended_security = 1;
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; return count;
} }
static int /* static int
ntlmv2_enabled_read(char *page, char **start, off_t off, ntlmv2_enabled_read(char *page, char **start, off_t off,
int count, int *eof, void *data) int count, int *eof, void *data)
{ {
@ -855,6 +933,8 @@ ntlmv2_enabled_write(struct file *file, const char __user *buffer,
ntlmv2_support = 0; ntlmv2_support = 0;
else if (c == '1' || c == 'y' || c == 'Y') else if (c == '1' || c == 'y' || c == 'Y')
ntlmv2_support = 1; ntlmv2_support = 1;
else if (c == '2')
ntlmv2_support = 2;
return count; return count;
} }
@ -898,7 +978,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer,
sign_CIFS_PDUs = 2; sign_CIFS_PDUs = 2;
return count; return count;
} } */
#endif #endif

Просмотреть файл

@ -24,6 +24,10 @@
#define _H_CIFS_DEBUG #define _H_CIFS_DEBUG
void cifs_dump_mem(char *label, void *data, int length); 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 */ extern int traceSMB; /* flag which enables the function below */
void dump_smb(struct smb_hdr *, int); void dump_smb(struct smb_hdr *, int);
#define CIFS_INFO 0x01 #define CIFS_INFO 0x01

Просмотреть файл

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

Просмотреть файл

@ -26,6 +26,8 @@
#include "md5.h" #include "md5.h"
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "cifsproto.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 */ /* 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 */ /* 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 mdfour(unsigned char *out, unsigned char *in, int n);
extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); 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, static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu,
const char * key, char * signature) const char * key, char * signature)
@ -45,7 +49,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu,
return -EINVAL; return -EINVAL;
MD5Init(&context); 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); MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
MD5Final(signature,&context); MD5Final(signature,&context);
return 0; return 0;
@ -90,7 +94,7 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
return -EINVAL; return -EINVAL;
MD5Init(&context); 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++) { for(i=0;i<n_vec;i++) {
if(iov[i].iov_base == NULL) { if(iov[i].iov_base == NULL) {
cERROR(1,("null iovec entry")); 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); E_md4hash(password, temp_key);
mdfour(key,temp_key,16); mdfour(key,temp_key,16);
memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE); memcpy(key+16,rn, CIFS_SESS_KEY_SIZE);
return 0; 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]; char temp_hash[16];
struct HMACMD5Context ctx; 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); user_name_len = strlen(ses->userName);
if(user_name_len > MAX_USERNAME_SIZE) if(user_name_len > MAX_USERNAME_SIZE)
return -EINVAL; return -EINVAL;
if(ses->domainName == NULL)
return -EINVAL; /* BB should we use CIFS_LINUX_DOM */
dom_name_len = strlen(ses->domainName); dom_name_len = strlen(ses->domainName);
if(dom_name_len > MAX_USERNAME_SIZE) if(dom_name_len > MAX_USERNAME_SIZE)
return -EINVAL; return -EINVAL;
@ -259,16 +266,131 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
kfree(unicode_buf); kfree(unicode_buf);
return 0; 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; struct HMACMD5Context context;
/* rest of v2 struct already generated */
memcpy(v2_session_response + 8, ses->server->cryptKey,8); 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_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+8,
/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ sizeof(struct ntlmv2_resp) - 8, &context);
hmac_md5_final(v2_session_response,&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 linuxExtEnabled = 1;
unsigned int lookupCacheEnabled = 1; unsigned int lookupCacheEnabled = 1;
unsigned int multiuser_mount = 0; unsigned int multiuser_mount = 0;
unsigned int extended_security = 0; unsigned int extended_security = CIFSSEC_DEF;
unsigned int ntlmv2_support = 0; /* unsigned int ntlmv2_support = 0; */
unsigned int sign_CIFS_PDUs = 1; unsigned int sign_CIFS_PDUs = 1;
extern struct task_struct * oplockThread; /* remove sparse warning */ extern struct task_struct * oplockThread; /* remove sparse warning */
struct task_struct * oplockThread = NULL; struct task_struct * oplockThread = NULL;
@ -908,7 +908,7 @@ static int cifs_dnotify_thread(void * dummyarg)
struct cifsSesInfo *ses; struct cifsSesInfo *ses;
do { do {
if(try_to_freeze()) if (try_to_freeze())
continue; continue;
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(15*HZ); schedule_timeout(15*HZ);

Просмотреть файл

@ -33,6 +33,7 @@
#endif #endif
extern struct address_space_operations cifs_addr_ops; extern struct address_space_operations cifs_addr_ops;
extern struct address_space_operations cifs_addr_ops_smallbuf;
/* Functions related to super block operations */ /* Functions related to super block operations */
extern struct super_operations cifs_super_ops; 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 ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern int cifs_ioctl (struct inode * inode, struct file * filep, extern int cifs_ioctl (struct inode * inode, struct file * filep,
unsigned int command, unsigned long arg); unsigned int command, unsigned long arg);
#define CIFS_VERSION "1.43" #define CIFS_VERSION "1.44"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */

Просмотреть файл

@ -88,7 +88,8 @@ enum statusEnum {
}; };
enum securityEnum { 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 */ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */
RawNTLMSSP, /* NTLMSSP without SPNEGO */ RawNTLMSSP, /* NTLMSSP without SPNEGO */
NTLMSSP, /* NTLMSSP via SPNEGO */ NTLMSSP, /* NTLMSSP via SPNEGO */
@ -157,7 +158,7 @@ struct TCP_Server_Info {
/* 16th byte of RFC1001 workstation name is always null */ /* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* needed for CIFS PDU signature */ __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 cifsSesInfo {
struct list_head cifsSessionList; struct list_head cifsSessionList;
struct semaphore sesSem; struct semaphore sesSem;
#if 0
struct cifsUidInfo *uidInfo; /* pointer to user info */ struct cifsUidInfo *uidInfo; /* pointer to user info */
#endif
struct TCP_Server_Info *server; /* pointer to server info */ struct TCP_Server_Info *server; /* pointer to server info */
atomic_t inUse; /* # of mounts (tree connections) on this ses */ atomic_t inUse; /* # of mounts (tree connections) on this ses */
enum statusEnum status; enum statusEnum status;
unsigned overrideSecFlg; /* if non-zero override global sec flags */
__u16 ipc_tid; /* special tid for connection to IPC share */ __u16 ipc_tid; /* special tid for connection to IPC share */
__u16 flags; __u16 flags;
char *serverOS; /* name of operating system underlying server */ 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 char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
TCP names - will ipv6 and sctp addresses fit? */ TCP names - will ipv6 and sctp addresses fit? */
char userName[MAX_USERNAME_SIZE + 1]; char userName[MAX_USERNAME_SIZE + 1];
char domainName[MAX_USERNAME_SIZE + 1]; char * domainName;
char * password; char * password;
}; };
/* session flags */ /* session flags */
@ -209,12 +213,12 @@ struct cifsTconInfo {
struct list_head openFileList; struct list_head openFileList;
struct semaphore tconSem; struct semaphore tconSem;
struct cifsSesInfo *ses; /* pointer to session associated with */ 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; char *nativeFileSystem;
__u16 tid; /* The 2 byte tree id */ __u16 tid; /* The 2 byte tree id */
__u16 Flags; /* optional support bits */ __u16 Flags; /* optional support bits */
enum statusEnum tidStatus; 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 #ifdef CONFIG_CIFS_STATS
atomic_t num_smbs_sent; atomic_t num_smbs_sent;
atomic_t num_writes; atomic_t num_writes;
@ -254,7 +258,7 @@ struct cifsTconInfo {
spinlock_t stat_lock; spinlock_t stat_lock;
#endif /* CONFIG_CIFS_STATS */ #endif /* CONFIG_CIFS_STATS */
FILE_SYSTEM_DEVICE_INFO fsDevInfo; 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; FILE_SYSTEM_UNIX_INFO fsUnixInfo;
unsigned retry:1; unsigned retry:1;
unsigned nocase:1; unsigned nocase:1;
@ -305,7 +309,6 @@ struct cifsFileInfo {
atomic_t wrtPending; /* handle in use - defer close */ atomic_t wrtPending; /* handle in use - defer close */
struct semaphore fh_sem; /* prevents reopen race after dead ses*/ struct semaphore fh_sem; /* prevents reopen race after dead ses*/
char * search_resume_name; /* BB removeme BB */ 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; struct cifs_search_info srch_inf;
}; };
@ -391,9 +394,9 @@ struct mid_q_entry {
struct smb_hdr *resp_buf; /* response buffer */ struct smb_hdr *resp_buf; /* response buffer */
int midState; /* wish this were enum but can not pass to wait_event */ int midState; /* wish this were enum but can not pass to wait_event */
__u8 command; /* smb command code */ __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 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 { struct oplock_q_entry {
@ -430,15 +433,35 @@ struct dir_notify_req {
#define CIFS_LARGE_BUFFER 2 #define CIFS_LARGE_BUFFER 2
#define CIFS_IOVEC 4 /* array of response buffers */ #define CIFS_IOVEC 4 /* array of response buffers */
/* Type of session setup needed */ /* Security Flags: indicate type of session setup needed */
#define CIFS_PLAINTEXT 0 #define CIFSSEC_MAY_SIGN 0x00001
#define CIFS_LANMAN 1 #define CIFSSEC_MAY_NTLM 0x00002
#define CIFS_NTLM 2 #define CIFSSEC_MAY_NTLMV2 0x00004
#define CIFS_NTLMSSP_NEG 3 #define CIFSSEC_MAY_KRB5 0x00008
#define CIFS_NTLMSSP_AUTH 4 #ifdef CONFIG_CIFS_WEAK_PW_HASH
#define CIFS_SPNEGO_INIT 5 #define CIFSSEC_MAY_LANMAN 0x00010
#define CIFS_SPNEGO_TARG 6 #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 * 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 GlobalOplock_Q;
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */ 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 transaction id (XID) information
*/ */
GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ 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 unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */ GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */
/* on midQ entries */ /* on midQ entries */
GLOBAL_EXTERN char Local_System_Name[15]; GLOBAL_EXTERN char Local_System_Name[15];
/* /*
@ -531,7 +554,7 @@ GLOBAL_EXTERN atomic_t smBufAllocCount;
GLOBAL_EXTERN atomic_t midCount; GLOBAL_EXTERN atomic_t midCount;
/* Misc globals */ /* 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 to be established on existing mount if we
have the uid/password or Kerberos credential have the uid/password or Kerberos credential
or equivalent for current user */ or equivalent for current user */
@ -540,8 +563,8 @@ GLOBAL_EXTERN unsigned int experimEnabled;
GLOBAL_EXTERN unsigned int lookupCacheEnabled; GLOBAL_EXTERN unsigned int lookupCacheEnabled;
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */ 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 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 linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */
GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ 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 * You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software * 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 #ifndef _CIFSPDU_H
@ -24,8 +24,14 @@
#include <net/sock.h> #include <net/sock.h>
#ifdef CONFIG_CIFS_WEAK_PW_HASH
#define LANMAN_PROT 0
#define CIFS_PROT 1
#else
#define CIFS_PROT 0 #define CIFS_PROT 0
#define BAD_PROT CIFS_PROT+1 #endif
#define POSIX_PROT CIFS_PROT+1
#define BAD_PROT 0xFFFF
/* SMB command codes */ /* SMB command codes */
/* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses /* 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 * 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 * Maximum user name length
@ -400,6 +406,29 @@ typedef struct negotiate_req {
unsigned char DialectsArray[1]; unsigned char DialectsArray[1];
} __attribute__((packed)) NEGOTIATE_REQ; } __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 { typedef struct negotiate_rsp {
struct smb_hdr hdr; /* wct = 17 */ struct smb_hdr hdr; /* wct = 17 */
__le16 DialectIndex; __le16 DialectIndex;
@ -509,7 +538,7 @@ typedef union smb_com_session_setup_andx {
/* unsigned char * NativeOS; */ /* unsigned char * NativeOS; */
/* unsigned char * NativeLanMan; */ /* unsigned char * NativeLanMan; */
/* unsigned char * PrimaryDomain; */ /* 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 { /* request format */
struct smb_hdr hdr; /* wct = 10 */ struct smb_hdr hdr; /* wct = 10 */
@ -520,8 +549,8 @@ typedef union smb_com_session_setup_andx {
__le16 MaxMpxCount; __le16 MaxMpxCount;
__le16 VcNumber; __le16 VcNumber;
__u32 SessionKey; __u32 SessionKey;
__le16 PassswordLength; __le16 PasswordLength;
__u32 Reserved; __u32 Reserved; /* encrypt key len and offset */
__le16 ByteCount; __le16 ByteCount;
unsigned char AccountPassword[1]; /* followed by */ unsigned char AccountPassword[1]; /* followed by */
/* STRING AccountName */ /* STRING AccountName */
@ -543,6 +572,26 @@ typedef union smb_com_session_setup_andx {
} __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */ } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */
} __attribute__((packed)) SESSION_SETUP_ANDX; } __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" #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
/* Capabilities bits (for NTLM SessSetup request) */ /* Capabilities bits (for NTLM SessSetup request) */
@ -573,7 +622,9 @@ typedef struct smb_com_tconx_req {
} __attribute__((packed)) TCONX_REQ; } __attribute__((packed)) TCONX_REQ;
typedef struct smb_com_tconx_rsp { 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 AndXCommand;
__u8 AndXReserved; __u8 AndXReserved;
__le16 AndXOffset; __le16 AndXOffset;
@ -1323,6 +1374,9 @@ struct smb_t2_rsp {
#define SMB_FILE_MAXIMUM_INFO 0x40d #define SMB_FILE_MAXIMUM_INFO 0x40d
/* Find File infolevels */ /* 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_DIRECTORY_INFO 0x101
#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
#define SMB_FIND_FILE_NAMES_INFO 0x103 #define SMB_FIND_FILE_NAMES_INFO 0x103
@ -1844,13 +1898,13 @@ typedef struct {
typedef struct { typedef struct {
__le32 DeviceType; __le32 DeviceType;
__le32 DeviceCharacteristics; __le32 DeviceCharacteristics;
} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ } __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
typedef struct { typedef struct {
__le32 Attributes; __le32 Attributes;
__le32 MaxPathNameComponentLength; __le32 MaxPathNameComponentLength;
__le32 FileSystemNameLen; __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; } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO;
/******************************************************************************/ /******************************************************************************/
@ -1947,7 +2001,8 @@ typedef struct {
struct file_allocation_info { struct file_allocation_info {
__le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ __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 { struct file_end_of_file_info {
__le64 FileSize; /* offset to end of file */ __le64 FileSize; /* offset to end of file */
@ -2054,7 +2109,7 @@ typedef struct {
__le32 ExtFileAttributes; __le32 ExtFileAttributes;
__le32 FileNameLength; __le32 FileNameLength;
char FileName[1]; 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 { typedef struct {
__le32 NextEntryOffset; __le32 NextEntryOffset;
@ -2069,7 +2124,7 @@ typedef struct {
__le32 FileNameLength; __le32 FileNameLength;
__le32 EaSize; /* length of the xattrs */ __le32 EaSize; /* length of the xattrs */
char FileName[1]; 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 { typedef struct {
__le32 NextEntryOffset; __le32 NextEntryOffset;
@ -2086,7 +2141,7 @@ typedef struct {
__le32 Reserved; __le32 Reserved;
__u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
char FileName[1]; 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 { typedef struct {
__le32 NextEntryOffset; __le32 NextEntryOffset;
@ -2104,7 +2159,22 @@ typedef struct {
__u8 Reserved; __u8 Reserved;
__u8 ShortName[12]; __u8 ShortName[12];
char FileName[1]; 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 { 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 */ , extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifsTconInfo *, int /* length of const struct cifsTconInfo *, int /* length of
fixed section (word count) in two byte units */); 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, extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
struct cifsSesInfo *ses, struct cifsSesInfo *ses,
void ** request_buf); void ** request_buf);
extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, 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); const struct nls_table *nls_cp);
#endif
extern __u16 GetNextMid(struct TCP_Server_Info *server); extern __u16 GetNextMid(struct TCP_Server_Info *server);
extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16,
struct cifsTconInfo *); 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, extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
__u32 expected_sequence_number); __u32 expected_sequence_number);
extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); 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 int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *,
extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); 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, extern int CIFSSMBCopy(int xid,
struct cifsTconInfo *source_tcon, struct cifsTconInfo *source_tcon,
const char *fromName, const char *fromName,

Просмотреть файл

@ -44,8 +44,11 @@ static struct {
int index; int index;
char *name; char *name;
} protocols[] = { } 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, "\2NT LM 0.12"},
{CIFS_PROT, "\2POSIX 2"}, {POSIX_PROT, "\2POSIX 2"},
{BAD_PROT, "\2"} {BAD_PROT, "\2"}
}; };
#else #else
@ -53,11 +56,29 @@ static struct {
int index; int index;
char *name; char *name;
} protocols[] = { } 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, "\2NT LM 0.12"},
{BAD_PROT, "\2"} {BAD_PROT, "\2"}
}; };
#endif #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 /* Mark as invalid, all open files on tree connections since they
were closed when session to server was lost */ 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; return rc;
} }
#ifdef CONFIG_CIFS_EXPERIMENTAL
int int
small_smb_init_no_tc(const int smb_command, const int wct, small_smb_init_no_tc(const int smb_command, const int wct,
struct cifsSesInfo *ses, void **request_buf) struct cifsSesInfo *ses, void **request_buf)
@ -214,7 +234,6 @@ small_smb_init_no_tc(const int smb_command, const int wct,
return rc; return rc;
} }
#endif /* CONFIG_CIFS_EXPERIMENTAL */
/* If the return code is zero, this function must fill in request_buf pointer */ /* If the return code is zero, this function must fill in request_buf pointer */
static int 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 */ /* potential retries of smb operations it turns out we can determine */
/* from the mid flags when the request buffer can be resent without */ /* from the mid flags when the request buffer can be resent without */
/* having to use a second distinct buffer for the response */ /* 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, header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
wct /*wct */ ); wct /*wct */ );
@ -373,8 +393,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
NEGOTIATE_RSP *pSMBr; NEGOTIATE_RSP *pSMBr;
int rc = 0; int rc = 0;
int bytes_returned; int bytes_returned;
int i;
struct TCP_Server_Info * server; struct TCP_Server_Info * server;
u16 count; u16 count;
unsigned int secFlags;
if(ses->server) if(ses->server)
server = ses->server; server = ses->server;
@ -386,101 +408,200 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
(void **) &pSMB, (void **) &pSMBr); (void **) &pSMB, (void **) &pSMBr);
if (rc) if (rc)
return 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.Mid = GetNextMid(server);
pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
if (extended_security) if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
count = strlen(protocols[0].name) + 1; count = 0;
strncpy(pSMB->DialectsArray, protocols[0].name, 30); for(i=0;i<CIFS_NUM_PROT;i++) {
/* null guaranteed to be at end of source and target buffers anyway */ 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->hdr.smb_buf_length += count;
pSMB->ByteCount = cpu_to_le16(count); pSMB->ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc == 0) { if (rc != 0)
server->secMode = pSMBr->SecurityMode; goto neg_err_exit;
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;
/* 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) && if((secFlags & CIFSSEC_MAY_LANMAN) ||
(server->capabilities & CAP_EXTENDED_SECURITY)) { (secFlags & CIFSSEC_MAY_PLNTXT))
count = pSMBr->ByteCount; server->secType = LANMAN;
if (count < 16) else {
rc = -EIO; cERROR(1, ("mount failed weak security disabled"
else if (count == 16) { " in /proc/fs/cifs/SecurityFlags"));
server->secType = RawNTLMSSP; rc = -EOPNOTSUPP;
if (server->socketUseCount.counter > 1) { goto neg_err_exit;
if (memcmp }
(server->server_GUID, server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
pSMBr->u.extended_response. server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
GUID, 16) != 0) { server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
cFYI(1, ("server UID changed")); (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
memcpy(server-> GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
server_GUID, /* even though we do not use raw we might as well set this
pSMBr->u. accurately, in case we ever find a need for it */
extended_response. if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
GUID, 16); server->maxRw = 0xFF00;
} server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
} else } else {
memcpy(server->server_GUID, server->maxRw = 0;/* we do not need to use raw anyway */
pSMBr->u.extended_response. server->capabilities = CAP_MPX_MODE;
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);
} }
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); cifs_buf_release(pSMB);
cFYI(1,("negprot rc %d",rc));
return rc; return rc;
} }
@ -2239,7 +2360,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
} }
symlinkinfo[buflen] = 0; /* just in case so the caller symlinkinfo[buflen] = 0; /* just in case so the caller
does not go off the end of the buffer */ does not go off the end of the buffer */
cFYI(1,("readlink result - %s ",symlinkinfo)); cFYI(1,("readlink result - %s",symlinkinfo));
} }
} }
qreparse_out: qreparse_out:

Просмотреть файл

@ -49,8 +49,6 @@
static DECLARE_COMPLETION(cifsd_complete); 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, extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24); unsigned char *p24);
@ -70,6 +68,7 @@ struct smb_vol {
gid_t linux_gid; gid_t linux_gid;
mode_t file_mode; mode_t file_mode;
mode_t dir_mode; mode_t dir_mode;
unsigned secFlg;
unsigned rw:1; unsigned rw:1;
unsigned retry:1; unsigned retry:1;
unsigned intr:1; unsigned intr:1;
@ -83,12 +82,7 @@ struct smb_vol {
unsigned remap:1; /* set to remap seven reserved chars in filenames */ unsigned remap:1; /* set to remap seven reserved chars in filenames */
unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
unsigned sfu_emul:1; unsigned sfu_emul:1;
unsigned krb5:1;
unsigned ntlm:1;
unsigned ntlmv2:1;
unsigned nullauth:1; /* attempt to authenticate with null user */ unsigned nullauth:1; /* attempt to authenticate with null user */
unsigned sign:1;
unsigned seal:1; /* encrypt */
unsigned nocase; /* request case insensitive filenames */ unsigned nocase; /* request case insensitive filenames */
unsigned nobrl; /* disable sending byte range locks to srv */ unsigned nobrl; /* disable sending byte range locks to srv */
unsigned int rsize; unsigned int rsize;
@ -369,21 +363,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
continue; continue;
if (bigbuf == NULL) { if (bigbuf == NULL) {
bigbuf = cifs_buf_get(); bigbuf = cifs_buf_get();
if(bigbuf == NULL) { if (!bigbuf) {
cERROR(1,("No memory for large SMB response")); cERROR(1, ("No memory for large SMB response"));
msleep(3000); msleep(3000);
/* retry will check if exiting */ /* retry will check if exiting */
continue; continue;
} }
} else if(isLargeBuf) { } else if (isLargeBuf) {
/* we are reusing a dirtry large buf, clear its start */ /* we are reusing a dirty large buf, clear its start */
memset(bigbuf, 0, sizeof (struct smb_hdr)); memset(bigbuf, 0, sizeof (struct smb_hdr));
} }
if (smallbuf == NULL) { if (smallbuf == NULL) {
smallbuf = cifs_small_buf_get(); smallbuf = cifs_small_buf_get();
if(smallbuf == NULL) { if (!smallbuf) {
cERROR(1,("No memory for SMB response")); cERROR(1, ("No memory for SMB response"));
msleep(1000); msleep(1000);
/* retry will check if exiting */ /* retry will check if exiting */
continue; continue;
@ -403,12 +397,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
kernel_recvmsg(csocket, &smb_msg, kernel_recvmsg(csocket, &smb_msg,
&iov, 1, 4, 0 /* BB see socket.h flags */); &iov, 1, 4, 0 /* BB see socket.h flags */);
if(server->tcpStatus == CifsExiting) { if (server->tcpStatus == CifsExiting) {
break; break;
} else if (server->tcpStatus == CifsNeedReconnect) { } else if (server->tcpStatus == CifsNeedReconnect) {
cFYI(1,("Reconnect after server stopped responding")); cFYI(1, ("Reconnect after server stopped responding"));
cifs_reconnect(server); cifs_reconnect(server);
cFYI(1,("call to reconnect done")); cFYI(1, ("call to reconnect done"));
csocket = server->ssocket; csocket = server->ssocket;
continue; continue;
} else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
@ -417,15 +411,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
tcpStatus CifsNeedReconnect if server hung */ tcpStatus CifsNeedReconnect if server hung */
continue; continue;
} else if (length <= 0) { } else if (length <= 0) {
if(server->tcpStatus == CifsNew) { if (server->tcpStatus == CifsNew) {
cFYI(1,("tcp session abend after SMBnegprot")); cFYI(1, ("tcp session abend after SMBnegprot"));
/* some servers kill the TCP session rather than /* some servers kill the TCP session rather than
returning an SMB negprot error, in which returning an SMB negprot error, in which
case reconnecting here is not going to help, case reconnecting here is not going to help,
and so simply return error to mount */ and so simply return error to mount */
break; break;
} }
if(length == -EINTR) { if (!try_to_freeze() && (length == -EINTR)) {
cFYI(1,("cifsd thread killed")); cFYI(1,("cifsd thread killed"));
break; break;
} }
@ -585,9 +579,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
/* merge response - fix up 1st*/ /* merge response - fix up 1st*/
if(coalesce_t2(smb_buffer, if(coalesce_t2(smb_buffer,
mid_entry->resp_buf)) { mid_entry->resp_buf)) {
mid_entry->multiRsp = 1;
break; break;
} else { } else {
/* all parts received */ /* all parts received */
mid_entry->multiEnd = 1;
goto multi_t2_fnd; goto multi_t2_fnd;
} }
} else { } else {
@ -632,9 +628,14 @@ multi_t2_fnd:
wake_up_process(task_to_wake); wake_up_process(task_to_wake);
} else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
&& (isMultiRsp == 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, cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
sizeof(struct smb_hdr)); sizeof(struct smb_hdr));
#ifdef CONFIG_CIFS_DEBUG2
cifs_dump_detail(smb_buffer);
cifs_dump_mids(server);
#endif /* CIFS_DEBUG2 */
} }
} /* end while !EXITING */ } /* 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->retry default is 0 (i.e. "soft" limited retry not hard retry) */
vol->rw = TRUE; vol->rw = TRUE;
vol->ntlm = TRUE;
/* default is always to request posix paths. */ /* default is always to request posix paths. */
vol->posix_paths = 1; 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")); cERROR(1,("no security value specified"));
continue; continue;
} else if (strnicmp(value, "krb5i", 5) == 0) { } else if (strnicmp(value, "krb5i", 5) == 0) {
vol->sign = 1; vol->secFlg |= CIFSSEC_MAY_KRB5 |
vol->krb5 = 1; CIFSSEC_MUST_SIGN;
} else if (strnicmp(value, "krb5p", 5) == 0) { } else if (strnicmp(value, "krb5p", 5) == 0) {
/* vol->seal = 1; /* vol->secFlg |= CIFSSEC_MUST_SEAL |
vol->krb5 = 1; */ CIFSSEC_MAY_KRB5; */
cERROR(1,("Krb5 cifs privacy not supported")); cERROR(1,("Krb5 cifs privacy not supported"));
return 1; return 1;
} else if (strnicmp(value, "krb5", 4) == 0) { } else if (strnicmp(value, "krb5", 4) == 0) {
vol->krb5 = 1; vol->secFlg |= CIFSSEC_MAY_KRB5;
} else if (strnicmp(value, "ntlmv2i", 7) == 0) { } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
vol->ntlmv2 = 1; vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
vol->sign = 1; CIFSSEC_MUST_SIGN;
} else if (strnicmp(value, "ntlmv2", 6) == 0) { } else if (strnicmp(value, "ntlmv2", 6) == 0) {
vol->ntlmv2 = 1; vol->secFlg |= CIFSSEC_MAY_NTLMV2;
} else if (strnicmp(value, "ntlmi", 5) == 0) { } else if (strnicmp(value, "ntlmi", 5) == 0) {
vol->ntlm = 1; vol->secFlg |= CIFSSEC_MAY_NTLM |
vol->sign = 1; CIFSSEC_MUST_SIGN;
} else if (strnicmp(value, "ntlm", 4) == 0) { } else if (strnicmp(value, "ntlm", 4) == 0) {
/* ntlm is default so can be turned off too */ /* ntlm is default so can be turned off too */
vol->ntlm = 1; vol->secFlg |= CIFSSEC_MAY_NTLM;
} else if (strnicmp(value, "nontlm", 6) == 0) { } 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) { } else if (strnicmp(value, "none", 4) == 0) {
vol->nullauth = 1; vol->nullauth = 1;
} else { } else {
cERROR(1,("bad security option: %s", value)); cERROR(1,("bad security option: %s", value));
return 1; 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 /* BB are there cases in which a comma can be valid in
a domain name and need special handling? */ a domain name and need special handling? */
if (strnlen(value, 65) < 65) { if (strnlen(value, 256) < 256) {
vol->domainname = value; vol->domainname = value;
cFYI(1, ("Domain name set")); cFYI(1, ("Domain name set"));
} else { } else {
@ -1168,6 +1173,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->no_psx_acl = 0; vol->no_psx_acl = 0;
} else if (strnicmp(data, "noacl",5) == 0) { } else if (strnicmp(data, "noacl",5) == 0) {
vol->no_psx_acl = 1; 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) { } else if (strnicmp(data, "direct",6) == 0) {
vol->direct_io = 1; vol->direct_io = 1;
} else if (strnicmp(data, "forcedirectio",13) == 0) { } 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) if (volume_info.username)
strncpy(pSesInfo->userName, strncpy(pSesInfo->userName,
volume_info.username,MAX_USERNAME_SIZE); volume_info.username,MAX_USERNAME_SIZE);
if (volume_info.domainname) if (volume_info.domainname) {
strncpy(pSesInfo->domainName, int len = strlen(volume_info.domainname);
volume_info.domainname,MAX_USERNAME_SIZE); pSesInfo->domainName =
kmalloc(len + 1, GFP_KERNEL);
if(pSesInfo->domainName)
strcpy(pSesInfo->domainName,
volume_info.domainname);
}
pSesInfo->linux_uid = volume_info.linux_uid; pSesInfo->linux_uid = volume_info.linux_uid;
pSesInfo->overrideSecFlg = volume_info.secFlg;
down(&pSesInfo->sesSem); down(&pSesInfo->sesSem);
/* BB FIXME need to pass vol->secFlgs BB */
rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
up(&pSesInfo->sesSem); up(&pSesInfo->sesSem);
if(!rc) if(!rc)
@ -1980,7 +1996,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
static int static int
CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, 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) const struct nls_table *nls_codepage)
{ {
struct smb_hdr *smb_buffer; 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.Capabilities = cpu_to_le32(capabilities);
pSMB->req_no_secext.CaseInsensitivePasswordLength = pSMB->req_no_secext.CaseInsensitivePasswordLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE); cpu_to_le16(CIFS_SESS_KEY_SIZE);
pSMB->req_no_secext.CaseSensitivePasswordLength = pSMB->req_no_secext.CaseSensitivePasswordLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE); cpu_to_le16(CIFS_SESS_KEY_SIZE);
bcc_ptr = pByteArea(smb_buffer); bcc_ptr = pByteArea(smb_buffer);
memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE; bcc_ptr += CIFS_SESS_KEY_SIZE;
memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE; bcc_ptr += CIFS_SESS_KEY_SIZE;
if (ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
@ -2054,7 +2070,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr++; bcc_ptr++;
} }
if(user == NULL) if(user == NULL)
bytes_returned = 0; /* skill null user */ bytes_returned = 0; /* skip null user */
else else
bytes_returned = bytes_returned =
cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
@ -2162,8 +2178,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if (remaining_words > 0) { if (remaining_words > 0) {
len = UniStrnlen((wchar_t *)bcc_ptr, len = UniStrnlen((wchar_t *)bcc_ptr,
remaining_words-1); remaining_words-1);
if(ses->serverNOS) kfree(ses->serverNOS);
kfree(ses->serverNOS);
ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL); ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
if(ses->serverNOS == NULL) if(ses->serverNOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
@ -2203,12 +2218,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
/* if these kcallocs fail not much we /* if these kcallocs fail not much we
can do, but better to not fail the can do, but better to not fail the
sesssetup itself */ sesssetup itself */
if(ses->serverDomain) kfree(ses->serverDomain);
kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(2, GFP_KERNEL); kzalloc(2, GFP_KERNEL);
if(ses->serverNOS) kfree(ses->serverNOS);
kfree(ses->serverNOS);
ses->serverNOS = ses->serverNOS =
kzalloc(2, GFP_KERNEL); kzalloc(2, GFP_KERNEL);
} }
@ -2217,8 +2230,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if (((long) bcc_ptr + len) - (long) if (((long) bcc_ptr + len) - (long)
pByteArea(smb_buffer_response) pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) { <= BCC(smb_buffer_response)) {
if(ses->serverOS) kfree(ses->serverOS);
kfree(ses->serverOS);
ses->serverOS = kzalloc(len + 1,GFP_KERNEL); ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
if(ses->serverOS == NULL) if(ses->serverOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
@ -2229,8 +2241,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr++; bcc_ptr++;
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
if(ses->serverNOS) kfree(ses->serverNOS);
kfree(ses->serverNOS);
ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
if(ses->serverNOS == NULL) if(ses->serverNOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
@ -2273,292 +2284,6 @@ sesssetup_nomem: /* do not return an error on nomem for the info strings,
return rc; 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 static int
CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
struct cifsSesInfo *ses, int * pNTLMv2_flag, struct cifsSesInfo *ses, int * pNTLMv2_flag,
@ -2635,8 +2360,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
/* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
if(sign_CIFS_PDUs) if(sign_CIFS_PDUs)
negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
if(ntlmv2_support) /* if(ntlmv2_support)
negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
/* setup pointers to domain name and workstation name */ /* setup pointers to domain name and workstation name */
bcc_ptr += SecurityBlobLength; bcc_ptr += SecurityBlobLength;
@ -2783,8 +2508,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
bcc_ptr, bcc_ptr,
remaining_words remaining_words
- 1); - 1);
if(ses->serverNOS) kfree(ses->serverNOS);
kfree(ses->serverNOS);
ses->serverNOS = ses->serverNOS =
kzalloc(2 * (len + 1), kzalloc(2 * (len + 1),
GFP_KERNEL); GFP_KERNEL);
@ -2802,8 +2526,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
if (remaining_words > 0) { if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */ /* 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 = ses->serverDomain =
kzalloc(2 * kzalloc(2 *
(len + (len +
@ -2822,19 +2545,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
= 0; = 0;
} /* else no more room so create dummy domain string */ } /* else no more room so create dummy domain string */
else { else {
if(ses->serverDomain) kfree(ses->serverDomain);
kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(2, kzalloc(2,
GFP_KERNEL); GFP_KERNEL);
} }
} else { /* no room so create dummy domain and NOS string */ } else { /* no room so create dummy domain and NOS string */
if(ses->serverDomain); kfree(ses->serverDomain);
kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(2, GFP_KERNEL); kzalloc(2, GFP_KERNEL);
if(ses->serverNOS) kfree(ses->serverNOS);
kfree(ses->serverNOS);
ses->serverNOS = ses->serverNOS =
kzalloc(2, GFP_KERNEL); kzalloc(2, GFP_KERNEL);
} }
@ -2856,8 +2576,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
bcc_ptr++; bcc_ptr++;
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
if(ses->serverNOS) kfree(ses->serverNOS);
kfree(ses->serverNOS);
ses->serverNOS = ses->serverNOS =
kzalloc(len + 1, kzalloc(len + 1,
GFP_KERNEL); GFP_KERNEL);
@ -2867,8 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
bcc_ptr++; bcc_ptr++;
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
if(ses->serverDomain) kfree(ses->serverDomain);
kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(len + 1, kzalloc(len + 1,
GFP_KERNEL); GFP_KERNEL);
@ -2994,14 +2712,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
SecurityBlob->LmChallengeResponse.Buffer = 0; SecurityBlob->LmChallengeResponse.Buffer = 0;
SecurityBlob->NtChallengeResponse.Length = SecurityBlob->NtChallengeResponse.Length =
cpu_to_le16(CIFS_SESSION_KEY_SIZE); cpu_to_le16(CIFS_SESS_KEY_SIZE);
SecurityBlob->NtChallengeResponse.MaximumLength = SecurityBlob->NtChallengeResponse.MaximumLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE); cpu_to_le16(CIFS_SESS_KEY_SIZE);
memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE); memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
SecurityBlob->NtChallengeResponse.Buffer = SecurityBlob->NtChallengeResponse.Buffer =
cpu_to_le32(SecurityBlobLength); cpu_to_le32(SecurityBlobLength);
SecurityBlobLength += CIFS_SESSION_KEY_SIZE; SecurityBlobLength += CIFS_SESS_KEY_SIZE;
bcc_ptr += CIFS_SESSION_KEY_SIZE; bcc_ptr += CIFS_SESS_KEY_SIZE;
if (ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
if (domain == NULL) { if (domain == NULL) {
@ -3190,8 +2908,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr, bcc_ptr,
remaining_words remaining_words
- 1); - 1);
if(ses->serverNOS) kfree(ses->serverNOS);
kfree(ses->serverNOS);
ses->serverNOS = ses->serverNOS =
kzalloc(2 * (len + 1), kzalloc(2 * (len + 1),
GFP_KERNEL); GFP_KERNEL);
@ -3244,8 +2961,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if(ses->serverDomain) if(ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = kzalloc(2, GFP_KERNEL); ses->serverDomain = kzalloc(2, GFP_KERNEL);
if(ses->serverNOS) kfree(ses->serverNOS);
kfree(ses->serverNOS);
ses->serverNOS = kzalloc(2, GFP_KERNEL); ses->serverNOS = kzalloc(2, GFP_KERNEL);
} }
} else { /* ASCII */ } else { /* ASCII */
@ -3263,8 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr++; bcc_ptr++;
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
if(ses->serverNOS) kfree(ses->serverNOS);
kfree(ses->serverNOS);
ses->serverNOS = kzalloc(len+1,GFP_KERNEL); ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
strncpy(ses->serverNOS, bcc_ptr, len); strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
@ -3340,22 +3055,33 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr = &pSMB->Password[0]; bcc_ptr = &pSMB->Password[0];
if((ses->server->secMode) & SECMODE_USER) { if((ses->server->secMode) & SECMODE_USER) {
pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
*bcc_ptr = 0; /* password is null byte */
bcc_ptr++; /* skip password */ bcc_ptr++; /* skip password */
/* already aligned so no need to do it below */
} else { } 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 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
specified as required (when that support is added to specified as required (when that support is added to
the vfs in the future) as only NTLM or the much 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 by Samba (not sure whether other servers allow
NTLMv2 password here) */ 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, SMBNTencrypt(ses->password,
ses->server->cryptKey, ses->server->cryptKey,
bcc_ptr); bcc_ptr);
bcc_ptr += CIFS_SESSION_KEY_SIZE; bcc_ptr += CIFS_SESS_KEY_SIZE;
*bcc_ptr = 0; if(ses->capabilities & CAP_UNICODE) {
bcc_ptr++; /* align */ /* must align unicode strings */
*bcc_ptr = 0; /* null byte password */
bcc_ptr++;
}
} }
if(ses->server->secMode & if(ses->server->secMode &
@ -3429,7 +3155,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
} }
/* else do not bother copying these informational fields */ /* 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)); cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
} else if ((rc == 0) && tcon == NULL) { } else if ((rc == 0) && tcon == NULL) {
/* all we need to save for IPC$ connection */ /* 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) struct nls_table * nls_info)
{ {
int rc = 0; int rc = 0;
char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; char ntlm_session_key[CIFS_SESS_KEY_SIZE];
int ntlmv2_flag = FALSE; int ntlmv2_flag = FALSE;
int first_time = 0; int first_time = 0;
@ -3526,20 +3255,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
pSesInfo->server->secMode, pSesInfo->server->secMode,
pSesInfo->server->capabilities, pSesInfo->server->capabilities,
pSesInfo->server->timeZone)); pSesInfo->server->timeZone));
#ifdef CONFIG_CIFS_EXPERIMENTAL if(experimEnabled < 2)
if(experimEnabled > 1) rc = CIFS_SessSetup(xid, pSesInfo,
rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */, first_time, nls_info);
&ntlmv2_flag, nls_info); else if (extended_security
else
#endif
if (extended_security
&& (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
&& (pSesInfo->server->secType == NTLMSSP)) { && (pSesInfo->server->secType == NTLMSSP)) {
cFYI(1, ("New style sesssetup")); rc = -EOPNOTSUPP;
rc = CIFSSpnegoSessSetup(xid, pSesInfo,
NULL /* security blob */,
0 /* blob length */,
nls_info);
} else if (extended_security } else if (extended_security
&& (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
&& (pSesInfo->server->secType == RawNTLMSSP)) { && (pSesInfo->server->secType == RawNTLMSSP)) {

Просмотреть файл

@ -113,7 +113,7 @@ cifs_bp_rename_retry:
full_path[namelen+2] = 0; full_path[namelen+2] = 0;
BB remove above eight lines BB */ 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 int
cifs_create(struct inode *inode, struct dentry *direntry, int mode, 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); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, desiredAccess, CREATE_NOT_DIR,
&fileHandle, &oplock, buf, cifs_sb->local_nls, &fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 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) { if(rc == -EIO) {
/* old server, retry the open legacy style */ /* old server, retry the open legacy style */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, 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); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
if (rc) { if (rc) {
cFYI(1, ("cifs_create returned 0x%x ", rc)); cFYI(1, ("cifs_create returned 0x%x", rc));
} else { } else {
/* If Open reported that we actually created a file /* If Open reported that we actually created a file
then we now have to set the mode if possible */ 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_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); 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) { if(!rc) {
/* BB Do not bother to decode buf since no /* BB Do not bother to decode buf since no
local inode yet to put timestamps in, 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) { if(full_path == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
} else { } 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, rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
GENERIC_READ | SYNCHRONIZE, 0 /* create options */, GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
&netfid, &oplock,NULL, cifs_sb->local_nls, &netfid, &oplock,NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
/* BB fixme - add this handle to a notify handle list */ /* BB fixme - add this handle to a notify handle list */
if(rc) { if(rc) {
cERROR(1,("Could not open directory for notify")); /* BB remove BB */ cFYI(1,("Could not open directory for notify"));
} else { } else {
filter = convert_to_cifs_notify_flags(arg); filter = convert_to_cifs_notify_flags(arg);
if(filter != 0) { if(filter != 0) {

Просмотреть файл

@ -110,7 +110,6 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
&pCifsInode->openFileList); &pCifsInode->openFileList);
} }
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
write_unlock(&file->f_owner.lock);
if (pCifsInode->clientCanCacheRead) { if (pCifsInode->clientCanCacheRead) {
/* we have the inode open somewhere else /* we have the inode open somewhere else
no need to discard cache data */ no need to discard cache data */
@ -201,7 +200,7 @@ int cifs_open(struct inode *inode, struct file *file)
} else { } else {
if (file->f_flags & O_EXCL) if (file->f_flags & O_EXCL)
cERROR(1, ("could not find file instance for " 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; rc = -ENOMEM;
goto out; 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_sb->local_nls, cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR); & CIFS_MOUNT_MAP_SPECIAL_CHR);
else
rc = -EIO; /* no NT SMB support fall into legacy open below */
if (rc == -EIO) { if (rc == -EIO) {
/* Old server, try legacy style OpenX */ /* Old server, try legacy style OpenX */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, 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); & CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
if (rc) { if (rc) {
cFYI(1, ("cifs_open returned 0x%x ", rc)); cFYI(1, ("cifs_open returned 0x%x", rc));
goto out; goto out;
} }
file->private_data = file->private_data =
@ -282,7 +286,6 @@ int cifs_open(struct inode *inode, struct file *file)
goto out; goto out;
} }
pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
write_lock(&file->f_owner.lock);
write_lock(&GlobalSMBSeslock); write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist, &pTcon->openFileList); list_add(&pCifsFile->tlist, &pTcon->openFileList);
@ -293,7 +296,6 @@ int cifs_open(struct inode *inode, struct file *file)
&oplock, buf, full_path, xid); &oplock, buf, full_path, xid);
} else { } else {
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
write_unlock(&file->f_owner.lock);
} }
if (oplock & CIFS_CREATE_ACTION) { 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); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) { if (rc) {
up(&pCifsFile->fh_sem); up(&pCifsFile->fh_sem);
cFYI(1, ("cifs_open returned 0x%x ", rc)); cFYI(1, ("cifs_open returned 0x%x", rc));
cFYI(1, ("oplock: %d ", oplock)); cFYI(1, ("oplock: %d", oplock));
} else { } else {
pCifsFile->netfid = netfid; pCifsFile->netfid = netfid;
pCifsFile->invalidHandle = FALSE; pCifsFile->invalidHandle = FALSE;
@ -472,7 +474,6 @@ int cifs_close(struct inode *inode, struct file *file)
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if (pSMBFile) { if (pSMBFile) {
pSMBFile->closePend = TRUE; pSMBFile->closePend = TRUE;
write_lock(&file->f_owner.lock);
if (pTcon) { if (pTcon) {
/* no sense reconnecting to close a file that is /* no sense reconnecting to close a file that is
already closed */ already closed */
@ -487,23 +488,18 @@ int cifs_close(struct inode *inode, struct file *file)
the struct would be in each open file, the struct would be in each open file,
but this should give enough time to but this should give enough time to
clear the socket */ clear the socket */
write_unlock(&file->f_owner.lock);
cERROR(1,("close with pending writes")); cERROR(1,("close with pending writes"));
msleep(timeout); msleep(timeout);
write_lock(&file->f_owner.lock);
timeout *= 4; timeout *= 4;
} }
write_unlock(&file->f_owner.lock);
rc = CIFSSMBClose(xid, pTcon, rc = CIFSSMBClose(xid, pTcon,
pSMBFile->netfid); pSMBFile->netfid);
write_lock(&file->f_owner.lock);
} }
} }
write_lock(&GlobalSMBSeslock); write_lock(&GlobalSMBSeslock);
list_del(&pSMBFile->flist); list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist); list_del(&pSMBFile->tlist);
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
write_unlock(&file->f_owner.lock);
kfree(pSMBFile->search_resume_name); kfree(pSMBFile->search_resume_name);
kfree(file->private_data); kfree(file->private_data);
file->private_data = NULL; file->private_data = NULL;
@ -531,7 +527,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
(struct cifsFileInfo *)file->private_data; (struct cifsFileInfo *)file->private_data;
char *ptmp; char *ptmp;
cFYI(1, ("Closedir inode = 0x%p with ", inode)); cFYI(1, ("Closedir inode = 0x%p", inode));
xid = GetXid(); xid = GetXid();
@ -605,7 +601,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
} }
if (pfLock->fl_flags & FL_ACCESS) if (pfLock->fl_flags & FL_ACCESS)
cFYI(1, ("Process suspended by mandatory locking - " cFYI(1, ("Process suspended by mandatory locking - "
"not implemented yet ")); "not implemented yet"));
if (pfLock->fl_flags & FL_LEASE) if (pfLock->fl_flags & FL_LEASE)
cFYI(1, ("Lease on file - not implemented yet")); cFYI(1, ("Lease on file - not implemented yet"));
if (pfLock->fl_flags & if (pfLock->fl_flags &
@ -1375,7 +1371,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
xid = GetXid(); 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)); dentry->d_name.name, datasync));
rc = filemap_fdatawrite(inode->i_mapping); 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 /* fill in rpages then
result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ 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 0
if (rc < 0) if (rc < 0)
@ -1836,7 +1832,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
if (rc < 0) if (rc < 0)
goto io_error; goto io_error;
else else
cFYI(1, ("Bytes read %d ",rc)); cFYI(1, ("Bytes read %d",rc));
file->f_dentry->d_inode->i_atime = file->f_dentry->d_inode->i_atime =
current_fs_time(file->f_dentry->d_inode->i_sb); 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, */ /* .sync_page = cifs_sync_page, */
/* .direct_IO = */ /* .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; char *tmp_path;
pTcon = cifs_sb->tcon; 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 */ /* could have done a find first instead but this returns more info */
rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
inode = *pinode; inode = *pinode;
cifsInfo = CIFS_I(inode); cifsInfo = CIFS_I(inode);
cFYI(1, ("Old time %ld ", cifsInfo->time)); cFYI(1, ("Old time %ld", cifsInfo->time));
cifsInfo->time = jiffies; 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 */ /* this is ok to set on every inode revalidate */
atomic_set(&cifsInfo->inUse,1); 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 */ else /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops; inode->i_fop = &cifs_file_ops;
inode->i_data.a_ops = &cifs_addr_ops;
/* check if server can support readpages */ /* check if server can support readpages */
if(pTcon->ses->server->maxBuf < if(pTcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE) PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops->readpages = NULL; 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)) { } else if (S_ISDIR(inode->i_mode)) {
cFYI(1, ("Directory inode")); cFYI(1, ("Directory inode"));
inode->i_op = &cifs_dir_inode_ops; inode->i_op = &cifs_dir_inode_ops;
@ -421,23 +422,23 @@ int cifs_get_inode_info(struct inode **pinode,
inode = *pinode; inode = *pinode;
cifsInfo = CIFS_I(inode); cifsInfo = CIFS_I(inode);
cifsInfo->cifsAttrs = attr; cifsInfo->cifsAttrs = attr;
cFYI(1, ("Old time %ld ", cifsInfo->time)); cFYI(1, ("Old time %ld", cifsInfo->time));
cifsInfo->time = jiffies; 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 needs to be multiple of two. So safer to default to
blksize and blkbits set in superblock so 2**blkbits and blksize blksize and blkbits set in superblock so 2**blkbits and blksize
will match rather than setting to: will match rather than setting to:
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ (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 = inode->i_atime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
inode->i_mtime = inode->i_mtime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
inode->i_ctime = inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); 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 */ /* set default mode. will override for dirs below */
if (atomic_read(&cifsInfo->inUse) == 0) 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 */ else /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops; inode->i_fop = &cifs_file_ops;
inode->i_data.a_ops = &cifs_addr_ops;
if(pTcon->ses->server->maxBuf < if(pTcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE) PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops->readpages = NULL; 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)) { } else if (S_ISDIR(inode->i_mode)) {
cFYI(1, ("Directory inode")); cFYI(1, ("Directory inode"));
inode->i_op = &cifs_dir_inode_ops; 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, rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) { if (rc) {
cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); cFYI(1, ("cifs_mkdir returned 0x%x", rc));
d_drop(direntry); d_drop(direntry);
} else { } else {
inode->i_nlink++; inode->i_nlink++;
@ -798,7 +800,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
char *full_path = NULL; char *full_path = NULL;
struct cifsInodeInfo *cifsInode; struct cifsInodeInfo *cifsInode;
cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode)); cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
xid = GetXid(); xid = GetXid();
@ -1121,7 +1123,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
xid = GetXid(); 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)); direntry->d_name.name, attrs->ia_valid));
cifs_sb = CIFS_SB(direntry->d_inode->i_sb); 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 when the local oplock break takes longer to flush
writebehind data than the SMB timeout for the SetPathInfo writebehind data than the SMB timeout for the SetPathInfo
request would allow */ request would allow */
open_file = find_writable_file(cifsInode); open_file = find_writable_file(cifsInode);
if (open_file) { if (open_file) {
__u16 nfid = open_file->netfid; __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 it may be useful to Windows - but we do
not want to set ctime unless some other not want to set ctime unless some other
timestamp is changing */ timestamp is changing */
cFYI(1, ("CIFS - CTIME changed ")); cFYI(1, ("CIFS - CTIME changed"));
time_buf.ChangeTime = time_buf.ChangeTime =
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
} else } else
@ -1356,7 +1359,7 @@ cifs_setattr_exit:
void cifs_delete_inode(struct inode *inode) 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 /* may have to add back in if and when safe distributed caching of
directories added e.g. via FindNotify */ directories added e.g. via FindNotify */
} }

Просмотреть файл

@ -167,7 +167,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
return -ENOMEM; return -ENOMEM;
} }
cFYI(1, ("Full path: %s ", full_path)); cFYI(1, ("Full path: %s", full_path));
cFYI(1, ("symname is %s", symname)); cFYI(1, ("symname is %s", symname));
/* BB what if DFS and this volume is on different share? BB */ /* 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); inode->i_sb,xid);
if (rc != 0) { if (rc != 0) {
cFYI(1, cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
("Create symlink worked but get_inode_info failed with rc = %d ",
rc)); rc));
} else { } else {
if (pTcon->nocase) if (pTcon->nocase)
@ -289,7 +288,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
else { else {
cFYI(1,("num referral: %d",num_referrals)); cFYI(1,("num referral: %d",num_referrals));
if(referrals) { if(referrals) {
cFYI(1,("referral string: %s ",referrals)); cFYI(1,("referral string: %s",referrals));
strncpy(tmpbuffer, referrals, len-1); strncpy(tmpbuffer, referrals, len-1);
} }
} }

Просмотреть файл

@ -101,6 +101,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
kfree(buf_to_free->serverDomain); kfree(buf_to_free->serverDomain);
kfree(buf_to_free->serverNOS); kfree(buf_to_free->serverNOS);
kfree(buf_to_free->password); kfree(buf_to_free->password);
kfree(buf_to_free->domainName);
kfree(buf_to_free); 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)) { if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
data_offset = le32_to_cpu(pSMBr->DataOffset); data_offset = le32_to_cpu(pSMBr->DataOffset);
pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol pnotify = (struct file_notify_information *)
+ data_offset); ((char *)&pSMBr->hdr.Protocol + data_offset);
cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName, cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName,
pnotify->Action)); /* BB removeme BB */ 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; return TRUE;
} }
if(pSMBr->hdr.Status.CifsError) { 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[] = { static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
{ERRerror, -EIO}, {ERRerror, -EIO},
{ERRbadpw, -EPERM}, {ERRbadpw, -EACCES}, /* was EPERM */
{ERRbadtype, -EREMOTE}, {ERRbadtype, -EREMOTE},
{ERRaccess, -EACCES}, {ERRaccess, -EACCES},
{ERRinvtid, -ENXIO}, {ERRinvtid, -ENXIO},
{ERRinvnetname, -ENODEV}, {ERRinvnetname, -ENXIO},
{ERRinvdevice, -ENXIO}, {ERRinvdevice, -ENXIO},
{ERRqfull, -ENOSPC}, {ERRqfull, -ENOSPC},
{ERRqtoobig, -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 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include "cifspdu.h" #include "cifspdu.h"
@ -31,8 +32,8 @@
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
#include "cifsfs.h" #include "cifsfs.h"
/* BB fixme - add debug wrappers around this function to disable it fixme BB */ #ifdef CONFIG_CIFS_DEBUG2
/* static void dump_cifs_file_struct(struct file *file, char *label) static void dump_cifs_file_struct(struct file *file, char *label)
{ {
struct cifsFileInfo * cf; struct cifsFileInfo * cf;
@ -53,7 +54,8 @@
} }
} }
} */ }
#endif /* DEBUG2 */
/* Returns one if new inode created (which therefore needs to be hashed) */ /* 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 */ /* 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; return rc;
} }
static void fill_in_inode(struct inode *tmp_inode, static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode) char * buf, int *pobject_type, int isNewInode)
{ {
loff_t local_size; loff_t local_size;
struct timespec local_mtime; struct timespec local_mtime;
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
__u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); __u32 attr;
__u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); __u64 allocation_size;
__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); __u64 end_of_file;
cifsInfo->cifsAttrs = attr;
cifsInfo->time = jiffies;
/* save mtime and size */ /* save mtime and size */
local_mtime = tmp_inode->i_mtime; local_mtime = tmp_inode->i_mtime;
local_size = tmp_inode->i_size; 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 */ /* Linux can not store file creation time unfortunately so ignore it */
tmp_inode->i_atime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); cifsInfo->cifsAttrs = attr;
tmp_inode->i_mtime = cifsInfo->time = jiffies;
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
tmp_inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
/* treat dos attribute of read-only as read-only mode bit e.g. 555? */ /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
/* 2767 perms - indicate mandatory locking */ /* 2767 perms - indicate mandatory locking */
/* BB fill in uid and gid here? with help from winbind? /* 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 else
tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_fop = &cifs_file_ops;
tmp_inode->i_data.a_ops = &cifs_addr_ops;
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf < (cifs_sb->tcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE)) PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops->readpages = NULL; tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
tmp_inode->i_data.a_ops = &cifs_addr_ops;
if(isNewInode) if(isNewInode)
return; /* No sense invalidating pages for new inode return; /* No sense invalidating pages for new inode
since have not started caching readahead file since have not started caching readahead file
@ -338,11 +362,12 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
else else
tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_fop = &cifs_file_ops;
tmp_inode->i_data.a_ops = &cifs_addr_ops;
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf < (cifs_sb->tcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE)) PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops->readpages = NULL; tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
tmp_inode->i_data.a_ops = &cifs_addr_ops;
if(isNewInode) if(isNewInode)
return; /* No sense invalidating pages for new inode since we 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: ffirst_retry:
/* test for Unix extensions */ /* test for Unix extensions */
if (pTcon->ses->capabilities & CAP_UNIX) { 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) { } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
} else /* not srvinos - BB fixme add check for backlevel? */ { } else /* not srvinos - BB fixme add check for backlevel? */ {
@ -451,12 +479,19 @@ static int cifs_unicode_bytelen(char *str)
return len << 1; 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; char * new_entry;
FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_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)); cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
/* validate that new_entry is not past end of SMB */ /* validate that new_entry is not past end of SMB */
if(new_entry >= 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", ("search entry %p began after end of SMB %p old entry %p",
new_entry, end_of_smb, old_entry)); new_entry, end_of_smb, old_entry));
return NULL; 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", cERROR(1,("search entry %p extends after end of SMB %p",
new_entry, end_of_smb)); new_entry, end_of_smb));
return NULL; return NULL;
@ -482,7 +520,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
char * filename = NULL; char * filename = NULL;
int len = 0; 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; FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
if(cfile->srch_inf.unicode) { 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? */ /* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, 5); 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 * pFindData =
(FILE_DIRECTORY_INFO *)current_entry; (FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); 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 * pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry; (FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); 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 * pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry; (SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); 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 * pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry; (FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); 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 { } else {
cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); 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 . and .. for the root of a drive and for those we need
to start two entries earlier */ 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) && if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
is_dir_changed(file)) || is_dir_changed(file)) ||
(index_to_find < first_entry_in_buffer)) { (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 first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
- cifsFile->srch_inf.entries_in_buffer; - cifsFile->srch_inf.entries_in_buffer;
pos_in_buf = index_to_find - first_entry_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++) { for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
/* go entry by entry figuring out which is first */ /* 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)) { if((current_entry == NULL) && (i < pos_in_buf)) {
/* BB fixme - check if we should flag this error */ /* 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 */ /* inode num, inode type and filename returned */
static int cifs_get_name_from_search_buf(struct qstr *pqst, static int cifs_get_name_from_search_buf(struct qstr *pqst,
char *current_entry, __u16 level, unsigned int unicode, 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; int rc = 0;
unsigned int len = 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; (FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); 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 { } else {
cFYI(1,("Unknown findfirst level %d",level)); cFYI(1,("Unknown findfirst level %d",level));
return -EINVAL; return -EINVAL;
} }
if(len > max_len) {
cERROR(1,("bad search response length %d past smb end", len));
return -EINVAL;
}
if(unicode) { if(unicode) {
/* BB fixme - test with long names */ /* BB fixme - test with long names */
/* Note converted filename can be longer than in unicode */ /* 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, 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; int rc = 0;
struct qstr qstring; 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, rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
pCifsF->srch_inf.info_level, pCifsF->srch_inf.info_level,
pCifsF->srch_inf.unicode,cifs_sb, pCifsF->srch_inf.unicode,cifs_sb,
max_len,
&inum /* returned */); &inum /* returned */);
if(rc) 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, /* we pass in rc below, indicating whether it is a new inode,
so we can figure out whether to invalidate the inode cached so we can figure out whether to invalidate the inode cached
data if the file has changed */ 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, unix_fill_in_inode(tmp_inode,
(FILE_UNIX_INFO *)pfindEntry,&obj_type, rc); (FILE_UNIX_INFO *)pfindEntry,
} else { &obj_type, rc);
fill_in_inode(tmp_inode, else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); 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, rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
tmp_inode->i_ino,obj_type); tmp_inode->i_ino,obj_type);
@ -864,6 +930,12 @@ static int cifs_save_resume_key(const char *current_entry,
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex; 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 { } else {
cFYI(1,("Unknown findfirst level %d",level)); cFYI(1,("Unknown findfirst level %d",level));
return -EINVAL; return -EINVAL;
@ -884,6 +956,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
int num_to_fill = 0; int num_to_fill = 0;
char * tmp_buf = NULL; char * tmp_buf = NULL;
char * end_of_smb; char * end_of_smb;
int max_len;
xid = GetXid(); xid = GetXid();
@ -909,7 +982,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
case 1: case 1:
if (filldir(direntry, "..", 2, file->f_pos, if (filldir(direntry, "..", 2, file->f_pos,
file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { 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; rc = -ENOMEM;
break; break;
} }
@ -959,10 +1032,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
goto rddir2_exit; goto rddir2_exit;
} }
cFYI(1,("loop through %d times filling dir for net buf %p", cFYI(1,("loop through %d times filling dir for net buf %p",
num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len = smbCalcSize((struct smb_hdr *)
smbCalcSize((struct smb_hdr *) cifsFile->srch_inf.ntwrk_buf_start);
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 /* To be safe - for UCS to UTF-8 with strings loaded
with the rare long characters alloc more to account for with the rare long characters alloc more to account for
such multibyte target UTF-8 characters. cifs_unicode.c, 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 /* if buggy server returns . and .. late do
we want to check for that here? */ we want to check for that here? */
rc = cifs_filldir(current_entry, file, rc = cifs_filldir(current_entry, file,
filldir, direntry,tmp_buf); filldir, direntry, tmp_buf, max_len);
file->f_pos++; 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", 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); cifs_save_resume_key(current_entry,cifsFile);
break; break;
} else } else
current_entry = nxt_dir_entry(current_entry, current_entry =
end_of_smb); nxt_dir_entry(current_entry, end_of_smb,
cifsFile->srch_inf.info_level);
} }
kfree(tmp_buf); kfree(tmp_buf);
break; break;

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 <linux/random.h>
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "cifspdu.h" #include "cifspdu.h"
#include "cifsglob.h"
#include "md5.h" #include "md5.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifsencrypt.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) { if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
up(&ses->server->tcpSem); up(&ses->server->tcpSem);
cERROR(1, cERROR(1, ("Illegal length, greater than maximum frame, %d",
("Illegal length, greater than maximum frame, %d ",
in_buf->smb_buf_length)); in_buf->smb_buf_length));
DeleteMidQEntry(midQ); DeleteMidQEntry(midQ);
/* If not lock req, update # of requests on wire to server */ /* If not lock req, update # of requests on wire to server */