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:
Коммит
f17a2686b1
40
fs/Kconfig
40
fs/Kconfig
|
@ -1722,7 +1722,7 @@ config CIFS_STATS
|
||||||
mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
|
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 */
|
||||||
|
|
|
@ -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 {
|
server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
|
||||||
rc = decode_negTokenInit(pSMBr->u.
|
|
||||||
extended_response.
|
/* BB get server time for time conversions and add
|
||||||
SecurityBlob,
|
code to use it and timezone since this is not UTC */
|
||||||
count - 16,
|
|
||||||
&server->secType);
|
if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
|
||||||
if(rc == 1) {
|
memcpy(server->cryptKey, rsp->EncryptionKey,
|
||||||
/* BB Need to fill struct for sessetup here */
|
CIFS_CRYPTO_KEY_SIZE);
|
||||||
rc = -EOPNOTSUPP;
|
} else if (server->secMode & SECMODE_PW_ENCRYPT) {
|
||||||
} else {
|
rc = -EIO; /* need cryptkey unless plain text */
|
||||||
rc = -EINVAL;
|
goto neg_err_exit;
|
||||||
}
|
|
||||||
}
|
|
||||||
} 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,28 +915,33 @@ 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 {
|
||||||
|
@ -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
|
||||||
|
@ -416,6 +441,9 @@ 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)) {
|
||||||
|
@ -645,9 +693,11 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
|
||||||
- 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;
|
||||||
}
|
}
|
||||||
|
@ -960,9 +1033,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
||||||
}
|
}
|
||||||
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,
|
||||||
|
@ -978,16 +1052,18 @@ 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;
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче