diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/CHANGES | 5 | ||||
-rw-r--r-- | fs/cifs/Makefile | 2 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.c | 84 | ||||
-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 | 2 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 4 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 51 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 37 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 95 | ||||
-rw-r--r-- | fs/cifs/connect.c | 39 | ||||
-rw-r--r-- | fs/cifs/dir.c | 2 | ||||
-rw-r--r-- | fs/cifs/fcntl.c | 4 | ||||
-rw-r--r-- | fs/cifs/inode.c | 3 | ||||
-rw-r--r-- | fs/cifs/misc.c | 10 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 16 | ||||
-rw-r--r-- | fs/cifs/sess.c | 511 | ||||
-rw-r--r-- | fs/cifs/smbencrypt.c | 1 |
19 files changed, 799 insertions, 74 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 953d2f7f88b0..b878dfcff0f0 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,8 @@ | |||
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 | |||
1 | Version 1.43 | 6 | Version 1.43 |
2 | ------------ | 7 | ------------ |
3 | POSIX locking to servers which support CIFS POSIX Extensions | 8 | POSIX locking to servers which support CIFS POSIX Extensions |
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/cifs_debug.c b/fs/cifs/cifs_debug.c index f4124a32bef8..7f4013a8607f 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" |
@@ -397,10 +447,10 @@ 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 extended_security_read; |
399 | static write_proc_t extended_security_write; | 449 | static write_proc_t extended_security_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; |
@@ -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("ExtendedSecurity",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); |
@@ -787,7 +837,7 @@ extended_security_read(char *page, char **start, off_t off, | |||
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; |
@@ -808,19 +858,25 @@ extended_security_write(struct file *file, const char __user *buffer, | |||
808 | { | 858 | { |
809 | char c; | 859 | char c; |
810 | int rc; | 860 | int rc; |
861 | cERROR(1,("size %ld",count)); /* BB removeme BB */ | ||
862 | if((count < 2) || (count > 8)) | ||
863 | return -EINVAL; | ||
811 | 864 | ||
812 | rc = get_user(c, buffer); | 865 | rc = get_user(c, buffer); |
866 | |||
867 | /* BB fixme need to parse more characters in order to handle CIFSSEC flags */ | ||
868 | |||
813 | if (rc) | 869 | if (rc) |
814 | return rc; | 870 | return rc; |
815 | if (c == '0' || c == 'n' || c == 'N') | 871 | if (c == '0' || c == 'n' || c == 'N') |
816 | extended_security = 0; | 872 | extended_security = CIFSSEC_DEF; /* default */ |
817 | else if (c == '1' || c == 'y' || c == 'Y') | 873 | else if (c == '1' || c == 'y' || c == 'Y') |
818 | extended_security = 1; | 874 | extended_security = CIFSSEC_MAX; |
819 | 875 | ||
820 | return count; | 876 | return count; |
821 | } | 877 | } |
822 | 878 | ||
823 | static int | 879 | /* static int |
824 | ntlmv2_enabled_read(char *page, char **start, off_t off, | 880 | ntlmv2_enabled_read(char *page, char **start, off_t off, |
825 | int count, int *eof, void *data) | 881 | int count, int *eof, void *data) |
826 | { | 882 | { |
@@ -855,6 +911,8 @@ ntlmv2_enabled_write(struct file *file, const char __user *buffer, | |||
855 | ntlmv2_support = 0; | 911 | ntlmv2_support = 0; |
856 | else if (c == '1' || c == 'y' || c == 'Y') | 912 | else if (c == '1' || c == 'y' || c == 'Y') |
857 | ntlmv2_support = 1; | 913 | ntlmv2_support = 1; |
914 | else if (c == '2') | ||
915 | ntlmv2_support = 2; | ||
858 | 916 | ||
859 | return count; | 917 | return count; |
860 | } | 918 | } |
@@ -898,7 +956,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer, | |||
898 | sign_CIFS_PDUs = 2; | 956 | sign_CIFS_PDUs = 2; |
899 | 957 | ||
900 | return count; | 958 | return count; |
901 | } | 959 | } */ |
902 | 960 | ||
903 | 961 | ||
904 | #endif | 962 | #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..08781a4698b4 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -225,6 +225,8 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ | |||
225 | user_name_len = strlen(ses->userName); | 225 | user_name_len = strlen(ses->userName); |
226 | if(user_name_len > MAX_USERNAME_SIZE) | 226 | if(user_name_len > MAX_USERNAME_SIZE) |
227 | return -EINVAL; | 227 | return -EINVAL; |
228 | if(ses->domainName == NULL) | ||
229 | return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ | ||
228 | dom_name_len = strlen(ses->domainName); | 230 | dom_name_len = strlen(ses->domainName); |
229 | if(dom_name_len > MAX_USERNAME_SIZE) | 231 | if(dom_name_len > MAX_USERNAME_SIZE) |
230 | return -EINVAL; | 232 | return -EINVAL; |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c262d8874ce9..700570522b23 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; |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 006eb33bff5f..7a042041a16a 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 */ |
@@ -179,7 +180,9 @@ 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; |
@@ -194,7 +197,7 @@ struct cifsSesInfo { | |||
194 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for | 197 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for |
195 | TCP names - will ipv6 and sctp addresses fit? */ | 198 | TCP names - will ipv6 and sctp addresses fit? */ |
196 | char userName[MAX_USERNAME_SIZE + 1]; | 199 | char userName[MAX_USERNAME_SIZE + 1]; |
197 | char domainName[MAX_USERNAME_SIZE + 1]; | 200 | char * domainName; |
198 | char * password; | 201 | char * password; |
199 | }; | 202 | }; |
200 | /* session flags */ | 203 | /* session flags */ |
@@ -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 |
@@ -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..e0ff9b56cc4c 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 |
@@ -400,6 +406,25 @@ 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 | |||
403 | typedef struct negotiate_rsp { | 428 | typedef struct negotiate_rsp { |
404 | struct smb_hdr hdr; /* wct = 17 */ | 429 | struct smb_hdr hdr; /* wct = 17 */ |
405 | __le16 DialectIndex; | 430 | __le16 DialectIndex; |
@@ -520,8 +545,8 @@ typedef union smb_com_session_setup_andx { | |||
520 | __le16 MaxMpxCount; | 545 | __le16 MaxMpxCount; |
521 | __le16 VcNumber; | 546 | __le16 VcNumber; |
522 | __u32 SessionKey; | 547 | __u32 SessionKey; |
523 | __le16 PassswordLength; | 548 | __le16 PasswordLength; |
524 | __u32 Reserved; | 549 | __u32 Reserved; /* encrypt key len and offset */ |
525 | __le16 ByteCount; | 550 | __le16 ByteCount; |
526 | unsigned char AccountPassword[1]; /* followed by */ | 551 | unsigned char AccountPassword[1]; /* followed by */ |
527 | /* STRING AccountName */ | 552 | /* STRING AccountName */ |
@@ -1844,13 +1869,13 @@ typedef struct { | |||
1844 | typedef struct { | 1869 | typedef struct { |
1845 | __le32 DeviceType; | 1870 | __le32 DeviceType; |
1846 | __le32 DeviceCharacteristics; | 1871 | __le32 DeviceCharacteristics; |
1847 | } __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ | 1872 | } __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */ |
1848 | 1873 | ||
1849 | typedef struct { | 1874 | typedef struct { |
1850 | __le32 Attributes; | 1875 | __le32 Attributes; |
1851 | __le32 MaxPathNameComponentLength; | 1876 | __le32 MaxPathNameComponentLength; |
1852 | __le32 FileSystemNameLen; | 1877 | __le32 FileSystemNameLen; |
1853 | char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ | 1878 | char FileSystemName[52]; /* do not have to save this - get subset? */ |
1854 | } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO; | 1879 | } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO; |
1855 | 1880 | ||
1856 | /******************************************************************************/ | 1881 | /******************************************************************************/ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 310ea2f0e0bf..ff78cf7b0d1b 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -69,7 +69,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct, | |||
69 | struct cifsSesInfo *ses, | 69 | struct cifsSesInfo *ses, |
70 | void ** request_buf); | 70 | void ** request_buf); |
71 | extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | 71 | extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, |
72 | const int stage, int * pNTLMv2_flg, | 72 | const int stage, |
73 | const struct nls_table *nls_cp); | 73 | const struct nls_table *nls_cp); |
74 | #endif | 74 | #endif |
75 | extern __u16 GetNextMid(struct TCP_Server_Info *server); | 75 | extern __u16 GetNextMid(struct TCP_Server_Info *server); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f00369277c06..da3154fa9c8a 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 */ |
@@ -322,7 +343,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
322 | /* potential retries of smb operations it turns out we can determine */ | 343 | /* potential retries of smb operations it turns out we can determine */ |
323 | /* from the mid flags when the request buffer can be resent without */ | 344 | /* from the mid flags when the request buffer can be resent without */ |
324 | /* having to use a second distinct buffer for the response */ | 345 | /* having to use a second distinct buffer for the response */ |
325 | *response_buf = *request_buf; | 346 | if(response_buf) |
347 | *response_buf = *request_buf; | ||
326 | 348 | ||
327 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, | 349 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, |
328 | wct /*wct */ ); | 350 | wct /*wct */ ); |
@@ -373,6 +395,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
373 | NEGOTIATE_RSP *pSMBr; | 395 | NEGOTIATE_RSP *pSMBr; |
374 | int rc = 0; | 396 | int rc = 0; |
375 | int bytes_returned; | 397 | int bytes_returned; |
398 | int i; | ||
376 | struct TCP_Server_Info * server; | 399 | struct TCP_Server_Info * server; |
377 | u16 count; | 400 | u16 count; |
378 | 401 | ||
@@ -388,19 +411,71 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
388 | return rc; | 411 | return rc; |
389 | pSMB->hdr.Mid = GetNextMid(server); | 412 | pSMB->hdr.Mid = GetNextMid(server); |
390 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 413 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
391 | if (extended_security) | 414 | /* if (extended_security) |
392 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 415 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/ |
393 | 416 | ||
394 | count = strlen(protocols[0].name) + 1; | 417 | count = 0; |
395 | strncpy(pSMB->DialectsArray, protocols[0].name, 30); | 418 | for(i=0;i<CIFS_NUM_PROT;i++) { |
396 | /* null guaranteed to be at end of source and target buffers anyway */ | 419 | strncpy(pSMB->DialectsArray+count, protocols[i].name, 16); |
397 | 420 | count += strlen(protocols[i].name) + 1; | |
421 | /* null at end of source and target buffers anyway */ | ||
422 | } | ||
398 | pSMB->hdr.smb_buf_length += count; | 423 | pSMB->hdr.smb_buf_length += count; |
399 | pSMB->ByteCount = cpu_to_le16(count); | 424 | pSMB->ByteCount = cpu_to_le16(count); |
400 | 425 | ||
401 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 426 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, |
402 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 427 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
403 | if (rc == 0) { | 428 | if (rc == 0) { |
429 | cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); | ||
430 | /* Check wct = 1 error case */ | ||
431 | if((pSMBr->hdr.WordCount < 13) | ||
432 | || (pSMBr->DialectIndex == BAD_PROT)) { | ||
433 | /* core returns wct = 1, but we do not ask for | ||
434 | core - otherwise it just comes when dialect | ||
435 | index is -1 indicating we could not negotiate | ||
436 | a common dialect */ | ||
437 | rc = -EOPNOTSUPP; | ||
438 | goto neg_err_exit; | ||
439 | } else if((pSMBr->hdr.WordCount == 13) && | ||
440 | (pSMBr->DialectIndex == LANMAN_PROT)) { | ||
441 | struct lanman_neg_rsp * rsp = | ||
442 | (struct lanman_neg_rsp *)pSMBr; | ||
443 | |||
444 | |||
445 | /* BB Mark ses struct as negotiated lanman level BB */ | ||
446 | server->secType = LANMAN; | ||
447 | server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); | ||
448 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); | ||
449 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), | ||
450 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | ||
451 | |||
452 | /* BB what do we do with raw mode? BB */ | ||
453 | server->timeZone = le16_to_cpu(rsp->ServerTimeZone); | ||
454 | /* Do we have to set signing flags? no signing | ||
455 | was available LANMAN - default should be ok */ | ||
456 | |||
457 | /* BB FIXME set default dummy capabilities since | ||
458 | they are not returned by the server in this dialect */ | ||
459 | |||
460 | /* get server time for time conversions and add | ||
461 | code to use it and timezone since this is not UTC */ | ||
462 | |||
463 | if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | ||
464 | memcpy(server->cryptKey, rsp->EncryptionKey, | ||
465 | CIFS_CRYPTO_KEY_SIZE); | ||
466 | } else { | ||
467 | rc = -EIO; | ||
468 | goto neg_err_exit; | ||
469 | } | ||
470 | |||
471 | cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ | ||
472 | goto neg_err_exit; | ||
473 | } else if(pSMBr->hdr.WordCount != 17) { | ||
474 | /* unknown wct */ | ||
475 | rc = -EOPNOTSUPP; | ||
476 | goto neg_err_exit; | ||
477 | } | ||
478 | |||
404 | server->secMode = pSMBr->SecurityMode; | 479 | server->secMode = pSMBr->SecurityMode; |
405 | if((server->secMode & SECMODE_USER) == 0) | 480 | if((server->secMode & SECMODE_USER) == 0) |
406 | cFYI(1,("share mode security")); | 481 | cFYI(1,("share mode security")); |
@@ -479,7 +554,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
479 | } | 554 | } |
480 | 555 | ||
481 | } | 556 | } |
482 | 557 | neg_err_exit: | |
483 | cifs_buf_release(pSMB); | 558 | cifs_buf_release(pSMB); |
484 | return rc; | 559 | return rc; |
485 | } | 560 | } |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index bae1479318d1..7ffb8f244f6a 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 | ||
@@ -585,9 +583,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
585 | /* merge response - fix up 1st*/ | 583 | /* merge response - fix up 1st*/ |
586 | if(coalesce_t2(smb_buffer, | 584 | if(coalesce_t2(smb_buffer, |
587 | mid_entry->resp_buf)) { | 585 | mid_entry->resp_buf)) { |
586 | mid_entry->multiRsp = 1; | ||
588 | break; | 587 | break; |
589 | } else { | 588 | } else { |
590 | /* all parts received */ | 589 | /* all parts received */ |
590 | mid_entry->multiEnd = 1; | ||
591 | goto multi_t2_fnd; | 591 | goto multi_t2_fnd; |
592 | } | 592 | } |
593 | } else { | 593 | } else { |
@@ -632,9 +632,14 @@ multi_t2_fnd: | |||
632 | wake_up_process(task_to_wake); | 632 | wake_up_process(task_to_wake); |
633 | } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) | 633 | } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) |
634 | && (isMultiRsp == FALSE)) { | 634 | && (isMultiRsp == FALSE)) { |
635 | cERROR(1, ("No task to wake, unknown frame rcvd!")); | 635 | cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter)); |
636 | cifs_dump_mem("Received Data is: ",(char *)smb_buffer, | 636 | cifs_dump_mem("Received Data is: ",(char *)smb_buffer, |
637 | sizeof(struct smb_hdr)); | 637 | sizeof(struct smb_hdr)); |
638 | #ifdef CONFIG_CIFS_DEBUG2 | ||
639 | cifs_dump_detail(smb_buffer); | ||
640 | cifs_dump_mids(server); | ||
641 | #endif /* CIFS_DEBUG2 */ | ||
642 | |||
638 | } | 643 | } |
639 | } /* end while !EXITING */ | 644 | } /* end while !EXITING */ |
640 | 645 | ||
@@ -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 { |
@@ -1762,9 +1767,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1762 | if (volume_info.username) | 1767 | if (volume_info.username) |
1763 | strncpy(pSesInfo->userName, | 1768 | strncpy(pSesInfo->userName, |
1764 | volume_info.username,MAX_USERNAME_SIZE); | 1769 | volume_info.username,MAX_USERNAME_SIZE); |
1765 | if (volume_info.domainname) | 1770 | if (volume_info.domainname) { |
1766 | strncpy(pSesInfo->domainName, | 1771 | int len = strlen(volume_info.domainname); |
1767 | volume_info.domainname,MAX_USERNAME_SIZE); | 1772 | pSesInfo->domainName = |
1773 | kmalloc(len + 1, GFP_KERNEL); | ||
1774 | if(pSesInfo->domainName) | ||
1775 | strcpy(pSesInfo->domainName, | ||
1776 | volume_info.domainname); | ||
1777 | } | ||
1768 | pSesInfo->linux_uid = volume_info.linux_uid; | 1778 | pSesInfo->linux_uid = volume_info.linux_uid; |
1769 | down(&pSesInfo->sesSem); | 1779 | down(&pSesInfo->sesSem); |
1770 | rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); | 1780 | rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); |
@@ -2054,7 +2064,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
2054 | bcc_ptr++; | 2064 | bcc_ptr++; |
2055 | } | 2065 | } |
2056 | if(user == NULL) | 2066 | if(user == NULL) |
2057 | bytes_returned = 0; /* skill null user */ | 2067 | bytes_returned = 0; /* skip null user */ |
2058 | else | 2068 | else |
2059 | bytes_returned = | 2069 | bytes_returned = |
2060 | cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, | 2070 | cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, |
@@ -2635,8 +2645,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
2635 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; | 2645 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; |
2636 | if(sign_CIFS_PDUs) | 2646 | if(sign_CIFS_PDUs) |
2637 | negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; | 2647 | negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; |
2638 | if(ntlmv2_support) | 2648 | /* if(ntlmv2_support) |
2639 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; | 2649 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/ |
2640 | /* setup pointers to domain name and workstation name */ | 2650 | /* setup pointers to domain name and workstation name */ |
2641 | bcc_ptr += SecurityBlobLength; | 2651 | bcc_ptr += SecurityBlobLength; |
2642 | 2652 | ||
@@ -3429,7 +3439,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3429 | } | 3439 | } |
3430 | /* else do not bother copying these informational fields */ | 3440 | /* else do not bother copying these informational fields */ |
3431 | } | 3441 | } |
3432 | tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); | 3442 | if(smb_buffer_response->WordCount == 3) |
3443 | tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); | ||
3444 | else | ||
3445 | tcon->Flags = 0; | ||
3433 | cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags)); | 3446 | cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags)); |
3434 | } else if ((rc == 0) && tcon == NULL) { | 3447 | } else if ((rc == 0) && tcon == NULL) { |
3435 | /* all we need to save for IPC$ connection */ | 3448 | /* all we need to save for IPC$ connection */ |
@@ -3528,8 +3541,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3528 | pSesInfo->server->timeZone)); | 3541 | pSesInfo->server->timeZone)); |
3529 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 3542 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
3530 | if(experimEnabled > 1) | 3543 | if(experimEnabled > 1) |
3531 | rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */, | 3544 | rc = CIFS_SessSetup(xid, pSesInfo, |
3532 | &ntlmv2_flag, nls_info); | 3545 | first_time, nls_info); |
3533 | else | 3546 | else |
3534 | #endif | 3547 | #endif |
3535 | if (extended_security | 3548 | if (extended_security |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 57bdf7f734bf..e6ed64e94b7b 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, |
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/inode.c b/fs/cifs/inode.c index 77a9e2f912fd..a609d2668032 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -1121,7 +1121,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1121 | 1121 | ||
1122 | xid = GetXid(); | 1122 | xid = GetXid(); |
1123 | 1123 | ||
1124 | cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x", | 1124 | cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", |
1125 | direntry->d_name.name, attrs->ia_valid)); | 1125 | direntry->d_name.name, attrs->ia_valid)); |
1126 | 1126 | ||
1127 | cifs_sb = CIFS_SB(direntry->d_inode->i_sb); | 1127 | cifs_sb = CIFS_SB(direntry->d_inode->i_sb); |
@@ -1157,6 +1157,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1157 | when the local oplock break takes longer to flush | 1157 | when the local oplock break takes longer to flush |
1158 | writebehind data than the SMB timeout for the SetPathInfo | 1158 | writebehind data than the SMB timeout for the SetPathInfo |
1159 | request would allow */ | 1159 | request would allow */ |
1160 | |||
1160 | open_file = find_writable_file(cifsInode); | 1161 | open_file = find_writable_file(cifsInode); |
1161 | if (open_file) { | 1162 | if (open_file) { |
1162 | __u16 nfid = open_file->netfid; | 1163 | __u16 nfid = open_file->netfid; |
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/readdir.c b/fs/cifs/readdir.c index 6b36c43d38f5..53903a27f786 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -31,8 +31,8 @@ | |||
31 | #include "cifs_fs_sb.h" | 31 | #include "cifs_fs_sb.h" |
32 | #include "cifsfs.h" | 32 | #include "cifsfs.h" |
33 | 33 | ||
34 | /* BB fixme - add debug wrappers around this function to disable it fixme BB */ | 34 | #ifdef CONFIG_CIFS_DEBUG2 |
35 | /* static void dump_cifs_file_struct(struct file *file, char *label) | 35 | static void dump_cifs_file_struct(struct file *file, char *label) |
36 | { | 36 | { |
37 | struct cifsFileInfo * cf; | 37 | struct cifsFileInfo * cf; |
38 | 38 | ||
@@ -53,7 +53,8 @@ | |||
53 | } | 53 | } |
54 | 54 | ||
55 | } | 55 | } |
56 | } */ | 56 | } |
57 | #endif /* DEBUG2 */ | ||
57 | 58 | ||
58 | /* Returns one if new inode created (which therefore needs to be hashed) */ | 59 | /* 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 */ | 60 | /* Might check in the future if inode number changed so we can rehash inode */ |
@@ -597,7 +598,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
597 | . and .. for the root of a drive and for those we need | 598 | . and .. for the root of a drive and for those we need |
598 | to start two entries earlier */ | 599 | to start two entries earlier */ |
599 | 600 | ||
600 | /* dump_cifs_file_struct(file, "In fce ");*/ | 601 | #ifdef CONFIG_CIFS_DEBUG2 |
602 | dump_cifs_file_struct(file, "In fce "); | ||
603 | #endif | ||
601 | if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && | 604 | if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && |
602 | is_dir_changed(file)) || | 605 | is_dir_changed(file)) || |
603 | (index_to_find < first_entry_in_buffer)) { | 606 | (index_to_find < first_entry_in_buffer)) { |
@@ -980,9 +983,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
980 | rc = cifs_filldir(current_entry, file, | 983 | rc = cifs_filldir(current_entry, file, |
981 | filldir, direntry,tmp_buf); | 984 | filldir, direntry,tmp_buf); |
982 | file->f_pos++; | 985 | file->f_pos++; |
983 | if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) { | 986 | if(file->f_pos == |
987 | cifsFile->srch_inf.index_of_last_entry) { | ||
984 | cFYI(1,("last entry in buf at pos %lld %s", | 988 | cFYI(1,("last entry in buf at pos %lld %s", |
985 | file->f_pos,tmp_buf)); /* BB removeme BB */ | 989 | file->f_pos,tmp_buf)); |
986 | cifs_save_resume_key(current_entry,cifsFile); | 990 | cifs_save_resume_key(current_entry,cifsFile); |
987 | break; | 991 | break; |
988 | } else | 992 | } else |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c new file mode 100644 index 000000000000..34998416eb73 --- /dev/null +++ b/fs/cifs/sess.c | |||
@@ -0,0 +1,511 @@ | |||
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/ctype.h> | ||
32 | |||
33 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, | ||
34 | unsigned char *p24); | ||
35 | |||
36 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | ||
37 | unsigned char *p24); | ||
38 | |||
39 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
40 | |||
41 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) | ||
42 | { | ||
43 | __u32 capabilities = 0; | ||
44 | |||
45 | /* init fields common to all four types of SessSetup */ | ||
46 | /* note that header is initialized to zero in header_assemble */ | ||
47 | pSMB->req.AndXCommand = 0xFF; | ||
48 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
49 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
50 | |||
51 | /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */ | ||
52 | |||
53 | /* BB verify whether signing required on neg or just on auth frame | ||
54 | (and NTLM case) */ | ||
55 | |||
56 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
57 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; | ||
58 | |||
59 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
60 | pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
61 | |||
62 | if (ses->capabilities & CAP_UNICODE) { | ||
63 | pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE; | ||
64 | capabilities |= CAP_UNICODE; | ||
65 | } | ||
66 | if (ses->capabilities & CAP_STATUS32) { | ||
67 | pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS; | ||
68 | capabilities |= CAP_STATUS32; | ||
69 | } | ||
70 | if (ses->capabilities & CAP_DFS) { | ||
71 | pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; | ||
72 | capabilities |= CAP_DFS; | ||
73 | } | ||
74 | if (ses->capabilities & CAP_UNIX) { | ||
75 | capabilities |= CAP_UNIX; | ||
76 | } | ||
77 | |||
78 | /* BB check whether to init vcnum BB */ | ||
79 | return capabilities; | ||
80 | } | ||
81 | |||
82 | void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, | ||
83 | const struct nls_table * nls_cp) | ||
84 | { | ||
85 | char * bcc_ptr = *pbcc_area; | ||
86 | int bytes_ret = 0; | ||
87 | |||
88 | /* BB FIXME add check that strings total less | ||
89 | than 335 or will need to send them as arrays */ | ||
90 | |||
91 | /* align unicode strings, must be word aligned */ | ||
92 | if ((long) bcc_ptr % 2) { | ||
93 | *bcc_ptr = 0; | ||
94 | bcc_ptr++; | ||
95 | } | ||
96 | /* copy user */ | ||
97 | if(ses->userName == NULL) { | ||
98 | /* BB what about null user mounts - check that we do this BB */ | ||
99 | } else { /* 300 should be long enough for any conceivable user name */ | ||
100 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, | ||
101 | 300, nls_cp); | ||
102 | } | ||
103 | bcc_ptr += 2 * bytes_ret; | ||
104 | bcc_ptr += 2; /* account for null termination */ | ||
105 | /* copy domain */ | ||
106 | if(ses->domainName == NULL) | ||
107 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, | ||
108 | "CIFS_LINUX_DOM", 32, nls_cp); | ||
109 | else | ||
110 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, | ||
111 | 256, nls_cp); | ||
112 | bcc_ptr += 2 * bytes_ret; | ||
113 | bcc_ptr += 2; /* account for null terminator */ | ||
114 | |||
115 | /* Copy OS version */ | ||
116 | bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, | ||
117 | nls_cp); | ||
118 | bcc_ptr += 2 * bytes_ret; | ||
119 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, | ||
120 | 32, nls_cp); | ||
121 | bcc_ptr += 2 * bytes_ret; | ||
122 | bcc_ptr += 2; /* trailing null */ | ||
123 | |||
124 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
125 | 32, nls_cp); | ||
126 | bcc_ptr += 2 * bytes_ret; | ||
127 | bcc_ptr += 2; /* trailing null */ | ||
128 | |||
129 | *pbcc_area = bcc_ptr; | ||
130 | } | ||
131 | |||
132 | void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, | ||
133 | const struct nls_table * nls_cp) | ||
134 | { | ||
135 | char * bcc_ptr = *pbcc_area; | ||
136 | |||
137 | /* copy user */ | ||
138 | /* BB what about null user mounts - check that we do this BB */ | ||
139 | /* copy user */ | ||
140 | if(ses->userName == NULL) { | ||
141 | /* BB what about null user mounts - check that we do this BB */ | ||
142 | } else { /* 300 should be long enough for any conceivable user name */ | ||
143 | strncpy(bcc_ptr, ses->userName, 300); | ||
144 | } | ||
145 | /* BB improve check for overflow */ | ||
146 | bcc_ptr += strnlen(ses->userName, 200); | ||
147 | *bcc_ptr = 0; | ||
148 | bcc_ptr++; /* account for null termination */ | ||
149 | |||
150 | /* copy domain */ | ||
151 | |||
152 | if(ses->domainName == NULL) { | ||
153 | strcpy(bcc_ptr, "CIFS_LINUX_DOM"); | ||
154 | bcc_ptr += 14; /* strlen(CIFS_LINUX_DOM) */ | ||
155 | } else { | ||
156 | strncpy(bcc_ptr, ses->domainName, 256); | ||
157 | bcc_ptr += strnlen(ses->domainName, 256); | ||
158 | } | ||
159 | *bcc_ptr = 0; | ||
160 | bcc_ptr++; | ||
161 | |||
162 | /* BB check for overflow here */ | ||
163 | |||
164 | strcpy(bcc_ptr, "Linux version "); | ||
165 | bcc_ptr += strlen("Linux version "); | ||
166 | strcpy(bcc_ptr, system_utsname.release); | ||
167 | bcc_ptr += strlen(system_utsname.release) + 1; | ||
168 | |||
169 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
170 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
171 | |||
172 | *pbcc_area = bcc_ptr; | ||
173 | } | ||
174 | |||
175 | int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, | ||
176 | const struct nls_table * nls_cp) | ||
177 | { | ||
178 | int rc = 0; | ||
179 | int words_left, len; | ||
180 | char * data = *pbcc_area; | ||
181 | |||
182 | |||
183 | |||
184 | cFYI(1,("bleft %d",bleft)); | ||
185 | |||
186 | |||
187 | /* word align, if bytes remaining is not even */ | ||
188 | if(bleft % 2) { | ||
189 | bleft--; | ||
190 | data++; | ||
191 | } | ||
192 | words_left = bleft / 2; | ||
193 | |||
194 | /* save off server operating system */ | ||
195 | len = UniStrnlen((wchar_t *) data, words_left); | ||
196 | |||
197 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
198 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
199 | terminating last Unicode string in response */ | ||
200 | if(len >= words_left) | ||
201 | return rc; | ||
202 | |||
203 | if(ses->serverOS) | ||
204 | kfree(ses->serverOS); | ||
205 | /* UTF-8 string will not grow more than four times as big as UCS-16 */ | ||
206 | ses->serverOS = kzalloc(4 * len, GFP_KERNEL); | ||
207 | if(ses->serverOS != NULL) { | ||
208 | cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, | ||
209 | nls_cp); | ||
210 | } | ||
211 | data += 2 * (len + 1); | ||
212 | words_left -= len + 1; | ||
213 | |||
214 | /* save off server network operating system */ | ||
215 | len = UniStrnlen((wchar_t *) data, words_left); | ||
216 | |||
217 | if(len >= words_left) | ||
218 | return rc; | ||
219 | |||
220 | if(ses->serverNOS) | ||
221 | kfree(ses->serverNOS); | ||
222 | ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */ | ||
223 | if(ses->serverNOS != NULL) { | ||
224 | cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, | ||
225 | nls_cp); | ||
226 | if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) { | ||
227 | cFYI(1,("NT4 server")); | ||
228 | ses->flags |= CIFS_SES_NT4; | ||
229 | } | ||
230 | } | ||
231 | data += 2 * (len + 1); | ||
232 | words_left -= len + 1; | ||
233 | |||
234 | /* save off server domain */ | ||
235 | len = UniStrnlen((wchar_t *) data, words_left); | ||
236 | |||
237 | if(len > words_left) | ||
238 | return rc; | ||
239 | |||
240 | if(ses->serverDomain) | ||
241 | kfree(ses->serverDomain); | ||
242 | ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ | ||
243 | if(ses->serverDomain != NULL) { | ||
244 | cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, | ||
245 | nls_cp); | ||
246 | ses->serverDomain[2*len] = 0; | ||
247 | ses->serverDomain[(2*len) + 1] = 0; | ||
248 | } | ||
249 | data += 2 * (len + 1); | ||
250 | words_left -= len + 1; | ||
251 | |||
252 | cFYI(1,("words left: %d",words_left)); | ||
253 | |||
254 | return rc; | ||
255 | } | ||
256 | |||
257 | int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, | ||
258 | const struct nls_table * nls_cp) | ||
259 | { | ||
260 | int rc = 0; | ||
261 | int len; | ||
262 | char * bcc_ptr = *pbcc_area; | ||
263 | |||
264 | cFYI(1,("decode sessetup ascii. bleft %d", bleft)); | ||
265 | |||
266 | len = strnlen(bcc_ptr, bleft); | ||
267 | if(len >= bleft) | ||
268 | return rc; | ||
269 | |||
270 | if(ses->serverOS) | ||
271 | kfree(ses->serverOS); | ||
272 | |||
273 | ses->serverOS = kzalloc(len + 1, GFP_KERNEL); | ||
274 | if(ses->serverOS) | ||
275 | strncpy(ses->serverOS, bcc_ptr, len); | ||
276 | |||
277 | bcc_ptr += len + 1; | ||
278 | bleft -= len + 1; | ||
279 | |||
280 | len = strnlen(bcc_ptr, bleft); | ||
281 | if(len >= bleft) | ||
282 | return rc; | ||
283 | |||
284 | if(ses->serverNOS) | ||
285 | kfree(ses->serverNOS); | ||
286 | |||
287 | ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); | ||
288 | if(ses->serverNOS) | ||
289 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
290 | |||
291 | bcc_ptr += len + 1; | ||
292 | bleft -= len + 1; | ||
293 | |||
294 | len = strnlen(bcc_ptr, bleft); | ||
295 | if(len > bleft) | ||
296 | return rc; | ||
297 | |||
298 | if(ses->serverDomain) | ||
299 | kfree(ses->serverDomain); | ||
300 | |||
301 | ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); | ||
302 | if(ses->serverOS) | ||
303 | strncpy(ses->serverOS, bcc_ptr, len); | ||
304 | |||
305 | bcc_ptr += len + 1; | ||
306 | bleft -= len + 1; | ||
307 | |||
308 | cFYI(1,("ascii: bytes left %d",bleft)); | ||
309 | |||
310 | return rc; | ||
311 | } | ||
312 | |||
313 | int | ||
314 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | ||
315 | const struct nls_table *nls_cp) | ||
316 | { | ||
317 | int rc = 0; | ||
318 | int wct; | ||
319 | int i; | ||
320 | struct smb_hdr *smb_buf; | ||
321 | char *bcc_ptr; | ||
322 | SESSION_SETUP_ANDX *pSMB; | ||
323 | __u32 capabilities; | ||
324 | int count; | ||
325 | int resp_buf_type = 0; | ||
326 | struct kvec iov[1]; | ||
327 | enum securityEnum type; | ||
328 | __u16 action; | ||
329 | int bytes_remaining; | ||
330 | |||
331 | if(ses == NULL) | ||
332 | return -EINVAL; | ||
333 | |||
334 | type = ses->server->secType; | ||
335 | if(type == LANMAN) { | ||
336 | #ifndef CONFIG_CIFS_WEAK_PW_HASH | ||
337 | /* LANMAN and plaintext are less secure and off by default. | ||
338 | So we make this explicitly be turned on in kconfig (in the | ||
339 | build) and turned on at runtime (changed from the default) | ||
340 | in proc/fs/cifs or via mount parm. Unfortunately this is | ||
341 | needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ | ||
342 | return -EOPNOTSUPP; | ||
343 | #endif | ||
344 | wct = 10; /* lanman 2 style sessionsetup */ | ||
345 | } else if(type == NTLM) /* NTLMv2 may retry NTLM */ | ||
346 | wct = 13; /* old style NTLM sessionsetup */ | ||
347 | else /* same size for negotiate or auth, NTLMSSP or extended security */ | ||
348 | wct = 12; | ||
349 | |||
350 | rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, | ||
351 | (void **)&smb_buf); | ||
352 | if(rc) | ||
353 | return rc; | ||
354 | |||
355 | pSMB = (SESSION_SETUP_ANDX *)smb_buf; | ||
356 | |||
357 | capabilities = cifs_ssetup_hdr(ses, pSMB); | ||
358 | bcc_ptr = pByteArea(smb_buf); | ||
359 | |||
360 | if(type == LANMAN) { | ||
361 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
362 | char lnm_session_key[CIFS_SESSION_KEY_SIZE]; | ||
363 | char password_with_pad[CIFS_ENCPWD_SIZE]; | ||
364 | |||
365 | /* no capabilities flags in old lanman negotiation */ | ||
366 | |||
367 | pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE; | ||
368 | /* BB calculate hash with password */ | ||
369 | /* and copy into bcc */ | ||
370 | |||
371 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); | ||
372 | strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); | ||
373 | |||
374 | /* calculate old style session key */ | ||
375 | /* toupper may be less broken then repeatedly calling | ||
376 | nls_toupper would be, but neither handles multibyte code pages | ||
377 | but the only alternative would be converting to UCS-16 (Unicode) | ||
378 | uppercasing and converting back which is only worth doing if | ||
379 | we knew it were utf8. utf8 code page needs its own | ||
380 | toupper and tolower and strnicmp functions */ | ||
381 | |||
382 | for(i = 0; i< CIFS_ENCPWD_SIZE; i++) { | ||
383 | password_with_pad[i] = toupper(password_with_pad[i]); | ||
384 | } | ||
385 | |||
386 | SMBencrypt(password_with_pad, ses->server->cryptKey, | ||
387 | lnm_session_key); | ||
388 | |||
389 | #ifdef CONFIG_CIFS_DEBUG2 | ||
390 | cifs_dump_mem("cryptkey: ",ses->server->cryptKey, | ||
391 | CIFS_SESSION_KEY_SIZE); | ||
392 | #endif | ||
393 | /* clear password before we return/free memory */ | ||
394 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); | ||
395 | memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE); | ||
396 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | ||
397 | |||
398 | /* can not sign if LANMAN negotiated so no need | ||
399 | to calculate signing key? but what if server | ||
400 | changed to do higher than lanman dialect and | ||
401 | we reconnected would we ever calc signing_key? */ | ||
402 | |||
403 | cERROR(1,("Negotiating LANMAN setting up strings")); | ||
404 | /* Unicode not allowed for LANMAN dialects */ | ||
405 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
406 | #endif | ||
407 | } else if (type == NTLM) { | ||
408 | char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; | ||
409 | |||
410 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
411 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | ||
412 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | ||
413 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
414 | cpu_to_le16(CIFS_SESSION_KEY_SIZE); | ||
415 | |||
416 | /* calculate session key */ | ||
417 | SMBNTencrypt(ses->password, ses->server->cryptKey, | ||
418 | ntlm_session_key); | ||
419 | |||
420 | if(first_time) /* should this be moved into common code | ||
421 | with similar ntlmv2 path? */ | ||
422 | cifs_calculate_mac_key( | ||
423 | ses->server->mac_signing_key, | ||
424 | ntlm_session_key, ses->password); | ||
425 | /* copy session key */ | ||
426 | |||
427 | memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); | ||
428 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | ||
429 | memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); | ||
430 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | ||
431 | if(ses->capabilities & CAP_UNICODE) | ||
432 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
433 | else | ||
434 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
435 | } else /* NTLMSSP or SPNEGO */ { | ||
436 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
437 | capabilities |= CAP_EXTENDED_SECURITY; | ||
438 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
439 | /* BB set password lengths */ | ||
440 | } | ||
441 | |||
442 | count = (long) bcc_ptr - (long) pByteArea(smb_buf); | ||
443 | smb_buf->smb_buf_length += count; | ||
444 | |||
445 | /* if we switch to small buffers, count will need to be fewer | ||
446 | than 383 (strings less than 335 bytes) */ | ||
447 | |||
448 | BCC_LE(smb_buf) = cpu_to_le16(count); | ||
449 | |||
450 | |||
451 | /* BB FIXME check for other non ntlm code paths */ | ||
452 | |||
453 | /* BB check is this too big for a small smb? */ | ||
454 | |||
455 | iov[0].iov_base = (char *)pSMB; | ||
456 | iov[0].iov_len = smb_buf->smb_buf_length + 4; | ||
457 | |||
458 | rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0); | ||
459 | /* SMB request buf freed in SendReceive2 */ | ||
460 | |||
461 | cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); | ||
462 | if(rc) | ||
463 | goto ssetup_exit; | ||
464 | |||
465 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | ||
466 | smb_buf = (struct smb_hdr *)iov[0].iov_base; | ||
467 | |||
468 | if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { | ||
469 | rc = -EIO; | ||
470 | cERROR(1,("bad word count %d", smb_buf->WordCount)); | ||
471 | goto ssetup_exit; | ||
472 | } | ||
473 | action = le16_to_cpu(pSMB->resp.Action); | ||
474 | if (action & GUEST_LOGIN) | ||
475 | cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */ | ||
476 | ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ | ||
477 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
478 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
479 | /* and lanman response is 3 */ | ||
480 | bytes_remaining = BCC(smb_buf); | ||
481 | bcc_ptr = pByteArea(smb_buf); | ||
482 | |||
483 | if(smb_buf->WordCount == 4) { | ||
484 | __u16 blob_len; | ||
485 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | ||
486 | bcc_ptr += blob_len; | ||
487 | if(blob_len > bytes_remaining) { | ||
488 | cERROR(1,("bad security blob length %d", blob_len)); | ||
489 | rc = -EINVAL; | ||
490 | goto ssetup_exit; | ||
491 | } | ||
492 | bytes_remaining -= blob_len; | ||
493 | } | ||
494 | |||
495 | /* BB check if Unicode and decode strings */ | ||
496 | if(smb_buf->Flags2 & SMBFLG2_UNICODE) | ||
497 | rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, | ||
498 | ses, nls_cp); | ||
499 | else | ||
500 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); | ||
501 | |||
502 | ssetup_exit: | ||
503 | if(resp_buf_type == CIFS_SMALL_BUFFER) { | ||
504 | cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base)); | ||
505 | cifs_small_buf_release(iov[0].iov_base); | ||
506 | } else if(resp_buf_type == CIFS_LARGE_BUFFER) | ||
507 | cifs_buf_release(iov[0].iov_base); | ||
508 | |||
509 | return rc; | ||
510 | } | ||
511 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
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" |