diff options
| -rw-r--r-- | fs/Kconfig | 40 | ||||
| -rw-r--r-- | fs/cifs/CHANGES | 17 | ||||
| -rw-r--r-- | fs/cifs/Makefile | 2 | ||||
| -rw-r--r-- | fs/cifs/README | 39 | ||||
| -rw-r--r-- | fs/cifs/asn1.c | 10 | ||||
| -rw-r--r-- | fs/cifs/cifs_debug.c | 134 | ||||
| -rw-r--r-- | fs/cifs/cifs_debug.h | 4 | ||||
| -rw-r--r-- | fs/cifs/cifs_unicode.c | 1 | ||||
| -rw-r--r-- | fs/cifs/cifsencrypt.c | 140 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 6 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 3 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 71 | ||||
| -rw-r--r-- | fs/cifs/cifspdu.h | 98 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 14 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 287 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 498 | ||||
| -rw-r--r-- | fs/cifs/dir.c | 15 | ||||
| -rw-r--r-- | fs/cifs/fcntl.c | 4 | ||||
| -rw-r--r-- | fs/cifs/file.c | 52 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 39 | ||||
| -rw-r--r-- | fs/cifs/link.c | 7 | ||||
| -rw-r--r-- | fs/cifs/misc.c | 10 | ||||
| -rw-r--r-- | fs/cifs/netmisc.c | 4 | ||||
| -rw-r--r-- | fs/cifs/ntlmssp.c | 143 | ||||
| -rw-r--r-- | fs/cifs/readdir.c | 184 | ||||
| -rw-r--r-- | fs/cifs/sess.c | 538 | ||||
| -rw-r--r-- | fs/cifs/smbencrypt.c | 1 | ||||
| -rw-r--r-- | fs/cifs/transport.c | 3 |
28 files changed, 1541 insertions, 823 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 6c5051802bd2..00aa3d5c5a83 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
| @@ -1722,7 +1722,7 @@ config CIFS_STATS | |||
| 1722 | mounted by the cifs client to be displayed in /proc/fs/cifs/Stats | 1722 | mounted by the cifs client to be displayed in /proc/fs/cifs/Stats |
| 1723 | 1723 | ||
| 1724 | config CIFS_STATS2 | 1724 | config CIFS_STATS2 |
| 1725 | bool "CIFS extended statistics" | 1725 | bool "Extended statistics" |
| 1726 | depends on CIFS_STATS | 1726 | depends on CIFS_STATS |
| 1727 | help | 1727 | help |
| 1728 | Enabling this option will allow more detailed statistics on SMB | 1728 | Enabling this option will allow more detailed statistics on SMB |
| @@ -1735,6 +1735,32 @@ config CIFS_STATS2 | |||
| 1735 | Unless you are a developer or are doing network performance analysis | 1735 | Unless you are a developer or are doing network performance analysis |
| 1736 | or tuning, say N. | 1736 | or tuning, say N. |
| 1737 | 1737 | ||
| 1738 | config CIFS_WEAK_PW_HASH | ||
| 1739 | bool "Support legacy servers which use weaker LANMAN security" | ||
| 1740 | depends on CIFS | ||
| 1741 | help | ||
| 1742 | Modern CIFS servers including Samba and most Windows versions | ||
| 1743 | (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos) | ||
| 1744 | security mechanisms. These hash the password more securely | ||
| 1745 | than the mechanisms used in the older LANMAN version of the | ||
| 1746 | SMB protocol needed to establish sessions with old SMB servers. | ||
| 1747 | |||
| 1748 | Enabling this option allows the cifs module to mount to older | ||
| 1749 | LANMAN based servers such as OS/2 and Windows 95, but such | ||
| 1750 | mounts may be less secure than mounts using NTLM or more recent | ||
| 1751 | security mechanisms if you are on a public network. Unless you | ||
| 1752 | have a need to access old SMB servers (and are on a private | ||
| 1753 | network) you probably want to say N. Even if this support | ||
| 1754 | is enabled in the kernel build, they will not be used | ||
| 1755 | automatically. At runtime LANMAN mounts are disabled but | ||
| 1756 | can be set to required (or optional) either in | ||
| 1757 | /proc/fs/cifs (see fs/cifs/README for more detail) or via an | ||
| 1758 | option on the mount command. This support is disabled by | ||
| 1759 | default in order to reduce the possibility of a downgrade | ||
| 1760 | attack. | ||
| 1761 | |||
| 1762 | If unsure, say N. | ||
| 1763 | |||
| 1738 | config CIFS_XATTR | 1764 | config CIFS_XATTR |
| 1739 | bool "CIFS extended attributes" | 1765 | bool "CIFS extended attributes" |
| 1740 | depends on CIFS | 1766 | depends on CIFS |
| @@ -1763,6 +1789,16 @@ config CIFS_POSIX | |||
| 1763 | (such as Samba 3.10 and later) which can negotiate | 1789 | (such as Samba 3.10 and later) which can negotiate |
| 1764 | CIFS POSIX ACL support. If unsure, say N. | 1790 | CIFS POSIX ACL support. If unsure, say N. |
| 1765 | 1791 | ||
| 1792 | config CIFS_DEBUG2 | ||
| 1793 | bool "Enable additional CIFS debugging routines" | ||
| 1794 | help | ||
| 1795 | Enabling this option adds a few more debugging routines | ||
| 1796 | to the cifs code which slightly increases the size of | ||
| 1797 | the cifs module and can cause additional logging of debug | ||
| 1798 | messages in some error paths, slowing performance. This | ||
| 1799 | option can be turned off unless you are debugging | ||
| 1800 | cifs problems. If unsure, say N. | ||
| 1801 | |||
| 1766 | config CIFS_EXPERIMENTAL | 1802 | config CIFS_EXPERIMENTAL |
| 1767 | bool "CIFS Experimental Features (EXPERIMENTAL)" | 1803 | bool "CIFS Experimental Features (EXPERIMENTAL)" |
| 1768 | depends on CIFS && EXPERIMENTAL | 1804 | depends on CIFS && EXPERIMENTAL |
| @@ -1778,7 +1814,7 @@ config CIFS_EXPERIMENTAL | |||
| 1778 | If unsure, say N. | 1814 | If unsure, say N. |
| 1779 | 1815 | ||
| 1780 | config CIFS_UPCALL | 1816 | config CIFS_UPCALL |
| 1781 | bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" | 1817 | bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" |
| 1782 | depends on CIFS_EXPERIMENTAL | 1818 | depends on CIFS_EXPERIMENTAL |
| 1783 | select CONNECTOR | 1819 | select CONNECTOR |
| 1784 | help | 1820 | help |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 7271bb0257f6..a61d17ed1827 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -1,9 +1,24 @@ | |||
| 1 | Version 1.44 | ||
| 2 | ------------ | ||
| 3 | Rewritten sessionsetup support, including support for legacy SMB | ||
| 4 | session setup needed for OS/2 and older servers such as Windows 95 and 98. | ||
| 5 | Fix oops on ls to OS/2 servers. Add support for level 1 FindFirst | ||
| 6 | so we can do search (ls etc.) to OS/2. Do not send NTCreateX | ||
| 7 | or recent levels of FindFirst unless server says it supports NT SMBs | ||
| 8 | (instead use legacy equivalents from LANMAN dialect). Fix to allow | ||
| 9 | NTLMv2 authentication support (now can use stronger password hashing | ||
| 10 | on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004). | ||
| 11 | Allow override of global cifs security flags on mount via "sec=" option(s). | ||
| 12 | |||
| 1 | Version 1.43 | 13 | Version 1.43 |
| 2 | ------------ | 14 | ------------ |
| 3 | POSIX locking to servers which support CIFS POSIX Extensions | 15 | POSIX locking to servers which support CIFS POSIX Extensions |
| 4 | (disabled by default controlled by proc/fs/cifs/Experimental). | 16 | (disabled by default controlled by proc/fs/cifs/Experimental). |
| 5 | Handle conversion of long share names (especially Asian languages) | 17 | Handle conversion of long share names (especially Asian languages) |
| 6 | to Unicode during mount. | 18 | to Unicode during mount. Fix memory leak in sess struct on reconnect. |
| 19 | Fix rare oops after acpi suspend. Fix O_TRUNC opens to overwrite on | ||
| 20 | cifs open which helps rare case when setpathinfo fails or server does | ||
| 21 | not support it. | ||
| 7 | 22 | ||
| 8 | Version 1.42 | 23 | Version 1.42 |
| 9 | ------------ | 24 | ------------ |
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 58c77254a23b..a26f26ed5a17 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile | |||
| @@ -3,4 +3,4 @@ | |||
| 3 | # | 3 | # |
| 4 | obj-$(CONFIG_CIFS) += cifs.o | 4 | obj-$(CONFIG_CIFS) += cifs.o |
| 5 | 5 | ||
| 6 | 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 | 6 | 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 |
diff --git a/fs/cifs/README b/fs/cifs/README index 0355003f4f0a..7986d0d97ace 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
| @@ -443,7 +443,10 @@ A partial list of the supported mount options follows: | |||
| 443 | SFU does). In the future the bottom 9 bits of the mode | 443 | SFU does). In the future the bottom 9 bits of the mode |
| 444 | mode also will be emulated using queries of the security | 444 | mode also will be emulated using queries of the security |
| 445 | descriptor (ACL). | 445 | descriptor (ACL). |
| 446 | sec Security mode. Allowed values are: | 446 | sign Must use packet signing (helps avoid unwanted data modification |
| 447 | by intermediate systems in the route). Note that signing | ||
| 448 | does not work with lanman or plaintext authentication. | ||
| 449 | sec Security mode. Allowed values are: | ||
| 447 | none attempt to connection as a null user (no name) | 450 | none attempt to connection as a null user (no name) |
| 448 | krb5 Use Kerberos version 5 authentication | 451 | krb5 Use Kerberos version 5 authentication |
| 449 | krb5i Use Kerberos authentication and packet signing | 452 | krb5i Use Kerberos authentication and packet signing |
| @@ -453,6 +456,8 @@ sec Security mode. Allowed values are: | |||
| 453 | server requires signing also can be the default) | 456 | server requires signing also can be the default) |
| 454 | ntlmv2 Use NTLMv2 password hashing | 457 | ntlmv2 Use NTLMv2 password hashing |
| 455 | ntlmv2i Use NTLMv2 password hashing with packet signing | 458 | ntlmv2i Use NTLMv2 password hashing with packet signing |
| 459 | lanman (if configured in kernel config) use older | ||
| 460 | lanman hash | ||
| 456 | 461 | ||
| 457 | The mount.cifs mount helper also accepts a few mount options before -o | 462 | The mount.cifs mount helper also accepts a few mount options before -o |
| 458 | including: | 463 | including: |
| @@ -485,14 +490,34 @@ PacketSigningEnabled If set to one, cifs packet signing is enabled | |||
| 485 | it. If set to two, cifs packet signing is | 490 | it. If set to two, cifs packet signing is |
| 486 | required even if the server considers packet | 491 | required even if the server considers packet |
| 487 | signing optional. (default 1) | 492 | signing optional. (default 1) |
| 493 | SecurityFlags Flags which control security negotiation and | ||
| 494 | also packet signing. Authentication (may/must) | ||
| 495 | flags (e.g. for NTLM and/or NTLMv2) may be combined with | ||
| 496 | the signing flags. Specifying two different password | ||
| 497 | hashing mechanisms (as "must use") on the other hand | ||
| 498 | does not make much sense. Default flags are | ||
| 499 | 0x07007 | ||
| 500 | (NTLM, NTLMv2 and packet signing allowed). Maximum | ||
| 501 | allowable flags if you want to allow mounts to servers | ||
| 502 | using weaker password hashes is 0x37037 (lanman, | ||
| 503 | plaintext, ntlm, ntlmv2, signing allowed): | ||
| 504 | |||
| 505 | may use packet signing 0x00001 | ||
| 506 | must use packet signing 0x01001 | ||
| 507 | may use NTLM (most common password hash) 0x00002 | ||
| 508 | must use NTLM 0x02002 | ||
| 509 | may use NTLMv2 0x00004 | ||
| 510 | must use NTLMv2 0x04004 | ||
| 511 | may use Kerberos security (not implemented yet) 0x00008 | ||
| 512 | must use Kerberos (not implemented yet) 0x08008 | ||
| 513 | may use lanman (weak) password hash 0x00010 | ||
| 514 | must use lanman password hash 0x10010 | ||
| 515 | may use plaintext passwords 0x00020 | ||
| 516 | must use plaintext passwords 0x20020 | ||
| 517 | (reserved for future packet encryption) 0x00040 | ||
| 518 | |||
| 488 | cifsFYI If set to one, additional debug information is | 519 | cifsFYI If set to one, additional debug information is |
| 489 | logged to the system error log. (default 0) | 520 | logged to the system error log. (default 0) |
| 490 | ExtendedSecurity If set to one, SPNEGO session establishment | ||
| 491 | is allowed which enables more advanced | ||
| 492 | secure CIFS session establishment (default 0) | ||
| 493 | NTLMV2Enabled If set to one, more secure password hashes | ||
| 494 | are used when the server supports them and | ||
| 495 | when kerberos is not negotiated (default 0) | ||
| 496 | traceSMB If set to one, debug information is logged to the | 521 | traceSMB If set to one, debug information is logged to the |
| 497 | system error log with the start of smb requests | 522 | system error log with the start of smb requests |
| 498 | and responses (default 0) | 523 | and responses (default 0) |
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 086ae8f4a207..031cdf293256 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c | |||
| @@ -467,7 +467,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
| 467 | asn1_open(&ctx, security_blob, length); | 467 | asn1_open(&ctx, security_blob, length); |
| 468 | 468 | ||
| 469 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 469 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 470 | cFYI(1, ("Error decoding negTokenInit header ")); | 470 | cFYI(1, ("Error decoding negTokenInit header")); |
| 471 | return 0; | 471 | return 0; |
| 472 | } else if ((cls != ASN1_APL) || (con != ASN1_CON) | 472 | } else if ((cls != ASN1_APL) || (con != ASN1_CON) |
| 473 | || (tag != ASN1_EOC)) { | 473 | || (tag != ASN1_EOC)) { |
| @@ -495,7 +495,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
| 495 | } | 495 | } |
| 496 | 496 | ||
| 497 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 497 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 498 | cFYI(1, ("Error decoding negTokenInit ")); | 498 | cFYI(1, ("Error decoding negTokenInit")); |
| 499 | return 0; | 499 | return 0; |
| 500 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON) | 500 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON) |
| 501 | || (tag != ASN1_EOC)) { | 501 | || (tag != ASN1_EOC)) { |
| @@ -505,7 +505,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 507 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 508 | cFYI(1, ("Error decoding negTokenInit ")); | 508 | cFYI(1, ("Error decoding negTokenInit")); |
| 509 | return 0; | 509 | return 0; |
| 510 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) | 510 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) |
| 511 | || (tag != ASN1_SEQ)) { | 511 | || (tag != ASN1_SEQ)) { |
| @@ -515,7 +515,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
| 515 | } | 515 | } |
| 516 | 516 | ||
| 517 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 517 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 518 | cFYI(1, ("Error decoding 2nd part of negTokenInit ")); | 518 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); |
| 519 | return 0; | 519 | return 0; |
| 520 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON) | 520 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON) |
| 521 | || (tag != ASN1_EOC)) { | 521 | || (tag != ASN1_EOC)) { |
| @@ -527,7 +527,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
| 527 | 527 | ||
| 528 | if (asn1_header_decode | 528 | if (asn1_header_decode |
| 529 | (&ctx, &sequence_end, &cls, &con, &tag) == 0) { | 529 | (&ctx, &sequence_end, &cls, &con, &tag) == 0) { |
| 530 | cFYI(1, ("Error decoding 2nd part of negTokenInit ")); | 530 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); |
| 531 | return 0; | 531 | return 0; |
| 532 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) | 532 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) |
| 533 | || (tag != ASN1_SEQ)) { | 533 | || (tag != ASN1_SEQ)) { |
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index f4124a32bef8..96abeb738978 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
| @@ -39,7 +39,7 @@ cifs_dump_mem(char *label, void *data, int length) | |||
| 39 | char *charptr = data; | 39 | char *charptr = data; |
| 40 | char buf[10], line[80]; | 40 | char buf[10], line[80]; |
| 41 | 41 | ||
| 42 | printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", | 42 | printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n", |
| 43 | label, length, data); | 43 | label, length, data); |
| 44 | for (i = 0; i < length; i += 16) { | 44 | for (i = 0; i < length; i += 16) { |
| 45 | line[0] = 0; | 45 | line[0] = 0; |
| @@ -57,6 +57,57 @@ cifs_dump_mem(char *label, void *data, int length) | |||
| 57 | } | 57 | } |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | #ifdef CONFIG_CIFS_DEBUG2 | ||
| 61 | void cifs_dump_detail(struct smb_hdr * smb) | ||
| 62 | { | ||
| 63 | cERROR(1,("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", | ||
| 64 | smb->Command, smb->Status.CifsError, | ||
| 65 | smb->Flags, smb->Flags2, smb->Mid, smb->Pid)); | ||
| 66 | cERROR(1,("smb buf %p len %d", smb, smbCalcSize_LE(smb))); | ||
| 67 | } | ||
| 68 | |||
| 69 | |||
| 70 | void cifs_dump_mids(struct TCP_Server_Info * server) | ||
| 71 | { | ||
| 72 | struct list_head *tmp; | ||
| 73 | struct mid_q_entry * mid_entry; | ||
| 74 | |||
| 75 | if(server == NULL) | ||
| 76 | return; | ||
| 77 | |||
| 78 | cERROR(1,("Dump pending requests:")); | ||
| 79 | spin_lock(&GlobalMid_Lock); | ||
| 80 | list_for_each(tmp, &server->pending_mid_q) { | ||
| 81 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | ||
| 82 | if(mid_entry) { | ||
| 83 | cERROR(1,("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", | ||
| 84 | mid_entry->midState, | ||
| 85 | (int)mid_entry->command, | ||
| 86 | mid_entry->pid, | ||
| 87 | mid_entry->tsk, | ||
| 88 | mid_entry->mid)); | ||
| 89 | #ifdef CONFIG_CIFS_STATS2 | ||
| 90 | cERROR(1,("IsLarge: %d buf: %p time rcv: %ld now: %ld", | ||
| 91 | mid_entry->largeBuf, | ||
| 92 | mid_entry->resp_buf, | ||
| 93 | mid_entry->when_received, | ||
| 94 | jiffies)); | ||
| 95 | #endif /* STATS2 */ | ||
| 96 | cERROR(1,("IsMult: %d IsEnd: %d", mid_entry->multiRsp, | ||
| 97 | mid_entry->multiEnd)); | ||
| 98 | if(mid_entry->resp_buf) { | ||
| 99 | cifs_dump_detail(mid_entry->resp_buf); | ||
| 100 | cifs_dump_mem("existing buf: ", | ||
| 101 | mid_entry->resp_buf, | ||
| 102 | 62 /* fixme */); | ||
| 103 | } | ||
| 104 | |||
| 105 | } | ||
| 106 | } | ||
| 107 | spin_unlock(&GlobalMid_Lock); | ||
| 108 | } | ||
| 109 | #endif /* CONFIG_CIFS_DEBUG2 */ | ||
| 110 | |||
| 60 | #ifdef CONFIG_PROC_FS | 111 | #ifdef CONFIG_PROC_FS |
| 61 | static int | 112 | static int |
| 62 | cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | 113 | 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, | |||
| 73 | 124 | ||
| 74 | *beginBuffer = buf + offset; | 125 | *beginBuffer = buf + offset; |
| 75 | 126 | ||
| 76 | |||
| 77 | length = | 127 | length = |
| 78 | sprintf(buf, | 128 | sprintf(buf, |
| 79 | "Display Internal CIFS Data Structures for Debugging\n" | 129 | "Display Internal CIFS Data Structures for Debugging\n" |
| @@ -395,12 +445,12 @@ static read_proc_t traceSMB_read; | |||
| 395 | static write_proc_t traceSMB_write; | 445 | static write_proc_t traceSMB_write; |
| 396 | static read_proc_t multiuser_mount_read; | 446 | static read_proc_t multiuser_mount_read; |
| 397 | static write_proc_t multiuser_mount_write; | 447 | static write_proc_t multiuser_mount_write; |
| 398 | static read_proc_t extended_security_read; | 448 | static read_proc_t security_flags_read; |
| 399 | static write_proc_t extended_security_write; | 449 | static write_proc_t security_flags_write; |
| 400 | static read_proc_t ntlmv2_enabled_read; | 450 | /* static read_proc_t ntlmv2_enabled_read; |
| 401 | static write_proc_t ntlmv2_enabled_write; | 451 | static write_proc_t ntlmv2_enabled_write; |
| 402 | static read_proc_t packet_signing_enabled_read; | 452 | static read_proc_t packet_signing_enabled_read; |
| 403 | static write_proc_t packet_signing_enabled_write; | 453 | static write_proc_t packet_signing_enabled_write;*/ |
| 404 | static read_proc_t experimEnabled_read; | 454 | static read_proc_t experimEnabled_read; |
| 405 | static write_proc_t experimEnabled_write; | 455 | static write_proc_t experimEnabled_write; |
| 406 | static read_proc_t linuxExtensionsEnabled_read; | 456 | static read_proc_t linuxExtensionsEnabled_read; |
| @@ -458,10 +508,10 @@ cifs_proc_init(void) | |||
| 458 | pde->write_proc = multiuser_mount_write; | 508 | pde->write_proc = multiuser_mount_write; |
| 459 | 509 | ||
| 460 | pde = | 510 | pde = |
| 461 | create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, | 511 | create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs, |
| 462 | extended_security_read, NULL); | 512 | security_flags_read, NULL); |
| 463 | if (pde) | 513 | if (pde) |
| 464 | pde->write_proc = extended_security_write; | 514 | pde->write_proc = security_flags_write; |
| 465 | 515 | ||
| 466 | pde = | 516 | pde = |
| 467 | create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, | 517 | create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, |
| @@ -469,7 +519,7 @@ cifs_proc_init(void) | |||
| 469 | if (pde) | 519 | if (pde) |
| 470 | pde->write_proc = lookupFlag_write; | 520 | pde->write_proc = lookupFlag_write; |
| 471 | 521 | ||
| 472 | pde = | 522 | /* pde = |
| 473 | create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, | 523 | create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, |
| 474 | ntlmv2_enabled_read, NULL); | 524 | ntlmv2_enabled_read, NULL); |
| 475 | if (pde) | 525 | if (pde) |
| @@ -479,7 +529,7 @@ cifs_proc_init(void) | |||
| 479 | create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, | 529 | create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, |
| 480 | packet_signing_enabled_read, NULL); | 530 | packet_signing_enabled_read, NULL); |
| 481 | if (pde) | 531 | if (pde) |
| 482 | pde->write_proc = packet_signing_enabled_write; | 532 | pde->write_proc = packet_signing_enabled_write;*/ |
| 483 | } | 533 | } |
| 484 | 534 | ||
| 485 | void | 535 | void |
| @@ -496,9 +546,9 @@ cifs_proc_clean(void) | |||
| 496 | #endif | 546 | #endif |
| 497 | remove_proc_entry("MultiuserMount", proc_fs_cifs); | 547 | remove_proc_entry("MultiuserMount", proc_fs_cifs); |
| 498 | remove_proc_entry("OplockEnabled", proc_fs_cifs); | 548 | remove_proc_entry("OplockEnabled", proc_fs_cifs); |
| 499 | remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); | 549 | /* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */ |
| 500 | remove_proc_entry("ExtendedSecurity",proc_fs_cifs); | 550 | remove_proc_entry("SecurityFlags",proc_fs_cifs); |
| 501 | remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); | 551 | /* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */ |
| 502 | remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); | 552 | remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); |
| 503 | remove_proc_entry("Experimental",proc_fs_cifs); | 553 | remove_proc_entry("Experimental",proc_fs_cifs); |
| 504 | remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); | 554 | remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); |
| @@ -782,12 +832,12 @@ multiuser_mount_write(struct file *file, const char __user *buffer, | |||
| 782 | } | 832 | } |
| 783 | 833 | ||
| 784 | static int | 834 | static int |
| 785 | extended_security_read(char *page, char **start, off_t off, | 835 | security_flags_read(char *page, char **start, off_t off, |
| 786 | int count, int *eof, void *data) | 836 | int count, int *eof, void *data) |
| 787 | { | 837 | { |
| 788 | int len; | 838 | int len; |
| 789 | 839 | ||
| 790 | len = sprintf(page, "%d\n", extended_security); | 840 | len = sprintf(page, "0x%x\n", extended_security); |
| 791 | 841 | ||
| 792 | len -= off; | 842 | len -= off; |
| 793 | *start = page + off; | 843 | *start = page + off; |
| @@ -803,24 +853,52 @@ extended_security_read(char *page, char **start, off_t off, | |||
| 803 | return len; | 853 | return len; |
| 804 | } | 854 | } |
| 805 | static int | 855 | static int |
| 806 | extended_security_write(struct file *file, const char __user *buffer, | 856 | security_flags_write(struct file *file, const char __user *buffer, |
| 807 | unsigned long count, void *data) | 857 | unsigned long count, void *data) |
| 808 | { | 858 | { |
| 859 | unsigned int flags; | ||
| 860 | char flags_string[12]; | ||
| 809 | char c; | 861 | char c; |
| 810 | int rc; | ||
| 811 | 862 | ||
| 812 | rc = get_user(c, buffer); | 863 | if((count < 1) || (count > 11)) |
| 813 | if (rc) | 864 | return -EINVAL; |
| 814 | return rc; | 865 | |
| 815 | if (c == '0' || c == 'n' || c == 'N') | 866 | memset(flags_string, 0, 12); |
| 816 | extended_security = 0; | 867 | |
| 817 | else if (c == '1' || c == 'y' || c == 'Y') | 868 | if(copy_from_user(flags_string, buffer, count)) |
| 818 | extended_security = 1; | 869 | return -EFAULT; |
| 870 | |||
| 871 | if(count < 3) { | ||
| 872 | /* single char or single char followed by null */ | ||
| 873 | c = flags_string[0]; | ||
| 874 | if (c == '0' || c == 'n' || c == 'N') | ||
| 875 | extended_security = CIFSSEC_DEF; /* default */ | ||
| 876 | else if (c == '1' || c == 'y' || c == 'Y') | ||
| 877 | extended_security = CIFSSEC_MAX; | ||
| 878 | return count; | ||
| 879 | } | ||
| 880 | /* else we have a number */ | ||
| 881 | |||
| 882 | flags = simple_strtoul(flags_string, NULL, 0); | ||
| 883 | |||
| 884 | cFYI(1,("sec flags 0x%x", flags)); | ||
| 885 | |||
| 886 | if(flags <= 0) { | ||
| 887 | cERROR(1,("invalid security flags %s",flags_string)); | ||
| 888 | return -EINVAL; | ||
| 889 | } | ||
| 819 | 890 | ||
| 891 | if(flags & ~CIFSSEC_MASK) { | ||
| 892 | cERROR(1,("attempt to set unsupported security flags 0x%x", | ||
| 893 | flags & ~CIFSSEC_MASK)); | ||
| 894 | return -EINVAL; | ||
| 895 | } | ||
| 896 | /* flags look ok - update the global security flags for cifs module */ | ||
| 897 | extended_security = flags; | ||
| 820 | return count; | 898 | return count; |
| 821 | } | 899 | } |
| 822 | 900 | ||
| 823 | static int | 901 | /* static int |
| 824 | ntlmv2_enabled_read(char *page, char **start, off_t off, | 902 | ntlmv2_enabled_read(char *page, char **start, off_t off, |
| 825 | int count, int *eof, void *data) | 903 | int count, int *eof, void *data) |
| 826 | { | 904 | { |
| @@ -855,6 +933,8 @@ ntlmv2_enabled_write(struct file *file, const char __user *buffer, | |||
| 855 | ntlmv2_support = 0; | 933 | ntlmv2_support = 0; |
| 856 | else if (c == '1' || c == 'y' || c == 'Y') | 934 | else if (c == '1' || c == 'y' || c == 'Y') |
| 857 | ntlmv2_support = 1; | 935 | ntlmv2_support = 1; |
| 936 | else if (c == '2') | ||
| 937 | ntlmv2_support = 2; | ||
| 858 | 938 | ||
| 859 | return count; | 939 | return count; |
| 860 | } | 940 | } |
| @@ -898,7 +978,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer, | |||
| 898 | sign_CIFS_PDUs = 2; | 978 | sign_CIFS_PDUs = 2; |
| 899 | 979 | ||
| 900 | return count; | 980 | return count; |
| 901 | } | 981 | } */ |
| 902 | 982 | ||
| 903 | 983 | ||
| 904 | #endif | 984 | #endif |
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index 4304d9dcfb6c..c26cd0d2c6d5 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h | |||
| @@ -24,6 +24,10 @@ | |||
| 24 | #define _H_CIFS_DEBUG | 24 | #define _H_CIFS_DEBUG |
| 25 | 25 | ||
| 26 | void cifs_dump_mem(char *label, void *data, int length); | 26 | void cifs_dump_mem(char *label, void *data, int length); |
| 27 | #ifdef CONFIG_CIFS_DEBUG2 | ||
| 28 | void cifs_dump_detail(struct smb_hdr *); | ||
| 29 | void cifs_dump_mids(struct TCP_Server_Info *); | ||
| 30 | #endif | ||
| 27 | extern int traceSMB; /* flag which enables the function below */ | 31 | extern int traceSMB; /* flag which enables the function below */ |
| 28 | void dump_smb(struct smb_hdr *, int); | 32 | void dump_smb(struct smb_hdr *, int); |
| 29 | #define CIFS_INFO 0x01 | 33 | #define CIFS_INFO 0x01 |
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index d2b128255944..d2a8b2941fc2 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "cifs_unicode.h" | 22 | #include "cifs_unicode.h" |
| 23 | #include "cifs_uniupr.h" | 23 | #include "cifs_uniupr.h" |
| 24 | #include "cifspdu.h" | 24 | #include "cifspdu.h" |
| 25 | #include "cifsglob.h" | ||
| 25 | #include "cifs_debug.h" | 26 | #include "cifs_debug.h" |
| 26 | 27 | ||
| 27 | /* | 28 | /* |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index e7d63737e651..a89efaf78a26 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
| @@ -26,6 +26,8 @@ | |||
| 26 | #include "md5.h" | 26 | #include "md5.h" |
| 27 | #include "cifs_unicode.h" | 27 | #include "cifs_unicode.h" |
| 28 | #include "cifsproto.h" | 28 | #include "cifsproto.h" |
| 29 | #include <linux/ctype.h> | ||
| 30 | #include <linux/random.h> | ||
| 29 | 31 | ||
| 30 | /* Calculate and return the CIFS signature based on the mac key and the smb pdu */ | 32 | /* Calculate and return the CIFS signature based on the mac key and the smb pdu */ |
| 31 | /* the 16 byte signature must be allocated by the caller */ | 33 | /* the 16 byte signature must be allocated by the caller */ |
| @@ -35,6 +37,8 @@ | |||
| 35 | 37 | ||
| 36 | extern void mdfour(unsigned char *out, unsigned char *in, int n); | 38 | extern void mdfour(unsigned char *out, unsigned char *in, int n); |
| 37 | extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); | 39 | extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); |
| 40 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, | ||
| 41 | unsigned char *p24); | ||
| 38 | 42 | ||
| 39 | static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, | 43 | static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, |
| 40 | const char * key, char * signature) | 44 | const char * key, char * signature) |
| @@ -45,7 +49,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, | |||
| 45 | return -EINVAL; | 49 | return -EINVAL; |
| 46 | 50 | ||
| 47 | MD5Init(&context); | 51 | MD5Init(&context); |
| 48 | MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); | 52 | MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); |
| 49 | MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); | 53 | MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); |
| 50 | MD5Final(signature,&context); | 54 | MD5Final(signature,&context); |
| 51 | return 0; | 55 | return 0; |
| @@ -90,7 +94,7 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec, | |||
| 90 | return -EINVAL; | 94 | return -EINVAL; |
| 91 | 95 | ||
| 92 | MD5Init(&context); | 96 | MD5Init(&context); |
| 93 | MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); | 97 | MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); |
| 94 | for(i=0;i<n_vec;i++) { | 98 | for(i=0;i<n_vec;i++) { |
| 95 | if(iov[i].iov_base == NULL) { | 99 | if(iov[i].iov_base == NULL) { |
| 96 | cERROR(1,("null iovec entry")); | 100 | cERROR(1,("null iovec entry")); |
| @@ -204,11 +208,12 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password) | |||
| 204 | 208 | ||
| 205 | E_md4hash(password, temp_key); | 209 | E_md4hash(password, temp_key); |
| 206 | mdfour(key,temp_key,16); | 210 | mdfour(key,temp_key,16); |
| 207 | memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE); | 211 | memcpy(key+16,rn, CIFS_SESS_KEY_SIZE); |
| 208 | return 0; | 212 | return 0; |
| 209 | } | 213 | } |
| 210 | 214 | ||
| 211 | int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info) | 215 | int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, |
| 216 | const struct nls_table * nls_info) | ||
| 212 | { | 217 | { |
| 213 | char temp_hash[16]; | 218 | char temp_hash[16]; |
| 214 | struct HMACMD5Context ctx; | 219 | struct HMACMD5Context ctx; |
| @@ -225,6 +230,8 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ | |||
| 225 | user_name_len = strlen(ses->userName); | 230 | user_name_len = strlen(ses->userName); |
| 226 | if(user_name_len > MAX_USERNAME_SIZE) | 231 | if(user_name_len > MAX_USERNAME_SIZE) |
| 227 | return -EINVAL; | 232 | return -EINVAL; |
| 233 | if(ses->domainName == NULL) | ||
| 234 | return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ | ||
| 228 | dom_name_len = strlen(ses->domainName); | 235 | dom_name_len = strlen(ses->domainName); |
| 229 | if(dom_name_len > MAX_USERNAME_SIZE) | 236 | if(dom_name_len > MAX_USERNAME_SIZE) |
| 230 | return -EINVAL; | 237 | return -EINVAL; |
| @@ -259,16 +266,131 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ | |||
| 259 | kfree(unicode_buf); | 266 | kfree(unicode_buf); |
| 260 | return 0; | 267 | return 0; |
| 261 | } | 268 | } |
| 262 | void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) | 269 | |
| 270 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 271 | void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) | ||
| 272 | { | ||
| 273 | int i; | ||
| 274 | char password_with_pad[CIFS_ENCPWD_SIZE]; | ||
| 275 | |||
| 276 | if(ses->server == NULL) | ||
| 277 | return; | ||
| 278 | |||
| 279 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); | ||
| 280 | strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); | ||
| 281 | |||
| 282 | if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) | ||
| 283 | if(extended_security & CIFSSEC_MAY_PLNTXT) { | ||
| 284 | memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); | ||
| 285 | return; | ||
| 286 | } | ||
| 287 | |||
| 288 | /* calculate old style session key */ | ||
| 289 | /* calling toupper is less broken than repeatedly | ||
| 290 | calling nls_toupper would be since that will never | ||
| 291 | work for UTF8, but neither handles multibyte code pages | ||
| 292 | but the only alternative would be converting to UCS-16 (Unicode) | ||
| 293 | (using a routine something like UniStrupr) then | ||
| 294 | uppercasing and then converting back from Unicode - which | ||
| 295 | would only worth doing it if we knew it were utf8. Basically | ||
| 296 | utf8 and other multibyte codepages each need their own strupper | ||
| 297 | function since a byte at a time will ont work. */ | ||
| 298 | |||
| 299 | for(i = 0; i < CIFS_ENCPWD_SIZE; i++) { | ||
| 300 | password_with_pad[i] = toupper(password_with_pad[i]); | ||
| 301 | } | ||
| 302 | |||
| 303 | SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key); | ||
| 304 | /* clear password before we return/free memory */ | ||
| 305 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); | ||
| 306 | } | ||
| 307 | #endif /* CIFS_WEAK_PW_HASH */ | ||
| 308 | |||
| 309 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | ||
| 310 | const struct nls_table * nls_cp) | ||
| 311 | { | ||
| 312 | int rc = 0; | ||
| 313 | int len; | ||
| 314 | char nt_hash[16]; | ||
| 315 | struct HMACMD5Context * pctxt; | ||
| 316 | wchar_t * user; | ||
| 317 | wchar_t * domain; | ||
| 318 | |||
| 319 | pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); | ||
| 320 | |||
| 321 | if(pctxt == NULL) | ||
| 322 | return -ENOMEM; | ||
| 323 | |||
| 324 | /* calculate md4 hash of password */ | ||
| 325 | E_md4hash(ses->password, nt_hash); | ||
| 326 | |||
| 327 | /* convert Domainname to unicode and uppercase */ | ||
| 328 | hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); | ||
| 329 | |||
| 330 | /* convert ses->userName to unicode and uppercase */ | ||
| 331 | len = strlen(ses->userName); | ||
| 332 | user = kmalloc(2 + (len * 2), GFP_KERNEL); | ||
| 333 | if(user == NULL) | ||
| 334 | goto calc_exit_2; | ||
| 335 | len = cifs_strtoUCS(user, ses->userName, len, nls_cp); | ||
| 336 | UniStrupr(user); | ||
| 337 | hmac_md5_update((char *)user, 2*len, pctxt); | ||
| 338 | |||
| 339 | /* convert ses->domainName to unicode and uppercase */ | ||
| 340 | if(ses->domainName) { | ||
| 341 | len = strlen(ses->domainName); | ||
| 342 | |||
| 343 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); | ||
| 344 | if(domain == NULL) | ||
| 345 | goto calc_exit_1; | ||
| 346 | len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); | ||
| 347 | UniStrupr(domain); | ||
| 348 | |||
| 349 | hmac_md5_update((char *)domain, 2*len, pctxt); | ||
| 350 | |||
| 351 | kfree(domain); | ||
| 352 | } | ||
| 353 | calc_exit_1: | ||
| 354 | kfree(user); | ||
| 355 | calc_exit_2: | ||
| 356 | /* BB FIXME what about bytes 24 through 40 of the signing key? | ||
| 357 | compare with the NTLM example */ | ||
| 358 | hmac_md5_final(ses->server->mac_signing_key, pctxt); | ||
| 359 | |||
| 360 | return rc; | ||
| 361 | } | ||
| 362 | |||
| 363 | void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, | ||
| 364 | const struct nls_table * nls_cp) | ||
| 365 | { | ||
| 366 | int rc; | ||
| 367 | struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; | ||
| 368 | |||
| 369 | buf->blob_signature = cpu_to_le32(0x00000101); | ||
| 370 | buf->reserved = 0; | ||
| 371 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
| 372 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); | ||
| 373 | buf->reserved2 = 0; | ||
| 374 | buf->names[0].type = 0; | ||
| 375 | buf->names[0].length = 0; | ||
| 376 | |||
| 377 | /* calculate buf->ntlmv2_hash */ | ||
| 378 | rc = calc_ntlmv2_hash(ses, nls_cp); | ||
| 379 | if(rc) | ||
| 380 | cERROR(1,("could not get v2 hash rc %d",rc)); | ||
| 381 | CalcNTLMv2_response(ses, resp_buf); | ||
| 382 | } | ||
| 383 | |||
| 384 | void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response) | ||
| 263 | { | 385 | { |
| 264 | struct HMACMD5Context context; | 386 | struct HMACMD5Context context; |
| 387 | /* rest of v2 struct already generated */ | ||
| 265 | memcpy(v2_session_response + 8, ses->server->cryptKey,8); | 388 | memcpy(v2_session_response + 8, ses->server->cryptKey,8); |
| 266 | /* gen_blob(v2_session_response + 16); */ | ||
| 267 | hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); | 389 | hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); |
| 268 | 390 | ||
| 269 | hmac_md5_update(ses->server->cryptKey,8,&context); | 391 | hmac_md5_update(v2_session_response+8, |
| 270 | /* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ | 392 | sizeof(struct ntlmv2_resp) - 8, &context); |
| 271 | 393 | ||
| 272 | hmac_md5_final(v2_session_response,&context); | 394 | hmac_md5_final(v2_session_response,&context); |
| 273 | cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); /* BB removeme BB */ | 395 | /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ |
| 274 | } | 396 | } |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8b4de6eaabd0..c28ede599946 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -56,8 +56,8 @@ unsigned int experimEnabled = 0; | |||
| 56 | unsigned int linuxExtEnabled = 1; | 56 | unsigned int linuxExtEnabled = 1; |
| 57 | unsigned int lookupCacheEnabled = 1; | 57 | unsigned int lookupCacheEnabled = 1; |
| 58 | unsigned int multiuser_mount = 0; | 58 | unsigned int multiuser_mount = 0; |
| 59 | unsigned int extended_security = 0; | 59 | unsigned int extended_security = CIFSSEC_DEF; |
| 60 | unsigned int ntlmv2_support = 0; | 60 | /* unsigned int ntlmv2_support = 0; */ |
| 61 | unsigned int sign_CIFS_PDUs = 1; | 61 | unsigned int sign_CIFS_PDUs = 1; |
| 62 | extern struct task_struct * oplockThread; /* remove sparse warning */ | 62 | extern struct task_struct * oplockThread; /* remove sparse warning */ |
| 63 | struct task_struct * oplockThread = NULL; | 63 | struct task_struct * oplockThread = NULL; |
| @@ -908,7 +908,7 @@ static int cifs_dnotify_thread(void * dummyarg) | |||
| 908 | struct cifsSesInfo *ses; | 908 | struct cifsSesInfo *ses; |
| 909 | 909 | ||
| 910 | do { | 910 | do { |
| 911 | if(try_to_freeze()) | 911 | if (try_to_freeze()) |
| 912 | continue; | 912 | continue; |
| 913 | set_current_state(TASK_INTERRUPTIBLE); | 913 | set_current_state(TASK_INTERRUPTIBLE); |
| 914 | schedule_timeout(15*HZ); | 914 | schedule_timeout(15*HZ); |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index d56c0577c710..a6384d83fdef 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #endif | 33 | #endif |
| 34 | 34 | ||
| 35 | extern struct address_space_operations cifs_addr_ops; | 35 | extern struct address_space_operations cifs_addr_ops; |
| 36 | extern struct address_space_operations cifs_addr_ops_smallbuf; | ||
| 36 | 37 | ||
| 37 | /* Functions related to super block operations */ | 38 | /* Functions related to super block operations */ |
| 38 | extern struct super_operations cifs_super_ops; | 39 | extern struct super_operations cifs_super_ops; |
| @@ -99,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | |||
| 99 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 100 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
| 100 | extern int cifs_ioctl (struct inode * inode, struct file * filep, | 101 | extern int cifs_ioctl (struct inode * inode, struct file * filep, |
| 101 | unsigned int command, unsigned long arg); | 102 | unsigned int command, unsigned long arg); |
| 102 | #define CIFS_VERSION "1.43" | 103 | #define CIFS_VERSION "1.44" |
| 103 | #endif /* _CIFSFS_H */ | 104 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 006eb33bff5f..6d7cf5f3bc0b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -88,7 +88,8 @@ enum statusEnum { | |||
| 88 | }; | 88 | }; |
| 89 | 89 | ||
| 90 | enum securityEnum { | 90 | enum securityEnum { |
| 91 | NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */ | 91 | LANMAN = 0, /* Legacy LANMAN auth */ |
| 92 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ | ||
| 92 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ | 93 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ |
| 93 | RawNTLMSSP, /* NTLMSSP without SPNEGO */ | 94 | RawNTLMSSP, /* NTLMSSP without SPNEGO */ |
| 94 | NTLMSSP, /* NTLMSSP via SPNEGO */ | 95 | NTLMSSP, /* NTLMSSP via SPNEGO */ |
| @@ -157,7 +158,7 @@ struct TCP_Server_Info { | |||
| 157 | /* 16th byte of RFC1001 workstation name is always null */ | 158 | /* 16th byte of RFC1001 workstation name is always null */ |
| 158 | char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; | 159 | char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; |
| 159 | __u32 sequence_number; /* needed for CIFS PDU signature */ | 160 | __u32 sequence_number; /* needed for CIFS PDU signature */ |
| 160 | char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; | 161 | char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; |
| 161 | }; | 162 | }; |
| 162 | 163 | ||
| 163 | /* | 164 | /* |
| @@ -179,10 +180,13 @@ struct cifsUidInfo { | |||
| 179 | struct cifsSesInfo { | 180 | struct cifsSesInfo { |
| 180 | struct list_head cifsSessionList; | 181 | struct list_head cifsSessionList; |
| 181 | struct semaphore sesSem; | 182 | struct semaphore sesSem; |
| 183 | #if 0 | ||
| 182 | struct cifsUidInfo *uidInfo; /* pointer to user info */ | 184 | struct cifsUidInfo *uidInfo; /* pointer to user info */ |
| 185 | #endif | ||
| 183 | struct TCP_Server_Info *server; /* pointer to server info */ | 186 | struct TCP_Server_Info *server; /* pointer to server info */ |
| 184 | atomic_t inUse; /* # of mounts (tree connections) on this ses */ | 187 | atomic_t inUse; /* # of mounts (tree connections) on this ses */ |
| 185 | enum statusEnum status; | 188 | enum statusEnum status; |
| 189 | unsigned overrideSecFlg; /* if non-zero override global sec flags */ | ||
| 186 | __u16 ipc_tid; /* special tid for connection to IPC share */ | 190 | __u16 ipc_tid; /* special tid for connection to IPC share */ |
| 187 | __u16 flags; | 191 | __u16 flags; |
| 188 | char *serverOS; /* name of operating system underlying server */ | 192 | char *serverOS; /* name of operating system underlying server */ |
| @@ -194,7 +198,7 @@ struct cifsSesInfo { | |||
| 194 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for | 198 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for |
| 195 | TCP names - will ipv6 and sctp addresses fit? */ | 199 | TCP names - will ipv6 and sctp addresses fit? */ |
| 196 | char userName[MAX_USERNAME_SIZE + 1]; | 200 | char userName[MAX_USERNAME_SIZE + 1]; |
| 197 | char domainName[MAX_USERNAME_SIZE + 1]; | 201 | char * domainName; |
| 198 | char * password; | 202 | char * password; |
| 199 | }; | 203 | }; |
| 200 | /* session flags */ | 204 | /* session flags */ |
| @@ -209,12 +213,12 @@ struct cifsTconInfo { | |||
| 209 | struct list_head openFileList; | 213 | struct list_head openFileList; |
| 210 | struct semaphore tconSem; | 214 | struct semaphore tconSem; |
| 211 | struct cifsSesInfo *ses; /* pointer to session associated with */ | 215 | struct cifsSesInfo *ses; /* pointer to session associated with */ |
| 212 | char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */ | 216 | char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ |
| 213 | char *nativeFileSystem; | 217 | char *nativeFileSystem; |
| 214 | __u16 tid; /* The 2 byte tree id */ | 218 | __u16 tid; /* The 2 byte tree id */ |
| 215 | __u16 Flags; /* optional support bits */ | 219 | __u16 Flags; /* optional support bits */ |
| 216 | enum statusEnum tidStatus; | 220 | enum statusEnum tidStatus; |
| 217 | atomic_t useCount; /* how many mounts (explicit or implicit) to this share */ | 221 | atomic_t useCount; /* how many explicit/implicit mounts to share */ |
| 218 | #ifdef CONFIG_CIFS_STATS | 222 | #ifdef CONFIG_CIFS_STATS |
| 219 | atomic_t num_smbs_sent; | 223 | atomic_t num_smbs_sent; |
| 220 | atomic_t num_writes; | 224 | atomic_t num_writes; |
| @@ -254,7 +258,7 @@ struct cifsTconInfo { | |||
| 254 | spinlock_t stat_lock; | 258 | spinlock_t stat_lock; |
| 255 | #endif /* CONFIG_CIFS_STATS */ | 259 | #endif /* CONFIG_CIFS_STATS */ |
| 256 | FILE_SYSTEM_DEVICE_INFO fsDevInfo; | 260 | FILE_SYSTEM_DEVICE_INFO fsDevInfo; |
| 257 | FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ | 261 | FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ |
| 258 | FILE_SYSTEM_UNIX_INFO fsUnixInfo; | 262 | FILE_SYSTEM_UNIX_INFO fsUnixInfo; |
| 259 | unsigned retry:1; | 263 | unsigned retry:1; |
| 260 | unsigned nocase:1; | 264 | unsigned nocase:1; |
| @@ -305,7 +309,6 @@ struct cifsFileInfo { | |||
| 305 | atomic_t wrtPending; /* handle in use - defer close */ | 309 | atomic_t wrtPending; /* handle in use - defer close */ |
| 306 | struct semaphore fh_sem; /* prevents reopen race after dead ses*/ | 310 | struct semaphore fh_sem; /* prevents reopen race after dead ses*/ |
| 307 | char * search_resume_name; /* BB removeme BB */ | 311 | char * search_resume_name; /* BB removeme BB */ |
| 308 | unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ | ||
| 309 | struct cifs_search_info srch_inf; | 312 | struct cifs_search_info srch_inf; |
| 310 | }; | 313 | }; |
| 311 | 314 | ||
| @@ -391,9 +394,9 @@ struct mid_q_entry { | |||
| 391 | struct smb_hdr *resp_buf; /* response buffer */ | 394 | struct smb_hdr *resp_buf; /* response buffer */ |
| 392 | int midState; /* wish this were enum but can not pass to wait_event */ | 395 | int midState; /* wish this were enum but can not pass to wait_event */ |
| 393 | __u8 command; /* smb command code */ | 396 | __u8 command; /* smb command code */ |
| 394 | unsigned multiPart:1; /* multiple responses to one SMB request */ | ||
| 395 | unsigned largeBuf:1; /* if valid response, is pointer to large buf */ | 397 | unsigned largeBuf:1; /* if valid response, is pointer to large buf */ |
| 396 | unsigned multiResp:1; /* multiple trans2 responses for one request */ | 398 | unsigned multiRsp:1; /* multiple trans2 responses for one request */ |
| 399 | unsigned multiEnd:1; /* both received */ | ||
| 397 | }; | 400 | }; |
| 398 | 401 | ||
| 399 | struct oplock_q_entry { | 402 | struct oplock_q_entry { |
| @@ -430,15 +433,35 @@ struct dir_notify_req { | |||
| 430 | #define CIFS_LARGE_BUFFER 2 | 433 | #define CIFS_LARGE_BUFFER 2 |
| 431 | #define CIFS_IOVEC 4 /* array of response buffers */ | 434 | #define CIFS_IOVEC 4 /* array of response buffers */ |
| 432 | 435 | ||
| 433 | /* Type of session setup needed */ | 436 | /* Security Flags: indicate type of session setup needed */ |
| 434 | #define CIFS_PLAINTEXT 0 | 437 | #define CIFSSEC_MAY_SIGN 0x00001 |
| 435 | #define CIFS_LANMAN 1 | 438 | #define CIFSSEC_MAY_NTLM 0x00002 |
| 436 | #define CIFS_NTLM 2 | 439 | #define CIFSSEC_MAY_NTLMV2 0x00004 |
| 437 | #define CIFS_NTLMSSP_NEG 3 | 440 | #define CIFSSEC_MAY_KRB5 0x00008 |
| 438 | #define CIFS_NTLMSSP_AUTH 4 | 441 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
| 439 | #define CIFS_SPNEGO_INIT 5 | 442 | #define CIFSSEC_MAY_LANMAN 0x00010 |
| 440 | #define CIFS_SPNEGO_TARG 6 | 443 | #define CIFSSEC_MAY_PLNTXT 0x00020 |
| 441 | 444 | #endif /* weak passwords */ | |
| 445 | #define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ | ||
| 446 | |||
| 447 | #define CIFSSEC_MUST_SIGN 0x01001 | ||
| 448 | /* note that only one of the following can be set so the | ||
| 449 | result of setting MUST flags more than once will be to | ||
| 450 | require use of the stronger protocol */ | ||
| 451 | #define CIFSSEC_MUST_NTLM 0x02002 | ||
| 452 | #define CIFSSEC_MUST_NTLMV2 0x04004 | ||
| 453 | #define CIFSSEC_MUST_KRB5 0x08008 | ||
| 454 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 455 | #define CIFSSEC_MUST_LANMAN 0x10010 | ||
| 456 | #define CIFSSEC_MUST_PLNTXT 0x20020 | ||
| 457 | #define CIFSSEC_MASK 0x37037 /* current flags supported if weak */ | ||
| 458 | #else | ||
| 459 | #define CIFSSEC_MASK 0x07007 /* flags supported if no weak config */ | ||
| 460 | #endif /* WEAK_PW_HASH */ | ||
| 461 | #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ | ||
| 462 | |||
| 463 | #define CIFSSEC_DEF CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | ||
| 464 | #define CIFSSEC_MAX CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2 | ||
| 442 | /* | 465 | /* |
| 443 | ***************************************************************** | 466 | ***************************************************************** |
| 444 | * All constants go here | 467 | * All constants go here |
| @@ -500,16 +523,16 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ | |||
| 500 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; | 523 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; |
| 501 | 524 | ||
| 502 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */ | 525 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */ |
| 503 | GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */ | 526 | GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;/* DirNotify response queue */ |
| 504 | 527 | ||
| 505 | /* | 528 | /* |
| 506 | * Global transaction id (XID) information | 529 | * Global transaction id (XID) information |
| 507 | */ | 530 | */ |
| 508 | GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ | 531 | GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ |
| 509 | GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ | 532 | GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ |
| 510 | GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ | 533 | GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ |
| 511 | GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */ | 534 | GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */ |
| 512 | /* on midQ entries */ | 535 | /* on midQ entries */ |
| 513 | GLOBAL_EXTERN char Local_System_Name[15]; | 536 | GLOBAL_EXTERN char Local_System_Name[15]; |
| 514 | 537 | ||
| 515 | /* | 538 | /* |
| @@ -531,7 +554,7 @@ GLOBAL_EXTERN atomic_t smBufAllocCount; | |||
| 531 | GLOBAL_EXTERN atomic_t midCount; | 554 | GLOBAL_EXTERN atomic_t midCount; |
| 532 | 555 | ||
| 533 | /* Misc globals */ | 556 | /* Misc globals */ |
| 534 | GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions | 557 | GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions |
| 535 | to be established on existing mount if we | 558 | to be established on existing mount if we |
| 536 | have the uid/password or Kerberos credential | 559 | have the uid/password or Kerberos credential |
| 537 | or equivalent for current user */ | 560 | or equivalent for current user */ |
| @@ -540,8 +563,8 @@ GLOBAL_EXTERN unsigned int experimEnabled; | |||
| 540 | GLOBAL_EXTERN unsigned int lookupCacheEnabled; | 563 | GLOBAL_EXTERN unsigned int lookupCacheEnabled; |
| 541 | GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent | 564 | GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent |
| 542 | with more secure ntlmssp2 challenge/resp */ | 565 | with more secure ntlmssp2 challenge/resp */ |
| 543 | GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ | ||
| 544 | GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ | 566 | GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ |
| 567 | GLOBAL_EXTERN unsigned int secFlags; | ||
| 545 | GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ | 568 | GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ |
| 546 | GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ | 569 | GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ |
| 547 | GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ | 570 | GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index b2233ac05bd2..86239023545b 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | * | 16 | * |
| 17 | * You should have received a copy of the GNU Lesser General Public License | 17 | * You should have received a copy of the GNU Lesser General Public License |
| 18 | * along with this library; if not, write to the Free Software | 18 | * along with this library; if not, write to the Free Software |
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #ifndef _CIFSPDU_H | 22 | #ifndef _CIFSPDU_H |
| @@ -24,8 +24,14 @@ | |||
| 24 | 24 | ||
| 25 | #include <net/sock.h> | 25 | #include <net/sock.h> |
| 26 | 26 | ||
| 27 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 28 | #define LANMAN_PROT 0 | ||
| 29 | #define CIFS_PROT 1 | ||
| 30 | #else | ||
| 27 | #define CIFS_PROT 0 | 31 | #define CIFS_PROT 0 |
| 28 | #define BAD_PROT CIFS_PROT+1 | 32 | #endif |
| 33 | #define POSIX_PROT CIFS_PROT+1 | ||
| 34 | #define BAD_PROT 0xFFFF | ||
| 29 | 35 | ||
| 30 | /* SMB command codes */ | 36 | /* SMB command codes */ |
| 31 | /* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses | 37 | /* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses |
| @@ -110,7 +116,7 @@ | |||
| 110 | /* | 116 | /* |
| 111 | * Size of the session key (crypto key encrypted with the password | 117 | * Size of the session key (crypto key encrypted with the password |
| 112 | */ | 118 | */ |
| 113 | #define CIFS_SESSION_KEY_SIZE (24) | 119 | #define CIFS_SESS_KEY_SIZE (24) |
| 114 | 120 | ||
| 115 | /* | 121 | /* |
| 116 | * Maximum user name length | 122 | * Maximum user name length |
| @@ -400,6 +406,29 @@ typedef struct negotiate_req { | |||
| 400 | unsigned char DialectsArray[1]; | 406 | unsigned char DialectsArray[1]; |
| 401 | } __attribute__((packed)) NEGOTIATE_REQ; | 407 | } __attribute__((packed)) NEGOTIATE_REQ; |
| 402 | 408 | ||
| 409 | /* Dialect index is 13 for LANMAN */ | ||
| 410 | |||
| 411 | typedef struct lanman_neg_rsp { | ||
| 412 | struct smb_hdr hdr; /* wct = 13 */ | ||
| 413 | __le16 DialectIndex; | ||
| 414 | __le16 SecurityMode; | ||
| 415 | __le16 MaxBufSize; | ||
| 416 | __le16 MaxMpxCount; | ||
| 417 | __le16 MaxNumberVcs; | ||
| 418 | __le16 RawMode; | ||
| 419 | __le32 SessionKey; | ||
| 420 | __le32 ServerTime; | ||
| 421 | __le16 ServerTimeZone; | ||
| 422 | __le16 EncryptionKeyLength; | ||
| 423 | __le16 Reserved; | ||
| 424 | __u16 ByteCount; | ||
| 425 | unsigned char EncryptionKey[1]; | ||
| 426 | } __attribute__((packed)) LANMAN_NEG_RSP; | ||
| 427 | |||
| 428 | #define READ_RAW_ENABLE 1 | ||
| 429 | #define WRITE_RAW_ENABLE 2 | ||
| 430 | #define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE) | ||
| 431 | |||
| 403 | typedef struct negotiate_rsp { | 432 | typedef struct negotiate_rsp { |
| 404 | struct smb_hdr hdr; /* wct = 17 */ | 433 | struct smb_hdr hdr; /* wct = 17 */ |
| 405 | __le16 DialectIndex; | 434 | __le16 DialectIndex; |
| @@ -509,7 +538,7 @@ typedef union smb_com_session_setup_andx { | |||
| 509 | /* unsigned char * NativeOS; */ | 538 | /* unsigned char * NativeOS; */ |
| 510 | /* unsigned char * NativeLanMan; */ | 539 | /* unsigned char * NativeLanMan; */ |
| 511 | /* unsigned char * PrimaryDomain; */ | 540 | /* unsigned char * PrimaryDomain; */ |
| 512 | } __attribute__((packed)) resp; /* NTLM response format (with or without extended security */ | 541 | } __attribute__((packed)) resp; /* NTLM response with or without extended sec*/ |
| 513 | 542 | ||
| 514 | struct { /* request format */ | 543 | struct { /* request format */ |
| 515 | struct smb_hdr hdr; /* wct = 10 */ | 544 | struct smb_hdr hdr; /* wct = 10 */ |
| @@ -520,8 +549,8 @@ typedef union smb_com_session_setup_andx { | |||
| 520 | __le16 MaxMpxCount; | 549 | __le16 MaxMpxCount; |
| 521 | __le16 VcNumber; | 550 | __le16 VcNumber; |
| 522 | __u32 SessionKey; | 551 | __u32 SessionKey; |
| 523 | __le16 PassswordLength; | 552 | __le16 PasswordLength; |
| 524 | __u32 Reserved; | 553 | __u32 Reserved; /* encrypt key len and offset */ |
| 525 | __le16 ByteCount; | 554 | __le16 ByteCount; |
| 526 | unsigned char AccountPassword[1]; /* followed by */ | 555 | unsigned char AccountPassword[1]; /* followed by */ |
| 527 | /* STRING AccountName */ | 556 | /* STRING AccountName */ |
| @@ -543,6 +572,26 @@ typedef union smb_com_session_setup_andx { | |||
| 543 | } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */ | 572 | } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */ |
| 544 | } __attribute__((packed)) SESSION_SETUP_ANDX; | 573 | } __attribute__((packed)) SESSION_SETUP_ANDX; |
| 545 | 574 | ||
| 575 | /* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */ | ||
| 576 | |||
| 577 | struct ntlmssp2_name { | ||
| 578 | __le16 type; | ||
| 579 | __le16 length; | ||
| 580 | /* char name[length]; */ | ||
| 581 | } __attribute__((packed)); | ||
| 582 | |||
| 583 | struct ntlmv2_resp { | ||
| 584 | char ntlmv2_hash[CIFS_ENCPWD_SIZE]; | ||
| 585 | __le32 blob_signature; | ||
| 586 | __u32 reserved; | ||
| 587 | __le64 time; | ||
| 588 | __u64 client_chal; /* random */ | ||
| 589 | __u32 reserved2; | ||
| 590 | struct ntlmssp2_name names[1]; | ||
| 591 | /* array of name entries could follow ending in minimum 4 byte struct */ | ||
| 592 | } __attribute__((packed)); | ||
| 593 | |||
| 594 | |||
| 546 | #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" | 595 | #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" |
| 547 | 596 | ||
| 548 | /* Capabilities bits (for NTLM SessSetup request) */ | 597 | /* Capabilities bits (for NTLM SessSetup request) */ |
| @@ -573,7 +622,9 @@ typedef struct smb_com_tconx_req { | |||
| 573 | } __attribute__((packed)) TCONX_REQ; | 622 | } __attribute__((packed)) TCONX_REQ; |
| 574 | 623 | ||
| 575 | typedef struct smb_com_tconx_rsp { | 624 | typedef struct smb_com_tconx_rsp { |
| 576 | struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ | 625 | struct smb_hdr hdr; /* wct = 3 note that Win2000 has sent wct = 7 |
| 626 | in some cases on responses. Four unspecified | ||
| 627 | words followed OptionalSupport */ | ||
| 577 | __u8 AndXCommand; | 628 | __u8 AndXCommand; |
| 578 | __u8 AndXReserved; | 629 | __u8 AndXReserved; |
| 579 | __le16 AndXOffset; | 630 | __le16 AndXOffset; |
| @@ -1323,6 +1374,9 @@ struct smb_t2_rsp { | |||
| 1323 | #define SMB_FILE_MAXIMUM_INFO 0x40d | 1374 | #define SMB_FILE_MAXIMUM_INFO 0x40d |
| 1324 | 1375 | ||
| 1325 | /* Find File infolevels */ | 1376 | /* Find File infolevels */ |
| 1377 | #define SMB_FIND_FILE_INFO_STANDARD 0x001 | ||
| 1378 | #define SMB_FIND_FILE_QUERY_EA_SIZE 0x002 | ||
| 1379 | #define SMB_FIND_FILE_QUERY_EAS_FROM_LIST 0x003 | ||
| 1326 | #define SMB_FIND_FILE_DIRECTORY_INFO 0x101 | 1380 | #define SMB_FIND_FILE_DIRECTORY_INFO 0x101 |
| 1327 | #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 | 1381 | #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 |
| 1328 | #define SMB_FIND_FILE_NAMES_INFO 0x103 | 1382 | #define SMB_FIND_FILE_NAMES_INFO 0x103 |
| @@ -1844,13 +1898,13 @@ typedef struct { | |||
| 1844 | typedef struct { | 1898 | typedef struct { |
| 1845 | __le32 DeviceType; | 1899 | __le32 DeviceType; |
| 1846 | __le32 DeviceCharacteristics; | 1900 | __le32 DeviceCharacteristics; |
| 1847 | } __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ | 1901 | } __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */ |
| 1848 | 1902 | ||
| 1849 | typedef struct { | 1903 | typedef struct { |
| 1850 | __le32 Attributes; | 1904 | __le32 Attributes; |
| 1851 | __le32 MaxPathNameComponentLength; | 1905 | __le32 MaxPathNameComponentLength; |
| 1852 | __le32 FileSystemNameLen; | 1906 | __le32 FileSystemNameLen; |
| 1853 | char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ | 1907 | char FileSystemName[52]; /* do not have to save this - get subset? */ |
| 1854 | } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO; | 1908 | } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO; |
| 1855 | 1909 | ||
| 1856 | /******************************************************************************/ | 1910 | /******************************************************************************/ |
| @@ -1947,7 +2001,8 @@ typedef struct { | |||
| 1947 | 2001 | ||
| 1948 | struct file_allocation_info { | 2002 | struct file_allocation_info { |
| 1949 | __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ | 2003 | __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ |
| 1950 | } __attribute__((packed)); /* size used on disk, level 0x103 for set, 0x105 for query */ | 2004 | } __attribute__((packed)); /* size used on disk, for level 0x103 for set, |
| 2005 | 0x105 for query */ | ||
| 1951 | 2006 | ||
| 1952 | struct file_end_of_file_info { | 2007 | struct file_end_of_file_info { |
| 1953 | __le64 FileSize; /* offset to end of file */ | 2008 | __le64 FileSize; /* offset to end of file */ |
| @@ -2054,7 +2109,7 @@ typedef struct { | |||
| 2054 | __le32 ExtFileAttributes; | 2109 | __le32 ExtFileAttributes; |
| 2055 | __le32 FileNameLength; | 2110 | __le32 FileNameLength; |
| 2056 | char FileName[1]; | 2111 | char FileName[1]; |
| 2057 | } __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ | 2112 | } __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF resp data */ |
| 2058 | 2113 | ||
| 2059 | typedef struct { | 2114 | typedef struct { |
| 2060 | __le32 NextEntryOffset; | 2115 | __le32 NextEntryOffset; |
| @@ -2069,7 +2124,7 @@ typedef struct { | |||
| 2069 | __le32 FileNameLength; | 2124 | __le32 FileNameLength; |
| 2070 | __le32 EaSize; /* length of the xattrs */ | 2125 | __le32 EaSize; /* length of the xattrs */ |
| 2071 | char FileName[1]; | 2126 | char FileName[1]; |
| 2072 | } __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */ | 2127 | } __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */ |
| 2073 | 2128 | ||
| 2074 | typedef struct { | 2129 | typedef struct { |
| 2075 | __le32 NextEntryOffset; | 2130 | __le32 NextEntryOffset; |
| @@ -2086,7 +2141,7 @@ typedef struct { | |||
| 2086 | __le32 Reserved; | 2141 | __le32 Reserved; |
| 2087 | __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ | 2142 | __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ |
| 2088 | char FileName[1]; | 2143 | char FileName[1]; |
| 2089 | } __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */ | 2144 | } __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */ |
| 2090 | 2145 | ||
| 2091 | typedef struct { | 2146 | typedef struct { |
| 2092 | __le32 NextEntryOffset; | 2147 | __le32 NextEntryOffset; |
| @@ -2104,7 +2159,22 @@ typedef struct { | |||
| 2104 | __u8 Reserved; | 2159 | __u8 Reserved; |
| 2105 | __u8 ShortName[12]; | 2160 | __u8 ShortName[12]; |
| 2106 | char FileName[1]; | 2161 | char FileName[1]; |
| 2107 | } __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ | 2162 | } __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */ |
| 2163 | |||
| 2164 | typedef struct { | ||
| 2165 | __u32 ResumeKey; | ||
| 2166 | __le16 CreationDate; /* SMB Date */ | ||
| 2167 | __le16 CreationTime; /* SMB Time */ | ||
| 2168 | __le16 LastAccessDate; | ||
| 2169 | __le16 LastAccessTime; | ||
| 2170 | __le16 LastWriteDate; | ||
| 2171 | __le16 LastWriteTime; | ||
| 2172 | __le32 DataSize; /* File Size (EOF) */ | ||
| 2173 | __le32 AllocationSize; | ||
| 2174 | __le16 Attributes; /* verify not u32 */ | ||
| 2175 | __u8 FileNameLength; | ||
| 2176 | char FileName[1]; | ||
| 2177 | } __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */ | ||
| 2108 | 2178 | ||
| 2109 | 2179 | ||
| 2110 | struct win_dev { | 2180 | struct win_dev { |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 310ea2f0e0bf..a5ddc62d6fe6 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -64,14 +64,12 @@ extern int map_smb_to_linux_error(struct smb_hdr *smb); | |||
| 64 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 64 | extern void header_assemble(struct smb_hdr *, char /* command */ , |
| 65 | const struct cifsTconInfo *, int /* length of | 65 | const struct cifsTconInfo *, int /* length of |
| 66 | fixed section (word count) in two byte units */); | 66 | fixed section (word count) in two byte units */); |
| 67 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
| 68 | extern int small_smb_init_no_tc(const int smb_cmd, const int wct, | 67 | extern int small_smb_init_no_tc(const int smb_cmd, const int wct, |
| 69 | struct cifsSesInfo *ses, | 68 | struct cifsSesInfo *ses, |
| 70 | void ** request_buf); | 69 | void ** request_buf); |
| 71 | extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | 70 | extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, |
| 72 | const int stage, int * pNTLMv2_flg, | 71 | const int stage, |
| 73 | const struct nls_table *nls_cp); | 72 | const struct nls_table *nls_cp); |
| 74 | #endif | ||
| 75 | extern __u16 GetNextMid(struct TCP_Server_Info *server); | 73 | extern __u16 GetNextMid(struct TCP_Server_Info *server); |
| 76 | extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, | 74 | extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, |
| 77 | struct cifsTconInfo *); | 75 | struct cifsTconInfo *); |
| @@ -285,8 +283,14 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, | |||
| 285 | extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, | 283 | extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, |
| 286 | __u32 expected_sequence_number); | 284 | __u32 expected_sequence_number); |
| 287 | extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); | 285 | extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); |
| 288 | extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); | 286 | extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, |
| 289 | extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); | 287 | const struct nls_table *); |
| 288 | extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * ); | ||
| 289 | extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, | ||
| 290 | const struct nls_table *); | ||
| 291 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 292 | extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key); | ||
| 293 | #endif /* CIFS_WEAK_PW_HASH */ | ||
| 290 | extern int CIFSSMBCopy(int xid, | 294 | extern int CIFSSMBCopy(int xid, |
| 291 | struct cifsTconInfo *source_tcon, | 295 | struct cifsTconInfo *source_tcon, |
| 292 | const char *fromName, | 296 | const char *fromName, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 925881e00ff2..19678c575dfc 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -44,8 +44,11 @@ static struct { | |||
| 44 | int index; | 44 | int index; |
| 45 | char *name; | 45 | char *name; |
| 46 | } protocols[] = { | 46 | } protocols[] = { |
| 47 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 48 | {LANMAN_PROT, "\2LM1.2X002"}, | ||
| 49 | #endif /* weak password hashing for legacy clients */ | ||
| 47 | {CIFS_PROT, "\2NT LM 0.12"}, | 50 | {CIFS_PROT, "\2NT LM 0.12"}, |
| 48 | {CIFS_PROT, "\2POSIX 2"}, | 51 | {POSIX_PROT, "\2POSIX 2"}, |
| 49 | {BAD_PROT, "\2"} | 52 | {BAD_PROT, "\2"} |
| 50 | }; | 53 | }; |
| 51 | #else | 54 | #else |
| @@ -53,11 +56,29 @@ static struct { | |||
| 53 | int index; | 56 | int index; |
| 54 | char *name; | 57 | char *name; |
| 55 | } protocols[] = { | 58 | } protocols[] = { |
| 59 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 60 | {LANMAN_PROT, "\2LM1.2X002"}, | ||
| 61 | #endif /* weak password hashing for legacy clients */ | ||
| 56 | {CIFS_PROT, "\2NT LM 0.12"}, | 62 | {CIFS_PROT, "\2NT LM 0.12"}, |
| 57 | {BAD_PROT, "\2"} | 63 | {BAD_PROT, "\2"} |
| 58 | }; | 64 | }; |
| 59 | #endif | 65 | #endif |
| 60 | 66 | ||
| 67 | /* define the number of elements in the cifs dialect array */ | ||
| 68 | #ifdef CONFIG_CIFS_POSIX | ||
| 69 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 70 | #define CIFS_NUM_PROT 3 | ||
| 71 | #else | ||
| 72 | #define CIFS_NUM_PROT 2 | ||
| 73 | #endif /* CIFS_WEAK_PW_HASH */ | ||
| 74 | #else /* not posix */ | ||
| 75 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 76 | #define CIFS_NUM_PROT 2 | ||
| 77 | #else | ||
| 78 | #define CIFS_NUM_PROT 1 | ||
| 79 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ | ||
| 80 | #endif /* CIFS_POSIX */ | ||
| 81 | |||
| 61 | 82 | ||
| 62 | /* Mark as invalid, all open files on tree connections since they | 83 | /* Mark as invalid, all open files on tree connections since they |
| 63 | were closed when session to server was lost */ | 84 | were closed when session to server was lost */ |
| @@ -188,7 +209,6 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
| 188 | return rc; | 209 | return rc; |
| 189 | } | 210 | } |
| 190 | 211 | ||
| 191 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
| 192 | int | 212 | int |
| 193 | small_smb_init_no_tc(const int smb_command, const int wct, | 213 | small_smb_init_no_tc(const int smb_command, const int wct, |
| 194 | struct cifsSesInfo *ses, void **request_buf) | 214 | struct cifsSesInfo *ses, void **request_buf) |
| @@ -214,7 +234,6 @@ small_smb_init_no_tc(const int smb_command, const int wct, | |||
| 214 | 234 | ||
| 215 | return rc; | 235 | return rc; |
| 216 | } | 236 | } |
| 217 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
| 218 | 237 | ||
| 219 | /* If the return code is zero, this function must fill in request_buf pointer */ | 238 | /* If the return code is zero, this function must fill in request_buf pointer */ |
| 220 | static int | 239 | static int |
| @@ -322,7 +341,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
| 322 | /* potential retries of smb operations it turns out we can determine */ | 341 | /* potential retries of smb operations it turns out we can determine */ |
| 323 | /* from the mid flags when the request buffer can be resent without */ | 342 | /* from the mid flags when the request buffer can be resent without */ |
| 324 | /* having to use a second distinct buffer for the response */ | 343 | /* having to use a second distinct buffer for the response */ |
| 325 | *response_buf = *request_buf; | 344 | if(response_buf) |
| 345 | *response_buf = *request_buf; | ||
| 326 | 346 | ||
| 327 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, | 347 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, |
| 328 | wct /*wct */ ); | 348 | wct /*wct */ ); |
| @@ -373,8 +393,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 373 | NEGOTIATE_RSP *pSMBr; | 393 | NEGOTIATE_RSP *pSMBr; |
| 374 | int rc = 0; | 394 | int rc = 0; |
| 375 | int bytes_returned; | 395 | int bytes_returned; |
| 396 | int i; | ||
| 376 | struct TCP_Server_Info * server; | 397 | struct TCP_Server_Info * server; |
| 377 | u16 count; | 398 | u16 count; |
| 399 | unsigned int secFlags; | ||
| 378 | 400 | ||
| 379 | if(ses->server) | 401 | if(ses->server) |
| 380 | server = ses->server; | 402 | server = ses->server; |
| @@ -386,101 +408,200 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 386 | (void **) &pSMB, (void **) &pSMBr); | 408 | (void **) &pSMB, (void **) &pSMBr); |
| 387 | if (rc) | 409 | if (rc) |
| 388 | return rc; | 410 | return rc; |
| 411 | |||
| 412 | /* if any of auth flags (ie not sign or seal) are overriden use them */ | ||
| 413 | if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) | ||
| 414 | secFlags = ses->overrideSecFlg; | ||
| 415 | else /* if override flags set only sign/seal OR them with global auth */ | ||
| 416 | secFlags = extended_security | ses->overrideSecFlg; | ||
| 417 | |||
| 418 | cFYI(1,("secFlags 0x%x",secFlags)); | ||
| 419 | |||
| 389 | pSMB->hdr.Mid = GetNextMid(server); | 420 | pSMB->hdr.Mid = GetNextMid(server); |
| 390 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 421 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
| 391 | if (extended_security) | 422 | if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) |
| 392 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 423 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
| 393 | 424 | ||
| 394 | count = strlen(protocols[0].name) + 1; | 425 | count = 0; |
| 395 | strncpy(pSMB->DialectsArray, protocols[0].name, 30); | 426 | for(i=0;i<CIFS_NUM_PROT;i++) { |
| 396 | /* null guaranteed to be at end of source and target buffers anyway */ | 427 | strncpy(pSMB->DialectsArray+count, protocols[i].name, 16); |
| 397 | 428 | count += strlen(protocols[i].name) + 1; | |
| 429 | /* null at end of source and target buffers anyway */ | ||
| 430 | } | ||
| 398 | pSMB->hdr.smb_buf_length += count; | 431 | pSMB->hdr.smb_buf_length += count; |
| 399 | pSMB->ByteCount = cpu_to_le16(count); | 432 | pSMB->ByteCount = cpu_to_le16(count); |
| 400 | 433 | ||
| 401 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 434 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, |
| 402 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 435 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 403 | if (rc == 0) { | 436 | if (rc != 0) |
| 404 | server->secMode = pSMBr->SecurityMode; | 437 | goto neg_err_exit; |
| 405 | if((server->secMode & SECMODE_USER) == 0) | 438 | |
| 406 | cFYI(1,("share mode security")); | 439 | cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); |
| 407 | server->secType = NTLM; /* BB override default for | 440 | /* Check wct = 1 error case */ |
| 408 | NTLMv2 or kerberos v5 */ | 441 | if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) { |
| 409 | /* one byte - no need to convert this or EncryptionKeyLen | 442 | /* core returns wct = 1, but we do not ask for core - otherwise |
| 410 | from little endian */ | 443 | small wct just comes when dialect index is -1 indicating we |
| 411 | server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); | 444 | could not negotiate a common dialect */ |
| 412 | /* probably no need to store and check maxvcs */ | 445 | rc = -EOPNOTSUPP; |
| 413 | server->maxBuf = | 446 | goto neg_err_exit; |
| 414 | min(le32_to_cpu(pSMBr->MaxBufferSize), | 447 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
| 448 | } else if((pSMBr->hdr.WordCount == 13) | ||
| 449 | && (pSMBr->DialectIndex == LANMAN_PROT)) { | ||
| 450 | struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; | ||
| 451 | |||
| 452 | if((secFlags & CIFSSEC_MAY_LANMAN) || | ||
| 453 | (secFlags & CIFSSEC_MAY_PLNTXT)) | ||
| 454 | server->secType = LANMAN; | ||
| 455 | else { | ||
| 456 | cERROR(1, ("mount failed weak security disabled" | ||
| 457 | " in /proc/fs/cifs/SecurityFlags")); | ||
| 458 | rc = -EOPNOTSUPP; | ||
| 459 | goto neg_err_exit; | ||
| 460 | } | ||
| 461 | server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); | ||
| 462 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); | ||
| 463 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), | ||
| 464 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | ||
| 465 | GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); | ||
| 466 | /* even though we do not use raw we might as well set this | ||
| 467 | accurately, in case we ever find a need for it */ | ||
| 468 | if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | ||
| 469 | server->maxRw = 0xFF00; | ||
| 470 | server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; | ||
| 471 | } else { | ||
| 472 | server->maxRw = 0;/* we do not need to use raw anyway */ | ||
| 473 | server->capabilities = CAP_MPX_MODE; | ||
| 474 | } | ||
| 475 | server->timeZone = le16_to_cpu(rsp->ServerTimeZone); | ||
| 476 | |||
| 477 | /* BB get server time for time conversions and add | ||
| 478 | code to use it and timezone since this is not UTC */ | ||
| 479 | |||
| 480 | if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | ||
| 481 | memcpy(server->cryptKey, rsp->EncryptionKey, | ||
| 482 | CIFS_CRYPTO_KEY_SIZE); | ||
| 483 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { | ||
| 484 | rc = -EIO; /* need cryptkey unless plain text */ | ||
| 485 | goto neg_err_exit; | ||
| 486 | } | ||
| 487 | |||
| 488 | cFYI(1,("LANMAN negotiated")); | ||
| 489 | /* we will not end up setting signing flags - as no signing | ||
| 490 | was in LANMAN and server did not return the flags on */ | ||
| 491 | goto signing_check; | ||
| 492 | #else /* weak security disabled */ | ||
| 493 | } else if(pSMBr->hdr.WordCount == 13) { | ||
| 494 | cERROR(1,("mount failed, cifs module not built " | ||
| 495 | "with CIFS_WEAK_PW_HASH support")); | ||
| 496 | rc = -EOPNOTSUPP; | ||
| 497 | #endif /* WEAK_PW_HASH */ | ||
| 498 | goto neg_err_exit; | ||
| 499 | } else if(pSMBr->hdr.WordCount != 17) { | ||
| 500 | /* unknown wct */ | ||
| 501 | rc = -EOPNOTSUPP; | ||
| 502 | goto neg_err_exit; | ||
| 503 | } | ||
| 504 | /* else wct == 17 NTLM */ | ||
| 505 | server->secMode = pSMBr->SecurityMode; | ||
| 506 | if((server->secMode & SECMODE_USER) == 0) | ||
| 507 | cFYI(1,("share mode security")); | ||
| 508 | |||
| 509 | if((server->secMode & SECMODE_PW_ENCRYPT) == 0) | ||
| 510 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 511 | if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0) | ||
| 512 | #endif /* CIFS_WEAK_PW_HASH */ | ||
| 513 | cERROR(1,("Server requests plain text password" | ||
| 514 | " but client support disabled")); | ||
| 515 | |||
| 516 | if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2) | ||
| 517 | server->secType = NTLMv2; | ||
| 518 | else if(secFlags & CIFSSEC_MAY_NTLM) | ||
| 519 | server->secType = NTLM; | ||
| 520 | else if(secFlags & CIFSSEC_MAY_NTLMV2) | ||
| 521 | server->secType = NTLMv2; | ||
| 522 | /* else krb5 ... any others ... */ | ||
| 523 | |||
| 524 | /* one byte, so no need to convert this or EncryptionKeyLen from | ||
| 525 | little endian */ | ||
| 526 | server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); | ||
| 527 | /* probably no need to store and check maxvcs */ | ||
| 528 | server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), | ||
| 415 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 529 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
| 416 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); | 530 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); |
| 417 | cFYI(0, ("Max buf = %d", ses->server->maxBuf)); | 531 | cFYI(0, ("Max buf = %d", ses->server->maxBuf)); |
| 418 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | 532 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); |
| 419 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 533 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
| 420 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); | 534 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); |
| 421 | /* BB with UTC do we ever need to be using srvr timezone? */ | 535 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { |
| 422 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | 536 | memcpy(server->cryptKey, pSMBr->u.EncryptionKey, |
| 423 | memcpy(server->cryptKey, pSMBr->u.EncryptionKey, | 537 | CIFS_CRYPTO_KEY_SIZE); |
| 424 | CIFS_CRYPTO_KEY_SIZE); | 538 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) |
| 425 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) | 539 | && (pSMBr->EncryptionKeyLength == 0)) { |
| 426 | && (pSMBr->EncryptionKeyLength == 0)) { | 540 | /* decode security blob */ |
| 427 | /* decode security blob */ | 541 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { |
| 428 | } else | 542 | rc = -EIO; /* no crypt key only if plain text pwd */ |
| 429 | rc = -EIO; | 543 | goto neg_err_exit; |
| 544 | } | ||
| 430 | 545 | ||
| 431 | /* BB might be helpful to save off the domain of server here */ | 546 | /* BB might be helpful to save off the domain of server here */ |
| 432 | 547 | ||
| 433 | if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && | 548 | if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && |
| 434 | (server->capabilities & CAP_EXTENDED_SECURITY)) { | 549 | (server->capabilities & CAP_EXTENDED_SECURITY)) { |
| 435 | count = pSMBr->ByteCount; | 550 | count = pSMBr->ByteCount; |
| 436 | if (count < 16) | 551 | if (count < 16) |
| 437 | rc = -EIO; | 552 | rc = -EIO; |
| 438 | else if (count == 16) { | 553 | else if (count == 16) { |
| 439 | server->secType = RawNTLMSSP; | 554 | server->secType = RawNTLMSSP; |
| 440 | if (server->socketUseCount.counter > 1) { | 555 | if (server->socketUseCount.counter > 1) { |
| 441 | if (memcmp | 556 | if (memcmp(server->server_GUID, |
| 442 | (server->server_GUID, | 557 | pSMBr->u.extended_response. |
| 443 | pSMBr->u.extended_response. | 558 | GUID, 16) != 0) { |
| 444 | GUID, 16) != 0) { | 559 | cFYI(1, ("server UID changed")); |
| 445 | cFYI(1, ("server UID changed")); | ||
| 446 | memcpy(server-> | ||
| 447 | server_GUID, | ||
| 448 | pSMBr->u. | ||
| 449 | extended_response. | ||
| 450 | GUID, 16); | ||
| 451 | } | ||
| 452 | } else | ||
| 453 | memcpy(server->server_GUID, | 560 | memcpy(server->server_GUID, |
| 454 | pSMBr->u.extended_response. | 561 | pSMBr->u.extended_response.GUID, |
| 455 | GUID, 16); | 562 | 16); |
| 456 | } else { | ||
| 457 | rc = decode_negTokenInit(pSMBr->u. | ||
| 458 | extended_response. | ||
| 459 | SecurityBlob, | ||
| 460 | count - 16, | ||
| 461 | &server->secType); | ||
| 462 | if(rc == 1) { | ||
| 463 | /* BB Need to fill struct for sessetup here */ | ||
| 464 | rc = -EOPNOTSUPP; | ||
| 465 | } else { | ||
| 466 | rc = -EINVAL; | ||
| 467 | } | 563 | } |
| 564 | } else | ||
| 565 | memcpy(server->server_GUID, | ||
| 566 | pSMBr->u.extended_response.GUID, 16); | ||
| 567 | } else { | ||
| 568 | rc = decode_negTokenInit(pSMBr->u.extended_response. | ||
| 569 | SecurityBlob, | ||
| 570 | count - 16, | ||
| 571 | &server->secType); | ||
| 572 | if(rc == 1) { | ||
| 573 | /* BB Need to fill struct for sessetup here */ | ||
| 574 | rc = -EOPNOTSUPP; | ||
| 575 | } else { | ||
| 576 | rc = -EINVAL; | ||
| 468 | } | 577 | } |
| 469 | } else | ||
| 470 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | ||
| 471 | if(sign_CIFS_PDUs == FALSE) { | ||
| 472 | if(server->secMode & SECMODE_SIGN_REQUIRED) | ||
| 473 | cERROR(1, | ||
| 474 | ("Server requires /proc/fs/cifs/PacketSigningEnabled")); | ||
| 475 | server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
| 476 | } else if(sign_CIFS_PDUs == 1) { | ||
| 477 | if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) | ||
| 478 | server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
| 479 | } | 578 | } |
| 480 | 579 | } else | |
| 580 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | ||
| 581 | |||
| 582 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 583 | signing_check: | ||
| 584 | #endif | ||
| 585 | if(sign_CIFS_PDUs == FALSE) { | ||
| 586 | if(server->secMode & SECMODE_SIGN_REQUIRED) | ||
| 587 | cERROR(1,("Server requires " | ||
| 588 | "/proc/fs/cifs/PacketSigningEnabled to be on")); | ||
| 589 | server->secMode &= | ||
| 590 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
| 591 | } else if(sign_CIFS_PDUs == 1) { | ||
| 592 | if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) | ||
| 593 | server->secMode &= | ||
| 594 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
| 595 | } else if(sign_CIFS_PDUs == 2) { | ||
| 596 | if((server->secMode & | ||
| 597 | (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { | ||
| 598 | cERROR(1,("signing required but server lacks support")); | ||
| 599 | } | ||
| 481 | } | 600 | } |
| 482 | 601 | neg_err_exit: | |
| 483 | cifs_buf_release(pSMB); | 602 | cifs_buf_release(pSMB); |
| 603 | |||
| 604 | cFYI(1,("negprot rc %d",rc)); | ||
| 484 | return rc; | 605 | return rc; |
| 485 | } | 606 | } |
| 486 | 607 | ||
| @@ -2239,7 +2360,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
| 2239 | } | 2360 | } |
| 2240 | symlinkinfo[buflen] = 0; /* just in case so the caller | 2361 | symlinkinfo[buflen] = 0; /* just in case so the caller |
| 2241 | does not go off the end of the buffer */ | 2362 | does not go off the end of the buffer */ |
| 2242 | cFYI(1,("readlink result - %s ",symlinkinfo)); | 2363 | cFYI(1,("readlink result - %s",symlinkinfo)); |
| 2243 | } | 2364 | } |
| 2244 | } | 2365 | } |
| 2245 | qreparse_out: | 2366 | qreparse_out: |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index bae1479318d1..876eb9ef85fe 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -49,8 +49,6 @@ | |||
| 49 | 49 | ||
| 50 | static DECLARE_COMPLETION(cifsd_complete); | 50 | static DECLARE_COMPLETION(cifsd_complete); |
| 51 | 51 | ||
| 52 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, | ||
| 53 | unsigned char *p24); | ||
| 54 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 52 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, |
| 55 | unsigned char *p24); | 53 | unsigned char *p24); |
| 56 | 54 | ||
| @@ -70,6 +68,7 @@ struct smb_vol { | |||
| 70 | gid_t linux_gid; | 68 | gid_t linux_gid; |
| 71 | mode_t file_mode; | 69 | mode_t file_mode; |
| 72 | mode_t dir_mode; | 70 | mode_t dir_mode; |
| 71 | unsigned secFlg; | ||
| 73 | unsigned rw:1; | 72 | unsigned rw:1; |
| 74 | unsigned retry:1; | 73 | unsigned retry:1; |
| 75 | unsigned intr:1; | 74 | unsigned intr:1; |
| @@ -83,12 +82,7 @@ struct smb_vol { | |||
| 83 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ | 82 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ |
| 84 | unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ | 83 | unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ |
| 85 | unsigned sfu_emul:1; | 84 | unsigned sfu_emul:1; |
| 86 | unsigned krb5:1; | ||
| 87 | unsigned ntlm:1; | ||
| 88 | unsigned ntlmv2:1; | ||
| 89 | unsigned nullauth:1; /* attempt to authenticate with null user */ | 85 | unsigned nullauth:1; /* attempt to authenticate with null user */ |
| 90 | unsigned sign:1; | ||
| 91 | unsigned seal:1; /* encrypt */ | ||
| 92 | unsigned nocase; /* request case insensitive filenames */ | 86 | unsigned nocase; /* request case insensitive filenames */ |
| 93 | unsigned nobrl; /* disable sending byte range locks to srv */ | 87 | unsigned nobrl; /* disable sending byte range locks to srv */ |
| 94 | unsigned int rsize; | 88 | unsigned int rsize; |
| @@ -369,21 +363,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 369 | continue; | 363 | continue; |
| 370 | if (bigbuf == NULL) { | 364 | if (bigbuf == NULL) { |
| 371 | bigbuf = cifs_buf_get(); | 365 | bigbuf = cifs_buf_get(); |
| 372 | if(bigbuf == NULL) { | 366 | if (!bigbuf) { |
| 373 | cERROR(1,("No memory for large SMB response")); | 367 | cERROR(1, ("No memory for large SMB response")); |
| 374 | msleep(3000); | 368 | msleep(3000); |
| 375 | /* retry will check if exiting */ | 369 | /* retry will check if exiting */ |
| 376 | continue; | 370 | continue; |
| 377 | } | 371 | } |
| 378 | } else if(isLargeBuf) { | 372 | } else if (isLargeBuf) { |
| 379 | /* we are reusing a dirtry large buf, clear its start */ | 373 | /* we are reusing a dirty large buf, clear its start */ |
| 380 | memset(bigbuf, 0, sizeof (struct smb_hdr)); | 374 | memset(bigbuf, 0, sizeof (struct smb_hdr)); |
| 381 | } | 375 | } |
| 382 | 376 | ||
| 383 | if (smallbuf == NULL) { | 377 | if (smallbuf == NULL) { |
| 384 | smallbuf = cifs_small_buf_get(); | 378 | smallbuf = cifs_small_buf_get(); |
| 385 | if(smallbuf == NULL) { | 379 | if (!smallbuf) { |
| 386 | cERROR(1,("No memory for SMB response")); | 380 | cERROR(1, ("No memory for SMB response")); |
| 387 | msleep(1000); | 381 | msleep(1000); |
| 388 | /* retry will check if exiting */ | 382 | /* retry will check if exiting */ |
| 389 | continue; | 383 | continue; |
| @@ -403,12 +397,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 403 | kernel_recvmsg(csocket, &smb_msg, | 397 | kernel_recvmsg(csocket, &smb_msg, |
| 404 | &iov, 1, 4, 0 /* BB see socket.h flags */); | 398 | &iov, 1, 4, 0 /* BB see socket.h flags */); |
| 405 | 399 | ||
| 406 | if(server->tcpStatus == CifsExiting) { | 400 | if (server->tcpStatus == CifsExiting) { |
| 407 | break; | 401 | break; |
| 408 | } else if (server->tcpStatus == CifsNeedReconnect) { | 402 | } else if (server->tcpStatus == CifsNeedReconnect) { |
| 409 | cFYI(1,("Reconnect after server stopped responding")); | 403 | cFYI(1, ("Reconnect after server stopped responding")); |
| 410 | cifs_reconnect(server); | 404 | cifs_reconnect(server); |
| 411 | cFYI(1,("call to reconnect done")); | 405 | cFYI(1, ("call to reconnect done")); |
| 412 | csocket = server->ssocket; | 406 | csocket = server->ssocket; |
| 413 | continue; | 407 | continue; |
| 414 | } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { | 408 | } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { |
| @@ -417,15 +411,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 417 | tcpStatus CifsNeedReconnect if server hung */ | 411 | tcpStatus CifsNeedReconnect if server hung */ |
| 418 | continue; | 412 | continue; |
| 419 | } else if (length <= 0) { | 413 | } else if (length <= 0) { |
| 420 | if(server->tcpStatus == CifsNew) { | 414 | if (server->tcpStatus == CifsNew) { |
| 421 | cFYI(1,("tcp session abend after SMBnegprot")); | 415 | cFYI(1, ("tcp session abend after SMBnegprot")); |
| 422 | /* some servers kill the TCP session rather than | 416 | /* some servers kill the TCP session rather than |
| 423 | returning an SMB negprot error, in which | 417 | returning an SMB negprot error, in which |
| 424 | case reconnecting here is not going to help, | 418 | case reconnecting here is not going to help, |
| 425 | and so simply return error to mount */ | 419 | and so simply return error to mount */ |
| 426 | break; | 420 | break; |
| 427 | } | 421 | } |
| 428 | if(length == -EINTR) { | 422 | if (!try_to_freeze() && (length == -EINTR)) { |
| 429 | cFYI(1,("cifsd thread killed")); | 423 | cFYI(1,("cifsd thread killed")); |
| 430 | break; | 424 | break; |
| 431 | } | 425 | } |
| @@ -585,9 +579,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 585 | /* merge response - fix up 1st*/ | 579 | /* merge response - fix up 1st*/ |
| 586 | if(coalesce_t2(smb_buffer, | 580 | if(coalesce_t2(smb_buffer, |
| 587 | mid_entry->resp_buf)) { | 581 | mid_entry->resp_buf)) { |
| 582 | mid_entry->multiRsp = 1; | ||
| 588 | break; | 583 | break; |
| 589 | } else { | 584 | } else { |
| 590 | /* all parts received */ | 585 | /* all parts received */ |
| 586 | mid_entry->multiEnd = 1; | ||
| 591 | goto multi_t2_fnd; | 587 | goto multi_t2_fnd; |
| 592 | } | 588 | } |
| 593 | } else { | 589 | } else { |
| @@ -632,9 +628,14 @@ multi_t2_fnd: | |||
| 632 | wake_up_process(task_to_wake); | 628 | wake_up_process(task_to_wake); |
| 633 | } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) | 629 | } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) |
| 634 | && (isMultiRsp == FALSE)) { | 630 | && (isMultiRsp == FALSE)) { |
| 635 | cERROR(1, ("No task to wake, unknown frame rcvd!")); | 631 | cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter)); |
| 636 | cifs_dump_mem("Received Data is: ",(char *)smb_buffer, | 632 | cifs_dump_mem("Received Data is: ",(char *)smb_buffer, |
| 637 | sizeof(struct smb_hdr)); | 633 | sizeof(struct smb_hdr)); |
| 634 | #ifdef CONFIG_CIFS_DEBUG2 | ||
| 635 | cifs_dump_detail(smb_buffer); | ||
| 636 | cifs_dump_mids(server); | ||
| 637 | #endif /* CIFS_DEBUG2 */ | ||
| 638 | |||
| 638 | } | 639 | } |
| 639 | } /* end while !EXITING */ | 640 | } /* end while !EXITING */ |
| 640 | 641 | ||
| @@ -784,7 +785,6 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 784 | 785 | ||
| 785 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ | 786 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ |
| 786 | vol->rw = TRUE; | 787 | vol->rw = TRUE; |
| 787 | vol->ntlm = TRUE; | ||
| 788 | /* default is always to request posix paths. */ | 788 | /* default is always to request posix paths. */ |
| 789 | vol->posix_paths = 1; | 789 | vol->posix_paths = 1; |
| 790 | 790 | ||
| @@ -915,30 +915,35 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 915 | cERROR(1,("no security value specified")); | 915 | cERROR(1,("no security value specified")); |
| 916 | continue; | 916 | continue; |
| 917 | } else if (strnicmp(value, "krb5i", 5) == 0) { | 917 | } else if (strnicmp(value, "krb5i", 5) == 0) { |
| 918 | vol->sign = 1; | 918 | vol->secFlg |= CIFSSEC_MAY_KRB5 | |
| 919 | vol->krb5 = 1; | 919 | CIFSSEC_MUST_SIGN; |
| 920 | } else if (strnicmp(value, "krb5p", 5) == 0) { | 920 | } else if (strnicmp(value, "krb5p", 5) == 0) { |
| 921 | /* vol->seal = 1; | 921 | /* vol->secFlg |= CIFSSEC_MUST_SEAL | |
| 922 | vol->krb5 = 1; */ | 922 | CIFSSEC_MAY_KRB5; */ |
| 923 | cERROR(1,("Krb5 cifs privacy not supported")); | 923 | cERROR(1,("Krb5 cifs privacy not supported")); |
| 924 | return 1; | 924 | return 1; |
| 925 | } else if (strnicmp(value, "krb5", 4) == 0) { | 925 | } else if (strnicmp(value, "krb5", 4) == 0) { |
| 926 | vol->krb5 = 1; | 926 | vol->secFlg |= CIFSSEC_MAY_KRB5; |
| 927 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { | 927 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { |
| 928 | vol->ntlmv2 = 1; | 928 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | |
| 929 | vol->sign = 1; | 929 | CIFSSEC_MUST_SIGN; |
| 930 | } else if (strnicmp(value, "ntlmv2", 6) == 0) { | 930 | } else if (strnicmp(value, "ntlmv2", 6) == 0) { |
| 931 | vol->ntlmv2 = 1; | 931 | vol->secFlg |= CIFSSEC_MAY_NTLMV2; |
| 932 | } else if (strnicmp(value, "ntlmi", 5) == 0) { | 932 | } else if (strnicmp(value, "ntlmi", 5) == 0) { |
| 933 | vol->ntlm = 1; | 933 | vol->secFlg |= CIFSSEC_MAY_NTLM | |
| 934 | vol->sign = 1; | 934 | CIFSSEC_MUST_SIGN; |
| 935 | } else if (strnicmp(value, "ntlm", 4) == 0) { | 935 | } else if (strnicmp(value, "ntlm", 4) == 0) { |
| 936 | /* ntlm is default so can be turned off too */ | 936 | /* ntlm is default so can be turned off too */ |
| 937 | vol->ntlm = 1; | 937 | vol->secFlg |= CIFSSEC_MAY_NTLM; |
| 938 | } else if (strnicmp(value, "nontlm", 6) == 0) { | 938 | } else if (strnicmp(value, "nontlm", 6) == 0) { |
| 939 | vol->ntlm = 0; | 939 | /* BB is there a better way to do this? */ |
| 940 | vol->secFlg |= CIFSSEC_MAY_NTLMV2; | ||
| 941 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 942 | } else if (strnicmp(value, "lanman", 6) == 0) { | ||
| 943 | vol->secFlg |= CIFSSEC_MAY_LANMAN; | ||
| 944 | #endif | ||
| 940 | } else if (strnicmp(value, "none", 4) == 0) { | 945 | } else if (strnicmp(value, "none", 4) == 0) { |
| 941 | vol->nullauth = 1; | 946 | vol->nullauth = 1; |
| 942 | } else { | 947 | } else { |
| 943 | cERROR(1,("bad security option: %s", value)); | 948 | cERROR(1,("bad security option: %s", value)); |
| 944 | return 1; | 949 | return 1; |
| @@ -976,7 +981,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 976 | } | 981 | } |
| 977 | /* BB are there cases in which a comma can be valid in | 982 | /* BB are there cases in which a comma can be valid in |
| 978 | a domain name and need special handling? */ | 983 | a domain name and need special handling? */ |
| 979 | if (strnlen(value, 65) < 65) { | 984 | if (strnlen(value, 256) < 256) { |
| 980 | vol->domainname = value; | 985 | vol->domainname = value; |
| 981 | cFYI(1, ("Domain name set")); | 986 | cFYI(1, ("Domain name set")); |
| 982 | } else { | 987 | } else { |
| @@ -1168,6 +1173,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 1168 | vol->no_psx_acl = 0; | 1173 | vol->no_psx_acl = 0; |
| 1169 | } else if (strnicmp(data, "noacl",5) == 0) { | 1174 | } else if (strnicmp(data, "noacl",5) == 0) { |
| 1170 | vol->no_psx_acl = 1; | 1175 | vol->no_psx_acl = 1; |
| 1176 | } else if (strnicmp(data, "sign",4) == 0) { | ||
| 1177 | vol->secFlg |= CIFSSEC_MUST_SIGN; | ||
| 1178 | /* } else if (strnicmp(data, "seal",4) == 0) { | ||
| 1179 | vol->secFlg |= CIFSSEC_MUST_SEAL; */ | ||
| 1171 | } else if (strnicmp(data, "direct",6) == 0) { | 1180 | } else if (strnicmp(data, "direct",6) == 0) { |
| 1172 | vol->direct_io = 1; | 1181 | vol->direct_io = 1; |
| 1173 | } else if (strnicmp(data, "forcedirectio",13) == 0) { | 1182 | } else if (strnicmp(data, "forcedirectio",13) == 0) { |
| @@ -1762,11 +1771,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1762 | if (volume_info.username) | 1771 | if (volume_info.username) |
| 1763 | strncpy(pSesInfo->userName, | 1772 | strncpy(pSesInfo->userName, |
| 1764 | volume_info.username,MAX_USERNAME_SIZE); | 1773 | volume_info.username,MAX_USERNAME_SIZE); |
| 1765 | if (volume_info.domainname) | 1774 | if (volume_info.domainname) { |
| 1766 | strncpy(pSesInfo->domainName, | 1775 | int len = strlen(volume_info.domainname); |
| 1767 | volume_info.domainname,MAX_USERNAME_SIZE); | 1776 | pSesInfo->domainName = |
| 1777 | kmalloc(len + 1, GFP_KERNEL); | ||
| 1778 | if(pSesInfo->domainName) | ||
| 1779 | strcpy(pSesInfo->domainName, | ||
| 1780 | volume_info.domainname); | ||
| 1781 | } | ||
| 1768 | pSesInfo->linux_uid = volume_info.linux_uid; | 1782 | pSesInfo->linux_uid = volume_info.linux_uid; |
| 1783 | pSesInfo->overrideSecFlg = volume_info.secFlg; | ||
| 1769 | down(&pSesInfo->sesSem); | 1784 | down(&pSesInfo->sesSem); |
| 1785 | /* BB FIXME need to pass vol->secFlgs BB */ | ||
| 1770 | rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); | 1786 | rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); |
| 1771 | up(&pSesInfo->sesSem); | 1787 | up(&pSesInfo->sesSem); |
| 1772 | if(!rc) | 1788 | if(!rc) |
| @@ -1980,7 +1996,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1980 | 1996 | ||
| 1981 | static int | 1997 | static int |
| 1982 | CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | 1998 | CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, |
| 1983 | char session_key[CIFS_SESSION_KEY_SIZE], | 1999 | char session_key[CIFS_SESS_KEY_SIZE], |
| 1984 | const struct nls_table *nls_codepage) | 2000 | const struct nls_table *nls_codepage) |
| 1985 | { | 2001 | { |
| 1986 | struct smb_hdr *smb_buffer; | 2002 | struct smb_hdr *smb_buffer; |
| @@ -2038,15 +2054,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2038 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | 2054 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); |
| 2039 | 2055 | ||
| 2040 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | 2056 | pSMB->req_no_secext.CaseInsensitivePasswordLength = |
| 2041 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | 2057 | cpu_to_le16(CIFS_SESS_KEY_SIZE); |
| 2042 | 2058 | ||
| 2043 | pSMB->req_no_secext.CaseSensitivePasswordLength = | 2059 | pSMB->req_no_secext.CaseSensitivePasswordLength = |
| 2044 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | 2060 | cpu_to_le16(CIFS_SESS_KEY_SIZE); |
| 2045 | bcc_ptr = pByteArea(smb_buffer); | 2061 | bcc_ptr = pByteArea(smb_buffer); |
| 2046 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); | 2062 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); |
| 2047 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | 2063 | bcc_ptr += CIFS_SESS_KEY_SIZE; |
| 2048 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); | 2064 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); |
| 2049 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | 2065 | bcc_ptr += CIFS_SESS_KEY_SIZE; |
| 2050 | 2066 | ||
| 2051 | if (ses->capabilities & CAP_UNICODE) { | 2067 | if (ses->capabilities & CAP_UNICODE) { |
| 2052 | if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ | 2068 | if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ |
| @@ -2054,7 +2070,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2054 | bcc_ptr++; | 2070 | bcc_ptr++; |
| 2055 | } | 2071 | } |
| 2056 | if(user == NULL) | 2072 | if(user == NULL) |
| 2057 | bytes_returned = 0; /* skill null user */ | 2073 | bytes_returned = 0; /* skip null user */ |
| 2058 | else | 2074 | else |
| 2059 | bytes_returned = | 2075 | bytes_returned = |
| 2060 | cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, | 2076 | cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, |
| @@ -2162,8 +2178,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2162 | if (remaining_words > 0) { | 2178 | if (remaining_words > 0) { |
| 2163 | len = UniStrnlen((wchar_t *)bcc_ptr, | 2179 | len = UniStrnlen((wchar_t *)bcc_ptr, |
| 2164 | remaining_words-1); | 2180 | remaining_words-1); |
| 2165 | if(ses->serverNOS) | 2181 | kfree(ses->serverNOS); |
| 2166 | kfree(ses->serverNOS); | ||
| 2167 | ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL); | 2182 | ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL); |
| 2168 | if(ses->serverNOS == NULL) | 2183 | if(ses->serverNOS == NULL) |
| 2169 | goto sesssetup_nomem; | 2184 | goto sesssetup_nomem; |
| @@ -2203,12 +2218,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2203 | /* if these kcallocs fail not much we | 2218 | /* if these kcallocs fail not much we |
| 2204 | can do, but better to not fail the | 2219 | can do, but better to not fail the |
| 2205 | sesssetup itself */ | 2220 | sesssetup itself */ |
| 2206 | if(ses->serverDomain) | 2221 | kfree(ses->serverDomain); |
| 2207 | kfree(ses->serverDomain); | ||
| 2208 | ses->serverDomain = | 2222 | ses->serverDomain = |
| 2209 | kzalloc(2, GFP_KERNEL); | 2223 | kzalloc(2, GFP_KERNEL); |
| 2210 | if(ses->serverNOS) | 2224 | kfree(ses->serverNOS); |
| 2211 | kfree(ses->serverNOS); | ||
| 2212 | ses->serverNOS = | 2225 | ses->serverNOS = |
| 2213 | kzalloc(2, GFP_KERNEL); | 2226 | kzalloc(2, GFP_KERNEL); |
| 2214 | } | 2227 | } |
| @@ -2217,8 +2230,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2217 | if (((long) bcc_ptr + len) - (long) | 2230 | if (((long) bcc_ptr + len) - (long) |
| 2218 | pByteArea(smb_buffer_response) | 2231 | pByteArea(smb_buffer_response) |
| 2219 | <= BCC(smb_buffer_response)) { | 2232 | <= BCC(smb_buffer_response)) { |
| 2220 | if(ses->serverOS) | 2233 | kfree(ses->serverOS); |
| 2221 | kfree(ses->serverOS); | ||
| 2222 | ses->serverOS = kzalloc(len + 1,GFP_KERNEL); | 2234 | ses->serverOS = kzalloc(len + 1,GFP_KERNEL); |
| 2223 | if(ses->serverOS == NULL) | 2235 | if(ses->serverOS == NULL) |
| 2224 | goto sesssetup_nomem; | 2236 | goto sesssetup_nomem; |
| @@ -2229,8 +2241,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2229 | bcc_ptr++; | 2241 | bcc_ptr++; |
| 2230 | 2242 | ||
| 2231 | len = strnlen(bcc_ptr, 1024); | 2243 | len = strnlen(bcc_ptr, 1024); |
| 2232 | if(ses->serverNOS) | 2244 | kfree(ses->serverNOS); |
| 2233 | kfree(ses->serverNOS); | ||
| 2234 | ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); | 2245 | ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); |
| 2235 | if(ses->serverNOS == NULL) | 2246 | if(ses->serverNOS == NULL) |
| 2236 | goto sesssetup_nomem; | 2247 | goto sesssetup_nomem; |
| @@ -2274,292 +2285,6 @@ sesssetup_nomem: /* do not return an error on nomem for the info strings, | |||
| 2274 | } | 2285 | } |
| 2275 | 2286 | ||
| 2276 | static int | 2287 | static int |
| 2277 | CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
| 2278 | char *SecurityBlob,int SecurityBlobLength, | ||
| 2279 | const struct nls_table *nls_codepage) | ||
| 2280 | { | ||
| 2281 | struct smb_hdr *smb_buffer; | ||
| 2282 | struct smb_hdr *smb_buffer_response; | ||
| 2283 | SESSION_SETUP_ANDX *pSMB; | ||
| 2284 | SESSION_SETUP_ANDX *pSMBr; | ||
| 2285 | char *bcc_ptr; | ||
| 2286 | char *user; | ||
| 2287 | char *domain; | ||
| 2288 | int rc = 0; | ||
| 2289 | int remaining_words = 0; | ||
| 2290 | int bytes_returned = 0; | ||
| 2291 | int len; | ||
| 2292 | __u32 capabilities; | ||
| 2293 | __u16 count; | ||
| 2294 | |||
| 2295 | cFYI(1, ("In spnego sesssetup ")); | ||
| 2296 | if(ses == NULL) | ||
| 2297 | return -EINVAL; | ||
| 2298 | user = ses->userName; | ||
| 2299 | domain = ses->domainName; | ||
| 2300 | |||
| 2301 | smb_buffer = cifs_buf_get(); | ||
| 2302 | if (smb_buffer == NULL) { | ||
| 2303 | return -ENOMEM; | ||
| 2304 | } | ||
| 2305 | smb_buffer_response = smb_buffer; | ||
| 2306 | pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
| 2307 | |||
| 2308 | /* send SMBsessionSetup here */ | ||
| 2309 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
| 2310 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
| 2311 | |||
| 2312 | smb_buffer->Mid = GetNextMid(ses->server); | ||
| 2313 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
| 2314 | pSMB->req.AndXCommand = 0xFF; | ||
| 2315 | if(ses->server->maxBuf > 64*1024) | ||
| 2316 | ses->server->maxBuf = (64*1023); | ||
| 2317 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
| 2318 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
| 2319 | |||
| 2320 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
| 2321 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
| 2322 | |||
| 2323 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
| 2324 | CAP_EXTENDED_SECURITY; | ||
| 2325 | if (ses->capabilities & CAP_UNICODE) { | ||
| 2326 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
| 2327 | capabilities |= CAP_UNICODE; | ||
| 2328 | } | ||
| 2329 | if (ses->capabilities & CAP_STATUS32) { | ||
| 2330 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
| 2331 | capabilities |= CAP_STATUS32; | ||
| 2332 | } | ||
| 2333 | if (ses->capabilities & CAP_DFS) { | ||
| 2334 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
| 2335 | capabilities |= CAP_DFS; | ||
| 2336 | } | ||
| 2337 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
| 2338 | |||
| 2339 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
| 2340 | bcc_ptr = pByteArea(smb_buffer); | ||
| 2341 | memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength); | ||
| 2342 | bcc_ptr += SecurityBlobLength; | ||
| 2343 | |||
| 2344 | if (ses->capabilities & CAP_UNICODE) { | ||
| 2345 | if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */ | ||
| 2346 | *bcc_ptr = 0; | ||
| 2347 | bcc_ptr++; | ||
| 2348 | } | ||
| 2349 | bytes_returned = | ||
| 2350 | cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage); | ||
| 2351 | bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */ | ||
| 2352 | bcc_ptr += 2; /* trailing null */ | ||
| 2353 | if (domain == NULL) | ||
| 2354 | bytes_returned = | ||
| 2355 | cifs_strtoUCS((__le16 *) bcc_ptr, | ||
| 2356 | "CIFS_LINUX_DOM", 32, nls_codepage); | ||
| 2357 | else | ||
| 2358 | bytes_returned = | ||
| 2359 | cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, | ||
| 2360 | nls_codepage); | ||
| 2361 | bcc_ptr += 2 * bytes_returned; | ||
| 2362 | bcc_ptr += 2; | ||
| 2363 | bytes_returned = | ||
| 2364 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
| 2365 | 32, nls_codepage); | ||
| 2366 | bcc_ptr += 2 * bytes_returned; | ||
| 2367 | bytes_returned = | ||
| 2368 | cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, | ||
| 2369 | nls_codepage); | ||
| 2370 | bcc_ptr += 2 * bytes_returned; | ||
| 2371 | bcc_ptr += 2; | ||
| 2372 | bytes_returned = | ||
| 2373 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
| 2374 | 64, nls_codepage); | ||
| 2375 | bcc_ptr += 2 * bytes_returned; | ||
| 2376 | bcc_ptr += 2; | ||
| 2377 | } else { | ||
| 2378 | strncpy(bcc_ptr, user, 200); | ||
| 2379 | bcc_ptr += strnlen(user, 200); | ||
| 2380 | *bcc_ptr = 0; | ||
| 2381 | bcc_ptr++; | ||
| 2382 | if (domain == NULL) { | ||
| 2383 | strcpy(bcc_ptr, "CIFS_LINUX_DOM"); | ||
| 2384 | bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; | ||
| 2385 | } else { | ||
| 2386 | strncpy(bcc_ptr, domain, 64); | ||
| 2387 | bcc_ptr += strnlen(domain, 64); | ||
| 2388 | *bcc_ptr = 0; | ||
| 2389 | bcc_ptr++; | ||
| 2390 | } | ||
| 2391 | strcpy(bcc_ptr, "Linux version "); | ||
| 2392 | bcc_ptr += strlen("Linux version "); | ||
| 2393 | strcpy(bcc_ptr, system_utsname.release); | ||
| 2394 | bcc_ptr += strlen(system_utsname.release) + 1; | ||
| 2395 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
| 2396 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
| 2397 | } | ||
| 2398 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
| 2399 | smb_buffer->smb_buf_length += count; | ||
| 2400 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
| 2401 | |||
| 2402 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
| 2403 | &bytes_returned, 1); | ||
| 2404 | if (rc) { | ||
| 2405 | /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ | ||
| 2406 | } else if ((smb_buffer_response->WordCount == 3) | ||
| 2407 | || (smb_buffer_response->WordCount == 4)) { | ||
| 2408 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
| 2409 | __u16 blob_len = | ||
| 2410 | le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
| 2411 | if (action & GUEST_LOGIN) | ||
| 2412 | cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ | ||
| 2413 | if (ses) { | ||
| 2414 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ | ||
| 2415 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
| 2416 | bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
| 2417 | |||
| 2418 | /* BB Fix below to make endian neutral !! */ | ||
| 2419 | |||
| 2420 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
| 2421 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
| 2422 | && (blob_len < | ||
| 2423 | pSMBr->resp.ByteCount))) { | ||
| 2424 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
| 2425 | bcc_ptr += | ||
| 2426 | blob_len; | ||
| 2427 | cFYI(1, | ||
| 2428 | ("Security Blob Length %d ", | ||
| 2429 | blob_len)); | ||
| 2430 | } | ||
| 2431 | |||
| 2432 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
| 2433 | if ((long) (bcc_ptr) % 2) { | ||
| 2434 | remaining_words = | ||
| 2435 | (BCC(smb_buffer_response) | ||
| 2436 | - 1) / 2; | ||
| 2437 | bcc_ptr++; /* Unicode strings must be word aligned */ | ||
| 2438 | } else { | ||
| 2439 | remaining_words = | ||
| 2440 | BCC | ||
| 2441 | (smb_buffer_response) / 2; | ||
| 2442 | } | ||
| 2443 | len = | ||
| 2444 | UniStrnlen((wchar_t *) bcc_ptr, | ||
| 2445 | remaining_words - 1); | ||
| 2446 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
| 2447 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
| 2448 | terminating last Unicode string in response */ | ||
| 2449 | if(ses->serverOS) | ||
| 2450 | kfree(ses->serverOS); | ||
| 2451 | ses->serverOS = | ||
| 2452 | kzalloc(2 * (len + 1), GFP_KERNEL); | ||
| 2453 | cifs_strfromUCS_le(ses->serverOS, | ||
| 2454 | (__le16 *) | ||
| 2455 | bcc_ptr, len, | ||
| 2456 | nls_codepage); | ||
| 2457 | bcc_ptr += 2 * (len + 1); | ||
| 2458 | remaining_words -= len + 1; | ||
| 2459 | ses->serverOS[2 * len] = 0; | ||
| 2460 | ses->serverOS[1 + (2 * len)] = 0; | ||
| 2461 | if (remaining_words > 0) { | ||
| 2462 | len = UniStrnlen((wchar_t *)bcc_ptr, | ||
| 2463 | remaining_words | ||
| 2464 | - 1); | ||
| 2465 | if(ses->serverNOS) | ||
| 2466 | kfree(ses->serverNOS); | ||
| 2467 | ses->serverNOS = | ||
| 2468 | kzalloc(2 * (len + 1), | ||
| 2469 | GFP_KERNEL); | ||
| 2470 | cifs_strfromUCS_le(ses->serverNOS, | ||
| 2471 | (__le16 *)bcc_ptr, | ||
| 2472 | len, | ||
| 2473 | nls_codepage); | ||
| 2474 | bcc_ptr += 2 * (len + 1); | ||
| 2475 | ses->serverNOS[2 * len] = 0; | ||
| 2476 | ses->serverNOS[1 + (2 * len)] = 0; | ||
| 2477 | remaining_words -= len + 1; | ||
| 2478 | if (remaining_words > 0) { | ||
| 2479 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
| 2480 | /* last string not null terminated (e.g.Windows XP/2000) */ | ||
| 2481 | if(ses->serverDomain) | ||
| 2482 | kfree(ses->serverDomain); | ||
| 2483 | ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL); | ||
| 2484 | cifs_strfromUCS_le(ses->serverDomain, | ||
| 2485 | (__le16 *)bcc_ptr, | ||
| 2486 | len, nls_codepage); | ||
| 2487 | bcc_ptr += 2*(len+1); | ||
| 2488 | ses->serverDomain[2*len] = 0; | ||
| 2489 | ses->serverDomain[1+(2*len)] = 0; | ||
| 2490 | } /* else no more room so create dummy domain string */ | ||
| 2491 | else { | ||
| 2492 | if(ses->serverDomain) | ||
| 2493 | kfree(ses->serverDomain); | ||
| 2494 | ses->serverDomain = | ||
| 2495 | kzalloc(2,GFP_KERNEL); | ||
| 2496 | } | ||
| 2497 | } else {/* no room use dummy domain&NOS */ | ||
| 2498 | if(ses->serverDomain) | ||
| 2499 | kfree(ses->serverDomain); | ||
| 2500 | ses->serverDomain = kzalloc(2, GFP_KERNEL); | ||
| 2501 | if(ses->serverNOS) | ||
| 2502 | kfree(ses->serverNOS); | ||
| 2503 | ses->serverNOS = kzalloc(2, GFP_KERNEL); | ||
| 2504 | } | ||
| 2505 | } else { /* ASCII */ | ||
| 2506 | |||
| 2507 | len = strnlen(bcc_ptr, 1024); | ||
| 2508 | if (((long) bcc_ptr + len) - (long) | ||
| 2509 | pByteArea(smb_buffer_response) | ||
| 2510 | <= BCC(smb_buffer_response)) { | ||
| 2511 | if(ses->serverOS) | ||
| 2512 | kfree(ses->serverOS); | ||
| 2513 | ses->serverOS = kzalloc(len + 1, GFP_KERNEL); | ||
| 2514 | strncpy(ses->serverOS, bcc_ptr, len); | ||
| 2515 | |||
| 2516 | bcc_ptr += len; | ||
| 2517 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
| 2518 | bcc_ptr++; | ||
| 2519 | |||
| 2520 | len = strnlen(bcc_ptr, 1024); | ||
| 2521 | if(ses->serverNOS) | ||
| 2522 | kfree(ses->serverNOS); | ||
| 2523 | ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); | ||
| 2524 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
| 2525 | bcc_ptr += len; | ||
| 2526 | bcc_ptr[0] = 0; | ||
| 2527 | bcc_ptr++; | ||
| 2528 | |||
| 2529 | len = strnlen(bcc_ptr, 1024); | ||
| 2530 | if(ses->serverDomain) | ||
| 2531 | kfree(ses->serverDomain); | ||
| 2532 | ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); | ||
| 2533 | strncpy(ses->serverDomain, bcc_ptr, len); | ||
| 2534 | bcc_ptr += len; | ||
| 2535 | bcc_ptr[0] = 0; | ||
| 2536 | bcc_ptr++; | ||
| 2537 | } else | ||
| 2538 | cFYI(1, | ||
| 2539 | ("Variable field of length %d extends beyond end of smb ", | ||
| 2540 | len)); | ||
| 2541 | } | ||
| 2542 | } else { | ||
| 2543 | cERROR(1, | ||
| 2544 | (" Security Blob Length extends beyond end of SMB")); | ||
| 2545 | } | ||
| 2546 | } else { | ||
| 2547 | cERROR(1, ("No session structure passed in.")); | ||
| 2548 | } | ||
| 2549 | } else { | ||
| 2550 | cERROR(1, | ||
| 2551 | (" Invalid Word count %d: ", | ||
| 2552 | smb_buffer_response->WordCount)); | ||
| 2553 | rc = -EIO; | ||
| 2554 | } | ||
| 2555 | |||
| 2556 | if (smb_buffer) | ||
| 2557 | cifs_buf_release(smb_buffer); | ||
| 2558 | |||
| 2559 | return rc; | ||
| 2560 | } | ||
| 2561 | |||
| 2562 | static int | ||
| 2563 | CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | 2288 | CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, |
| 2564 | struct cifsSesInfo *ses, int * pNTLMv2_flag, | 2289 | struct cifsSesInfo *ses, int * pNTLMv2_flag, |
| 2565 | const struct nls_table *nls_codepage) | 2290 | const struct nls_table *nls_codepage) |
| @@ -2635,8 +2360,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2635 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; | 2360 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; |
| 2636 | if(sign_CIFS_PDUs) | 2361 | if(sign_CIFS_PDUs) |
| 2637 | negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; | 2362 | negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; |
| 2638 | if(ntlmv2_support) | 2363 | /* if(ntlmv2_support) |
| 2639 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; | 2364 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/ |
| 2640 | /* setup pointers to domain name and workstation name */ | 2365 | /* setup pointers to domain name and workstation name */ |
| 2641 | bcc_ptr += SecurityBlobLength; | 2366 | bcc_ptr += SecurityBlobLength; |
| 2642 | 2367 | ||
| @@ -2783,8 +2508,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2783 | bcc_ptr, | 2508 | bcc_ptr, |
| 2784 | remaining_words | 2509 | remaining_words |
| 2785 | - 1); | 2510 | - 1); |
| 2786 | if(ses->serverNOS) | 2511 | kfree(ses->serverNOS); |
| 2787 | kfree(ses->serverNOS); | ||
| 2788 | ses->serverNOS = | 2512 | ses->serverNOS = |
| 2789 | kzalloc(2 * (len + 1), | 2513 | kzalloc(2 * (len + 1), |
| 2790 | GFP_KERNEL); | 2514 | GFP_KERNEL); |
| @@ -2802,8 +2526,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2802 | if (remaining_words > 0) { | 2526 | if (remaining_words > 0) { |
| 2803 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | 2527 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); |
| 2804 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ | 2528 | /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ |
| 2805 | if(ses->serverDomain) | 2529 | kfree(ses->serverDomain); |
| 2806 | kfree(ses->serverDomain); | ||
| 2807 | ses->serverDomain = | 2530 | ses->serverDomain = |
| 2808 | kzalloc(2 * | 2531 | kzalloc(2 * |
| 2809 | (len + | 2532 | (len + |
| @@ -2822,19 +2545,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2822 | = 0; | 2545 | = 0; |
| 2823 | } /* else no more room so create dummy domain string */ | 2546 | } /* else no more room so create dummy domain string */ |
| 2824 | else { | 2547 | else { |
| 2825 | if(ses->serverDomain) | 2548 | kfree(ses->serverDomain); |
| 2826 | kfree(ses->serverDomain); | ||
| 2827 | ses->serverDomain = | 2549 | ses->serverDomain = |
| 2828 | kzalloc(2, | 2550 | kzalloc(2, |
| 2829 | GFP_KERNEL); | 2551 | GFP_KERNEL); |
| 2830 | } | 2552 | } |
| 2831 | } else { /* no room so create dummy domain and NOS string */ | 2553 | } else { /* no room so create dummy domain and NOS string */ |
| 2832 | if(ses->serverDomain); | 2554 | kfree(ses->serverDomain); |
| 2833 | kfree(ses->serverDomain); | ||
| 2834 | ses->serverDomain = | 2555 | ses->serverDomain = |
| 2835 | kzalloc(2, GFP_KERNEL); | 2556 | kzalloc(2, GFP_KERNEL); |
| 2836 | if(ses->serverNOS) | 2557 | kfree(ses->serverNOS); |
| 2837 | kfree(ses->serverNOS); | ||
| 2838 | ses->serverNOS = | 2558 | ses->serverNOS = |
| 2839 | kzalloc(2, GFP_KERNEL); | 2559 | kzalloc(2, GFP_KERNEL); |
| 2840 | } | 2560 | } |
| @@ -2856,8 +2576,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2856 | bcc_ptr++; | 2576 | bcc_ptr++; |
| 2857 | 2577 | ||
| 2858 | len = strnlen(bcc_ptr, 1024); | 2578 | len = strnlen(bcc_ptr, 1024); |
| 2859 | if(ses->serverNOS) | 2579 | kfree(ses->serverNOS); |
| 2860 | kfree(ses->serverNOS); | ||
| 2861 | ses->serverNOS = | 2580 | ses->serverNOS = |
| 2862 | kzalloc(len + 1, | 2581 | kzalloc(len + 1, |
| 2863 | GFP_KERNEL); | 2582 | GFP_KERNEL); |
| @@ -2867,8 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2867 | bcc_ptr++; | 2586 | bcc_ptr++; |
| 2868 | 2587 | ||
| 2869 | len = strnlen(bcc_ptr, 1024); | 2588 | len = strnlen(bcc_ptr, 1024); |
| 2870 | if(ses->serverDomain) | 2589 | kfree(ses->serverDomain); |
| 2871 | kfree(ses->serverDomain); | ||
| 2872 | ses->serverDomain = | 2590 | ses->serverDomain = |
| 2873 | kzalloc(len + 1, | 2591 | kzalloc(len + 1, |
| 2874 | GFP_KERNEL); | 2592 | GFP_KERNEL); |
| @@ -2994,14 +2712,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2994 | SecurityBlob->LmChallengeResponse.Buffer = 0; | 2712 | SecurityBlob->LmChallengeResponse.Buffer = 0; |
| 2995 | 2713 | ||
| 2996 | SecurityBlob->NtChallengeResponse.Length = | 2714 | SecurityBlob->NtChallengeResponse.Length = |
| 2997 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | 2715 | cpu_to_le16(CIFS_SESS_KEY_SIZE); |
| 2998 | SecurityBlob->NtChallengeResponse.MaximumLength = | 2716 | SecurityBlob->NtChallengeResponse.MaximumLength = |
| 2999 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | 2717 | cpu_to_le16(CIFS_SESS_KEY_SIZE); |
| 3000 | memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE); | 2718 | memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE); |
| 3001 | SecurityBlob->NtChallengeResponse.Buffer = | 2719 | SecurityBlob->NtChallengeResponse.Buffer = |
| 3002 | cpu_to_le32(SecurityBlobLength); | 2720 | cpu_to_le32(SecurityBlobLength); |
| 3003 | SecurityBlobLength += CIFS_SESSION_KEY_SIZE; | 2721 | SecurityBlobLength += CIFS_SESS_KEY_SIZE; |
| 3004 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | 2722 | bcc_ptr += CIFS_SESS_KEY_SIZE; |
| 3005 | 2723 | ||
| 3006 | if (ses->capabilities & CAP_UNICODE) { | 2724 | if (ses->capabilities & CAP_UNICODE) { |
| 3007 | if (domain == NULL) { | 2725 | if (domain == NULL) { |
| @@ -3190,8 +2908,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3190 | bcc_ptr, | 2908 | bcc_ptr, |
| 3191 | remaining_words | 2909 | remaining_words |
| 3192 | - 1); | 2910 | - 1); |
| 3193 | if(ses->serverNOS) | 2911 | kfree(ses->serverNOS); |
| 3194 | kfree(ses->serverNOS); | ||
| 3195 | ses->serverNOS = | 2912 | ses->serverNOS = |
| 3196 | kzalloc(2 * (len + 1), | 2913 | kzalloc(2 * (len + 1), |
| 3197 | GFP_KERNEL); | 2914 | GFP_KERNEL); |
| @@ -3244,8 +2961,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3244 | if(ses->serverDomain) | 2961 | if(ses->serverDomain) |
| 3245 | kfree(ses->serverDomain); | 2962 | kfree(ses->serverDomain); |
| 3246 | ses->serverDomain = kzalloc(2, GFP_KERNEL); | 2963 | ses->serverDomain = kzalloc(2, GFP_KERNEL); |
| 3247 | if(ses->serverNOS) | 2964 | kfree(ses->serverNOS); |
| 3248 | kfree(ses->serverNOS); | ||
| 3249 | ses->serverNOS = kzalloc(2, GFP_KERNEL); | 2965 | ses->serverNOS = kzalloc(2, GFP_KERNEL); |
| 3250 | } | 2966 | } |
| 3251 | } else { /* ASCII */ | 2967 | } else { /* ASCII */ |
| @@ -3263,8 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3263 | bcc_ptr++; | 2979 | bcc_ptr++; |
| 3264 | 2980 | ||
| 3265 | len = strnlen(bcc_ptr, 1024); | 2981 | len = strnlen(bcc_ptr, 1024); |
| 3266 | if(ses->serverNOS) | 2982 | kfree(ses->serverNOS); |
| 3267 | kfree(ses->serverNOS); | ||
| 3268 | ses->serverNOS = kzalloc(len+1,GFP_KERNEL); | 2983 | ses->serverNOS = kzalloc(len+1,GFP_KERNEL); |
| 3269 | strncpy(ses->serverNOS, bcc_ptr, len); | 2984 | strncpy(ses->serverNOS, bcc_ptr, len); |
| 3270 | bcc_ptr += len; | 2985 | bcc_ptr += len; |
| @@ -3340,22 +3055,33 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3340 | bcc_ptr = &pSMB->Password[0]; | 3055 | bcc_ptr = &pSMB->Password[0]; |
| 3341 | if((ses->server->secMode) & SECMODE_USER) { | 3056 | if((ses->server->secMode) & SECMODE_USER) { |
| 3342 | pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ | 3057 | pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ |
| 3058 | *bcc_ptr = 0; /* password is null byte */ | ||
| 3343 | bcc_ptr++; /* skip password */ | 3059 | bcc_ptr++; /* skip password */ |
| 3060 | /* already aligned so no need to do it below */ | ||
| 3344 | } else { | 3061 | } else { |
| 3345 | pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE); | 3062 | pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); |
| 3346 | /* BB FIXME add code to fail this if NTLMv2 or Kerberos | 3063 | /* BB FIXME add code to fail this if NTLMv2 or Kerberos |
| 3347 | specified as required (when that support is added to | 3064 | specified as required (when that support is added to |
| 3348 | the vfs in the future) as only NTLM or the much | 3065 | the vfs in the future) as only NTLM or the much |
| 3349 | weaker LANMAN (which we do not send) is accepted | 3066 | weaker LANMAN (which we do not send by default) is accepted |
| 3350 | by Samba (not sure whether other servers allow | 3067 | by Samba (not sure whether other servers allow |
| 3351 | NTLMv2 password here) */ | 3068 | NTLMv2 password here) */ |
| 3069 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 3070 | if((extended_security & CIFSSEC_MAY_LANMAN) && | ||
| 3071 | (ses->server->secType == LANMAN)) | ||
| 3072 | calc_lanman_hash(ses, bcc_ptr); | ||
| 3073 | else | ||
| 3074 | #endif /* CIFS_WEAK_PW_HASH */ | ||
| 3352 | SMBNTencrypt(ses->password, | 3075 | SMBNTencrypt(ses->password, |
| 3353 | ses->server->cryptKey, | 3076 | ses->server->cryptKey, |
| 3354 | bcc_ptr); | 3077 | bcc_ptr); |
| 3355 | 3078 | ||
| 3356 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | 3079 | bcc_ptr += CIFS_SESS_KEY_SIZE; |
| 3357 | *bcc_ptr = 0; | 3080 | if(ses->capabilities & CAP_UNICODE) { |
| 3358 | bcc_ptr++; /* align */ | 3081 | /* must align unicode strings */ |
| 3082 | *bcc_ptr = 0; /* null byte password */ | ||
| 3083 | bcc_ptr++; | ||
| 3084 | } | ||
| 3359 | } | 3085 | } |
| 3360 | 3086 | ||
| 3361 | if(ses->server->secMode & | 3087 | if(ses->server->secMode & |
| @@ -3429,7 +3155,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3429 | } | 3155 | } |
| 3430 | /* else do not bother copying these informational fields */ | 3156 | /* else do not bother copying these informational fields */ |
| 3431 | } | 3157 | } |
| 3432 | tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); | 3158 | if(smb_buffer_response->WordCount == 3) |
| 3159 | tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); | ||
| 3160 | else | ||
| 3161 | tcon->Flags = 0; | ||
| 3433 | cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags)); | 3162 | cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags)); |
| 3434 | } else if ((rc == 0) && tcon == NULL) { | 3163 | } else if ((rc == 0) && tcon == NULL) { |
| 3435 | /* all we need to save for IPC$ connection */ | 3164 | /* all we need to save for IPC$ connection */ |
| @@ -3494,7 +3223,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3494 | struct nls_table * nls_info) | 3223 | struct nls_table * nls_info) |
| 3495 | { | 3224 | { |
| 3496 | int rc = 0; | 3225 | int rc = 0; |
| 3497 | char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; | 3226 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; |
| 3498 | int ntlmv2_flag = FALSE; | 3227 | int ntlmv2_flag = FALSE; |
| 3499 | int first_time = 0; | 3228 | int first_time = 0; |
| 3500 | 3229 | ||
| @@ -3526,20 +3255,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3526 | pSesInfo->server->secMode, | 3255 | pSesInfo->server->secMode, |
| 3527 | pSesInfo->server->capabilities, | 3256 | pSesInfo->server->capabilities, |
| 3528 | pSesInfo->server->timeZone)); | 3257 | pSesInfo->server->timeZone)); |
| 3529 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 3258 | if(experimEnabled < 2) |
| 3530 | if(experimEnabled > 1) | 3259 | rc = CIFS_SessSetup(xid, pSesInfo, |
| 3531 | rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */, | 3260 | first_time, nls_info); |
| 3532 | &ntlmv2_flag, nls_info); | 3261 | else if (extended_security |
| 3533 | else | ||
| 3534 | #endif | ||
| 3535 | if (extended_security | ||
| 3536 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | 3262 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) |
| 3537 | && (pSesInfo->server->secType == NTLMSSP)) { | 3263 | && (pSesInfo->server->secType == NTLMSSP)) { |
| 3538 | cFYI(1, ("New style sesssetup")); | 3264 | rc = -EOPNOTSUPP; |
| 3539 | rc = CIFSSpnegoSessSetup(xid, pSesInfo, | ||
| 3540 | NULL /* security blob */, | ||
| 3541 | 0 /* blob length */, | ||
| 3542 | nls_info); | ||
| 3543 | } else if (extended_security | 3265 | } else if (extended_security |
| 3544 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | 3266 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) |
| 3545 | && (pSesInfo->server->secType == RawNTLMSSP)) { | 3267 | && (pSesInfo->server->secType == RawNTLMSSP)) { |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 82315edc77d7..ba4cbe9b0684 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -113,7 +113,7 @@ cifs_bp_rename_retry: | |||
| 113 | full_path[namelen+2] = 0; | 113 | full_path[namelen+2] = 0; |
| 114 | BB remove above eight lines BB */ | 114 | BB remove above eight lines BB */ |
| 115 | 115 | ||
| 116 | /* Inode operations in similar order to how they appear in the Linux file fs.h */ | 116 | /* Inode operations in similar order to how they appear in Linux file fs.h */ |
| 117 | 117 | ||
| 118 | int | 118 | int |
| 119 | cifs_create(struct inode *inode, struct dentry *direntry, int mode, | 119 | cifs_create(struct inode *inode, struct dentry *direntry, int mode, |
| @@ -178,11 +178,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 178 | FreeXid(xid); | 178 | FreeXid(xid); |
| 179 | return -ENOMEM; | 179 | return -ENOMEM; |
| 180 | } | 180 | } |
| 181 | 181 | if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) | |
| 182 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, | 182 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, |
| 183 | desiredAccess, CREATE_NOT_DIR, | 183 | desiredAccess, CREATE_NOT_DIR, |
| 184 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 184 | &fileHandle, &oplock, buf, cifs_sb->local_nls, |
| 185 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 185 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 186 | else | ||
| 187 | rc = -EIO; /* no NT SMB support fall into legacy open below */ | ||
| 188 | |||
| 186 | if(rc == -EIO) { | 189 | if(rc == -EIO) { |
| 187 | /* old server, retry the open legacy style */ | 190 | /* old server, retry the open legacy style */ |
| 188 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | 191 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, |
| @@ -191,7 +194,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 191 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 194 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 192 | } | 195 | } |
| 193 | if (rc) { | 196 | if (rc) { |
| 194 | cFYI(1, ("cifs_create returned 0x%x ", rc)); | 197 | cFYI(1, ("cifs_create returned 0x%x", rc)); |
| 195 | } else { | 198 | } else { |
| 196 | /* If Open reported that we actually created a file | 199 | /* If Open reported that we actually created a file |
| 197 | then we now have to set the mode if possible */ | 200 | 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, | |||
| 369 | cifs_sb->mnt_cifs_flags & | 372 | cifs_sb->mnt_cifs_flags & |
| 370 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 373 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 371 | 374 | ||
| 375 | /* BB FIXME - add handling for backlevel servers | ||
| 376 | which need legacy open and check for all | ||
| 377 | calls to SMBOpen for fallback to | ||
| 378 | SMBLeagcyOpen */ | ||
| 372 | if(!rc) { | 379 | if(!rc) { |
| 373 | /* BB Do not bother to decode buf since no | 380 | /* BB Do not bother to decode buf since no |
| 374 | local inode yet to put timestamps in, | 381 | local inode yet to put timestamps in, |
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 633a93811328..d91a3d44e9e3 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c | |||
| @@ -91,14 +91,14 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
| 91 | if(full_path == NULL) { | 91 | if(full_path == NULL) { |
| 92 | rc = -ENOMEM; | 92 | rc = -ENOMEM; |
| 93 | } else { | 93 | } else { |
| 94 | cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */ | 94 | cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg)); |
| 95 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | 95 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, |
| 96 | GENERIC_READ | SYNCHRONIZE, 0 /* create options */, | 96 | GENERIC_READ | SYNCHRONIZE, 0 /* create options */, |
| 97 | &netfid, &oplock,NULL, cifs_sb->local_nls, | 97 | &netfid, &oplock,NULL, cifs_sb->local_nls, |
| 98 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 98 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 99 | /* BB fixme - add this handle to a notify handle list */ | 99 | /* BB fixme - add this handle to a notify handle list */ |
| 100 | if(rc) { | 100 | if(rc) { |
| 101 | cERROR(1,("Could not open directory for notify")); /* BB remove BB */ | 101 | cFYI(1,("Could not open directory for notify")); |
| 102 | } else { | 102 | } else { |
| 103 | filter = convert_to_cifs_notify_flags(arg); | 103 | filter = convert_to_cifs_notify_flags(arg); |
| 104 | if(filter != 0) { | 104 | if(filter != 0) { |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index b4a18c1cab0a..e9c1573f6aa7 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -110,7 +110,6 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, | |||
| 110 | &pCifsInode->openFileList); | 110 | &pCifsInode->openFileList); |
| 111 | } | 111 | } |
| 112 | write_unlock(&GlobalSMBSeslock); | 112 | write_unlock(&GlobalSMBSeslock); |
| 113 | write_unlock(&file->f_owner.lock); | ||
| 114 | if (pCifsInode->clientCanCacheRead) { | 113 | if (pCifsInode->clientCanCacheRead) { |
| 115 | /* we have the inode open somewhere else | 114 | /* we have the inode open somewhere else |
| 116 | no need to discard cache data */ | 115 | no need to discard cache data */ |
| @@ -201,7 +200,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
| 201 | } else { | 200 | } else { |
| 202 | if (file->f_flags & O_EXCL) | 201 | if (file->f_flags & O_EXCL) |
| 203 | cERROR(1, ("could not find file instance for " | 202 | cERROR(1, ("could not find file instance for " |
| 204 | "new file %p ", file)); | 203 | "new file %p", file)); |
| 205 | } | 204 | } |
| 206 | } | 205 | } |
| 207 | 206 | ||
| @@ -260,10 +259,15 @@ int cifs_open(struct inode *inode, struct file *file) | |||
| 260 | rc = -ENOMEM; | 259 | rc = -ENOMEM; |
| 261 | goto out; | 260 | goto out; |
| 262 | } | 261 | } |
| 263 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, | 262 | |
| 264 | CREATE_NOT_DIR, &netfid, &oplock, buf, | 263 | if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) |
| 264 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, | ||
| 265 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
| 265 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | 266 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags |
| 266 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | 267 | & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 268 | else | ||
| 269 | rc = -EIO; /* no NT SMB support fall into legacy open below */ | ||
| 270 | |||
| 267 | if (rc == -EIO) { | 271 | if (rc == -EIO) { |
| 268 | /* Old server, try legacy style OpenX */ | 272 | /* Old server, try legacy style OpenX */ |
| 269 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | 273 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, |
| @@ -272,7 +276,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
| 272 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | 276 | & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 273 | } | 277 | } |
| 274 | if (rc) { | 278 | if (rc) { |
| 275 | cFYI(1, ("cifs_open returned 0x%x ", rc)); | 279 | cFYI(1, ("cifs_open returned 0x%x", rc)); |
| 276 | goto out; | 280 | goto out; |
| 277 | } | 281 | } |
| 278 | file->private_data = | 282 | file->private_data = |
| @@ -282,7 +286,6 @@ int cifs_open(struct inode *inode, struct file *file) | |||
| 282 | goto out; | 286 | goto out; |
| 283 | } | 287 | } |
| 284 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); | 288 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); |
| 285 | write_lock(&file->f_owner.lock); | ||
| 286 | write_lock(&GlobalSMBSeslock); | 289 | write_lock(&GlobalSMBSeslock); |
| 287 | list_add(&pCifsFile->tlist, &pTcon->openFileList); | 290 | list_add(&pCifsFile->tlist, &pTcon->openFileList); |
| 288 | 291 | ||
| @@ -293,7 +296,6 @@ int cifs_open(struct inode *inode, struct file *file) | |||
| 293 | &oplock, buf, full_path, xid); | 296 | &oplock, buf, full_path, xid); |
| 294 | } else { | 297 | } else { |
| 295 | write_unlock(&GlobalSMBSeslock); | 298 | write_unlock(&GlobalSMBSeslock); |
| 296 | write_unlock(&file->f_owner.lock); | ||
| 297 | } | 299 | } |
| 298 | 300 | ||
| 299 | if (oplock & CIFS_CREATE_ACTION) { | 301 | if (oplock & CIFS_CREATE_ACTION) { |
| @@ -409,8 +411,8 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, | |||
| 409 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 411 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 410 | if (rc) { | 412 | if (rc) { |
| 411 | up(&pCifsFile->fh_sem); | 413 | up(&pCifsFile->fh_sem); |
| 412 | cFYI(1, ("cifs_open returned 0x%x ", rc)); | 414 | cFYI(1, ("cifs_open returned 0x%x", rc)); |
| 413 | cFYI(1, ("oplock: %d ", oplock)); | 415 | cFYI(1, ("oplock: %d", oplock)); |
| 414 | } else { | 416 | } else { |
| 415 | pCifsFile->netfid = netfid; | 417 | pCifsFile->netfid = netfid; |
| 416 | pCifsFile->invalidHandle = FALSE; | 418 | pCifsFile->invalidHandle = FALSE; |
| @@ -472,7 +474,6 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 472 | pTcon = cifs_sb->tcon; | 474 | pTcon = cifs_sb->tcon; |
| 473 | if (pSMBFile) { | 475 | if (pSMBFile) { |
| 474 | pSMBFile->closePend = TRUE; | 476 | pSMBFile->closePend = TRUE; |
| 475 | write_lock(&file->f_owner.lock); | ||
| 476 | if (pTcon) { | 477 | if (pTcon) { |
| 477 | /* no sense reconnecting to close a file that is | 478 | /* no sense reconnecting to close a file that is |
| 478 | already closed */ | 479 | already closed */ |
| @@ -487,23 +488,18 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 487 | the struct would be in each open file, | 488 | the struct would be in each open file, |
| 488 | but this should give enough time to | 489 | but this should give enough time to |
| 489 | clear the socket */ | 490 | clear the socket */ |
| 490 | write_unlock(&file->f_owner.lock); | ||
| 491 | cERROR(1,("close with pending writes")); | 491 | cERROR(1,("close with pending writes")); |
| 492 | msleep(timeout); | 492 | msleep(timeout); |
| 493 | write_lock(&file->f_owner.lock); | ||
| 494 | timeout *= 4; | 493 | timeout *= 4; |
| 495 | } | 494 | } |
| 496 | write_unlock(&file->f_owner.lock); | ||
| 497 | rc = CIFSSMBClose(xid, pTcon, | 495 | rc = CIFSSMBClose(xid, pTcon, |
| 498 | pSMBFile->netfid); | 496 | pSMBFile->netfid); |
| 499 | write_lock(&file->f_owner.lock); | ||
| 500 | } | 497 | } |
| 501 | } | 498 | } |
| 502 | write_lock(&GlobalSMBSeslock); | 499 | write_lock(&GlobalSMBSeslock); |
| 503 | list_del(&pSMBFile->flist); | 500 | list_del(&pSMBFile->flist); |
| 504 | list_del(&pSMBFile->tlist); | 501 | list_del(&pSMBFile->tlist); |
| 505 | write_unlock(&GlobalSMBSeslock); | 502 | write_unlock(&GlobalSMBSeslock); |
| 506 | write_unlock(&file->f_owner.lock); | ||
| 507 | kfree(pSMBFile->search_resume_name); | 503 | kfree(pSMBFile->search_resume_name); |
| 508 | kfree(file->private_data); | 504 | kfree(file->private_data); |
| 509 | file->private_data = NULL; | 505 | file->private_data = NULL; |
| @@ -531,7 +527,7 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
| 531 | (struct cifsFileInfo *)file->private_data; | 527 | (struct cifsFileInfo *)file->private_data; |
| 532 | char *ptmp; | 528 | char *ptmp; |
| 533 | 529 | ||
| 534 | cFYI(1, ("Closedir inode = 0x%p with ", inode)); | 530 | cFYI(1, ("Closedir inode = 0x%p", inode)); |
| 535 | 531 | ||
| 536 | xid = GetXid(); | 532 | xid = GetXid(); |
| 537 | 533 | ||
| @@ -605,7 +601,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 605 | } | 601 | } |
| 606 | if (pfLock->fl_flags & FL_ACCESS) | 602 | if (pfLock->fl_flags & FL_ACCESS) |
| 607 | cFYI(1, ("Process suspended by mandatory locking - " | 603 | cFYI(1, ("Process suspended by mandatory locking - " |
| 608 | "not implemented yet ")); | 604 | "not implemented yet")); |
| 609 | if (pfLock->fl_flags & FL_LEASE) | 605 | if (pfLock->fl_flags & FL_LEASE) |
| 610 | cFYI(1, ("Lease on file - not implemented yet")); | 606 | cFYI(1, ("Lease on file - not implemented yet")); |
| 611 | if (pfLock->fl_flags & | 607 | if (pfLock->fl_flags & |
| @@ -1375,7 +1371,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) | |||
| 1375 | 1371 | ||
| 1376 | xid = GetXid(); | 1372 | xid = GetXid(); |
| 1377 | 1373 | ||
| 1378 | cFYI(1, ("Sync file - name: %s datasync: 0x%x ", | 1374 | cFYI(1, ("Sync file - name: %s datasync: 0x%x", |
| 1379 | dentry->d_name.name, datasync)); | 1375 | dentry->d_name.name, datasync)); |
| 1380 | 1376 | ||
| 1381 | rc = filemap_fdatawrite(inode->i_mapping); | 1377 | rc = filemap_fdatawrite(inode->i_mapping); |
| @@ -1404,7 +1400,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) | |||
| 1404 | /* fill in rpages then | 1400 | /* fill in rpages then |
| 1405 | result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ | 1401 | result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ |
| 1406 | 1402 | ||
| 1407 | /* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); | 1403 | /* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index)); |
| 1408 | 1404 | ||
| 1409 | #if 0 | 1405 | #if 0 |
| 1410 | if (rc < 0) | 1406 | if (rc < 0) |
| @@ -1836,7 +1832,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page, | |||
| 1836 | if (rc < 0) | 1832 | if (rc < 0) |
| 1837 | goto io_error; | 1833 | goto io_error; |
| 1838 | else | 1834 | else |
| 1839 | cFYI(1, ("Bytes read %d ",rc)); | 1835 | cFYI(1, ("Bytes read %d",rc)); |
| 1840 | 1836 | ||
| 1841 | file->f_dentry->d_inode->i_atime = | 1837 | file->f_dentry->d_inode->i_atime = |
| 1842 | current_fs_time(file->f_dentry->d_inode->i_sb); | 1838 | current_fs_time(file->f_dentry->d_inode->i_sb); |
| @@ -1957,3 +1953,19 @@ struct address_space_operations cifs_addr_ops = { | |||
| 1957 | /* .sync_page = cifs_sync_page, */ | 1953 | /* .sync_page = cifs_sync_page, */ |
| 1958 | /* .direct_IO = */ | 1954 | /* .direct_IO = */ |
| 1959 | }; | 1955 | }; |
| 1956 | |||
| 1957 | /* | ||
| 1958 | * cifs_readpages requires the server to support a buffer large enough to | ||
| 1959 | * contain the header plus one complete page of data. Otherwise, we need | ||
| 1960 | * to leave cifs_readpages out of the address space operations. | ||
| 1961 | */ | ||
| 1962 | struct address_space_operations cifs_addr_ops_smallbuf = { | ||
| 1963 | .readpage = cifs_readpage, | ||
| 1964 | .writepage = cifs_writepage, | ||
| 1965 | .writepages = cifs_writepages, | ||
| 1966 | .prepare_write = cifs_prepare_write, | ||
| 1967 | .commit_write = cifs_commit_write, | ||
| 1968 | .set_page_dirty = __set_page_dirty_nobuffers, | ||
| 1969 | /* .sync_page = cifs_sync_page, */ | ||
| 1970 | /* .direct_IO = */ | ||
| 1971 | }; | ||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 4093764ef461..b88147c1dc27 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -41,7 +41,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
| 41 | char *tmp_path; | 41 | char *tmp_path; |
| 42 | 42 | ||
| 43 | pTcon = cifs_sb->tcon; | 43 | pTcon = cifs_sb->tcon; |
| 44 | cFYI(1, ("Getting info on %s ", search_path)); | 44 | cFYI(1, ("Getting info on %s", search_path)); |
| 45 | /* could have done a find first instead but this returns more info */ | 45 | /* could have done a find first instead but this returns more info */ |
| 46 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, | 46 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, |
| 47 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 47 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
| @@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
| 97 | inode = *pinode; | 97 | inode = *pinode; |
| 98 | cifsInfo = CIFS_I(inode); | 98 | cifsInfo = CIFS_I(inode); |
| 99 | 99 | ||
| 100 | cFYI(1, ("Old time %ld ", cifsInfo->time)); | 100 | cFYI(1, ("Old time %ld", cifsInfo->time)); |
| 101 | cifsInfo->time = jiffies; | 101 | cifsInfo->time = jiffies; |
| 102 | cFYI(1, ("New time %ld ", cifsInfo->time)); | 102 | cFYI(1, ("New time %ld", cifsInfo->time)); |
| 103 | /* this is ok to set on every inode revalidate */ | 103 | /* this is ok to set on every inode revalidate */ |
| 104 | atomic_set(&cifsInfo->inUse,1); | 104 | atomic_set(&cifsInfo->inUse,1); |
| 105 | 105 | ||
| @@ -180,11 +180,12 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
| 180 | else /* not direct, send byte range locks */ | 180 | else /* not direct, send byte range locks */ |
| 181 | inode->i_fop = &cifs_file_ops; | 181 | inode->i_fop = &cifs_file_ops; |
| 182 | 182 | ||
| 183 | inode->i_data.a_ops = &cifs_addr_ops; | ||
| 184 | /* check if server can support readpages */ | 183 | /* check if server can support readpages */ |
| 185 | if(pTcon->ses->server->maxBuf < | 184 | if(pTcon->ses->server->maxBuf < |
| 186 | 4096 + MAX_CIFS_HDR_SIZE) | 185 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) |
| 187 | inode->i_data.a_ops->readpages = NULL; | 186 | inode->i_data.a_ops = &cifs_addr_ops_smallbuf; |
| 187 | else | ||
| 188 | inode->i_data.a_ops = &cifs_addr_ops; | ||
| 188 | } else if (S_ISDIR(inode->i_mode)) { | 189 | } else if (S_ISDIR(inode->i_mode)) { |
| 189 | cFYI(1, ("Directory inode")); | 190 | cFYI(1, ("Directory inode")); |
| 190 | inode->i_op = &cifs_dir_inode_ops; | 191 | inode->i_op = &cifs_dir_inode_ops; |
| @@ -421,23 +422,23 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 421 | inode = *pinode; | 422 | inode = *pinode; |
| 422 | cifsInfo = CIFS_I(inode); | 423 | cifsInfo = CIFS_I(inode); |
| 423 | cifsInfo->cifsAttrs = attr; | 424 | cifsInfo->cifsAttrs = attr; |
| 424 | cFYI(1, ("Old time %ld ", cifsInfo->time)); | 425 | cFYI(1, ("Old time %ld", cifsInfo->time)); |
| 425 | cifsInfo->time = jiffies; | 426 | cifsInfo->time = jiffies; |
| 426 | cFYI(1, ("New time %ld ", cifsInfo->time)); | 427 | cFYI(1, ("New time %ld", cifsInfo->time)); |
| 427 | 428 | ||
| 428 | /* blksize needs to be multiple of two. So safer to default to | 429 | /* blksize needs to be multiple of two. So safer to default to |
| 429 | blksize and blkbits set in superblock so 2**blkbits and blksize | 430 | blksize and blkbits set in superblock so 2**blkbits and blksize |
| 430 | will match rather than setting to: | 431 | will match rather than setting to: |
| 431 | (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ | 432 | (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ |
| 432 | 433 | ||
| 433 | /* Linux can not store file creation time unfortunately so we ignore it */ | 434 | /* Linux can not store file creation time so ignore it */ |
| 434 | inode->i_atime = | 435 | inode->i_atime = |
| 435 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); | 436 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); |
| 436 | inode->i_mtime = | 437 | inode->i_mtime = |
| 437 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); | 438 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); |
| 438 | inode->i_ctime = | 439 | inode->i_ctime = |
| 439 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); | 440 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); |
| 440 | cFYI(0, ("Attributes came in as 0x%x ", attr)); | 441 | cFYI(0, ("Attributes came in as 0x%x", attr)); |
| 441 | 442 | ||
| 442 | /* set default mode. will override for dirs below */ | 443 | /* set default mode. will override for dirs below */ |
| 443 | if (atomic_read(&cifsInfo->inUse) == 0) | 444 | if (atomic_read(&cifsInfo->inUse) == 0) |
| @@ -519,10 +520,11 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 519 | else /* not direct, send byte range locks */ | 520 | else /* not direct, send byte range locks */ |
| 520 | inode->i_fop = &cifs_file_ops; | 521 | inode->i_fop = &cifs_file_ops; |
| 521 | 522 | ||
| 522 | inode->i_data.a_ops = &cifs_addr_ops; | ||
| 523 | if(pTcon->ses->server->maxBuf < | 523 | if(pTcon->ses->server->maxBuf < |
| 524 | 4096 + MAX_CIFS_HDR_SIZE) | 524 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) |
| 525 | inode->i_data.a_ops->readpages = NULL; | 525 | inode->i_data.a_ops = &cifs_addr_ops_smallbuf; |
| 526 | else | ||
| 527 | inode->i_data.a_ops = &cifs_addr_ops; | ||
| 526 | } else if (S_ISDIR(inode->i_mode)) { | 528 | } else if (S_ISDIR(inode->i_mode)) { |
| 527 | cFYI(1, ("Directory inode")); | 529 | cFYI(1, ("Directory inode")); |
| 528 | inode->i_op = &cifs_dir_inode_ops; | 530 | inode->i_op = &cifs_dir_inode_ops; |
| @@ -731,7 +733,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
| 731 | rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, | 733 | rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, |
| 732 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 734 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 733 | if (rc) { | 735 | if (rc) { |
| 734 | cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); | 736 | cFYI(1, ("cifs_mkdir returned 0x%x", rc)); |
| 735 | d_drop(direntry); | 737 | d_drop(direntry); |
| 736 | } else { | 738 | } else { |
| 737 | inode->i_nlink++; | 739 | inode->i_nlink++; |
| @@ -798,7 +800,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
| 798 | char *full_path = NULL; | 800 | char *full_path = NULL; |
| 799 | struct cifsInodeInfo *cifsInode; | 801 | struct cifsInodeInfo *cifsInode; |
| 800 | 802 | ||
| 801 | cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode)); | 803 | cFYI(1, ("cifs_rmdir, inode = 0x%p", inode)); |
| 802 | 804 | ||
| 803 | xid = GetXid(); | 805 | xid = GetXid(); |
| 804 | 806 | ||
| @@ -1121,7 +1123,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1121 | 1123 | ||
| 1122 | xid = GetXid(); | 1124 | xid = GetXid(); |
| 1123 | 1125 | ||
| 1124 | cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x ", | 1126 | cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", |
| 1125 | direntry->d_name.name, attrs->ia_valid)); | 1127 | direntry->d_name.name, attrs->ia_valid)); |
| 1126 | 1128 | ||
| 1127 | cifs_sb = CIFS_SB(direntry->d_inode->i_sb); | 1129 | cifs_sb = CIFS_SB(direntry->d_inode->i_sb); |
| @@ -1157,6 +1159,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1157 | when the local oplock break takes longer to flush | 1159 | when the local oplock break takes longer to flush |
| 1158 | writebehind data than the SMB timeout for the SetPathInfo | 1160 | writebehind data than the SMB timeout for the SetPathInfo |
| 1159 | request would allow */ | 1161 | request would allow */ |
| 1162 | |||
| 1160 | open_file = find_writable_file(cifsInode); | 1163 | open_file = find_writable_file(cifsInode); |
| 1161 | if (open_file) { | 1164 | if (open_file) { |
| 1162 | __u16 nfid = open_file->netfid; | 1165 | __u16 nfid = open_file->netfid; |
| @@ -1289,7 +1292,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1289 | it may be useful to Windows - but we do | 1292 | it may be useful to Windows - but we do |
| 1290 | not want to set ctime unless some other | 1293 | not want to set ctime unless some other |
| 1291 | timestamp is changing */ | 1294 | timestamp is changing */ |
| 1292 | cFYI(1, ("CIFS - CTIME changed ")); | 1295 | cFYI(1, ("CIFS - CTIME changed")); |
| 1293 | time_buf.ChangeTime = | 1296 | time_buf.ChangeTime = |
| 1294 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | 1297 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); |
| 1295 | } else | 1298 | } else |
| @@ -1356,7 +1359,7 @@ cifs_setattr_exit: | |||
| 1356 | 1359 | ||
| 1357 | void cifs_delete_inode(struct inode *inode) | 1360 | void cifs_delete_inode(struct inode *inode) |
| 1358 | { | 1361 | { |
| 1359 | cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode)); | 1362 | cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode)); |
| 1360 | /* may have to add back in if and when safe distributed caching of | 1363 | /* may have to add back in if and when safe distributed caching of |
| 1361 | directories added e.g. via FindNotify */ | 1364 | directories added e.g. via FindNotify */ |
| 1362 | } | 1365 | } |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 2ec99f833142..a57f5d6e6213 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
| @@ -167,7 +167,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
| 167 | return -ENOMEM; | 167 | return -ENOMEM; |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | cFYI(1, ("Full path: %s ", full_path)); | 170 | cFYI(1, ("Full path: %s", full_path)); |
| 171 | cFYI(1, ("symname is %s", symname)); | 171 | cFYI(1, ("symname is %s", symname)); |
| 172 | 172 | ||
| 173 | /* BB what if DFS and this volume is on different share? BB */ | 173 | /* 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) | |||
| 186 | inode->i_sb,xid); | 186 | inode->i_sb,xid); |
| 187 | 187 | ||
| 188 | if (rc != 0) { | 188 | if (rc != 0) { |
| 189 | cFYI(1, | 189 | cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d", |
| 190 | ("Create symlink worked but get_inode_info failed with rc = %d ", | ||
| 191 | rc)); | 190 | rc)); |
| 192 | } else { | 191 | } else { |
| 193 | if (pTcon->nocase) | 192 | if (pTcon->nocase) |
| @@ -289,7 +288,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) | |||
| 289 | else { | 288 | else { |
| 290 | cFYI(1,("num referral: %d",num_referrals)); | 289 | cFYI(1,("num referral: %d",num_referrals)); |
| 291 | if(referrals) { | 290 | if(referrals) { |
| 292 | cFYI(1,("referral string: %s ",referrals)); | 291 | cFYI(1,("referral string: %s",referrals)); |
| 293 | strncpy(tmpbuffer, referrals, len-1); | 292 | strncpy(tmpbuffer, referrals, len-1); |
| 294 | } | 293 | } |
| 295 | } | 294 | } |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index fafd056426e4..22c937e5884f 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -101,6 +101,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free) | |||
| 101 | kfree(buf_to_free->serverDomain); | 101 | kfree(buf_to_free->serverDomain); |
| 102 | kfree(buf_to_free->serverNOS); | 102 | kfree(buf_to_free->serverNOS); |
| 103 | kfree(buf_to_free->password); | 103 | kfree(buf_to_free->password); |
| 104 | kfree(buf_to_free->domainName); | ||
| 104 | kfree(buf_to_free); | 105 | kfree(buf_to_free); |
| 105 | } | 106 | } |
| 106 | 107 | ||
| @@ -499,11 +500,12 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
| 499 | if(pSMBr->ByteCount > sizeof(struct file_notify_information)) { | 500 | if(pSMBr->ByteCount > sizeof(struct file_notify_information)) { |
| 500 | data_offset = le32_to_cpu(pSMBr->DataOffset); | 501 | data_offset = le32_to_cpu(pSMBr->DataOffset); |
| 501 | 502 | ||
| 502 | pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol | 503 | pnotify = (struct file_notify_information *) |
| 503 | + data_offset); | 504 | ((char *)&pSMBr->hdr.Protocol + data_offset); |
| 504 | cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName, | 505 | cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName, |
| 505 | pnotify->Action)); /* BB removeme BB */ | 506 | pnotify->Action)); /* BB removeme BB */ |
| 506 | /* cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */ | 507 | /* cifs_dump_mem("Rcvd notify Data: ",buf, |
| 508 | sizeof(struct smb_hdr)+60); */ | ||
| 507 | return TRUE; | 509 | return TRUE; |
| 508 | } | 510 | } |
| 509 | if(pSMBr->hdr.Status.CifsError) { | 511 | if(pSMBr->hdr.Status.CifsError) { |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 5de74d216fdd..b66eff5dc624 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
| @@ -84,11 +84,11 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { | |||
| 84 | 84 | ||
| 85 | static const struct smb_to_posix_error mapping_table_ERRSRV[] = { | 85 | static const struct smb_to_posix_error mapping_table_ERRSRV[] = { |
| 86 | {ERRerror, -EIO}, | 86 | {ERRerror, -EIO}, |
| 87 | {ERRbadpw, -EPERM}, | 87 | {ERRbadpw, -EACCES}, /* was EPERM */ |
| 88 | {ERRbadtype, -EREMOTE}, | 88 | {ERRbadtype, -EREMOTE}, |
| 89 | {ERRaccess, -EACCES}, | 89 | {ERRaccess, -EACCES}, |
| 90 | {ERRinvtid, -ENXIO}, | 90 | {ERRinvtid, -ENXIO}, |
| 91 | {ERRinvnetname, -ENODEV}, | 91 | {ERRinvnetname, -ENXIO}, |
| 92 | {ERRinvdevice, -ENXIO}, | 92 | {ERRinvdevice, -ENXIO}, |
| 93 | {ERRqfull, -ENOSPC}, | 93 | {ERRqfull, -ENOSPC}, |
| 94 | {ERRqtoobig, -ENOSPC}, | 94 | {ERRqtoobig, -ENOSPC}, |
diff --git a/fs/cifs/ntlmssp.c b/fs/cifs/ntlmssp.c deleted file mode 100644 index 115359cc7a32..000000000000 --- a/fs/cifs/ntlmssp.c +++ /dev/null | |||
| @@ -1,143 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * fs/cifs/ntlmssp.h | ||
| 3 | * | ||
| 4 | * Copyright (c) International Business Machines Corp., 2006 | ||
| 5 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
| 6 | * | ||
| 7 | * This library is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Lesser General Public License as published | ||
| 9 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This library is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
| 15 | * the GNU Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public License | ||
| 18 | * along with this library; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "cifspdu.h" | ||
| 23 | #include "cifsglob.h" | ||
| 24 | #include "cifsproto.h" | ||
| 25 | #include "cifs_unicode.h" | ||
| 26 | #include "cifs_debug.h" | ||
| 27 | #include "ntlmssp.h" | ||
| 28 | #include "nterr.h" | ||
| 29 | |||
| 30 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
| 31 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) | ||
| 32 | { | ||
| 33 | __u32 capabilities = 0; | ||
| 34 | |||
| 35 | /* init fields common to all four types of SessSetup */ | ||
| 36 | /* note that header is initialized to zero in header_assemble */ | ||
| 37 | pSMB->req.AndXCommand = 0xFF; | ||
| 38 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
| 39 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
| 40 | |||
| 41 | /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */ | ||
| 42 | |||
| 43 | /* BB verify whether signing required on neg or just on auth frame | ||
| 44 | (and NTLM case) */ | ||
| 45 | |||
| 46 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
| 47 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; | ||
| 48 | |||
| 49 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
| 50 | pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
| 51 | |||
| 52 | if (ses->capabilities & CAP_UNICODE) { | ||
| 53 | pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE; | ||
| 54 | capabilities |= CAP_UNICODE; | ||
| 55 | } | ||
| 56 | if (ses->capabilities & CAP_STATUS32) { | ||
| 57 | pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS; | ||
| 58 | capabilities |= CAP_STATUS32; | ||
| 59 | } | ||
| 60 | if (ses->capabilities & CAP_DFS) { | ||
| 61 | pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; | ||
| 62 | capabilities |= CAP_DFS; | ||
| 63 | } | ||
| 64 | |||
| 65 | /* BB check whether to init vcnum BB */ | ||
| 66 | return capabilities; | ||
| 67 | } | ||
| 68 | int | ||
| 69 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int type, | ||
| 70 | int * pNTLMv2_flg, const struct nls_table *nls_cp) | ||
| 71 | { | ||
| 72 | int rc = 0; | ||
| 73 | int wct; | ||
| 74 | struct smb_hdr *smb_buffer; | ||
| 75 | char *bcc_ptr; | ||
| 76 | SESSION_SETUP_ANDX *pSMB; | ||
| 77 | __u32 capabilities; | ||
| 78 | |||
| 79 | if(ses == NULL) | ||
| 80 | return -EINVAL; | ||
| 81 | |||
| 82 | cFYI(1,("SStp type: %d",type)); | ||
| 83 | if(type < CIFS_NTLM) { | ||
| 84 | #ifndef CONFIG_CIFS_WEAK_PW_HASH | ||
| 85 | /* LANMAN and plaintext are less secure and off by default. | ||
| 86 | So we make this explicitly be turned on in kconfig (in the | ||
| 87 | build) and turned on at runtime (changed from the default) | ||
| 88 | in proc/fs/cifs or via mount parm. Unfortunately this is | ||
| 89 | needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ | ||
| 90 | return -EOPNOTSUPP; | ||
| 91 | #endif | ||
| 92 | wct = 10; /* lanman 2 style sessionsetup */ | ||
| 93 | } else if(type < CIFS_NTLMSSP_NEG) | ||
| 94 | wct = 13; /* old style NTLM sessionsetup */ | ||
| 95 | else /* same size for negotiate or auth, NTLMSSP or extended security */ | ||
| 96 | wct = 12; | ||
| 97 | |||
| 98 | rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, | ||
| 99 | (void **)&smb_buffer); | ||
| 100 | if(rc) | ||
| 101 | return rc; | ||
| 102 | |||
| 103 | pSMB = (SESSION_SETUP_ANDX *)smb_buffer; | ||
| 104 | |||
| 105 | capabilities = cifs_ssetup_hdr(ses, pSMB); | ||
| 106 | bcc_ptr = pByteArea(smb_buffer); | ||
| 107 | if(type > CIFS_NTLM) { | ||
| 108 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
| 109 | capabilities |= CAP_EXTENDED_SECURITY; | ||
| 110 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
| 111 | /* BB set password lengths */ | ||
| 112 | } else if(type < CIFS_NTLM) /* lanman */ { | ||
| 113 | /* no capabilities flags in old lanman negotiation */ | ||
| 114 | /* pSMB->old_req.PasswordLength = */ /* BB fixme BB */ | ||
| 115 | } else /* type CIFS_NTLM */ { | ||
| 116 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
| 117 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | ||
| 118 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | ||
| 119 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
| 120 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | ||
| 121 | } | ||
| 122 | |||
| 123 | |||
| 124 | /* copy session key */ | ||
| 125 | |||
| 126 | /* if Unicode, align strings to two byte boundary */ | ||
| 127 | |||
| 128 | /* copy user name */ /* BB Do we need to special case null user name? */ | ||
| 129 | |||
| 130 | /* copy domain name */ | ||
| 131 | |||
| 132 | /* copy Linux version */ | ||
| 133 | |||
| 134 | /* copy network operating system name */ | ||
| 135 | |||
| 136 | /* update bcc and smb buffer length */ | ||
| 137 | |||
| 138 | /* rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */ | ||
| 139 | /* SMB request buf freed in SendReceive2 */ | ||
| 140 | |||
| 141 | return rc; | ||
| 142 | } | ||
| 143 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index b689c5035124..03bbcb377913 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 22 | */ | 22 | */ |
| 23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
| 24 | #include <linux/pagemap.h> | ||
| 24 | #include <linux/stat.h> | 25 | #include <linux/stat.h> |
| 25 | #include <linux/smp_lock.h> | 26 | #include <linux/smp_lock.h> |
| 26 | #include "cifspdu.h" | 27 | #include "cifspdu.h" |
| @@ -31,8 +32,8 @@ | |||
| 31 | #include "cifs_fs_sb.h" | 32 | #include "cifs_fs_sb.h" |
| 32 | #include "cifsfs.h" | 33 | #include "cifsfs.h" |
| 33 | 34 | ||
| 34 | /* BB fixme - add debug wrappers around this function to disable it fixme BB */ | 35 | #ifdef CONFIG_CIFS_DEBUG2 |
| 35 | /* static void dump_cifs_file_struct(struct file *file, char *label) | 36 | static void dump_cifs_file_struct(struct file *file, char *label) |
| 36 | { | 37 | { |
| 37 | struct cifsFileInfo * cf; | 38 | struct cifsFileInfo * cf; |
| 38 | 39 | ||
| @@ -53,7 +54,8 @@ | |||
| 53 | } | 54 | } |
| 54 | 55 | ||
| 55 | } | 56 | } |
| 56 | } */ | 57 | } |
| 58 | #endif /* DEBUG2 */ | ||
| 57 | 59 | ||
| 58 | /* Returns one if new inode created (which therefore needs to be hashed) */ | 60 | /* Returns one if new inode created (which therefore needs to be hashed) */ |
| 59 | /* Might check in the future if inode number changed so we can rehash inode */ | 61 | /* 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, | |||
| 107 | return rc; | 109 | return rc; |
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | static void fill_in_inode(struct inode *tmp_inode, | 112 | static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, |
| 111 | FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode) | 113 | char * buf, int *pobject_type, int isNewInode) |
| 112 | { | 114 | { |
| 113 | loff_t local_size; | 115 | loff_t local_size; |
| 114 | struct timespec local_mtime; | 116 | struct timespec local_mtime; |
| 115 | 117 | ||
| 116 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | 118 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); |
| 117 | struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); | 119 | struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); |
| 118 | __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); | 120 | __u32 attr; |
| 119 | __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); | 121 | __u64 allocation_size; |
| 120 | __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); | 122 | __u64 end_of_file; |
| 121 | |||
| 122 | cifsInfo->cifsAttrs = attr; | ||
| 123 | cifsInfo->time = jiffies; | ||
| 124 | 123 | ||
| 125 | /* save mtime and size */ | 124 | /* save mtime and size */ |
| 126 | local_mtime = tmp_inode->i_mtime; | 125 | local_mtime = tmp_inode->i_mtime; |
| 127 | local_size = tmp_inode->i_size; | 126 | local_size = tmp_inode->i_size; |
| 128 | 127 | ||
| 128 | if(new_buf_type) { | ||
| 129 | FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf; | ||
| 130 | |||
| 131 | attr = le32_to_cpu(pfindData->ExtFileAttributes); | ||
| 132 | allocation_size = le64_to_cpu(pfindData->AllocationSize); | ||
| 133 | end_of_file = le64_to_cpu(pfindData->EndOfFile); | ||
| 134 | tmp_inode->i_atime = | ||
| 135 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); | ||
| 136 | tmp_inode->i_mtime = | ||
| 137 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); | ||
| 138 | tmp_inode->i_ctime = | ||
| 139 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); | ||
| 140 | } else { /* legacy, OS2 and DOS style */ | ||
| 141 | FIND_FILE_STANDARD_INFO * pfindData = | ||
| 142 | (FIND_FILE_STANDARD_INFO *)buf; | ||
| 143 | |||
| 144 | attr = le16_to_cpu(pfindData->Attributes); | ||
| 145 | allocation_size = le32_to_cpu(pfindData->AllocationSize); | ||
| 146 | end_of_file = le32_to_cpu(pfindData->DataSize); | ||
| 147 | tmp_inode->i_atime = CURRENT_TIME; | ||
| 148 | /* tmp_inode->i_mtime = BB FIXME - add dos time handling | ||
| 149 | tmp_inode->i_ctime = 0; BB FIXME */ | ||
| 150 | |||
| 151 | } | ||
| 152 | |||
| 129 | /* Linux can not store file creation time unfortunately so ignore it */ | 153 | /* Linux can not store file creation time unfortunately so ignore it */ |
| 130 | tmp_inode->i_atime = | 154 | |
| 131 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); | 155 | cifsInfo->cifsAttrs = attr; |
| 132 | tmp_inode->i_mtime = | 156 | cifsInfo->time = jiffies; |
| 133 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); | 157 | |
| 134 | tmp_inode->i_ctime = | ||
| 135 | cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); | ||
| 136 | /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ | 158 | /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ |
| 137 | /* 2767 perms - indicate mandatory locking */ | 159 | /* 2767 perms - indicate mandatory locking */ |
| 138 | /* BB fill in uid and gid here? with help from winbind? | 160 | /* BB fill in uid and gid here? with help from winbind? |
| @@ -215,11 +237,13 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
| 215 | else | 237 | else |
| 216 | tmp_inode->i_fop = &cifs_file_ops; | 238 | tmp_inode->i_fop = &cifs_file_ops; |
| 217 | 239 | ||
| 218 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
| 219 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | 240 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && |
| 220 | (cifs_sb->tcon->ses->server->maxBuf < | 241 | (cifs_sb->tcon->ses->server->maxBuf < |
| 221 | 4096 + MAX_CIFS_HDR_SIZE)) | 242 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) |
| 222 | tmp_inode->i_data.a_ops->readpages = NULL; | 243 | tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; |
| 244 | else | ||
| 245 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
| 246 | |||
| 223 | if(isNewInode) | 247 | if(isNewInode) |
| 224 | return; /* No sense invalidating pages for new inode | 248 | return; /* No sense invalidating pages for new inode |
| 225 | since have not started caching readahead file | 249 | since have not started caching readahead file |
| @@ -338,11 +362,12 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
| 338 | else | 362 | else |
| 339 | tmp_inode->i_fop = &cifs_file_ops; | 363 | tmp_inode->i_fop = &cifs_file_ops; |
| 340 | 364 | ||
| 341 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
| 342 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | 365 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && |
| 343 | (cifs_sb->tcon->ses->server->maxBuf < | 366 | (cifs_sb->tcon->ses->server->maxBuf < |
| 344 | 4096 + MAX_CIFS_HDR_SIZE)) | 367 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) |
| 345 | tmp_inode->i_data.a_ops->readpages = NULL; | 368 | tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; |
| 369 | else | ||
| 370 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
| 346 | 371 | ||
| 347 | if(isNewInode) | 372 | if(isNewInode) |
| 348 | return; /* No sense invalidating pages for new inode since we | 373 | return; /* No sense invalidating pages for new inode since we |
| @@ -415,7 +440,10 @@ static int initiate_cifs_search(const int xid, struct file *file) | |||
| 415 | ffirst_retry: | 440 | ffirst_retry: |
| 416 | /* test for Unix extensions */ | 441 | /* test for Unix extensions */ |
| 417 | if (pTcon->ses->capabilities & CAP_UNIX) { | 442 | if (pTcon->ses->capabilities & CAP_UNIX) { |
| 418 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; | 443 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; |
| 444 | } else if ((pTcon->ses->capabilities & | ||
| 445 | (CAP_NT_SMBS | CAP_NT_FIND)) == 0) { | ||
| 446 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD; | ||
| 419 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | 447 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { |
| 420 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; | 448 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; |
| 421 | } else /* not srvinos - BB fixme add check for backlevel? */ { | 449 | } else /* not srvinos - BB fixme add check for backlevel? */ { |
| @@ -451,12 +479,19 @@ static int cifs_unicode_bytelen(char *str) | |||
| 451 | return len << 1; | 479 | return len << 1; |
| 452 | } | 480 | } |
| 453 | 481 | ||
| 454 | static char *nxt_dir_entry(char *old_entry, char *end_of_smb) | 482 | static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) |
| 455 | { | 483 | { |
| 456 | char * new_entry; | 484 | char * new_entry; |
| 457 | FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; | 485 | FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; |
| 458 | 486 | ||
| 459 | new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); | 487 | if(level == SMB_FIND_FILE_INFO_STANDARD) { |
| 488 | FIND_FILE_STANDARD_INFO * pfData; | ||
| 489 | pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo; | ||
| 490 | |||
| 491 | new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) + | ||
| 492 | pfData->FileNameLength; | ||
| 493 | } else | ||
| 494 | new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); | ||
| 460 | cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); | 495 | cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); |
| 461 | /* validate that new_entry is not past end of SMB */ | 496 | /* validate that new_entry is not past end of SMB */ |
| 462 | if(new_entry >= end_of_smb) { | 497 | if(new_entry >= end_of_smb) { |
| @@ -464,7 +499,10 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb) | |||
| 464 | ("search entry %p began after end of SMB %p old entry %p", | 499 | ("search entry %p began after end of SMB %p old entry %p", |
| 465 | new_entry, end_of_smb, old_entry)); | 500 | new_entry, end_of_smb, old_entry)); |
| 466 | return NULL; | 501 | return NULL; |
| 467 | } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) { | 502 | } else if(((level == SMB_FIND_FILE_INFO_STANDARD) && |
| 503 | (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) || | ||
| 504 | ((level != SMB_FIND_FILE_INFO_STANDARD) && | ||
| 505 | (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) { | ||
| 468 | cERROR(1,("search entry %p extends after end of SMB %p", | 506 | cERROR(1,("search entry %p extends after end of SMB %p", |
| 469 | new_entry, end_of_smb)); | 507 | new_entry, end_of_smb)); |
| 470 | return NULL; | 508 | return NULL; |
| @@ -482,7 +520,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) | |||
| 482 | char * filename = NULL; | 520 | char * filename = NULL; |
| 483 | int len = 0; | 521 | int len = 0; |
| 484 | 522 | ||
| 485 | if(cfile->srch_inf.info_level == 0x202) { | 523 | if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) { |
| 486 | FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; | 524 | FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; |
| 487 | filename = &pFindData->FileName[0]; | 525 | filename = &pFindData->FileName[0]; |
| 488 | if(cfile->srch_inf.unicode) { | 526 | if(cfile->srch_inf.unicode) { |
| @@ -491,26 +529,34 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) | |||
| 491 | /* BB should we make this strnlen of PATH_MAX? */ | 529 | /* BB should we make this strnlen of PATH_MAX? */ |
| 492 | len = strnlen(filename, 5); | 530 | len = strnlen(filename, 5); |
| 493 | } | 531 | } |
| 494 | } else if(cfile->srch_inf.info_level == 0x101) { | 532 | } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) { |
| 495 | FILE_DIRECTORY_INFO * pFindData = | 533 | FILE_DIRECTORY_INFO * pFindData = |
| 496 | (FILE_DIRECTORY_INFO *)current_entry; | 534 | (FILE_DIRECTORY_INFO *)current_entry; |
| 497 | filename = &pFindData->FileName[0]; | 535 | filename = &pFindData->FileName[0]; |
| 498 | len = le32_to_cpu(pFindData->FileNameLength); | 536 | len = le32_to_cpu(pFindData->FileNameLength); |
| 499 | } else if(cfile->srch_inf.info_level == 0x102) { | 537 | } else if(cfile->srch_inf.info_level == |
| 538 | SMB_FIND_FILE_FULL_DIRECTORY_INFO) { | ||
| 500 | FILE_FULL_DIRECTORY_INFO * pFindData = | 539 | FILE_FULL_DIRECTORY_INFO * pFindData = |
| 501 | (FILE_FULL_DIRECTORY_INFO *)current_entry; | 540 | (FILE_FULL_DIRECTORY_INFO *)current_entry; |
| 502 | filename = &pFindData->FileName[0]; | 541 | filename = &pFindData->FileName[0]; |
| 503 | len = le32_to_cpu(pFindData->FileNameLength); | 542 | len = le32_to_cpu(pFindData->FileNameLength); |
| 504 | } else if(cfile->srch_inf.info_level == 0x105) { | 543 | } else if(cfile->srch_inf.info_level == |
| 544 | SMB_FIND_FILE_ID_FULL_DIR_INFO) { | ||
| 505 | SEARCH_ID_FULL_DIR_INFO * pFindData = | 545 | SEARCH_ID_FULL_DIR_INFO * pFindData = |
| 506 | (SEARCH_ID_FULL_DIR_INFO *)current_entry; | 546 | (SEARCH_ID_FULL_DIR_INFO *)current_entry; |
| 507 | filename = &pFindData->FileName[0]; | 547 | filename = &pFindData->FileName[0]; |
| 508 | len = le32_to_cpu(pFindData->FileNameLength); | 548 | len = le32_to_cpu(pFindData->FileNameLength); |
| 509 | } else if(cfile->srch_inf.info_level == 0x104) { | 549 | } else if(cfile->srch_inf.info_level == |
| 550 | SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { | ||
| 510 | FILE_BOTH_DIRECTORY_INFO * pFindData = | 551 | FILE_BOTH_DIRECTORY_INFO * pFindData = |
| 511 | (FILE_BOTH_DIRECTORY_INFO *)current_entry; | 552 | (FILE_BOTH_DIRECTORY_INFO *)current_entry; |
| 512 | filename = &pFindData->FileName[0]; | 553 | filename = &pFindData->FileName[0]; |
| 513 | len = le32_to_cpu(pFindData->FileNameLength); | 554 | len = le32_to_cpu(pFindData->FileNameLength); |
| 555 | } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) { | ||
| 556 | FIND_FILE_STANDARD_INFO * pFindData = | ||
| 557 | (FIND_FILE_STANDARD_INFO *)current_entry; | ||
| 558 | filename = &pFindData->FileName[0]; | ||
| 559 | len = le32_to_cpu(pFindData->FileNameLength); | ||
| 514 | } else { | 560 | } else { |
| 515 | cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); | 561 | cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); |
| 516 | } | 562 | } |
| @@ -597,7 +643,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 597 | . and .. for the root of a drive and for those we need | 643 | . and .. for the root of a drive and for those we need |
| 598 | to start two entries earlier */ | 644 | to start two entries earlier */ |
| 599 | 645 | ||
| 600 | /* dump_cifs_file_struct(file, "In fce ");*/ | 646 | #ifdef CONFIG_CIFS_DEBUG2 |
| 647 | dump_cifs_file_struct(file, "In fce "); | ||
| 648 | #endif | ||
| 601 | if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && | 649 | if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && |
| 602 | is_dir_changed(file)) || | 650 | is_dir_changed(file)) || |
| 603 | (index_to_find < first_entry_in_buffer)) { | 651 | (index_to_find < first_entry_in_buffer)) { |
| @@ -644,10 +692,12 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 644 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry | 692 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry |
| 645 | - cifsFile->srch_inf.entries_in_buffer; | 693 | - cifsFile->srch_inf.entries_in_buffer; |
| 646 | pos_in_buf = index_to_find - first_entry_in_buffer; | 694 | pos_in_buf = index_to_find - first_entry_in_buffer; |
| 647 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); | 695 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); |
| 696 | |||
| 648 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { | 697 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { |
| 649 | /* go entry by entry figuring out which is first */ | 698 | /* go entry by entry figuring out which is first */ |
| 650 | current_entry = nxt_dir_entry(current_entry,end_of_smb); | 699 | current_entry = nxt_dir_entry(current_entry,end_of_smb, |
| 700 | cifsFile->srch_inf.info_level); | ||
| 651 | } | 701 | } |
| 652 | if((current_entry == NULL) && (i < pos_in_buf)) { | 702 | if((current_entry == NULL) && (i < pos_in_buf)) { |
| 653 | /* BB fixme - check if we should flag this error */ | 703 | /* BB fixme - check if we should flag this error */ |
| @@ -674,7 +724,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 674 | /* inode num, inode type and filename returned */ | 724 | /* inode num, inode type and filename returned */ |
| 675 | static int cifs_get_name_from_search_buf(struct qstr *pqst, | 725 | static int cifs_get_name_from_search_buf(struct qstr *pqst, |
| 676 | char *current_entry, __u16 level, unsigned int unicode, | 726 | char *current_entry, __u16 level, unsigned int unicode, |
| 677 | struct cifs_sb_info * cifs_sb, ino_t *pinum) | 727 | struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum) |
| 678 | { | 728 | { |
| 679 | int rc = 0; | 729 | int rc = 0; |
| 680 | unsigned int len = 0; | 730 | unsigned int len = 0; |
| @@ -718,10 +768,22 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
| 718 | (FILE_BOTH_DIRECTORY_INFO *)current_entry; | 768 | (FILE_BOTH_DIRECTORY_INFO *)current_entry; |
| 719 | filename = &pFindData->FileName[0]; | 769 | filename = &pFindData->FileName[0]; |
| 720 | len = le32_to_cpu(pFindData->FileNameLength); | 770 | len = le32_to_cpu(pFindData->FileNameLength); |
| 771 | } else if(level == SMB_FIND_FILE_INFO_STANDARD) { | ||
| 772 | FIND_FILE_STANDARD_INFO * pFindData = | ||
| 773 | (FIND_FILE_STANDARD_INFO *)current_entry; | ||
| 774 | filename = &pFindData->FileName[0]; | ||
| 775 | /* one byte length, no name conversion */ | ||
| 776 | len = (unsigned int)pFindData->FileNameLength; | ||
| 721 | } else { | 777 | } else { |
| 722 | cFYI(1,("Unknown findfirst level %d",level)); | 778 | cFYI(1,("Unknown findfirst level %d",level)); |
| 723 | return -EINVAL; | 779 | return -EINVAL; |
| 724 | } | 780 | } |
| 781 | |||
| 782 | if(len > max_len) { | ||
| 783 | cERROR(1,("bad search response length %d past smb end", len)); | ||
| 784 | return -EINVAL; | ||
| 785 | } | ||
| 786 | |||
| 725 | if(unicode) { | 787 | if(unicode) { |
| 726 | /* BB fixme - test with long names */ | 788 | /* BB fixme - test with long names */ |
| 727 | /* Note converted filename can be longer than in unicode */ | 789 | /* Note converted filename can be longer than in unicode */ |
| @@ -741,7 +803,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
| 741 | } | 803 | } |
| 742 | 804 | ||
| 743 | static int cifs_filldir(char *pfindEntry, struct file *file, | 805 | static int cifs_filldir(char *pfindEntry, struct file *file, |
| 744 | filldir_t filldir, void *direntry, char *scratch_buf) | 806 | filldir_t filldir, void *direntry, char *scratch_buf, int max_len) |
| 745 | { | 807 | { |
| 746 | int rc = 0; | 808 | int rc = 0; |
| 747 | struct qstr qstring; | 809 | struct qstr qstring; |
| @@ -777,6 +839,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
| 777 | rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, | 839 | rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, |
| 778 | pCifsF->srch_inf.info_level, | 840 | pCifsF->srch_inf.info_level, |
| 779 | pCifsF->srch_inf.unicode,cifs_sb, | 841 | pCifsF->srch_inf.unicode,cifs_sb, |
| 842 | max_len, | ||
| 780 | &inum /* returned */); | 843 | &inum /* returned */); |
| 781 | 844 | ||
| 782 | if(rc) | 845 | if(rc) |
| @@ -798,13 +861,16 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
| 798 | /* we pass in rc below, indicating whether it is a new inode, | 861 | /* we pass in rc below, indicating whether it is a new inode, |
| 799 | so we can figure out whether to invalidate the inode cached | 862 | so we can figure out whether to invalidate the inode cached |
| 800 | data if the file has changed */ | 863 | data if the file has changed */ |
| 801 | if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { | 864 | if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) |
| 802 | unix_fill_in_inode(tmp_inode, | 865 | unix_fill_in_inode(tmp_inode, |
| 803 | (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc); | 866 | (FILE_UNIX_INFO *)pfindEntry, |
| 804 | } else { | 867 | &obj_type, rc); |
| 805 | fill_in_inode(tmp_inode, | 868 | else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) |
| 806 | (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); | 869 | fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */, |
| 807 | } | 870 | pfindEntry, &obj_type, rc); |
| 871 | else | ||
| 872 | fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); | ||
| 873 | |||
| 808 | 874 | ||
| 809 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, | 875 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, |
| 810 | tmp_inode->i_ino,obj_type); | 876 | tmp_inode->i_ino,obj_type); |
| @@ -864,6 +930,12 @@ static int cifs_save_resume_key(const char *current_entry, | |||
| 864 | filename = &pFindData->FileName[0]; | 930 | filename = &pFindData->FileName[0]; |
| 865 | len = le32_to_cpu(pFindData->FileNameLength); | 931 | len = le32_to_cpu(pFindData->FileNameLength); |
| 866 | cifsFile->srch_inf.resume_key = pFindData->FileIndex; | 932 | cifsFile->srch_inf.resume_key = pFindData->FileIndex; |
| 933 | } else if(level == SMB_FIND_FILE_INFO_STANDARD) { | ||
| 934 | FIND_FILE_STANDARD_INFO * pFindData = | ||
| 935 | (FIND_FILE_STANDARD_INFO *)current_entry; | ||
| 936 | filename = &pFindData->FileName[0]; | ||
| 937 | /* one byte length, no name conversion */ | ||
| 938 | len = (unsigned int)pFindData->FileNameLength; | ||
| 867 | } else { | 939 | } else { |
| 868 | cFYI(1,("Unknown findfirst level %d",level)); | 940 | cFYI(1,("Unknown findfirst level %d",level)); |
| 869 | return -EINVAL; | 941 | return -EINVAL; |
| @@ -884,6 +956,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 884 | int num_to_fill = 0; | 956 | int num_to_fill = 0; |
| 885 | char * tmp_buf = NULL; | 957 | char * tmp_buf = NULL; |
| 886 | char * end_of_smb; | 958 | char * end_of_smb; |
| 959 | int max_len; | ||
| 887 | 960 | ||
| 888 | xid = GetXid(); | 961 | xid = GetXid(); |
| 889 | 962 | ||
| @@ -909,7 +982,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 909 | case 1: | 982 | case 1: |
| 910 | if (filldir(direntry, "..", 2, file->f_pos, | 983 | if (filldir(direntry, "..", 2, file->f_pos, |
| 911 | file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { | 984 | file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { |
| 912 | cERROR(1, ("Filldir for parent dir failed ")); | 985 | cERROR(1, ("Filldir for parent dir failed")); |
| 913 | rc = -ENOMEM; | 986 | rc = -ENOMEM; |
| 914 | break; | 987 | break; |
| 915 | } | 988 | } |
| @@ -959,10 +1032,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 959 | goto rddir2_exit; | 1032 | goto rddir2_exit; |
| 960 | } | 1033 | } |
| 961 | cFYI(1,("loop through %d times filling dir for net buf %p", | 1034 | cFYI(1,("loop through %d times filling dir for net buf %p", |
| 962 | num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); | 1035 | num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); |
| 963 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + | 1036 | max_len = smbCalcSize((struct smb_hdr *) |
| 964 | smbCalcSize((struct smb_hdr *) | 1037 | cifsFile->srch_inf.ntwrk_buf_start); |
| 965 | cifsFile->srch_inf.ntwrk_buf_start); | 1038 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; |
| 1039 | |||
| 966 | /* To be safe - for UCS to UTF-8 with strings loaded | 1040 | /* To be safe - for UCS to UTF-8 with strings loaded |
| 967 | with the rare long characters alloc more to account for | 1041 | with the rare long characters alloc more to account for |
| 968 | such multibyte target UTF-8 characters. cifs_unicode.c, | 1042 | such multibyte target UTF-8 characters. cifs_unicode.c, |
| @@ -977,17 +1051,19 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 977 | } | 1051 | } |
| 978 | /* if buggy server returns . and .. late do | 1052 | /* if buggy server returns . and .. late do |
| 979 | we want to check for that here? */ | 1053 | we want to check for that here? */ |
| 980 | rc = cifs_filldir(current_entry, file, | 1054 | rc = cifs_filldir(current_entry, file, |
| 981 | filldir, direntry,tmp_buf); | 1055 | filldir, direntry, tmp_buf, max_len); |
| 982 | file->f_pos++; | 1056 | file->f_pos++; |
| 983 | if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) { | 1057 | if(file->f_pos == |
| 1058 | cifsFile->srch_inf.index_of_last_entry) { | ||
| 984 | cFYI(1,("last entry in buf at pos %lld %s", | 1059 | cFYI(1,("last entry in buf at pos %lld %s", |
| 985 | file->f_pos,tmp_buf)); /* BB removeme BB */ | 1060 | file->f_pos,tmp_buf)); |
| 986 | cifs_save_resume_key(current_entry,cifsFile); | 1061 | cifs_save_resume_key(current_entry,cifsFile); |
| 987 | break; | 1062 | break; |
| 988 | } else | 1063 | } else |
| 989 | current_entry = nxt_dir_entry(current_entry, | 1064 | current_entry = |
| 990 | end_of_smb); | 1065 | nxt_dir_entry(current_entry, end_of_smb, |
| 1066 | cifsFile->srch_inf.info_level); | ||
| 991 | } | 1067 | } |
| 992 | kfree(tmp_buf); | 1068 | kfree(tmp_buf); |
| 993 | break; | 1069 | break; |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c new file mode 100644 index 000000000000..7202d534ef0b --- /dev/null +++ b/fs/cifs/sess.c | |||
| @@ -0,0 +1,538 @@ | |||
| 1 | /* | ||
| 2 | * fs/cifs/sess.c | ||
| 3 | * | ||
| 4 | * SMB/CIFS session setup handling routines | ||
| 5 | * | ||
| 6 | * Copyright (c) International Business Machines Corp., 2006 | ||
| 7 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
| 8 | * | ||
| 9 | * This library is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU Lesser General Public License as published | ||
| 11 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This library is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
| 17 | * the GNU Lesser General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU Lesser General Public License | ||
| 20 | * along with this library; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include "cifspdu.h" | ||
| 25 | #include "cifsglob.h" | ||
| 26 | #include "cifsproto.h" | ||
| 27 | #include "cifs_unicode.h" | ||
| 28 | #include "cifs_debug.h" | ||
| 29 | #include "ntlmssp.h" | ||
| 30 | #include "nterr.h" | ||
| 31 | #include <linux/utsname.h> | ||
| 32 | |||
| 33 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | ||
| 34 | unsigned char *p24); | ||
| 35 | |||
| 36 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) | ||
| 37 | { | ||
| 38 | __u32 capabilities = 0; | ||
| 39 | |||
| 40 | /* init fields common to all four types of SessSetup */ | ||
| 41 | /* note that header is initialized to zero in header_assemble */ | ||
| 42 | pSMB->req.AndXCommand = 0xFF; | ||
| 43 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
| 44 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
| 45 | |||
| 46 | /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */ | ||
| 47 | |||
| 48 | /* BB verify whether signing required on neg or just on auth frame | ||
| 49 | (and NTLM case) */ | ||
| 50 | |||
| 51 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
| 52 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; | ||
| 53 | |||
| 54 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
| 55 | pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
| 56 | |||
| 57 | if (ses->capabilities & CAP_UNICODE) { | ||
| 58 | pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE; | ||
| 59 | capabilities |= CAP_UNICODE; | ||
| 60 | } | ||
| 61 | if (ses->capabilities & CAP_STATUS32) { | ||
| 62 | pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS; | ||
| 63 | capabilities |= CAP_STATUS32; | ||
| 64 | } | ||
| 65 | if (ses->capabilities & CAP_DFS) { | ||
| 66 | pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; | ||
| 67 | capabilities |= CAP_DFS; | ||
| 68 | } | ||
| 69 | if (ses->capabilities & CAP_UNIX) { | ||
| 70 | capabilities |= CAP_UNIX; | ||
| 71 | } | ||
| 72 | |||
| 73 | /* BB check whether to init vcnum BB */ | ||
| 74 | return capabilities; | ||
| 75 | } | ||
| 76 | |||
| 77 | static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, | ||
| 78 | const struct nls_table * nls_cp) | ||
| 79 | { | ||
| 80 | char * bcc_ptr = *pbcc_area; | ||
| 81 | int bytes_ret = 0; | ||
| 82 | |||
| 83 | /* BB FIXME add check that strings total less | ||
| 84 | than 335 or will need to send them as arrays */ | ||
| 85 | |||
| 86 | /* unicode strings, must be word aligned before the call */ | ||
| 87 | /* if ((long) bcc_ptr % 2) { | ||
| 88 | *bcc_ptr = 0; | ||
| 89 | bcc_ptr++; | ||
| 90 | } */ | ||
| 91 | /* copy user */ | ||
| 92 | if(ses->userName == NULL) { | ||
| 93 | /* BB what about null user mounts - check that we do this BB */ | ||
| 94 | } else { /* 300 should be long enough for any conceivable user name */ | ||
| 95 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, | ||
| 96 | 300, nls_cp); | ||
| 97 | } | ||
| 98 | bcc_ptr += 2 * bytes_ret; | ||
| 99 | bcc_ptr += 2; /* account for null termination */ | ||
| 100 | /* copy domain */ | ||
| 101 | if(ses->domainName == NULL) | ||
| 102 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, | ||
| 103 | "CIFS_LINUX_DOM", 32, nls_cp); | ||
| 104 | else | ||
| 105 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, | ||
| 106 | 256, nls_cp); | ||
| 107 | bcc_ptr += 2 * bytes_ret; | ||
| 108 | bcc_ptr += 2; /* account for null terminator */ | ||
| 109 | |||
| 110 | /* Copy OS version */ | ||
| 111 | bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, | ||
| 112 | nls_cp); | ||
| 113 | bcc_ptr += 2 * bytes_ret; | ||
| 114 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, | ||
| 115 | 32, nls_cp); | ||
| 116 | bcc_ptr += 2 * bytes_ret; | ||
| 117 | bcc_ptr += 2; /* trailing null */ | ||
| 118 | |||
| 119 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
| 120 | 32, nls_cp); | ||
| 121 | bcc_ptr += 2 * bytes_ret; | ||
| 122 | bcc_ptr += 2; /* trailing null */ | ||
| 123 | |||
| 124 | *pbcc_area = bcc_ptr; | ||
| 125 | } | ||
| 126 | |||
| 127 | static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, | ||
| 128 | const struct nls_table * nls_cp) | ||
| 129 | { | ||
| 130 | char * bcc_ptr = *pbcc_area; | ||
| 131 | |||
| 132 | /* copy user */ | ||
| 133 | /* BB what about null user mounts - check that we do this BB */ | ||
| 134 | /* copy user */ | ||
| 135 | if(ses->userName == NULL) { | ||
| 136 | /* BB what about null user mounts - check that we do this BB */ | ||
| 137 | } else { /* 300 should be long enough for any conceivable user name */ | ||
| 138 | strncpy(bcc_ptr, ses->userName, 300); | ||
| 139 | } | ||
| 140 | /* BB improve check for overflow */ | ||
| 141 | bcc_ptr += strnlen(ses->userName, 300); | ||
| 142 | *bcc_ptr = 0; | ||
| 143 | bcc_ptr++; /* account for null termination */ | ||
| 144 | |||
| 145 | /* copy domain */ | ||
| 146 | |||
| 147 | if(ses->domainName == NULL) { | ||
| 148 | strcpy(bcc_ptr, "CIFS_LINUX_DOM"); | ||
| 149 | bcc_ptr += 14; /* strlen(CIFS_LINUX_DOM) */ | ||
| 150 | } else { | ||
| 151 | strncpy(bcc_ptr, ses->domainName, 256); | ||
| 152 | bcc_ptr += strnlen(ses->domainName, 256); | ||
| 153 | } | ||
| 154 | *bcc_ptr = 0; | ||
| 155 | bcc_ptr++; | ||
| 156 | |||
| 157 | /* BB check for overflow here */ | ||
| 158 | |||
| 159 | strcpy(bcc_ptr, "Linux version "); | ||
| 160 | bcc_ptr += strlen("Linux version "); | ||
| 161 | strcpy(bcc_ptr, system_utsname.release); | ||
| 162 | bcc_ptr += strlen(system_utsname.release) + 1; | ||
| 163 | |||
| 164 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
| 165 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
| 166 | |||
| 167 | *pbcc_area = bcc_ptr; | ||
| 168 | } | ||
| 169 | |||
| 170 | static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, | ||
| 171 | const struct nls_table * nls_cp) | ||
| 172 | { | ||
| 173 | int rc = 0; | ||
| 174 | int words_left, len; | ||
| 175 | char * data = *pbcc_area; | ||
| 176 | |||
| 177 | |||
| 178 | |||
| 179 | cFYI(1,("bleft %d",bleft)); | ||
| 180 | |||
| 181 | |||
| 182 | /* word align, if bytes remaining is not even */ | ||
| 183 | if(bleft % 2) { | ||
| 184 | bleft--; | ||
| 185 | data++; | ||
| 186 | } | ||
| 187 | words_left = bleft / 2; | ||
| 188 | |||
| 189 | /* save off server operating system */ | ||
| 190 | len = UniStrnlen((wchar_t *) data, words_left); | ||
| 191 | |||
| 192 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
| 193 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
| 194 | terminating last Unicode string in response */ | ||
| 195 | if(len >= words_left) | ||
| 196 | return rc; | ||
| 197 | |||
| 198 | if(ses->serverOS) | ||
| 199 | kfree(ses->serverOS); | ||
| 200 | /* UTF-8 string will not grow more than four times as big as UCS-16 */ | ||
| 201 | ses->serverOS = kzalloc(4 * len, GFP_KERNEL); | ||
| 202 | if(ses->serverOS != NULL) { | ||
| 203 | cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, | ||
| 204 | nls_cp); | ||
| 205 | } | ||
| 206 | data += 2 * (len + 1); | ||
| 207 | words_left -= len + 1; | ||
| 208 | |||
| 209 | /* save off server network operating system */ | ||
| 210 | len = UniStrnlen((wchar_t *) data, words_left); | ||
| 211 | |||
| 212 | if(len >= words_left) | ||
| 213 | return rc; | ||
| 214 | |||
| 215 | if(ses->serverNOS) | ||
| 216 | kfree(ses->serverNOS); | ||
| 217 | ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */ | ||
| 218 | if(ses->serverNOS != NULL) { | ||
| 219 | cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, | ||
| 220 | nls_cp); | ||
| 221 | if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) { | ||
| 222 | cFYI(1,("NT4 server")); | ||
| 223 | ses->flags |= CIFS_SES_NT4; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | data += 2 * (len + 1); | ||
| 227 | words_left -= len + 1; | ||
| 228 | |||
| 229 | /* save off server domain */ | ||
| 230 | len = UniStrnlen((wchar_t *) data, words_left); | ||
| 231 | |||
| 232 | if(len > words_left) | ||
| 233 | return rc; | ||
| 234 | |||
| 235 | if(ses->serverDomain) | ||
| 236 | kfree(ses->serverDomain); | ||
| 237 | ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ | ||
| 238 | if(ses->serverDomain != NULL) { | ||
| 239 | cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, | ||
| 240 | nls_cp); | ||
| 241 | ses->serverDomain[2*len] = 0; | ||
| 242 | ses->serverDomain[(2*len) + 1] = 0; | ||
| 243 | } | ||
| 244 | data += 2 * (len + 1); | ||
| 245 | words_left -= len + 1; | ||
| 246 | |||
| 247 | cFYI(1,("words left: %d",words_left)); | ||
| 248 | |||
| 249 | return rc; | ||
| 250 | } | ||
| 251 | |||
| 252 | static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, | ||
| 253 | const struct nls_table * nls_cp) | ||
| 254 | { | ||
| 255 | int rc = 0; | ||
| 256 | int len; | ||
| 257 | char * bcc_ptr = *pbcc_area; | ||
| 258 | |||
| 259 | cFYI(1,("decode sessetup ascii. bleft %d", bleft)); | ||
| 260 | |||
| 261 | len = strnlen(bcc_ptr, bleft); | ||
| 262 | if(len >= bleft) | ||
| 263 | return rc; | ||
| 264 | |||
| 265 | if(ses->serverOS) | ||
| 266 | kfree(ses->serverOS); | ||
| 267 | |||
| 268 | ses->serverOS = kzalloc(len + 1, GFP_KERNEL); | ||
| 269 | if(ses->serverOS) | ||
| 270 | strncpy(ses->serverOS, bcc_ptr, len); | ||
| 271 | |||
| 272 | bcc_ptr += len + 1; | ||
| 273 | bleft -= len + 1; | ||
| 274 | |||
| 275 | len = strnlen(bcc_ptr, bleft); | ||
| 276 | if(len >= bleft) | ||
| 277 | return rc; | ||
| 278 | |||
| 279 | if(ses->serverNOS) | ||
| 280 | kfree(ses->serverNOS); | ||
| 281 | |||
| 282 | ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); | ||
| 283 | if(ses->serverNOS) | ||
| 284 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
| 285 | |||
| 286 | bcc_ptr += len + 1; | ||
| 287 | bleft -= len + 1; | ||
| 288 | |||
| 289 | len = strnlen(bcc_ptr, bleft); | ||
| 290 | if(len > bleft) | ||
| 291 | return rc; | ||
| 292 | |||
| 293 | if(ses->serverDomain) | ||
| 294 | kfree(ses->serverDomain); | ||
| 295 | |||
| 296 | ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); | ||
| 297 | if(ses->serverOS) | ||
| 298 | strncpy(ses->serverOS, bcc_ptr, len); | ||
| 299 | |||
| 300 | bcc_ptr += len + 1; | ||
| 301 | bleft -= len + 1; | ||
| 302 | |||
| 303 | cFYI(1,("ascii: bytes left %d",bleft)); | ||
| 304 | |||
| 305 | return rc; | ||
| 306 | } | ||
| 307 | |||
| 308 | int | ||
| 309 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | ||
| 310 | const struct nls_table *nls_cp) | ||
| 311 | { | ||
| 312 | int rc = 0; | ||
| 313 | int wct; | ||
| 314 | struct smb_hdr *smb_buf; | ||
| 315 | char *bcc_ptr; | ||
| 316 | char *str_area; | ||
| 317 | SESSION_SETUP_ANDX *pSMB; | ||
| 318 | __u32 capabilities; | ||
| 319 | int count; | ||
| 320 | int resp_buf_type = 0; | ||
| 321 | struct kvec iov[2]; | ||
| 322 | enum securityEnum type; | ||
| 323 | __u16 action; | ||
| 324 | int bytes_remaining; | ||
| 325 | |||
| 326 | if(ses == NULL) | ||
| 327 | return -EINVAL; | ||
| 328 | |||
| 329 | type = ses->server->secType; | ||
| 330 | |||
| 331 | cFYI(1,("sess setup type %d",type)); | ||
| 332 | if(type == LANMAN) { | ||
| 333 | #ifndef CONFIG_CIFS_WEAK_PW_HASH | ||
| 334 | /* LANMAN and plaintext are less secure and off by default. | ||
| 335 | So we make this explicitly be turned on in kconfig (in the | ||
| 336 | build) and turned on at runtime (changed from the default) | ||
| 337 | in proc/fs/cifs or via mount parm. Unfortunately this is | ||
| 338 | needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ | ||
| 339 | return -EOPNOTSUPP; | ||
| 340 | #endif | ||
| 341 | wct = 10; /* lanman 2 style sessionsetup */ | ||
| 342 | } else if((type == NTLM) || (type == NTLMv2)) { | ||
| 343 | /* For NTLMv2 failures eventually may need to retry NTLM */ | ||
| 344 | wct = 13; /* old style NTLM sessionsetup */ | ||
| 345 | } else /* same size for negotiate or auth, NTLMSSP or extended security */ | ||
| 346 | wct = 12; | ||
| 347 | |||
| 348 | rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, | ||
| 349 | (void **)&smb_buf); | ||
| 350 | if(rc) | ||
| 351 | return rc; | ||
| 352 | |||
| 353 | pSMB = (SESSION_SETUP_ANDX *)smb_buf; | ||
| 354 | |||
| 355 | capabilities = cifs_ssetup_hdr(ses, pSMB); | ||
| 356 | |||
| 357 | /* we will send the SMB in two pieces, | ||
| 358 | a fixed length beginning part, and a | ||
| 359 | second part which will include the strings | ||
| 360 | and rest of bcc area, in order to avoid having | ||
| 361 | to do a large buffer 17K allocation */ | ||
| 362 | iov[0].iov_base = (char *)pSMB; | ||
| 363 | iov[0].iov_len = smb_buf->smb_buf_length + 4; | ||
| 364 | |||
| 365 | /* 2000 big enough to fit max user, domain, NOS name etc. */ | ||
| 366 | str_area = kmalloc(2000, GFP_KERNEL); | ||
| 367 | bcc_ptr = str_area; | ||
| 368 | |||
| 369 | if(type == LANMAN) { | ||
| 370 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 371 | char lnm_session_key[CIFS_SESS_KEY_SIZE]; | ||
| 372 | |||
| 373 | /* no capabilities flags in old lanman negotiation */ | ||
| 374 | |||
| 375 | pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE; | ||
| 376 | /* BB calculate hash with password */ | ||
| 377 | /* and copy into bcc */ | ||
| 378 | |||
| 379 | calc_lanman_hash(ses, lnm_session_key); | ||
| 380 | |||
| 381 | /* #ifdef CONFIG_CIFS_DEBUG2 | ||
| 382 | cifs_dump_mem("cryptkey: ",ses->server->cryptKey, | ||
| 383 | CIFS_SESS_KEY_SIZE); | ||
| 384 | #endif */ | ||
| 385 | memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); | ||
| 386 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
| 387 | |||
| 388 | /* can not sign if LANMAN negotiated so no need | ||
| 389 | to calculate signing key? but what if server | ||
| 390 | changed to do higher than lanman dialect and | ||
| 391 | we reconnected would we ever calc signing_key? */ | ||
| 392 | |||
| 393 | cFYI(1,("Negotiating LANMAN setting up strings")); | ||
| 394 | /* Unicode not allowed for LANMAN dialects */ | ||
| 395 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
| 396 | #endif | ||
| 397 | } else if (type == NTLM) { | ||
| 398 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
| 399 | |||
| 400 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
| 401 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | ||
| 402 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
| 403 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
| 404 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
| 405 | |||
| 406 | /* calculate session key */ | ||
| 407 | SMBNTencrypt(ses->password, ses->server->cryptKey, | ||
| 408 | ntlm_session_key); | ||
| 409 | |||
| 410 | if(first_time) /* should this be moved into common code | ||
| 411 | with similar ntlmv2 path? */ | ||
| 412 | cifs_calculate_mac_key(ses->server->mac_signing_key, | ||
| 413 | ntlm_session_key, ses->password); | ||
| 414 | /* copy session key */ | ||
| 415 | |||
| 416 | memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); | ||
| 417 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
| 418 | memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); | ||
| 419 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
| 420 | if(ses->capabilities & CAP_UNICODE) { | ||
| 421 | /* unicode strings must be word aligned */ | ||
| 422 | if (iov[0].iov_len % 2) { | ||
| 423 | *bcc_ptr = 0; | ||
| 424 | bcc_ptr++; | ||
| 425 | } | ||
| 426 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
| 427 | } else | ||
| 428 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
| 429 | } else if (type == NTLMv2) { | ||
| 430 | char * v2_sess_key = | ||
| 431 | kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL); | ||
| 432 | |||
| 433 | /* BB FIXME change all users of v2_sess_key to | ||
| 434 | struct ntlmv2_resp */ | ||
| 435 | |||
| 436 | if(v2_sess_key == NULL) { | ||
| 437 | cifs_small_buf_release(smb_buf); | ||
| 438 | return -ENOMEM; | ||
| 439 | } | ||
| 440 | |||
| 441 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
| 442 | |||
| 443 | /* LM2 password would be here if we supported it */ | ||
| 444 | pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; | ||
| 445 | /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ | ||
| 446 | |||
| 447 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
| 448 | cpu_to_le16(sizeof(struct ntlmv2_resp)); | ||
| 449 | |||
| 450 | /* calculate session key */ | ||
| 451 | setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); | ||
| 452 | if(first_time) /* should this be moved into common code | ||
| 453 | with similar ntlmv2 path? */ | ||
| 454 | /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, | ||
| 455 | response BB FIXME, v2_sess_key); */ | ||
| 456 | |||
| 457 | /* copy session key */ | ||
| 458 | |||
| 459 | /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); | ||
| 460 | bcc_ptr += LM2_SESS_KEY_SIZE; */ | ||
| 461 | memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); | ||
| 462 | bcc_ptr += sizeof(struct ntlmv2_resp); | ||
| 463 | kfree(v2_sess_key); | ||
| 464 | if(ses->capabilities & CAP_UNICODE) { | ||
| 465 | if(iov[0].iov_len % 2) { | ||
| 466 | *bcc_ptr = 0; | ||
| 467 | } bcc_ptr++; | ||
| 468 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
| 469 | } else | ||
| 470 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
| 471 | } else /* NTLMSSP or SPNEGO */ { | ||
| 472 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
| 473 | capabilities |= CAP_EXTENDED_SECURITY; | ||
| 474 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
| 475 | /* BB set password lengths */ | ||
| 476 | } | ||
| 477 | |||
| 478 | count = (long) bcc_ptr - (long) str_area; | ||
| 479 | smb_buf->smb_buf_length += count; | ||
| 480 | |||
| 481 | BCC_LE(smb_buf) = cpu_to_le16(count); | ||
| 482 | |||
| 483 | iov[1].iov_base = str_area; | ||
| 484 | iov[1].iov_len = count; | ||
| 485 | rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0); | ||
| 486 | /* SMB request buf freed in SendReceive2 */ | ||
| 487 | |||
| 488 | cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); | ||
| 489 | if(rc) | ||
| 490 | goto ssetup_exit; | ||
| 491 | |||
| 492 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | ||
| 493 | smb_buf = (struct smb_hdr *)iov[0].iov_base; | ||
| 494 | |||
| 495 | if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { | ||
| 496 | rc = -EIO; | ||
| 497 | cERROR(1,("bad word count %d", smb_buf->WordCount)); | ||
| 498 | goto ssetup_exit; | ||
| 499 | } | ||
| 500 | action = le16_to_cpu(pSMB->resp.Action); | ||
| 501 | if (action & GUEST_LOGIN) | ||
| 502 | cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ | ||
| 503 | ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ | ||
| 504 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
| 505 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
| 506 | /* and lanman response is 3 */ | ||
| 507 | bytes_remaining = BCC(smb_buf); | ||
| 508 | bcc_ptr = pByteArea(smb_buf); | ||
| 509 | |||
| 510 | if(smb_buf->WordCount == 4) { | ||
| 511 | __u16 blob_len; | ||
| 512 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | ||
| 513 | bcc_ptr += blob_len; | ||
| 514 | if(blob_len > bytes_remaining) { | ||
| 515 | cERROR(1,("bad security blob length %d", blob_len)); | ||
| 516 | rc = -EINVAL; | ||
| 517 | goto ssetup_exit; | ||
| 518 | } | ||
| 519 | bytes_remaining -= blob_len; | ||
| 520 | } | ||
| 521 | |||
| 522 | /* BB check if Unicode and decode strings */ | ||
| 523 | if(smb_buf->Flags2 & SMBFLG2_UNICODE) | ||
| 524 | rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, | ||
| 525 | ses, nls_cp); | ||
| 526 | else | ||
| 527 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); | ||
| 528 | |||
| 529 | ssetup_exit: | ||
| 530 | kfree(str_area); | ||
| 531 | if(resp_buf_type == CIFS_SMALL_BUFFER) { | ||
| 532 | cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base)); | ||
| 533 | cifs_small_buf_release(iov[0].iov_base); | ||
| 534 | } else if(resp_buf_type == CIFS_LARGE_BUFFER) | ||
| 535 | cifs_buf_release(iov[0].iov_base); | ||
| 536 | |||
| 537 | return rc; | ||
| 538 | } | ||
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 6103bcdfb16d..f518c5e45035 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/random.h> | 30 | #include <linux/random.h> |
| 31 | #include "cifs_unicode.h" | 31 | #include "cifs_unicode.h" |
| 32 | #include "cifspdu.h" | 32 | #include "cifspdu.h" |
| 33 | #include "cifsglob.h" | ||
| 33 | #include "md5.h" | 34 | #include "md5.h" |
| 34 | #include "cifs_debug.h" | 35 | #include "cifs_debug.h" |
| 35 | #include "cifsencrypt.h" | 36 | #include "cifsencrypt.h" |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 3da80409466c..17ba329e2b3d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -654,8 +654,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 654 | 654 | ||
| 655 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | 655 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { |
| 656 | up(&ses->server->tcpSem); | 656 | up(&ses->server->tcpSem); |
| 657 | cERROR(1, | 657 | cERROR(1, ("Illegal length, greater than maximum frame, %d", |
| 658 | ("Illegal length, greater than maximum frame, %d ", | ||
| 659 | in_buf->smb_buf_length)); | 658 | in_buf->smb_buf_length)); |
| 660 | DeleteMidQEntry(midQ); | 659 | DeleteMidQEntry(midQ); |
| 661 | /* If not lock req, update # of requests on wire to server */ | 660 | /* If not lock req, update # of requests on wire to server */ |
