diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-05-11 08:44:27 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-11 08:44:31 -0400 |
commit | 41fb454ebe6024f5c1e3b3cbc0abc0da762e7b51 (patch) | |
tree | 51c50bcb67a5039448ddfa1869d7948cab1217e9 /fs/cifs | |
parent | 19c1a6f5764d787113fa323ffb18be7991208f82 (diff) | |
parent | 091bf7624d1c90cec9e578a18529f615213ff847 (diff) |
Merge commit 'v2.6.30-rc5' into core/iommu
Merge reason: core/iommu was on an .30-rc1 base,
update it to .30-rc5 to refresh.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/CHANGES | 16 | ||||
-rw-r--r-- | fs/cifs/README | 10 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 32 | ||||
-rw-r--r-- | fs/cifs/cifs_spnego.c | 2 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.c | 198 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.h | 23 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 48 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 19 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 8 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 223 | ||||
-rw-r--r-- | fs/cifs/connect.c | 1357 | ||||
-rw-r--r-- | fs/cifs/dir.c | 160 | ||||
-rw-r--r-- | fs/cifs/dns_resolve.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 141 | ||||
-rw-r--r-- | fs/cifs/inode.c | 98 | ||||
-rw-r--r-- | fs/cifs/link.c | 114 | ||||
-rw-r--r-- | fs/cifs/misc.c | 71 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 2 | ||||
-rw-r--r-- | fs/cifs/nterr.h | 9 | ||||
-rw-r--r-- | fs/cifs/ntlmssp.h | 68 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 78 | ||||
-rw-r--r-- | fs/cifs/sess.c | 373 | ||||
-rw-r--r-- | fs/cifs/smberr.h | 1 |
25 files changed, 1172 insertions, 1888 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 65984006192c..f20c4069c220 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,16 @@ | |||
1 | Version 1.58 | ||
2 | ------------ | ||
3 | Guard against buffer overruns in various UCS-2 to UTF-8 string conversions | ||
4 | when the UTF-8 string is composed of unusually long (more than 4 byte) converted | ||
5 | characters. Add support for mounting root of a share which redirects immediately | ||
6 | to DFS target. Convert string conversion functions from Unicode to more | ||
7 | accurately mark string length before allocating memory (which may help the | ||
8 | rare cases where a UTF-8 string is much larger than the UCS2 string that | ||
9 | we converted from). Fix endianness of the vcnum field used during | ||
10 | session setup to distinguish multiple mounts to same server from different | ||
11 | userids. Raw NTLMSSP fixed (it requires /proc/fs/cifs/experimental | ||
12 | flag to be set to 2, and mount must enable krb5 to turn on extended security). | ||
13 | |||
1 | Version 1.57 | 14 | Version 1.57 |
2 | ------------ | 15 | ------------ |
3 | Improve support for multiple security contexts to the same server. We | 16 | Improve support for multiple security contexts to the same server. We |
@@ -15,7 +28,8 @@ Posix file open support added (turned off after one attempt if server | |||
15 | fails to support it properly, as with Samba server versions prior to 3.3.2) | 28 | fails to support it properly, as with Samba server versions prior to 3.3.2) |
16 | Fix "redzone overwritten" bug in cifs_put_tcon (CIFSTcon may allocate too | 29 | Fix "redzone overwritten" bug in cifs_put_tcon (CIFSTcon may allocate too |
17 | little memory for the "nativeFileSystem" field returned by the server | 30 | little memory for the "nativeFileSystem" field returned by the server |
18 | during mount). | 31 | during mount). Endian convert inode numbers if necessary (makes it easier |
32 | to compare inode numbers on network files from big endian systems). | ||
19 | 33 | ||
20 | Version 1.56 | 34 | Version 1.56 |
21 | ------------ | 35 | ------------ |
diff --git a/fs/cifs/README b/fs/cifs/README index 07434181623b..db208ddb9899 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -651,7 +651,15 @@ Experimental When set to 1 used to enable certain experimental | |||
651 | signing turned on in case buffer was modified | 651 | signing turned on in case buffer was modified |
652 | just before it was sent, also this flag will | 652 | just before it was sent, also this flag will |
653 | be used to use the new experimental directory change | 653 | be used to use the new experimental directory change |
654 | notification code). | 654 | notification code). When set to 2 enables |
655 | an additional experimental feature, "raw ntlmssp" | ||
656 | session establishment support (which allows | ||
657 | specifying "sec=ntlmssp" on mount). The Linux cifs | ||
658 | module will use ntlmv2 authentication encapsulated | ||
659 | in "raw ntlmssp" (not using SPNEGO) when | ||
660 | "sec=ntlmssp" is specified on mount. | ||
661 | This support also requires building cifs with | ||
662 | the CONFIG_CIFS_EXPERIMENTAL configuration flag. | ||
655 | 663 | ||
656 | These experimental features and tracing can be enabled by changing flags in | 664 | These experimental features and tracing can be enabled by changing flags in |
657 | /proc/fs/cifs (after the cifs module has been installed or built into the | 665 | /proc/fs/cifs (after the cifs module has been installed or built into the |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 5fdbf8a14472..83d62759c7c7 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -340,28 +340,24 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
340 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 340 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
341 | 341 | ||
342 | for (i = 0; i < num_referrals; i++) { | 342 | for (i = 0; i < num_referrals; i++) { |
343 | int len; | ||
343 | dump_referral(referrals+i); | 344 | dump_referral(referrals+i); |
344 | /* connect to a storage node */ | 345 | /* connect to a node */ |
345 | if (referrals[i].flags & DFSREF_STORAGE_SERVER) { | 346 | len = strlen(referrals[i].node_name); |
346 | int len; | 347 | if (len < 2) { |
347 | len = strlen(referrals[i].node_name); | 348 | cERROR(1, ("%s: Net Address path too short: %s", |
348 | if (len < 2) { | ||
349 | cERROR(1, ("%s: Net Address path too short: %s", | ||
350 | __func__, referrals[i].node_name)); | 349 | __func__, referrals[i].node_name)); |
351 | rc = -EINVAL; | 350 | rc = -EINVAL; |
352 | goto out_err; | 351 | goto out_err; |
353 | } | 352 | } |
354 | mnt = cifs_dfs_do_refmount(nd->path.mnt, | 353 | mnt = cifs_dfs_do_refmount(nd->path.mnt, |
355 | nd->path.dentry, | 354 | nd->path.dentry, referrals + i); |
356 | referrals + i); | 355 | cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, |
357 | cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", | ||
358 | __func__, | ||
359 | referrals[i].node_name, mnt)); | 356 | referrals[i].node_name, mnt)); |
360 | 357 | ||
361 | /* complete mount procedure if we accured submount */ | 358 | /* complete mount procedure if we accured submount */ |
362 | if (!IS_ERR(mnt)) | 359 | if (!IS_ERR(mnt)) |
363 | break; | 360 | break; |
364 | } | ||
365 | } | 361 | } |
366 | 362 | ||
367 | /* we need it cause for() above could exit without valid submount */ | 363 | /* we need it cause for() above could exit without valid submount */ |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 3fd3a9df043a..67bf93a40d2e 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
@@ -41,7 +41,7 @@ cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen) | |||
41 | 41 | ||
42 | /* attach the data */ | 42 | /* attach the data */ |
43 | memcpy(payload, data, datalen); | 43 | memcpy(payload, data, datalen); |
44 | rcu_assign_pointer(key->payload.data, payload); | 44 | key->payload.data = payload; |
45 | ret = 0; | 45 | ret = 0; |
46 | 46 | ||
47 | error: | 47 | error: |
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 7d75272a6b3f..60e3c4253de0 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/cifs_unicode.c | 2 | * fs/cifs/cifs_unicode.c |
3 | * | 3 | * |
4 | * Copyright (c) International Business Machines Corp., 2000,2005 | 4 | * Copyright (c) International Business Machines Corp., 2000,2009 |
5 | * Modified by Steve French (sfrench@us.ibm.com) | 5 | * Modified by Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
@@ -26,31 +26,157 @@ | |||
26 | #include "cifs_debug.h" | 26 | #include "cifs_debug.h" |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * NAME: cifs_strfromUCS() | 29 | * cifs_ucs2_bytes - how long will a string be after conversion? |
30 | * | 30 | * @ucs - pointer to input string |
31 | * FUNCTION: Convert little-endian unicode string to character string | 31 | * @maxbytes - don't go past this many bytes of input string |
32 | * @codepage - destination codepage | ||
32 | * | 33 | * |
34 | * Walk a ucs2le string and return the number of bytes that the string will | ||
35 | * be after being converted to the given charset, not including any null | ||
36 | * termination required. Don't walk past maxbytes in the source buffer. | ||
33 | */ | 37 | */ |
34 | int | 38 | int |
35 | cifs_strfromUCS_le(char *to, const __le16 *from, | 39 | cifs_ucs2_bytes(const __le16 *from, int maxbytes, |
36 | int len, const struct nls_table *codepage) | 40 | const struct nls_table *codepage) |
37 | { | 41 | { |
38 | int i; | 42 | int i; |
39 | int outlen = 0; | 43 | int charlen, outlen = 0; |
44 | int maxwords = maxbytes / 2; | ||
45 | char tmp[NLS_MAX_CHARSET_SIZE]; | ||
40 | 46 | ||
41 | for (i = 0; (i < len) && from[i]; i++) { | 47 | for (i = 0; from[i] && i < maxwords; i++) { |
42 | int charlen; | 48 | charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, |
43 | /* 2.4.0 kernel or greater */ | 49 | NLS_MAX_CHARSET_SIZE); |
44 | charlen = | 50 | if (charlen > 0) |
45 | codepage->uni2char(le16_to_cpu(from[i]), &to[outlen], | ||
46 | NLS_MAX_CHARSET_SIZE); | ||
47 | if (charlen > 0) { | ||
48 | outlen += charlen; | 51 | outlen += charlen; |
49 | } else { | 52 | else |
50 | to[outlen++] = '?'; | 53 | outlen++; |
54 | } | ||
55 | |||
56 | return outlen; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * cifs_mapchar - convert a little-endian char to proper char in codepage | ||
61 | * @target - where converted character should be copied | ||
62 | * @src_char - 2 byte little-endian source character | ||
63 | * @cp - codepage to which character should be converted | ||
64 | * @mapchar - should character be mapped according to mapchars mount option? | ||
65 | * | ||
66 | * This function handles the conversion of a single character. It is the | ||
67 | * responsibility of the caller to ensure that the target buffer is large | ||
68 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). | ||
69 | */ | ||
70 | static int | ||
71 | cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, | ||
72 | bool mapchar) | ||
73 | { | ||
74 | int len = 1; | ||
75 | |||
76 | if (!mapchar) | ||
77 | goto cp_convert; | ||
78 | |||
79 | /* | ||
80 | * BB: Cannot handle remapping UNI_SLASH until all the calls to | ||
81 | * build_path_from_dentry are modified, as they use slash as | ||
82 | * separator. | ||
83 | */ | ||
84 | switch (le16_to_cpu(src_char)) { | ||
85 | case UNI_COLON: | ||
86 | *target = ':'; | ||
87 | break; | ||
88 | case UNI_ASTERIK: | ||
89 | *target = '*'; | ||
90 | break; | ||
91 | case UNI_QUESTION: | ||
92 | *target = '?'; | ||
93 | break; | ||
94 | case UNI_PIPE: | ||
95 | *target = '|'; | ||
96 | break; | ||
97 | case UNI_GRTRTHAN: | ||
98 | *target = '>'; | ||
99 | break; | ||
100 | case UNI_LESSTHAN: | ||
101 | *target = '<'; | ||
102 | break; | ||
103 | default: | ||
104 | goto cp_convert; | ||
105 | } | ||
106 | |||
107 | out: | ||
108 | return len; | ||
109 | |||
110 | cp_convert: | ||
111 | len = cp->uni2char(le16_to_cpu(src_char), target, | ||
112 | NLS_MAX_CHARSET_SIZE); | ||
113 | if (len <= 0) { | ||
114 | *target = '?'; | ||
115 | len = 1; | ||
116 | } | ||
117 | goto out; | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * cifs_from_ucs2 - convert utf16le string to local charset | ||
122 | * @to - destination buffer | ||
123 | * @from - source buffer | ||
124 | * @tolen - destination buffer size (in bytes) | ||
125 | * @fromlen - source buffer size (in bytes) | ||
126 | * @codepage - codepage to which characters should be converted | ||
127 | * @mapchar - should characters be remapped according to the mapchars option? | ||
128 | * | ||
129 | * Convert a little-endian ucs2le string (as sent by the server) to a string | ||
130 | * in the provided codepage. The tolen and fromlen parameters are to ensure | ||
131 | * that the code doesn't walk off of the end of the buffer (which is always | ||
132 | * a danger if the alignment of the source buffer is off). The destination | ||
133 | * string is always properly null terminated and fits in the destination | ||
134 | * buffer. Returns the length of the destination string in bytes (including | ||
135 | * null terminator). | ||
136 | * | ||
137 | * Note that some windows versions actually send multiword UTF-16 characters | ||
138 | * instead of straight UCS-2. The linux nls routines however aren't able to | ||
139 | * deal with those characters properly. In the event that we get some of | ||
140 | * those characters, they won't be translated properly. | ||
141 | */ | ||
142 | int | ||
143 | cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | ||
144 | const struct nls_table *codepage, bool mapchar) | ||
145 | { | ||
146 | int i, charlen, safelen; | ||
147 | int outlen = 0; | ||
148 | int nullsize = nls_nullsize(codepage); | ||
149 | int fromwords = fromlen / 2; | ||
150 | char tmp[NLS_MAX_CHARSET_SIZE]; | ||
151 | |||
152 | /* | ||
153 | * because the chars can be of varying widths, we need to take care | ||
154 | * not to overflow the destination buffer when we get close to the | ||
155 | * end of it. Until we get to this offset, we don't need to check | ||
156 | * for overflow however. | ||
157 | */ | ||
158 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); | ||
159 | |||
160 | for (i = 0; i < fromwords && from[i]; i++) { | ||
161 | /* | ||
162 | * check to see if converting this character might make the | ||
163 | * conversion bleed into the null terminator | ||
164 | */ | ||
165 | if (outlen >= safelen) { | ||
166 | charlen = cifs_mapchar(tmp, from[i], codepage, mapchar); | ||
167 | if ((outlen + charlen) > (tolen - nullsize)) | ||
168 | break; | ||
51 | } | 169 | } |
170 | |||
171 | /* put converted char into 'to' buffer */ | ||
172 | charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar); | ||
173 | outlen += charlen; | ||
52 | } | 174 | } |
53 | to[outlen] = 0; | 175 | |
176 | /* properly null-terminate string */ | ||
177 | for (i = 0; i < nullsize; i++) | ||
178 | to[outlen++] = 0; | ||
179 | |||
54 | return outlen; | 180 | return outlen; |
55 | } | 181 | } |
56 | 182 | ||
@@ -88,3 +214,41 @@ cifs_strtoUCS(__le16 *to, const char *from, int len, | |||
88 | return i; | 214 | return i; |
89 | } | 215 | } |
90 | 216 | ||
217 | /* | ||
218 | * cifs_strndup_from_ucs - copy a string from wire format to the local codepage | ||
219 | * @src - source string | ||
220 | * @maxlen - don't walk past this many bytes in the source string | ||
221 | * @is_unicode - is this a unicode string? | ||
222 | * @codepage - destination codepage | ||
223 | * | ||
224 | * Take a string given by the server, convert it to the local codepage and | ||
225 | * put it in a new buffer. Returns a pointer to the new string or NULL on | ||
226 | * error. | ||
227 | */ | ||
228 | char * | ||
229 | cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, | ||
230 | const struct nls_table *codepage) | ||
231 | { | ||
232 | int len; | ||
233 | char *dst; | ||
234 | |||
235 | if (is_unicode) { | ||
236 | len = cifs_ucs2_bytes((__le16 *) src, maxlen, codepage); | ||
237 | len += nls_nullsize(codepage); | ||
238 | dst = kmalloc(len, GFP_KERNEL); | ||
239 | if (!dst) | ||
240 | return NULL; | ||
241 | cifs_from_ucs2(dst, (__le16 *) src, len, maxlen, codepage, | ||
242 | false); | ||
243 | } else { | ||
244 | len = strnlen(src, maxlen); | ||
245 | len++; | ||
246 | dst = kmalloc(len, GFP_KERNEL); | ||
247 | if (!dst) | ||
248 | return NULL; | ||
249 | strlcpy(dst, src, len); | ||
250 | } | ||
251 | |||
252 | return dst; | ||
253 | } | ||
254 | |||
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 14eb9a2395d3..650638275a6f 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * Convert a unicode character to upper or lower case using | 5 | * Convert a unicode character to upper or lower case using |
6 | * compressed tables. | 6 | * compressed tables. |
7 | * | 7 | * |
8 | * Copyright (c) International Business Machines Corp., 2000,2007 | 8 | * Copyright (c) International Business Machines Corp., 2000,2009 |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -37,6 +37,19 @@ | |||
37 | 37 | ||
38 | #define UNIUPR_NOLOWER /* Example to not expand lower case tables */ | 38 | #define UNIUPR_NOLOWER /* Example to not expand lower case tables */ |
39 | 39 | ||
40 | /* | ||
41 | * Windows maps these to the user defined 16 bit Unicode range since they are | ||
42 | * reserved symbols (along with \ and /), otherwise illegal to store | ||
43 | * in filenames in NTFS | ||
44 | */ | ||
45 | #define UNI_ASTERIK (__u16) ('*' + 0xF000) | ||
46 | #define UNI_QUESTION (__u16) ('?' + 0xF000) | ||
47 | #define UNI_COLON (__u16) (':' + 0xF000) | ||
48 | #define UNI_GRTRTHAN (__u16) ('>' + 0xF000) | ||
49 | #define UNI_LESSTHAN (__u16) ('<' + 0xF000) | ||
50 | #define UNI_PIPE (__u16) ('|' + 0xF000) | ||
51 | #define UNI_SLASH (__u16) ('\\' + 0xF000) | ||
52 | |||
40 | /* Just define what we want from uniupr.h. We don't want to define the tables | 53 | /* Just define what we want from uniupr.h. We don't want to define the tables |
41 | * in each source file. | 54 | * in each source file. |
42 | */ | 55 | */ |
@@ -59,8 +72,14 @@ extern struct UniCaseRange UniLowerRange[]; | |||
59 | #endif /* UNIUPR_NOLOWER */ | 72 | #endif /* UNIUPR_NOLOWER */ |
60 | 73 | ||
61 | #ifdef __KERNEL__ | 74 | #ifdef __KERNEL__ |
62 | int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *); | 75 | int cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, |
76 | const struct nls_table *codepage, bool mapchar); | ||
77 | int cifs_ucs2_bytes(const __le16 *from, int maxbytes, | ||
78 | const struct nls_table *codepage); | ||
63 | int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); | 79 | int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); |
80 | char *cifs_strndup_from_ucs(const char *src, const int maxlen, | ||
81 | const bool is_unicode, | ||
82 | const struct nls_table *codepage); | ||
64 | #endif | 83 | #endif |
65 | 84 | ||
66 | /* | 85 | /* |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 38491fd3871d..0d6d8b573652 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -66,9 +66,6 @@ unsigned int sign_CIFS_PDUs = 1; | |||
66 | extern struct task_struct *oplockThread; /* remove sparse warning */ | 66 | extern struct task_struct *oplockThread; /* remove sparse warning */ |
67 | struct task_struct *oplockThread = NULL; | 67 | struct task_struct *oplockThread = NULL; |
68 | /* extern struct task_struct * dnotifyThread; remove sparse warning */ | 68 | /* extern struct task_struct * dnotifyThread; remove sparse warning */ |
69 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
70 | static struct task_struct *dnotifyThread = NULL; | ||
71 | #endif | ||
72 | static const struct super_operations cifs_super_ops; | 69 | static const struct super_operations cifs_super_ops; |
73 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; | 70 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; |
74 | module_param(CIFSMaxBufSize, int, 0); | 71 | module_param(CIFSMaxBufSize, int, 0); |
@@ -316,6 +313,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
316 | cifs_inode->clientCanCacheAll = false; | 313 | cifs_inode->clientCanCacheAll = false; |
317 | cifs_inode->delete_pending = false; | 314 | cifs_inode->delete_pending = false; |
318 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 315 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
316 | cifs_inode->server_eof = 0; | ||
319 | 317 | ||
320 | /* Can not set i_flags here - they get immediately overwritten | 318 | /* Can not set i_flags here - they get immediately overwritten |
321 | to zero by the VFS */ | 319 | to zero by the VFS */ |
@@ -1040,34 +1038,6 @@ static int cifs_oplock_thread(void *dummyarg) | |||
1040 | return 0; | 1038 | return 0; |
1041 | } | 1039 | } |
1042 | 1040 | ||
1043 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1044 | static int cifs_dnotify_thread(void *dummyarg) | ||
1045 | { | ||
1046 | struct list_head *tmp; | ||
1047 | struct TCP_Server_Info *server; | ||
1048 | |||
1049 | do { | ||
1050 | if (try_to_freeze()) | ||
1051 | continue; | ||
1052 | set_current_state(TASK_INTERRUPTIBLE); | ||
1053 | schedule_timeout(15*HZ); | ||
1054 | /* check if any stuck requests that need | ||
1055 | to be woken up and wakeq so the | ||
1056 | thread can wake up and error out */ | ||
1057 | read_lock(&cifs_tcp_ses_lock); | ||
1058 | list_for_each(tmp, &cifs_tcp_ses_list) { | ||
1059 | server = list_entry(tmp, struct TCP_Server_Info, | ||
1060 | tcp_ses_list); | ||
1061 | if (atomic_read(&server->inFlight)) | ||
1062 | wake_up_all(&server->response_q); | ||
1063 | } | ||
1064 | read_unlock(&cifs_tcp_ses_lock); | ||
1065 | } while (!kthread_should_stop()); | ||
1066 | |||
1067 | return 0; | ||
1068 | } | ||
1069 | #endif | ||
1070 | |||
1071 | static int __init | 1041 | static int __init |
1072 | init_cifs(void) | 1042 | init_cifs(void) |
1073 | { | 1043 | { |
@@ -1144,21 +1114,8 @@ init_cifs(void) | |||
1144 | goto out_unregister_dfs_key_type; | 1114 | goto out_unregister_dfs_key_type; |
1145 | } | 1115 | } |
1146 | 1116 | ||
1147 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1148 | dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd"); | ||
1149 | if (IS_ERR(dnotifyThread)) { | ||
1150 | rc = PTR_ERR(dnotifyThread); | ||
1151 | cERROR(1, ("error %d create dnotify thread", rc)); | ||
1152 | goto out_stop_oplock_thread; | ||
1153 | } | ||
1154 | #endif | ||
1155 | |||
1156 | return 0; | 1117 | return 0; |
1157 | 1118 | ||
1158 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1159 | out_stop_oplock_thread: | ||
1160 | #endif | ||
1161 | kthread_stop(oplockThread); | ||
1162 | out_unregister_dfs_key_type: | 1119 | out_unregister_dfs_key_type: |
1163 | #ifdef CONFIG_CIFS_DFS_UPCALL | 1120 | #ifdef CONFIG_CIFS_DFS_UPCALL |
1164 | unregister_key_type(&key_type_dns_resolver); | 1121 | unregister_key_type(&key_type_dns_resolver); |
@@ -1196,9 +1153,6 @@ exit_cifs(void) | |||
1196 | cifs_destroy_inodecache(); | 1153 | cifs_destroy_inodecache(); |
1197 | cifs_destroy_mids(); | 1154 | cifs_destroy_mids(); |
1198 | cifs_destroy_request_bufs(); | 1155 | cifs_destroy_request_bufs(); |
1199 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1200 | kthread_stop(dnotifyThread); | ||
1201 | #endif | ||
1202 | kthread_stop(oplockThread); | 1156 | kthread_stop(oplockThread); |
1203 | } | 1157 | } |
1204 | 1158 | ||
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 77e190dc2883..051b71cfdea9 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -100,5 +100,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
100 | extern const struct export_operations cifs_export_ops; | 100 | extern const struct export_operations cifs_export_ops; |
101 | #endif /* EXPERIMENTAL */ | 101 | #endif /* EXPERIMENTAL */ |
102 | 102 | ||
103 | #define CIFS_VERSION "1.57" | 103 | #define CIFS_VERSION "1.58" |
104 | #endif /* _CIFSFS_H */ | 104 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 9fbf4dff5da6..a61ab772c6f6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -82,8 +82,8 @@ enum securityEnum { | |||
82 | LANMAN, /* Legacy LANMAN auth */ | 82 | LANMAN, /* Legacy LANMAN auth */ |
83 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ | 83 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ |
84 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ | 84 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ |
85 | RawNTLMSSP, /* NTLMSSP without SPNEGO */ | 85 | RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ |
86 | NTLMSSP, /* NTLMSSP via SPNEGO */ | 86 | NTLMSSP, /* NTLMSSP via SPNEGO, NTLMv2 hash */ |
87 | Kerberos, /* Kerberos via SPNEGO */ | 87 | Kerberos, /* Kerberos via SPNEGO */ |
88 | MSKerberos, /* MS Kerberos via SPNEGO */ | 88 | MSKerberos, /* MS Kerberos via SPNEGO */ |
89 | }; | 89 | }; |
@@ -350,7 +350,7 @@ struct cifsFileInfo { | |||
350 | bool invalidHandle:1; /* file closed via session abend */ | 350 | bool invalidHandle:1; /* file closed via session abend */ |
351 | bool messageMode:1; /* for pipes: message vs byte mode */ | 351 | bool messageMode:1; /* for pipes: message vs byte mode */ |
352 | atomic_t wrtPending; /* handle in use - defer close */ | 352 | atomic_t wrtPending; /* handle in use - defer close */ |
353 | struct semaphore fh_sem; /* prevents reopen race after dead ses*/ | 353 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ |
354 | struct cifs_search_info srch_inf; | 354 | struct cifs_search_info srch_inf; |
355 | }; | 355 | }; |
356 | 356 | ||
@@ -370,6 +370,7 @@ struct cifsInodeInfo { | |||
370 | bool clientCanCacheAll:1; /* read and writebehind oplock */ | 370 | bool clientCanCacheAll:1; /* read and writebehind oplock */ |
371 | bool oplockPending:1; | 371 | bool oplockPending:1; |
372 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ | 372 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ |
373 | u64 server_eof; /* current file size on server */ | ||
373 | struct inode vfs_inode; | 374 | struct inode vfs_inode; |
374 | }; | 375 | }; |
375 | 376 | ||
@@ -530,6 +531,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
530 | #define CIFSSEC_MAY_PLNTXT 0 | 531 | #define CIFSSEC_MAY_PLNTXT 0 |
531 | #endif /* weak passwords */ | 532 | #endif /* weak passwords */ |
532 | #define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ | 533 | #define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ |
534 | #define CIFSSEC_MAY_NTLMSSP 0x00080 /* raw ntlmssp with ntlmv2 */ | ||
533 | 535 | ||
534 | #define CIFSSEC_MUST_SIGN 0x01001 | 536 | #define CIFSSEC_MUST_SIGN 0x01001 |
535 | /* note that only one of the following can be set so the | 537 | /* note that only one of the following can be set so the |
@@ -542,22 +544,23 @@ require use of the stronger protocol */ | |||
542 | #define CIFSSEC_MUST_LANMAN 0x10010 | 544 | #define CIFSSEC_MUST_LANMAN 0x10010 |
543 | #define CIFSSEC_MUST_PLNTXT 0x20020 | 545 | #define CIFSSEC_MUST_PLNTXT 0x20020 |
544 | #ifdef CONFIG_CIFS_UPCALL | 546 | #ifdef CONFIG_CIFS_UPCALL |
545 | #define CIFSSEC_MASK 0x3F03F /* allows weak security but also krb5 */ | 547 | #define CIFSSEC_MASK 0xAF0AF /* allows weak security but also krb5 */ |
546 | #else | 548 | #else |
547 | #define CIFSSEC_MASK 0x37037 /* current flags supported if weak */ | 549 | #define CIFSSEC_MASK 0xA70A7 /* current flags supported if weak */ |
548 | #endif /* UPCALL */ | 550 | #endif /* UPCALL */ |
549 | #else /* do not allow weak pw hash */ | 551 | #else /* do not allow weak pw hash */ |
550 | #ifdef CONFIG_CIFS_UPCALL | 552 | #ifdef CONFIG_CIFS_UPCALL |
551 | #define CIFSSEC_MASK 0x0F00F /* flags supported if no weak allowed */ | 553 | #define CIFSSEC_MASK 0x8F08F /* flags supported if no weak allowed */ |
552 | #else | 554 | #else |
553 | #define CIFSSEC_MASK 0x07007 /* flags supported if no weak allowed */ | 555 | #define CIFSSEC_MASK 0x87087 /* flags supported if no weak allowed */ |
554 | #endif /* UPCALL */ | 556 | #endif /* UPCALL */ |
555 | #endif /* WEAK_PW_HASH */ | 557 | #endif /* WEAK_PW_HASH */ |
556 | #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ | 558 | #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ |
559 | #define CIFSSEC_MUST_NTLMSSP 0x80080 /* raw ntlmssp with ntlmv2 */ | ||
557 | 560 | ||
558 | #define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2) | 561 | #define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2) |
559 | #define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) | 562 | #define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) |
560 | #define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5) | 563 | #define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP) |
561 | /* | 564 | /* |
562 | ***************************************************************** | 565 | ***************************************************************** |
563 | * All constants go here | 566 | * All constants go here |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index b370489c8da5..a785f69dbc9f 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -2163,7 +2163,7 @@ typedef struct { | |||
2163 | __le32 Type; | 2163 | __le32 Type; |
2164 | __le64 DevMajor; | 2164 | __le64 DevMajor; |
2165 | __le64 DevMinor; | 2165 | __le64 DevMinor; |
2166 | __u64 UniqueId; | 2166 | __le64 UniqueId; |
2167 | __le64 Permissions; | 2167 | __le64 Permissions; |
2168 | __le64 Nlinks; | 2168 | __le64 Nlinks; |
2169 | } __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ | 2169 | } __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ |
@@ -2308,7 +2308,7 @@ struct unlink_psx_rq { /* level 0x20a SetPathInfo */ | |||
2308 | } __attribute__((packed)); | 2308 | } __attribute__((packed)); |
2309 | 2309 | ||
2310 | struct file_internal_info { | 2310 | struct file_internal_info { |
2311 | __u64 UniqueId; /* inode number */ | 2311 | __le64 UniqueId; /* inode number */ |
2312 | } __attribute__((packed)); /* level 0x3ee */ | 2312 | } __attribute__((packed)); /* level 0x3ee */ |
2313 | 2313 | ||
2314 | struct file_mode_info { | 2314 | struct file_mode_info { |
@@ -2338,7 +2338,7 @@ typedef struct { | |||
2338 | __le32 Type; | 2338 | __le32 Type; |
2339 | __le64 DevMajor; | 2339 | __le64 DevMajor; |
2340 | __le64 DevMinor; | 2340 | __le64 DevMinor; |
2341 | __u64 UniqueId; | 2341 | __le64 UniqueId; |
2342 | __le64 Permissions; | 2342 | __le64 Permissions; |
2343 | __le64 Nlinks; | 2343 | __le64 Nlinks; |
2344 | char FileName[1]; | 2344 | char FileName[1]; |
@@ -2386,7 +2386,7 @@ typedef struct { | |||
2386 | __le32 FileNameLength; | 2386 | __le32 FileNameLength; |
2387 | __le32 EaSize; /* EA size */ | 2387 | __le32 EaSize; /* EA size */ |
2388 | __le32 Reserved; | 2388 | __le32 Reserved; |
2389 | __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ | 2389 | __le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ |
2390 | char FileName[1]; | 2390 | char FileName[1]; |
2391 | } __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */ | 2391 | } __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */ |
2392 | 2392 | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 4167716d32f2..fae083930eee 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -260,8 +260,7 @@ extern int CIFSUnixCreateSymLink(const int xid, | |||
260 | const struct nls_table *nls_codepage); | 260 | const struct nls_table *nls_codepage); |
261 | extern int CIFSSMBUnixQuerySymLink(const int xid, | 261 | extern int CIFSSMBUnixQuerySymLink(const int xid, |
262 | struct cifsTconInfo *tcon, | 262 | struct cifsTconInfo *tcon, |
263 | const unsigned char *searchName, | 263 | const unsigned char *searchName, char **syminfo, |
264 | char *syminfo, const int buflen, | ||
265 | const struct nls_table *nls_codepage); | 264 | const struct nls_table *nls_codepage); |
266 | extern int CIFSSMBQueryReparseLinkInfo(const int xid, | 265 | extern int CIFSSMBQueryReparseLinkInfo(const int xid, |
267 | struct cifsTconInfo *tcon, | 266 | struct cifsTconInfo *tcon, |
@@ -307,8 +306,6 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | |||
307 | const unsigned char *searchName, __u64 *inode_number, | 306 | const unsigned char *searchName, __u64 *inode_number, |
308 | const struct nls_table *nls_codepage, | 307 | const struct nls_table *nls_codepage, |
309 | int remap_special_chars); | 308 | int remap_special_chars); |
310 | extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, | ||
311 | const struct nls_table *codepage); | ||
312 | extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | 309 | extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, |
313 | const struct nls_table *cp, int mapChars); | 310 | const struct nls_table *cp, int mapChars); |
314 | 311 | ||
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index bc09c998631f..75e6623a8635 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/cifssmb.c | 2 | * fs/cifs/cifssmb.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002,2008 | 4 | * Copyright (C) International Business Machines Corp., 2002,2009 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * Contains the routines for constructing the SMB PDUs themselves | 7 | * Contains the routines for constructing the SMB PDUs themselves |
@@ -81,41 +81,6 @@ static struct { | |||
81 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ | 81 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ |
82 | #endif /* CIFS_POSIX */ | 82 | #endif /* CIFS_POSIX */ |
83 | 83 | ||
84 | /* Allocates buffer into dst and copies smb string from src to it. | ||
85 | * caller is responsible for freeing dst if function returned 0. | ||
86 | * returns: | ||
87 | * on success - 0 | ||
88 | * on failure - errno | ||
89 | */ | ||
90 | static int | ||
91 | cifs_strncpy_to_host(char **dst, const char *src, const int maxlen, | ||
92 | const bool is_unicode, const struct nls_table *nls_codepage) | ||
93 | { | ||
94 | int plen; | ||
95 | |||
96 | if (is_unicode) { | ||
97 | plen = UniStrnlen((wchar_t *)src, maxlen); | ||
98 | *dst = kmalloc(plen + 2, GFP_KERNEL); | ||
99 | if (!*dst) | ||
100 | goto cifs_strncpy_to_host_ErrExit; | ||
101 | cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage); | ||
102 | } else { | ||
103 | plen = strnlen(src, maxlen); | ||
104 | *dst = kmalloc(plen + 2, GFP_KERNEL); | ||
105 | if (!*dst) | ||
106 | goto cifs_strncpy_to_host_ErrExit; | ||
107 | strncpy(*dst, src, plen); | ||
108 | } | ||
109 | (*dst)[plen] = 0; | ||
110 | (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */ | ||
111 | return 0; | ||
112 | |||
113 | cifs_strncpy_to_host_ErrExit: | ||
114 | cERROR(1, ("Failed to allocate buffer for string\n")); | ||
115 | return -ENOMEM; | ||
116 | } | ||
117 | |||
118 | |||
119 | /* Mark as invalid, all open files on tree connections since they | 84 | /* Mark as invalid, all open files on tree connections since they |
120 | were closed when session to server was lost */ | 85 | were closed when session to server was lost */ |
121 | static void mark_open_files_invalid(struct cifsTconInfo *pTcon) | 86 | static void mark_open_files_invalid(struct cifsTconInfo *pTcon) |
@@ -484,6 +449,14 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
484 | cFYI(1, ("Kerberos only mechanism, enable extended security")); | 449 | cFYI(1, ("Kerberos only mechanism, enable extended security")); |
485 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 450 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
486 | } | 451 | } |
452 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
453 | else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) | ||
454 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
455 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { | ||
456 | cFYI(1, ("NTLMSSP only mechanism, enable extended security")); | ||
457 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
458 | } | ||
459 | #endif | ||
487 | 460 | ||
488 | count = 0; | 461 | count = 0; |
489 | for (i = 0; i < CIFS_NUM_PROT; i++) { | 462 | for (i = 0; i < CIFS_NUM_PROT; i++) { |
@@ -620,6 +593,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
620 | server->secType = NTLMv2; | 593 | server->secType = NTLMv2; |
621 | else if (secFlags & CIFSSEC_MAY_KRB5) | 594 | else if (secFlags & CIFSSEC_MAY_KRB5) |
622 | server->secType = Kerberos; | 595 | server->secType = Kerberos; |
596 | else if (secFlags & CIFSSEC_MAY_NTLMSSP) | ||
597 | server->secType = NTLMSSP; | ||
623 | else if (secFlags & CIFSSEC_MAY_LANMAN) | 598 | else if (secFlags & CIFSSEC_MAY_LANMAN) |
624 | server->secType = LANMAN; | 599 | server->secType = LANMAN; |
625 | /* #ifdef CONFIG_CIFS_EXPERIMENTAL | 600 | /* #ifdef CONFIG_CIFS_EXPERIMENTAL |
@@ -1626,6 +1601,8 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1626 | int smb_hdr_len; | 1601 | int smb_hdr_len; |
1627 | int resp_buf_type = 0; | 1602 | int resp_buf_type = 0; |
1628 | 1603 | ||
1604 | *nbytes = 0; | ||
1605 | |||
1629 | cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count)); | 1606 | cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count)); |
1630 | 1607 | ||
1631 | if (tcon->ses->capabilities & CAP_LARGE_FILES) { | 1608 | if (tcon->ses->capabilities & CAP_LARGE_FILES) { |
@@ -1682,11 +1659,9 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1682 | cifs_stats_inc(&tcon->num_writes); | 1659 | cifs_stats_inc(&tcon->num_writes); |
1683 | if (rc) { | 1660 | if (rc) { |
1684 | cFYI(1, ("Send error Write2 = %d", rc)); | 1661 | cFYI(1, ("Send error Write2 = %d", rc)); |
1685 | *nbytes = 0; | ||
1686 | } else if (resp_buf_type == 0) { | 1662 | } else if (resp_buf_type == 0) { |
1687 | /* presumably this can not happen, but best to be safe */ | 1663 | /* presumably this can not happen, but best to be safe */ |
1688 | rc = -EIO; | 1664 | rc = -EIO; |
1689 | *nbytes = 0; | ||
1690 | } else { | 1665 | } else { |
1691 | WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base; | 1666 | WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base; |
1692 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | 1667 | *nbytes = le16_to_cpu(pSMBr->CountHigh); |
@@ -2417,8 +2392,7 @@ winCreateHardLinkRetry: | |||
2417 | 2392 | ||
2418 | int | 2393 | int |
2419 | CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, | 2394 | CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, |
2420 | const unsigned char *searchName, | 2395 | const unsigned char *searchName, char **symlinkinfo, |
2421 | char *symlinkinfo, const int buflen, | ||
2422 | const struct nls_table *nls_codepage) | 2396 | const struct nls_table *nls_codepage) |
2423 | { | 2397 | { |
2424 | /* SMB_QUERY_FILE_UNIX_LINK */ | 2398 | /* SMB_QUERY_FILE_UNIX_LINK */ |
@@ -2428,6 +2402,7 @@ CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, | |||
2428 | int bytes_returned; | 2402 | int bytes_returned; |
2429 | int name_len; | 2403 | int name_len; |
2430 | __u16 params, byte_count; | 2404 | __u16 params, byte_count; |
2405 | char *data_start; | ||
2431 | 2406 | ||
2432 | cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); | 2407 | cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); |
2433 | 2408 | ||
@@ -2482,30 +2457,26 @@ querySymLinkRetry: | |||
2482 | /* decode response */ | 2457 | /* decode response */ |
2483 | 2458 | ||
2484 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 2459 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
2485 | if (rc || (pSMBr->ByteCount < 2)) | ||
2486 | /* BB also check enough total bytes returned */ | 2460 | /* BB also check enough total bytes returned */ |
2487 | rc = -EIO; /* bad smb */ | 2461 | if (rc || (pSMBr->ByteCount < 2)) |
2462 | rc = -EIO; | ||
2488 | else { | 2463 | else { |
2489 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 2464 | bool is_unicode; |
2490 | __u16 count = le16_to_cpu(pSMBr->t2.DataCount); | 2465 | u16 count = le16_to_cpu(pSMBr->t2.DataCount); |
2466 | |||
2467 | data_start = ((char *) &pSMBr->hdr.Protocol) + | ||
2468 | le16_to_cpu(pSMBr->t2.DataOffset); | ||
2469 | |||
2470 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) | ||
2471 | is_unicode = true; | ||
2472 | else | ||
2473 | is_unicode = false; | ||
2491 | 2474 | ||
2492 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2493 | name_len = UniStrnlen((wchar_t *) ((char *) | ||
2494 | &pSMBr->hdr.Protocol + data_offset), | ||
2495 | min_t(const int, buflen, count) / 2); | ||
2496 | /* BB FIXME investigate remapping reserved chars here */ | 2475 | /* BB FIXME investigate remapping reserved chars here */ |
2497 | cifs_strfromUCS_le(symlinkinfo, | 2476 | *symlinkinfo = cifs_strndup_from_ucs(data_start, count, |
2498 | (__le16 *) ((char *)&pSMBr->hdr.Protocol | 2477 | is_unicode, nls_codepage); |
2499 | + data_offset), | 2478 | if (!symlinkinfo) |
2500 | name_len, nls_codepage); | 2479 | rc = -ENOMEM; |
2501 | } else { | ||
2502 | strncpy(symlinkinfo, | ||
2503 | (char *) &pSMBr->hdr.Protocol + | ||
2504 | data_offset, | ||
2505 | min_t(const int, buflen, count)); | ||
2506 | } | ||
2507 | symlinkinfo[buflen] = 0; | ||
2508 | /* just in case so calling code does not go off the end of buffer */ | ||
2509 | } | 2480 | } |
2510 | } | 2481 | } |
2511 | cifs_buf_release(pSMB); | 2482 | cifs_buf_release(pSMB); |
@@ -2603,7 +2574,6 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, | |||
2603 | *pparmlen = parm_count; | 2574 | *pparmlen = parm_count; |
2604 | return 0; | 2575 | return 0; |
2605 | } | 2576 | } |
2606 | #endif /* CIFS_EXPERIMENTAL */ | ||
2607 | 2577 | ||
2608 | int | 2578 | int |
2609 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | 2579 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, |
@@ -2613,7 +2583,6 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
2613 | { | 2583 | { |
2614 | int rc = 0; | 2584 | int rc = 0; |
2615 | int bytes_returned; | 2585 | int bytes_returned; |
2616 | int name_len; | ||
2617 | struct smb_com_transaction_ioctl_req *pSMB; | 2586 | struct smb_com_transaction_ioctl_req *pSMB; |
2618 | struct smb_com_transaction_ioctl_rsp *pSMBr; | 2587 | struct smb_com_transaction_ioctl_rsp *pSMBr; |
2619 | 2588 | ||
@@ -2650,59 +2619,55 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
2650 | } else { /* decode response */ | 2619 | } else { /* decode response */ |
2651 | __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); | 2620 | __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); |
2652 | __u32 data_count = le32_to_cpu(pSMBr->DataCount); | 2621 | __u32 data_count = le32_to_cpu(pSMBr->DataCount); |
2653 | if ((pSMBr->ByteCount < 2) || (data_offset > 512)) | 2622 | if ((pSMBr->ByteCount < 2) || (data_offset > 512)) { |
2654 | /* BB also check enough total bytes returned */ | 2623 | /* BB also check enough total bytes returned */ |
2655 | rc = -EIO; /* bad smb */ | 2624 | rc = -EIO; /* bad smb */ |
2656 | else { | 2625 | goto qreparse_out; |
2657 | if (data_count && (data_count < 2048)) { | 2626 | } |
2658 | char *end_of_smb = 2 /* sizeof byte count */ + | 2627 | if (data_count && (data_count < 2048)) { |
2659 | pSMBr->ByteCount + | 2628 | char *end_of_smb = 2 /* sizeof byte count */ + |
2660 | (char *)&pSMBr->ByteCount; | 2629 | pSMBr->ByteCount + (char *)&pSMBr->ByteCount; |
2661 | 2630 | ||
2662 | struct reparse_data *reparse_buf = | 2631 | struct reparse_data *reparse_buf = |
2663 | (struct reparse_data *) | 2632 | (struct reparse_data *) |
2664 | ((char *)&pSMBr->hdr.Protocol | 2633 | ((char *)&pSMBr->hdr.Protocol |
2665 | + data_offset); | 2634 | + data_offset); |
2666 | if ((char *)reparse_buf >= end_of_smb) { | 2635 | if ((char *)reparse_buf >= end_of_smb) { |
2667 | rc = -EIO; | 2636 | rc = -EIO; |
2668 | goto qreparse_out; | 2637 | goto qreparse_out; |
2669 | } | 2638 | } |
2670 | if ((reparse_buf->LinkNamesBuf + | 2639 | if ((reparse_buf->LinkNamesBuf + |
2671 | reparse_buf->TargetNameOffset + | 2640 | reparse_buf->TargetNameOffset + |
2672 | reparse_buf->TargetNameLen) > | 2641 | reparse_buf->TargetNameLen) > end_of_smb) { |
2673 | end_of_smb) { | 2642 | cFYI(1, ("reparse buf beyond SMB")); |
2674 | cFYI(1, ("reparse buf beyond SMB")); | 2643 | rc = -EIO; |
2675 | rc = -EIO; | 2644 | goto qreparse_out; |
2676 | goto qreparse_out; | 2645 | } |
2677 | } | ||
2678 | 2646 | ||
2679 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { | 2647 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { |
2680 | name_len = UniStrnlen((wchar_t *) | 2648 | cifs_from_ucs2(symlinkinfo, (__le16 *) |
2681 | (reparse_buf->LinkNamesBuf + | 2649 | (reparse_buf->LinkNamesBuf + |
2682 | reparse_buf->TargetNameOffset), | 2650 | reparse_buf->TargetNameOffset), |
2683 | min(buflen/2, | 2651 | buflen, |
2684 | reparse_buf->TargetNameLen / 2)); | 2652 | reparse_buf->TargetNameLen, |
2685 | cifs_strfromUCS_le(symlinkinfo, | 2653 | nls_codepage, 0); |
2686 | (__le16 *) (reparse_buf->LinkNamesBuf + | 2654 | } else { /* ASCII names */ |
2687 | reparse_buf->TargetNameOffset), | 2655 | strncpy(symlinkinfo, |
2688 | name_len, nls_codepage); | 2656 | reparse_buf->LinkNamesBuf + |
2689 | } else { /* ASCII names */ | 2657 | reparse_buf->TargetNameOffset, |
2690 | strncpy(symlinkinfo, | 2658 | min_t(const int, buflen, |
2691 | reparse_buf->LinkNamesBuf + | 2659 | reparse_buf->TargetNameLen)); |
2692 | reparse_buf->TargetNameOffset, | ||
2693 | min_t(const int, buflen, | ||
2694 | reparse_buf->TargetNameLen)); | ||
2695 | } | ||
2696 | } else { | ||
2697 | rc = -EIO; | ||
2698 | cFYI(1, ("Invalid return data count on " | ||
2699 | "get reparse info ioctl")); | ||
2700 | } | 2660 | } |
2701 | symlinkinfo[buflen] = 0; /* just in case so the caller | 2661 | } else { |
2702 | does not go off the end of the buffer */ | 2662 | rc = -EIO; |
2703 | cFYI(1, ("readlink result - %s", symlinkinfo)); | 2663 | cFYI(1, ("Invalid return data count on " |
2664 | "get reparse info ioctl")); | ||
2704 | } | 2665 | } |
2666 | symlinkinfo[buflen] = 0; /* just in case so the caller | ||
2667 | does not go off the end of the buffer */ | ||
2668 | cFYI(1, ("readlink result - %s", symlinkinfo)); | ||
2705 | } | 2669 | } |
2670 | |||
2706 | qreparse_out: | 2671 | qreparse_out: |
2707 | cifs_buf_release(pSMB); | 2672 | cifs_buf_release(pSMB); |
2708 | 2673 | ||
@@ -2711,6 +2676,7 @@ qreparse_out: | |||
2711 | 2676 | ||
2712 | return rc; | 2677 | return rc; |
2713 | } | 2678 | } |
2679 | #endif /* CIFS_EXPERIMENTAL */ | ||
2714 | 2680 | ||
2715 | #ifdef CONFIG_CIFS_POSIX | 2681 | #ifdef CONFIG_CIFS_POSIX |
2716 | 2682 | ||
@@ -3918,7 +3884,7 @@ GetInodeNumberRetry: | |||
3918 | } | 3884 | } |
3919 | pfinfo = (struct file_internal_info *) | 3885 | pfinfo = (struct file_internal_info *) |
3920 | (data_offset + (char *) &pSMBr->hdr.Protocol); | 3886 | (data_offset + (char *) &pSMBr->hdr.Protocol); |
3921 | *inode_number = pfinfo->UniqueId; | 3887 | *inode_number = le64_to_cpu(pfinfo->UniqueId); |
3922 | } | 3888 | } |
3923 | } | 3889 | } |
3924 | GetInodeNumOut: | 3890 | GetInodeNumOut: |
@@ -3928,27 +3894,6 @@ GetInodeNumOut: | |||
3928 | return rc; | 3894 | return rc; |
3929 | } | 3895 | } |
3930 | 3896 | ||
3931 | /* computes length of UCS string converted to host codepage | ||
3932 | * @src: UCS string | ||
3933 | * @maxlen: length of the input string in UCS characters | ||
3934 | * (not in bytes) | ||
3935 | * | ||
3936 | * return: size of input string in host codepage | ||
3937 | */ | ||
3938 | static int hostlen_fromUCS(const __le16 *src, const int maxlen, | ||
3939 | const struct nls_table *nls_codepage) { | ||
3940 | int i; | ||
3941 | int hostlen = 0; | ||
3942 | char to[4]; | ||
3943 | int charlen; | ||
3944 | for (i = 0; (i < maxlen) && src[i]; ++i) { | ||
3945 | charlen = nls_codepage->uni2char(le16_to_cpu(src[i]), | ||
3946 | to, NLS_MAX_CHARSET_SIZE); | ||
3947 | hostlen += charlen > 0 ? charlen : 1; | ||
3948 | } | ||
3949 | return hostlen; | ||
3950 | } | ||
3951 | |||
3952 | /* parses DFS refferal V3 structure | 3897 | /* parses DFS refferal V3 structure |
3953 | * caller is responsible for freeing target_nodes | 3898 | * caller is responsible for freeing target_nodes |
3954 | * returns: | 3899 | * returns: |
@@ -3994,7 +3939,7 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
3994 | 3939 | ||
3995 | cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n", | 3940 | cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n", |
3996 | *num_of_nodes, | 3941 | *num_of_nodes, |
3997 | le16_to_cpu(pSMBr->DFSFlags))); | 3942 | le32_to_cpu(pSMBr->DFSFlags))); |
3998 | 3943 | ||
3999 | *target_nodes = kzalloc(sizeof(struct dfs_info3_param) * | 3944 | *target_nodes = kzalloc(sizeof(struct dfs_info3_param) * |
4000 | *num_of_nodes, GFP_KERNEL); | 3945 | *num_of_nodes, GFP_KERNEL); |
@@ -4010,14 +3955,14 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
4010 | int max_len; | 3955 | int max_len; |
4011 | struct dfs_info3_param *node = (*target_nodes)+i; | 3956 | struct dfs_info3_param *node = (*target_nodes)+i; |
4012 | 3957 | ||
4013 | node->flags = le16_to_cpu(pSMBr->DFSFlags); | 3958 | node->flags = le32_to_cpu(pSMBr->DFSFlags); |
4014 | if (is_unicode) { | 3959 | if (is_unicode) { |
4015 | __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, | 3960 | __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, |
4016 | GFP_KERNEL); | 3961 | GFP_KERNEL); |
4017 | cifsConvertToUCS((__le16 *) tmp, searchName, | 3962 | cifsConvertToUCS((__le16 *) tmp, searchName, |
4018 | PATH_MAX, nls_codepage, remap); | 3963 | PATH_MAX, nls_codepage, remap); |
4019 | node->path_consumed = hostlen_fromUCS(tmp, | 3964 | node->path_consumed = cifs_ucs2_bytes(tmp, |
4020 | le16_to_cpu(pSMBr->PathConsumed)/2, | 3965 | le16_to_cpu(pSMBr->PathConsumed), |
4021 | nls_codepage); | 3966 | nls_codepage); |
4022 | kfree(tmp); | 3967 | kfree(tmp); |
4023 | } else | 3968 | } else |
@@ -4029,20 +3974,24 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
4029 | /* copy DfsPath */ | 3974 | /* copy DfsPath */ |
4030 | temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); | 3975 | temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); |
4031 | max_len = data_end - temp; | 3976 | max_len = data_end - temp; |
4032 | rc = cifs_strncpy_to_host(&(node->path_name), temp, | 3977 | node->path_name = cifs_strndup_from_ucs(temp, max_len, |
4033 | max_len, is_unicode, nls_codepage); | 3978 | is_unicode, nls_codepage); |
4034 | if (rc) | 3979 | if (IS_ERR(node->path_name)) { |
3980 | rc = PTR_ERR(node->path_name); | ||
3981 | node->path_name = NULL; | ||
4035 | goto parse_DFS_referrals_exit; | 3982 | goto parse_DFS_referrals_exit; |
3983 | } | ||
4036 | 3984 | ||
4037 | /* copy link target UNC */ | 3985 | /* copy link target UNC */ |
4038 | temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); | 3986 | temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); |
4039 | max_len = data_end - temp; | 3987 | max_len = data_end - temp; |
4040 | rc = cifs_strncpy_to_host(&(node->node_name), temp, | 3988 | node->node_name = cifs_strndup_from_ucs(temp, max_len, |
4041 | max_len, is_unicode, nls_codepage); | 3989 | is_unicode, nls_codepage); |
4042 | if (rc) | 3990 | if (IS_ERR(node->node_name)) { |
3991 | rc = PTR_ERR(node->node_name); | ||
3992 | node->node_name = NULL; | ||
4043 | goto parse_DFS_referrals_exit; | 3993 | goto parse_DFS_referrals_exit; |
4044 | 3994 | } | |
4045 | ref += le16_to_cpu(ref->Size); | ||
4046 | } | 3995 | } |
4047 | 3996 | ||
4048 | parse_DFS_referrals_exit: | 3997 | parse_DFS_referrals_exit: |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0de3b5615a22..4aa81a507b74 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/connect.c | 2 | * fs/cifs/connect.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002,2008 | 4 | * Copyright (C) International Business Machines Corp., 2002,2009 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/kthread.h> | 32 | #include <linux/kthread.h> |
33 | #include <linux/pagevec.h> | 33 | #include <linux/pagevec.h> |
34 | #include <linux/freezer.h> | 34 | #include <linux/freezer.h> |
35 | #include <linux/namei.h> | ||
35 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
36 | #include <asm/processor.h> | 37 | #include <asm/processor.h> |
37 | #include <net/ipv6.h> | 38 | #include <net/ipv6.h> |
@@ -978,6 +979,13 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
978 | return 1; | 979 | return 1; |
979 | } else if (strnicmp(value, "krb5", 4) == 0) { | 980 | } else if (strnicmp(value, "krb5", 4) == 0) { |
980 | vol->secFlg |= CIFSSEC_MAY_KRB5; | 981 | vol->secFlg |= CIFSSEC_MAY_KRB5; |
982 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
983 | } else if (strnicmp(value, "ntlmsspi", 8) == 0) { | ||
984 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP | | ||
985 | CIFSSEC_MUST_SIGN; | ||
986 | } else if (strnicmp(value, "ntlmssp", 7) == 0) { | ||
987 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP; | ||
988 | #endif | ||
981 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { | 989 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { |
982 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | | 990 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | |
983 | CIFSSEC_MUST_SIGN; | 991 | CIFSSEC_MUST_SIGN; |
@@ -2214,9 +2222,58 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon, | |||
2214 | return rc; | 2222 | return rc; |
2215 | } | 2223 | } |
2216 | 2224 | ||
2225 | static void | ||
2226 | cleanup_volume_info(struct smb_vol **pvolume_info) | ||
2227 | { | ||
2228 | struct smb_vol *volume_info; | ||
2229 | |||
2230 | if (!pvolume_info && !*pvolume_info) | ||
2231 | return; | ||
2232 | |||
2233 | volume_info = *pvolume_info; | ||
2234 | kzfree(volume_info->password); | ||
2235 | kfree(volume_info->UNC); | ||
2236 | kfree(volume_info->prepath); | ||
2237 | kfree(volume_info); | ||
2238 | *pvolume_info = NULL; | ||
2239 | return; | ||
2240 | } | ||
2241 | |||
2242 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
2243 | /* build_path_to_root returns full path to root when | ||
2244 | * we do not have an exiting connection (tcon) */ | ||
2245 | static char * | ||
2246 | build_unc_path_to_root(const struct smb_vol *volume_info, | ||
2247 | const struct cifs_sb_info *cifs_sb) | ||
2248 | { | ||
2249 | char *full_path; | ||
2250 | |||
2251 | int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1); | ||
2252 | full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL); | ||
2253 | if (full_path == NULL) | ||
2254 | return ERR_PTR(-ENOMEM); | ||
2255 | |||
2256 | strncpy(full_path, volume_info->UNC, unc_len); | ||
2257 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { | ||
2258 | int i; | ||
2259 | for (i = 0; i < unc_len; i++) { | ||
2260 | if (full_path[i] == '\\') | ||
2261 | full_path[i] = '/'; | ||
2262 | } | ||
2263 | } | ||
2264 | |||
2265 | if (cifs_sb->prepathlen) | ||
2266 | strncpy(full_path + unc_len, cifs_sb->prepath, | ||
2267 | cifs_sb->prepathlen); | ||
2268 | |||
2269 | full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */ | ||
2270 | return full_path; | ||
2271 | } | ||
2272 | #endif | ||
2273 | |||
2217 | int | 2274 | int |
2218 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | 2275 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, |
2219 | char *mount_data, const char *devname) | 2276 | char *mount_data_global, const char *devname) |
2220 | { | 2277 | { |
2221 | int rc = 0; | 2278 | int rc = 0; |
2222 | int xid; | 2279 | int xid; |
@@ -2225,6 +2282,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2225 | struct cifsTconInfo *tcon = NULL; | 2282 | struct cifsTconInfo *tcon = NULL; |
2226 | struct TCP_Server_Info *srvTcp = NULL; | 2283 | struct TCP_Server_Info *srvTcp = NULL; |
2227 | char *full_path; | 2284 | char *full_path; |
2285 | char *mount_data = mount_data_global; | ||
2286 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
2287 | struct dfs_info3_param *referrals = NULL; | ||
2288 | unsigned int num_referrals = 0; | ||
2289 | int referral_walks_count = 0; | ||
2290 | try_mount_again: | ||
2291 | #endif | ||
2292 | full_path = NULL; | ||
2228 | 2293 | ||
2229 | xid = GetXid(); | 2294 | xid = GetXid(); |
2230 | 2295 | ||
@@ -2371,11 +2436,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2371 | } | 2436 | } |
2372 | } | 2437 | } |
2373 | 2438 | ||
2374 | /* check for null share name ie connect to dfs root */ | ||
2375 | if ((strchr(volume_info->UNC + 3, '\\') == NULL) | 2439 | if ((strchr(volume_info->UNC + 3, '\\') == NULL) |
2376 | && (strchr(volume_info->UNC + 3, '/') == NULL)) { | 2440 | && (strchr(volume_info->UNC + 3, '/') == NULL)) { |
2377 | /* rc = connect_to_dfs_path(...) */ | 2441 | cERROR(1, ("Missing share name")); |
2378 | cFYI(1, ("DFS root not supported")); | ||
2379 | rc = -ENODEV; | 2442 | rc = -ENODEV; |
2380 | goto mount_fail_check; | 2443 | goto mount_fail_check; |
2381 | } else { | 2444 | } else { |
@@ -2392,7 +2455,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2392 | } | 2455 | } |
2393 | } | 2456 | } |
2394 | if (rc) | 2457 | if (rc) |
2395 | goto mount_fail_check; | 2458 | goto remote_path_check; |
2396 | tcon->seal = volume_info->seal; | 2459 | tcon->seal = volume_info->seal; |
2397 | write_lock(&cifs_tcp_ses_lock); | 2460 | write_lock(&cifs_tcp_ses_lock); |
2398 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); | 2461 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); |
@@ -2417,19 +2480,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2417 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ | 2480 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ |
2418 | sb->s_time_gran = 100; | 2481 | sb->s_time_gran = 100; |
2419 | 2482 | ||
2420 | mount_fail_check: | 2483 | if (rc) |
2421 | /* on error free sesinfo and tcon struct if needed */ | 2484 | goto remote_path_check; |
2422 | if (rc) { | 2485 | |
2423 | /* If find_unc succeeded then rc == 0 so we can not end */ | ||
2424 | /* up accidently freeing someone elses tcon struct */ | ||
2425 | if (tcon) | ||
2426 | cifs_put_tcon(tcon); | ||
2427 | else if (pSesInfo) | ||
2428 | cifs_put_smb_ses(pSesInfo); | ||
2429 | else | ||
2430 | cifs_put_tcp_session(srvTcp); | ||
2431 | goto out; | ||
2432 | } | ||
2433 | cifs_sb->tcon = tcon; | 2486 | cifs_sb->tcon = tcon; |
2434 | 2487 | ||
2435 | /* do not care if following two calls succeed - informational */ | 2488 | /* do not care if following two calls succeed - informational */ |
@@ -2461,7 +2514,9 @@ mount_fail_check: | |||
2461 | cifs_sb->rsize = min(cifs_sb->rsize, | 2514 | cifs_sb->rsize = min(cifs_sb->rsize, |
2462 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); | 2515 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); |
2463 | 2516 | ||
2464 | if (!rc && cifs_sb->prepathlen) { | 2517 | remote_path_check: |
2518 | /* check if a whole path (including prepath) is not remote */ | ||
2519 | if (!rc && cifs_sb->prepathlen && tcon) { | ||
2465 | /* build_path_to_root works only when we have a valid tcon */ | 2520 | /* build_path_to_root works only when we have a valid tcon */ |
2466 | full_path = cifs_build_path_to_root(cifs_sb); | 2521 | full_path = cifs_build_path_to_root(cifs_sb); |
2467 | if (full_path == NULL) { | 2522 | if (full_path == NULL) { |
@@ -2469,1079 +2524,91 @@ mount_fail_check: | |||
2469 | goto mount_fail_check; | 2524 | goto mount_fail_check; |
2470 | } | 2525 | } |
2471 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); | 2526 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); |
2472 | if (rc) { | 2527 | if (rc != -EREMOTE) { |
2473 | cERROR(1, ("Path %s in not accessible: %d", | ||
2474 | full_path, rc)); | ||
2475 | kfree(full_path); | 2528 | kfree(full_path); |
2476 | goto mount_fail_check; | 2529 | goto mount_fail_check; |
2477 | } | 2530 | } |
2478 | kfree(full_path); | 2531 | kfree(full_path); |
2479 | } | 2532 | } |
2480 | 2533 | ||
2481 | /* volume_info->password is freed above when existing session found | 2534 | /* get referral if needed */ |
2482 | (in which case it is not needed anymore) but when new sesion is created | 2535 | if (rc == -EREMOTE) { |
2483 | the password ptr is put in the new session structure (in which case the | 2536 | #ifdef CONFIG_CIFS_DFS_UPCALL |
2484 | password will be freed at unmount time) */ | 2537 | if (referral_walks_count > MAX_NESTED_LINKS) { |
2485 | out: | 2538 | /* |
2486 | /* zero out password before freeing */ | 2539 | * BB: when we implement proper loop detection, |
2487 | if (volume_info) { | 2540 | * we will remove this check. But now we need it |
2488 | if (volume_info->password != NULL) { | 2541 | * to prevent an indefinite loop if 'DFS tree' is |
2489 | memset(volume_info->password, 0, | 2542 | * misconfigured (i.e. has loops). |
2490 | strlen(volume_info->password)); | 2543 | */ |
2491 | kfree(volume_info->password); | 2544 | rc = -ELOOP; |
2492 | } | 2545 | goto mount_fail_check; |
2493 | kfree(volume_info->UNC); | ||
2494 | kfree(volume_info->prepath); | ||
2495 | kfree(volume_info); | ||
2496 | } | ||
2497 | FreeXid(xid); | ||
2498 | return rc; | ||
2499 | } | ||
2500 | |||
2501 | static int | ||
2502 | CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
2503 | char session_key[CIFS_SESS_KEY_SIZE], | ||
2504 | const struct nls_table *nls_codepage) | ||
2505 | { | ||
2506 | struct smb_hdr *smb_buffer; | ||
2507 | struct smb_hdr *smb_buffer_response; | ||
2508 | SESSION_SETUP_ANDX *pSMB; | ||
2509 | SESSION_SETUP_ANDX *pSMBr; | ||
2510 | char *bcc_ptr; | ||
2511 | char *user; | ||
2512 | char *domain; | ||
2513 | int rc = 0; | ||
2514 | int remaining_words = 0; | ||
2515 | int bytes_returned = 0; | ||
2516 | int len; | ||
2517 | __u32 capabilities; | ||
2518 | __u16 count; | ||
2519 | |||
2520 | cFYI(1, ("In sesssetup")); | ||
2521 | if (ses == NULL) | ||
2522 | return -EINVAL; | ||
2523 | user = ses->userName; | ||
2524 | domain = ses->domainName; | ||
2525 | smb_buffer = cifs_buf_get(); | ||
2526 | |||
2527 | if (smb_buffer == NULL) | ||
2528 | return -ENOMEM; | ||
2529 | |||
2530 | smb_buffer_response = smb_buffer; | ||
2531 | pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
2532 | |||
2533 | /* send SMBsessionSetup here */ | ||
2534 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
2535 | NULL /* no tCon exists yet */ , 13 /* wct */ ); | ||
2536 | |||
2537 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2538 | pSMB->req_no_secext.AndXCommand = 0xFF; | ||
2539 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
2540 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
2541 | |||
2542 | if (ses->server->secMode & | ||
2543 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
2544 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
2545 | |||
2546 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
2547 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; | ||
2548 | if (ses->capabilities & CAP_UNICODE) { | ||
2549 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
2550 | capabilities |= CAP_UNICODE; | ||
2551 | } | ||
2552 | if (ses->capabilities & CAP_STATUS32) { | ||
2553 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
2554 | capabilities |= CAP_STATUS32; | ||
2555 | } | ||
2556 | if (ses->capabilities & CAP_DFS) { | ||
2557 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
2558 | capabilities |= CAP_DFS; | ||
2559 | } | ||
2560 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
2561 | |||
2562 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | ||
2563 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
2564 | |||
2565 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
2566 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
2567 | bcc_ptr = pByteArea(smb_buffer); | ||
2568 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); | ||
2569 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
2570 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); | ||
2571 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
2572 | |||
2573 | if (ses->capabilities & CAP_UNICODE) { | ||
2574 | if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ | ||
2575 | *bcc_ptr = 0; | ||
2576 | bcc_ptr++; | ||
2577 | } | ||
2578 | if (user == NULL) | ||
2579 | bytes_returned = 0; /* skip null user */ | ||
2580 | else | ||
2581 | bytes_returned = | ||
2582 | cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, | ||
2583 | nls_codepage); | ||
2584 | /* convert number of 16 bit words to bytes */ | ||
2585 | bcc_ptr += 2 * bytes_returned; | ||
2586 | bcc_ptr += 2; /* trailing null */ | ||
2587 | if (domain == NULL) | ||
2588 | bytes_returned = | ||
2589 | cifs_strtoUCS((__le16 *) bcc_ptr, | ||
2590 | "CIFS_LINUX_DOM", 32, nls_codepage); | ||
2591 | else | ||
2592 | bytes_returned = | ||
2593 | cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, | ||
2594 | nls_codepage); | ||
2595 | bcc_ptr += 2 * bytes_returned; | ||
2596 | bcc_ptr += 2; | ||
2597 | bytes_returned = | ||
2598 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
2599 | 32, nls_codepage); | ||
2600 | bcc_ptr += 2 * bytes_returned; | ||
2601 | bytes_returned = | ||
2602 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, | ||
2603 | 32, nls_codepage); | ||
2604 | bcc_ptr += 2 * bytes_returned; | ||
2605 | bcc_ptr += 2; | ||
2606 | bytes_returned = | ||
2607 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
2608 | 64, nls_codepage); | ||
2609 | bcc_ptr += 2 * bytes_returned; | ||
2610 | bcc_ptr += 2; | ||
2611 | } else { | ||
2612 | if (user != NULL) { | ||
2613 | strncpy(bcc_ptr, user, 200); | ||
2614 | bcc_ptr += strnlen(user, 200); | ||
2615 | } | ||
2616 | *bcc_ptr = 0; | ||
2617 | bcc_ptr++; | ||
2618 | if (domain == NULL) { | ||
2619 | strcpy(bcc_ptr, "CIFS_LINUX_DOM"); | ||
2620 | bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; | ||
2621 | } else { | ||
2622 | strncpy(bcc_ptr, domain, 64); | ||
2623 | bcc_ptr += strnlen(domain, 64); | ||
2624 | *bcc_ptr = 0; | ||
2625 | bcc_ptr++; | ||
2626 | } | ||
2627 | strcpy(bcc_ptr, "Linux version "); | ||
2628 | bcc_ptr += strlen("Linux version "); | ||
2629 | strcpy(bcc_ptr, utsname()->release); | ||
2630 | bcc_ptr += strlen(utsname()->release) + 1; | ||
2631 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
2632 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
2633 | } | ||
2634 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
2635 | smb_buffer->smb_buf_length += count; | ||
2636 | pSMB->req_no_secext.ByteCount = cpu_to_le16(count); | ||
2637 | |||
2638 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
2639 | &bytes_returned, CIFS_LONG_OP); | ||
2640 | if (rc) { | ||
2641 | /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ | ||
2642 | } else if ((smb_buffer_response->WordCount == 3) | ||
2643 | || (smb_buffer_response->WordCount == 4)) { | ||
2644 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
2645 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
2646 | if (action & GUEST_LOGIN) | ||
2647 | cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ | ||
2648 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format | ||
2649 | (little endian) */ | ||
2650 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
2651 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
2652 | bcc_ptr = pByteArea(smb_buffer_response); | ||
2653 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
2654 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
2655 | && (blob_len < pSMBr->resp.ByteCount))) { | ||
2656 | if (pSMBr->resp.hdr.WordCount == 4) | ||
2657 | bcc_ptr += blob_len; | ||
2658 | |||
2659 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
2660 | if ((long) (bcc_ptr) % 2) { | ||
2661 | remaining_words = | ||
2662 | (BCC(smb_buffer_response) - 1) / 2; | ||
2663 | /* Unicode strings must be word | ||
2664 | aligned */ | ||
2665 | bcc_ptr++; | ||
2666 | } else { | ||
2667 | remaining_words = | ||
2668 | BCC(smb_buffer_response) / 2; | ||
2669 | } | ||
2670 | len = | ||
2671 | UniStrnlen((wchar_t *) bcc_ptr, | ||
2672 | remaining_words - 1); | ||
2673 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
2674 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
2675 | terminating last Unicode string in response */ | ||
2676 | if (ses->serverOS) | ||
2677 | kfree(ses->serverOS); | ||
2678 | ses->serverOS = kzalloc(2 * (len + 1), | ||
2679 | GFP_KERNEL); | ||
2680 | if (ses->serverOS == NULL) | ||
2681 | goto sesssetup_nomem; | ||
2682 | cifs_strfromUCS_le(ses->serverOS, | ||
2683 | (__le16 *)bcc_ptr, | ||
2684 | len, nls_codepage); | ||
2685 | bcc_ptr += 2 * (len + 1); | ||
2686 | remaining_words -= len + 1; | ||
2687 | ses->serverOS[2 * len] = 0; | ||
2688 | ses->serverOS[1 + (2 * len)] = 0; | ||
2689 | if (remaining_words > 0) { | ||
2690 | len = UniStrnlen((wchar_t *)bcc_ptr, | ||
2691 | remaining_words-1); | ||
2692 | kfree(ses->serverNOS); | ||
2693 | ses->serverNOS = kzalloc(2 * (len + 1), | ||
2694 | GFP_KERNEL); | ||
2695 | if (ses->serverNOS == NULL) | ||
2696 | goto sesssetup_nomem; | ||
2697 | cifs_strfromUCS_le(ses->serverNOS, | ||
2698 | (__le16 *)bcc_ptr, | ||
2699 | len, nls_codepage); | ||
2700 | bcc_ptr += 2 * (len + 1); | ||
2701 | ses->serverNOS[2 * len] = 0; | ||
2702 | ses->serverNOS[1 + (2 * len)] = 0; | ||
2703 | if (strncmp(ses->serverNOS, | ||
2704 | "NT LAN Manager 4", 16) == 0) { | ||
2705 | cFYI(1, ("NT4 server")); | ||
2706 | ses->flags |= CIFS_SES_NT4; | ||
2707 | } | ||
2708 | remaining_words -= len + 1; | ||
2709 | if (remaining_words > 0) { | ||
2710 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
2711 | /* last string is not always null terminated | ||
2712 | (for e.g. for Windows XP & 2000) */ | ||
2713 | if (ses->serverDomain) | ||
2714 | kfree(ses->serverDomain); | ||
2715 | ses->serverDomain = | ||
2716 | kzalloc(2*(len+1), | ||
2717 | GFP_KERNEL); | ||
2718 | if (ses->serverDomain == NULL) | ||
2719 | goto sesssetup_nomem; | ||
2720 | cifs_strfromUCS_le(ses->serverDomain, | ||
2721 | (__le16 *)bcc_ptr, | ||
2722 | len, nls_codepage); | ||
2723 | bcc_ptr += 2 * (len + 1); | ||
2724 | ses->serverDomain[2*len] = 0; | ||
2725 | ses->serverDomain[1+(2*len)] = 0; | ||
2726 | } else { /* else no more room so create | ||
2727 | dummy domain string */ | ||
2728 | if (ses->serverDomain) | ||
2729 | kfree(ses->serverDomain); | ||
2730 | ses->serverDomain = | ||
2731 | kzalloc(2, GFP_KERNEL); | ||
2732 | } | ||
2733 | } else { /* no room so create dummy domain | ||
2734 | and NOS string */ | ||
2735 | |||
2736 | /* if these kcallocs fail not much we | ||
2737 | can do, but better to not fail the | ||
2738 | sesssetup itself */ | ||
2739 | kfree(ses->serverDomain); | ||
2740 | ses->serverDomain = | ||
2741 | kzalloc(2, GFP_KERNEL); | ||
2742 | kfree(ses->serverNOS); | ||
2743 | ses->serverNOS = | ||
2744 | kzalloc(2, GFP_KERNEL); | ||
2745 | } | ||
2746 | } else { /* ASCII */ | ||
2747 | len = strnlen(bcc_ptr, 1024); | ||
2748 | if (((long) bcc_ptr + len) - (long) | ||
2749 | pByteArea(smb_buffer_response) | ||
2750 | <= BCC(smb_buffer_response)) { | ||
2751 | kfree(ses->serverOS); | ||
2752 | ses->serverOS = kzalloc(len + 1, | ||
2753 | GFP_KERNEL); | ||
2754 | if (ses->serverOS == NULL) | ||
2755 | goto sesssetup_nomem; | ||
2756 | strncpy(ses->serverOS, bcc_ptr, len); | ||
2757 | |||
2758 | bcc_ptr += len; | ||
2759 | /* null terminate the string */ | ||
2760 | bcc_ptr[0] = 0; | ||
2761 | bcc_ptr++; | ||
2762 | |||
2763 | len = strnlen(bcc_ptr, 1024); | ||
2764 | kfree(ses->serverNOS); | ||
2765 | ses->serverNOS = kzalloc(len + 1, | ||
2766 | GFP_KERNEL); | ||
2767 | if (ses->serverNOS == NULL) | ||
2768 | goto sesssetup_nomem; | ||
2769 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
2770 | bcc_ptr += len; | ||
2771 | bcc_ptr[0] = 0; | ||
2772 | bcc_ptr++; | ||
2773 | |||
2774 | len = strnlen(bcc_ptr, 1024); | ||
2775 | if (ses->serverDomain) | ||
2776 | kfree(ses->serverDomain); | ||
2777 | ses->serverDomain = kzalloc(len + 1, | ||
2778 | GFP_KERNEL); | ||
2779 | if (ses->serverDomain == NULL) | ||
2780 | goto sesssetup_nomem; | ||
2781 | strncpy(ses->serverDomain, bcc_ptr, | ||
2782 | len); | ||
2783 | bcc_ptr += len; | ||
2784 | bcc_ptr[0] = 0; | ||
2785 | bcc_ptr++; | ||
2786 | } else | ||
2787 | cFYI(1, | ||
2788 | ("Variable field of length %d " | ||
2789 | "extends beyond end of smb ", | ||
2790 | len)); | ||
2791 | } | ||
2792 | } else { | ||
2793 | cERROR(1, ("Security Blob Length extends beyond " | ||
2794 | "end of SMB")); | ||
2795 | } | 2546 | } |
2796 | } else { | 2547 | /* convert forward to back slashes in prepath here if needed */ |
2797 | cERROR(1, ("Invalid Word count %d: ", | 2548 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) |
2798 | smb_buffer_response->WordCount)); | 2549 | convert_delimiter(cifs_sb->prepath, |
2799 | rc = -EIO; | 2550 | CIFS_DIR_SEP(cifs_sb)); |
2800 | } | 2551 | full_path = build_unc_path_to_root(volume_info, cifs_sb); |
2801 | sesssetup_nomem: /* do not return an error on nomem for the info strings, | 2552 | if (IS_ERR(full_path)) { |
2802 | since that could make reconnection harder, and | 2553 | rc = PTR_ERR(full_path); |
2803 | reconnection might be needed to free memory */ | 2554 | goto mount_fail_check; |
2804 | cifs_buf_release(smb_buffer); | ||
2805 | |||
2806 | return rc; | ||
2807 | } | ||
2808 | |||
2809 | static int | ||
2810 | CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | ||
2811 | struct cifsSesInfo *ses, bool *pNTLMv2_flag, | ||
2812 | const struct nls_table *nls_codepage) | ||
2813 | { | ||
2814 | struct smb_hdr *smb_buffer; | ||
2815 | struct smb_hdr *smb_buffer_response; | ||
2816 | SESSION_SETUP_ANDX *pSMB; | ||
2817 | SESSION_SETUP_ANDX *pSMBr; | ||
2818 | char *bcc_ptr; | ||
2819 | char *domain; | ||
2820 | int rc = 0; | ||
2821 | int remaining_words = 0; | ||
2822 | int bytes_returned = 0; | ||
2823 | int len; | ||
2824 | int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE); | ||
2825 | PNEGOTIATE_MESSAGE SecurityBlob; | ||
2826 | PCHALLENGE_MESSAGE SecurityBlob2; | ||
2827 | __u32 negotiate_flags, capabilities; | ||
2828 | __u16 count; | ||
2829 | |||
2830 | cFYI(1, ("In NTLMSSP sesssetup (negotiate)")); | ||
2831 | if (ses == NULL) | ||
2832 | return -EINVAL; | ||
2833 | domain = ses->domainName; | ||
2834 | *pNTLMv2_flag = false; | ||
2835 | smb_buffer = cifs_buf_get(); | ||
2836 | if (smb_buffer == NULL) { | ||
2837 | return -ENOMEM; | ||
2838 | } | ||
2839 | smb_buffer_response = smb_buffer; | ||
2840 | pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
2841 | pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; | ||
2842 | |||
2843 | /* send SMBsessionSetup here */ | ||
2844 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
2845 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
2846 | |||
2847 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2848 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
2849 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | ||
2850 | |||
2851 | pSMB->req.AndXCommand = 0xFF; | ||
2852 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
2853 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
2854 | |||
2855 | if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
2856 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
2857 | |||
2858 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
2859 | CAP_EXTENDED_SECURITY; | ||
2860 | if (ses->capabilities & CAP_UNICODE) { | ||
2861 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
2862 | capabilities |= CAP_UNICODE; | ||
2863 | } | ||
2864 | if (ses->capabilities & CAP_STATUS32) { | ||
2865 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
2866 | capabilities |= CAP_STATUS32; | ||
2867 | } | ||
2868 | if (ses->capabilities & CAP_DFS) { | ||
2869 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
2870 | capabilities |= CAP_DFS; | ||
2871 | } | ||
2872 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
2873 | |||
2874 | bcc_ptr = (char *) &pSMB->req.SecurityBlob; | ||
2875 | SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; | ||
2876 | strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); | ||
2877 | SecurityBlob->MessageType = NtLmNegotiate; | ||
2878 | negotiate_flags = | ||
2879 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | | ||
2880 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | | ||
2881 | NTLMSSP_NEGOTIATE_56 | | ||
2882 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; | ||
2883 | if (sign_CIFS_PDUs) | ||
2884 | negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
2885 | /* if (ntlmv2_support) | ||
2886 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/ | ||
2887 | /* setup pointers to domain name and workstation name */ | ||
2888 | bcc_ptr += SecurityBlobLength; | ||
2889 | |||
2890 | SecurityBlob->WorkstationName.Buffer = 0; | ||
2891 | SecurityBlob->WorkstationName.Length = 0; | ||
2892 | SecurityBlob->WorkstationName.MaximumLength = 0; | ||
2893 | |||
2894 | /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent | ||
2895 | along with username on auth request (ie the response to challenge) */ | ||
2896 | SecurityBlob->DomainName.Buffer = 0; | ||
2897 | SecurityBlob->DomainName.Length = 0; | ||
2898 | SecurityBlob->DomainName.MaximumLength = 0; | ||
2899 | if (ses->capabilities & CAP_UNICODE) { | ||
2900 | if ((long) bcc_ptr % 2) { | ||
2901 | *bcc_ptr = 0; | ||
2902 | bcc_ptr++; | ||
2903 | } | 2555 | } |
2904 | 2556 | ||
2905 | bytes_returned = | 2557 | cFYI(1, ("Getting referral for: %s", full_path)); |
2906 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | 2558 | rc = get_dfs_path(xid, pSesInfo , full_path + 1, |
2907 | 32, nls_codepage); | 2559 | cifs_sb->local_nls, &num_referrals, &referrals, |
2908 | bcc_ptr += 2 * bytes_returned; | 2560 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
2909 | bytes_returned = | 2561 | if (!rc && num_referrals > 0) { |
2910 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, | 2562 | char *fake_devname = NULL; |
2911 | nls_codepage); | 2563 | |
2912 | bcc_ptr += 2 * bytes_returned; | 2564 | if (mount_data != mount_data_global) |
2913 | bcc_ptr += 2; /* null terminate Linux version */ | 2565 | kfree(mount_data); |
2914 | bytes_returned = | 2566 | mount_data = cifs_compose_mount_options( |
2915 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | 2567 | cifs_sb->mountdata, full_path + 1, |
2916 | 64, nls_codepage); | 2568 | referrals, &fake_devname); |
2917 | bcc_ptr += 2 * bytes_returned; | 2569 | kfree(fake_devname); |
2918 | *(bcc_ptr + 1) = 0; | 2570 | free_dfs_info_array(referrals, num_referrals); |
2919 | *(bcc_ptr + 2) = 0; | 2571 | |
2920 | bcc_ptr += 2; /* null terminate network opsys string */ | 2572 | if (tcon) |
2921 | *(bcc_ptr + 1) = 0; | 2573 | cifs_put_tcon(tcon); |
2922 | *(bcc_ptr + 2) = 0; | 2574 | else if (pSesInfo) |
2923 | bcc_ptr += 2; /* null domain */ | 2575 | cifs_put_smb_ses(pSesInfo); |
2924 | } else { /* ASCII */ | 2576 | |
2925 | strcpy(bcc_ptr, "Linux version "); | 2577 | cleanup_volume_info(&volume_info); |
2926 | bcc_ptr += strlen("Linux version "); | 2578 | FreeXid(xid); |
2927 | strcpy(bcc_ptr, utsname()->release); | 2579 | kfree(full_path); |
2928 | bcc_ptr += strlen(utsname()->release) + 1; | 2580 | referral_walks_count++; |
2929 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | 2581 | goto try_mount_again; |
2930 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
2931 | bcc_ptr++; /* empty domain field */ | ||
2932 | *bcc_ptr = 0; | ||
2933 | } | ||
2934 | SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); | ||
2935 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
2936 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
2937 | smb_buffer->smb_buf_length += count; | ||
2938 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
2939 | |||
2940 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
2941 | &bytes_returned, CIFS_LONG_OP); | ||
2942 | |||
2943 | if (smb_buffer_response->Status.CifsError == | ||
2944 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) | ||
2945 | rc = 0; | ||
2946 | |||
2947 | if (rc) { | ||
2948 | /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ | ||
2949 | } else if ((smb_buffer_response->WordCount == 3) | ||
2950 | || (smb_buffer_response->WordCount == 4)) { | ||
2951 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
2952 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
2953 | |||
2954 | if (action & GUEST_LOGIN) | ||
2955 | cFYI(1, ("Guest login")); | ||
2956 | /* Do we want to set anything in SesInfo struct when guest login? */ | ||
2957 | |||
2958 | bcc_ptr = pByteArea(smb_buffer_response); | ||
2959 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
2960 | |||
2961 | SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; | ||
2962 | if (SecurityBlob2->MessageType != NtLmChallenge) { | ||
2963 | cFYI(1, ("Unexpected NTLMSSP message type received %d", | ||
2964 | SecurityBlob2->MessageType)); | ||
2965 | } else if (ses) { | ||
2966 | ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ | ||
2967 | cFYI(1, ("UID = %d", ses->Suid)); | ||
2968 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
2969 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
2970 | && (blob_len < | ||
2971 | pSMBr->resp.ByteCount))) { | ||
2972 | |||
2973 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
2974 | bcc_ptr += blob_len; | ||
2975 | cFYI(1, ("Security Blob Length %d", | ||
2976 | blob_len)); | ||
2977 | } | ||
2978 | |||
2979 | cFYI(1, ("NTLMSSP Challenge rcvd")); | ||
2980 | |||
2981 | memcpy(ses->server->cryptKey, | ||
2982 | SecurityBlob2->Challenge, | ||
2983 | CIFS_CRYPTO_KEY_SIZE); | ||
2984 | if (SecurityBlob2->NegotiateFlags & | ||
2985 | cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2)) | ||
2986 | *pNTLMv2_flag = true; | ||
2987 | |||
2988 | if ((SecurityBlob2->NegotiateFlags & | ||
2989 | cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) | ||
2990 | || (sign_CIFS_PDUs > 1)) | ||
2991 | ses->server->secMode |= | ||
2992 | SECMODE_SIGN_REQUIRED; | ||
2993 | if ((SecurityBlob2->NegotiateFlags & | ||
2994 | cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs)) | ||
2995 | ses->server->secMode |= | ||
2996 | SECMODE_SIGN_ENABLED; | ||
2997 | |||
2998 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
2999 | if ((long) (bcc_ptr) % 2) { | ||
3000 | remaining_words = | ||
3001 | (BCC(smb_buffer_response) | ||
3002 | - 1) / 2; | ||
3003 | /* Must word align unicode strings */ | ||
3004 | bcc_ptr++; | ||
3005 | } else { | ||
3006 | remaining_words = | ||
3007 | BCC | ||
3008 | (smb_buffer_response) / 2; | ||
3009 | } | ||
3010 | len = | ||
3011 | UniStrnlen((wchar_t *) bcc_ptr, | ||
3012 | remaining_words - 1); | ||
3013 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
3014 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
3015 | terminating last Unicode string in response */ | ||
3016 | if (ses->serverOS) | ||
3017 | kfree(ses->serverOS); | ||
3018 | ses->serverOS = | ||
3019 | kzalloc(2 * (len + 1), GFP_KERNEL); | ||
3020 | cifs_strfromUCS_le(ses->serverOS, | ||
3021 | (__le16 *) | ||
3022 | bcc_ptr, len, | ||
3023 | nls_codepage); | ||
3024 | bcc_ptr += 2 * (len + 1); | ||
3025 | remaining_words -= len + 1; | ||
3026 | ses->serverOS[2 * len] = 0; | ||
3027 | ses->serverOS[1 + (2 * len)] = 0; | ||
3028 | if (remaining_words > 0) { | ||
3029 | len = UniStrnlen((wchar_t *) | ||
3030 | bcc_ptr, | ||
3031 | remaining_words | ||
3032 | - 1); | ||
3033 | kfree(ses->serverNOS); | ||
3034 | ses->serverNOS = | ||
3035 | kzalloc(2 * (len + 1), | ||
3036 | GFP_KERNEL); | ||
3037 | cifs_strfromUCS_le(ses-> | ||
3038 | serverNOS, | ||
3039 | (__le16 *) | ||
3040 | bcc_ptr, | ||
3041 | len, | ||
3042 | nls_codepage); | ||
3043 | bcc_ptr += 2 * (len + 1); | ||
3044 | ses->serverNOS[2 * len] = 0; | ||
3045 | ses->serverNOS[1 + | ||
3046 | (2 * len)] = 0; | ||
3047 | remaining_words -= len + 1; | ||
3048 | if (remaining_words > 0) { | ||
3049 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
3050 | /* last string not always null terminated | ||
3051 | (for e.g. for Windows XP & 2000) */ | ||
3052 | kfree(ses->serverDomain); | ||
3053 | ses->serverDomain = | ||
3054 | kzalloc(2 * | ||
3055 | (len + | ||
3056 | 1), | ||
3057 | GFP_KERNEL); | ||
3058 | cifs_strfromUCS_le | ||
3059 | (ses->serverDomain, | ||
3060 | (__le16 *)bcc_ptr, | ||
3061 | len, nls_codepage); | ||
3062 | bcc_ptr += | ||
3063 | 2 * (len + 1); | ||
3064 | ses->serverDomain[2*len] | ||
3065 | = 0; | ||
3066 | ses->serverDomain | ||
3067 | [1 + (2 * len)] | ||
3068 | = 0; | ||
3069 | } /* else no more room so create dummy domain string */ | ||
3070 | else { | ||
3071 | kfree(ses->serverDomain); | ||
3072 | ses->serverDomain = | ||
3073 | kzalloc(2, | ||
3074 | GFP_KERNEL); | ||
3075 | } | ||
3076 | } else { /* no room so create dummy domain and NOS string */ | ||
3077 | kfree(ses->serverDomain); | ||
3078 | ses->serverDomain = | ||
3079 | kzalloc(2, GFP_KERNEL); | ||
3080 | kfree(ses->serverNOS); | ||
3081 | ses->serverNOS = | ||
3082 | kzalloc(2, GFP_KERNEL); | ||
3083 | } | ||
3084 | } else { /* ASCII */ | ||
3085 | len = strnlen(bcc_ptr, 1024); | ||
3086 | if (((long) bcc_ptr + len) - (long) | ||
3087 | pByteArea(smb_buffer_response) | ||
3088 | <= BCC(smb_buffer_response)) { | ||
3089 | if (ses->serverOS) | ||
3090 | kfree(ses->serverOS); | ||
3091 | ses->serverOS = | ||
3092 | kzalloc(len + 1, | ||
3093 | GFP_KERNEL); | ||
3094 | strncpy(ses->serverOS, | ||
3095 | bcc_ptr, len); | ||
3096 | |||
3097 | bcc_ptr += len; | ||
3098 | bcc_ptr[0] = 0; /* null terminate string */ | ||
3099 | bcc_ptr++; | ||
3100 | |||
3101 | len = strnlen(bcc_ptr, 1024); | ||
3102 | kfree(ses->serverNOS); | ||
3103 | ses->serverNOS = | ||
3104 | kzalloc(len + 1, | ||
3105 | GFP_KERNEL); | ||
3106 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
3107 | bcc_ptr += len; | ||
3108 | bcc_ptr[0] = 0; | ||
3109 | bcc_ptr++; | ||
3110 | |||
3111 | len = strnlen(bcc_ptr, 1024); | ||
3112 | kfree(ses->serverDomain); | ||
3113 | ses->serverDomain = | ||
3114 | kzalloc(len + 1, | ||
3115 | GFP_KERNEL); | ||
3116 | strncpy(ses->serverDomain, | ||
3117 | bcc_ptr, len); | ||
3118 | bcc_ptr += len; | ||
3119 | bcc_ptr[0] = 0; | ||
3120 | bcc_ptr++; | ||
3121 | } else | ||
3122 | cFYI(1, | ||
3123 | ("field of length %d " | ||
3124 | "extends beyond end of smb", | ||
3125 | len)); | ||
3126 | } | ||
3127 | } else { | ||
3128 | cERROR(1, ("Security Blob Length extends beyond" | ||
3129 | " end of SMB")); | ||
3130 | } | ||
3131 | } else { | ||
3132 | cERROR(1, ("No session structure passed in.")); | ||
3133 | } | 2582 | } |
3134 | } else { | 2583 | #else /* No DFS support, return error on mount */ |
3135 | cERROR(1, ("Invalid Word count %d:", | 2584 | rc = -EOPNOTSUPP; |
3136 | smb_buffer_response->WordCount)); | 2585 | #endif |
3137 | rc = -EIO; | ||
3138 | } | ||
3139 | |||
3140 | cifs_buf_release(smb_buffer); | ||
3141 | |||
3142 | return rc; | ||
3143 | } | ||
3144 | static int | ||
3145 | CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
3146 | char *ntlm_session_key, bool ntlmv2_flag, | ||
3147 | const struct nls_table *nls_codepage) | ||
3148 | { | ||
3149 | struct smb_hdr *smb_buffer; | ||
3150 | struct smb_hdr *smb_buffer_response; | ||
3151 | SESSION_SETUP_ANDX *pSMB; | ||
3152 | SESSION_SETUP_ANDX *pSMBr; | ||
3153 | char *bcc_ptr; | ||
3154 | char *user; | ||
3155 | char *domain; | ||
3156 | int rc = 0; | ||
3157 | int remaining_words = 0; | ||
3158 | int bytes_returned = 0; | ||
3159 | int len; | ||
3160 | int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE); | ||
3161 | PAUTHENTICATE_MESSAGE SecurityBlob; | ||
3162 | __u32 negotiate_flags, capabilities; | ||
3163 | __u16 count; | ||
3164 | |||
3165 | cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); | ||
3166 | if (ses == NULL) | ||
3167 | return -EINVAL; | ||
3168 | user = ses->userName; | ||
3169 | domain = ses->domainName; | ||
3170 | smb_buffer = cifs_buf_get(); | ||
3171 | if (smb_buffer == NULL) { | ||
3172 | return -ENOMEM; | ||
3173 | } | ||
3174 | smb_buffer_response = smb_buffer; | ||
3175 | pSMB = (SESSION_SETUP_ANDX *)smb_buffer; | ||
3176 | pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response; | ||
3177 | |||
3178 | /* send SMBsessionSetup here */ | ||
3179 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
3180 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
3181 | |||
3182 | smb_buffer->Mid = GetNextMid(ses->server); | ||
3183 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | ||
3184 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
3185 | pSMB->req.AndXCommand = 0xFF; | ||
3186 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
3187 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
3188 | |||
3189 | pSMB->req.hdr.Uid = ses->Suid; | ||
3190 | |||
3191 | if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
3192 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
3193 | |||
3194 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
3195 | CAP_EXTENDED_SECURITY; | ||
3196 | if (ses->capabilities & CAP_UNICODE) { | ||
3197 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
3198 | capabilities |= CAP_UNICODE; | ||
3199 | } | ||
3200 | if (ses->capabilities & CAP_STATUS32) { | ||
3201 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
3202 | capabilities |= CAP_STATUS32; | ||
3203 | } | 2586 | } |
3204 | if (ses->capabilities & CAP_DFS) { | ||
3205 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
3206 | capabilities |= CAP_DFS; | ||
3207 | } | ||
3208 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
3209 | |||
3210 | bcc_ptr = (char *)&pSMB->req.SecurityBlob; | ||
3211 | SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr; | ||
3212 | strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); | ||
3213 | SecurityBlob->MessageType = NtLmAuthenticate; | ||
3214 | bcc_ptr += SecurityBlobLength; | ||
3215 | negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | | ||
3216 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | | ||
3217 | 0x80000000 | NTLMSSP_NEGOTIATE_128; | ||
3218 | if (sign_CIFS_PDUs) | ||
3219 | negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; | ||
3220 | if (ntlmv2_flag) | ||
3221 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; | ||
3222 | |||
3223 | /* setup pointers to domain name and workstation name */ | ||
3224 | |||
3225 | SecurityBlob->WorkstationName.Buffer = 0; | ||
3226 | SecurityBlob->WorkstationName.Length = 0; | ||
3227 | SecurityBlob->WorkstationName.MaximumLength = 0; | ||
3228 | SecurityBlob->SessionKey.Length = 0; | ||
3229 | SecurityBlob->SessionKey.MaximumLength = 0; | ||
3230 | SecurityBlob->SessionKey.Buffer = 0; | ||
3231 | |||
3232 | SecurityBlob->LmChallengeResponse.Length = 0; | ||
3233 | SecurityBlob->LmChallengeResponse.MaximumLength = 0; | ||
3234 | SecurityBlob->LmChallengeResponse.Buffer = 0; | ||
3235 | |||
3236 | SecurityBlob->NtChallengeResponse.Length = | ||
3237 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
3238 | SecurityBlob->NtChallengeResponse.MaximumLength = | ||
3239 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
3240 | memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
3241 | SecurityBlob->NtChallengeResponse.Buffer = | ||
3242 | cpu_to_le32(SecurityBlobLength); | ||
3243 | SecurityBlobLength += CIFS_SESS_KEY_SIZE; | ||
3244 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
3245 | 2587 | ||
3246 | if (ses->capabilities & CAP_UNICODE) { | 2588 | mount_fail_check: |
3247 | if (domain == NULL) { | 2589 | /* on error free sesinfo and tcon struct if needed */ |
3248 | SecurityBlob->DomainName.Buffer = 0; | ||
3249 | SecurityBlob->DomainName.Length = 0; | ||
3250 | SecurityBlob->DomainName.MaximumLength = 0; | ||
3251 | } else { | ||
3252 | __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, | ||
3253 | nls_codepage); | ||
3254 | ln *= 2; | ||
3255 | SecurityBlob->DomainName.MaximumLength = | ||
3256 | cpu_to_le16(ln); | ||
3257 | SecurityBlob->DomainName.Buffer = | ||
3258 | cpu_to_le32(SecurityBlobLength); | ||
3259 | bcc_ptr += ln; | ||
3260 | SecurityBlobLength += ln; | ||
3261 | SecurityBlob->DomainName.Length = cpu_to_le16(ln); | ||
3262 | } | ||
3263 | if (user == NULL) { | ||
3264 | SecurityBlob->UserName.Buffer = 0; | ||
3265 | SecurityBlob->UserName.Length = 0; | ||
3266 | SecurityBlob->UserName.MaximumLength = 0; | ||
3267 | } else { | ||
3268 | __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, | ||
3269 | nls_codepage); | ||
3270 | ln *= 2; | ||
3271 | SecurityBlob->UserName.MaximumLength = | ||
3272 | cpu_to_le16(ln); | ||
3273 | SecurityBlob->UserName.Buffer = | ||
3274 | cpu_to_le32(SecurityBlobLength); | ||
3275 | bcc_ptr += ln; | ||
3276 | SecurityBlobLength += ln; | ||
3277 | SecurityBlob->UserName.Length = cpu_to_le16(ln); | ||
3278 | } | ||
3279 | |||
3280 | /* SecurityBlob->WorkstationName.Length = | ||
3281 | cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); | ||
3282 | SecurityBlob->WorkstationName.Length *= 2; | ||
3283 | SecurityBlob->WorkstationName.MaximumLength = | ||
3284 | cpu_to_le16(SecurityBlob->WorkstationName.Length); | ||
3285 | SecurityBlob->WorkstationName.Buffer = | ||
3286 | cpu_to_le32(SecurityBlobLength); | ||
3287 | bcc_ptr += SecurityBlob->WorkstationName.Length; | ||
3288 | SecurityBlobLength += SecurityBlob->WorkstationName.Length; | ||
3289 | SecurityBlob->WorkstationName.Length = | ||
3290 | cpu_to_le16(SecurityBlob->WorkstationName.Length); */ | ||
3291 | |||
3292 | if ((long) bcc_ptr % 2) { | ||
3293 | *bcc_ptr = 0; | ||
3294 | bcc_ptr++; | ||
3295 | } | ||
3296 | bytes_returned = | ||
3297 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
3298 | 32, nls_codepage); | ||
3299 | bcc_ptr += 2 * bytes_returned; | ||
3300 | bytes_returned = | ||
3301 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, | ||
3302 | nls_codepage); | ||
3303 | bcc_ptr += 2 * bytes_returned; | ||
3304 | bcc_ptr += 2; /* null term version string */ | ||
3305 | bytes_returned = | ||
3306 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
3307 | 64, nls_codepage); | ||
3308 | bcc_ptr += 2 * bytes_returned; | ||
3309 | *(bcc_ptr + 1) = 0; | ||
3310 | *(bcc_ptr + 2) = 0; | ||
3311 | bcc_ptr += 2; /* null terminate network opsys string */ | ||
3312 | *(bcc_ptr + 1) = 0; | ||
3313 | *(bcc_ptr + 2) = 0; | ||
3314 | bcc_ptr += 2; /* null domain */ | ||
3315 | } else { /* ASCII */ | ||
3316 | if (domain == NULL) { | ||
3317 | SecurityBlob->DomainName.Buffer = 0; | ||
3318 | SecurityBlob->DomainName.Length = 0; | ||
3319 | SecurityBlob->DomainName.MaximumLength = 0; | ||
3320 | } else { | ||
3321 | __u16 ln; | ||
3322 | negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; | ||
3323 | strncpy(bcc_ptr, domain, 63); | ||
3324 | ln = strnlen(domain, 64); | ||
3325 | SecurityBlob->DomainName.MaximumLength = | ||
3326 | cpu_to_le16(ln); | ||
3327 | SecurityBlob->DomainName.Buffer = | ||
3328 | cpu_to_le32(SecurityBlobLength); | ||
3329 | bcc_ptr += ln; | ||
3330 | SecurityBlobLength += ln; | ||
3331 | SecurityBlob->DomainName.Length = cpu_to_le16(ln); | ||
3332 | } | ||
3333 | if (user == NULL) { | ||
3334 | SecurityBlob->UserName.Buffer = 0; | ||
3335 | SecurityBlob->UserName.Length = 0; | ||
3336 | SecurityBlob->UserName.MaximumLength = 0; | ||
3337 | } else { | ||
3338 | __u16 ln; | ||
3339 | strncpy(bcc_ptr, user, 63); | ||
3340 | ln = strnlen(user, 64); | ||
3341 | SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); | ||
3342 | SecurityBlob->UserName.Buffer = | ||
3343 | cpu_to_le32(SecurityBlobLength); | ||
3344 | bcc_ptr += ln; | ||
3345 | SecurityBlobLength += ln; | ||
3346 | SecurityBlob->UserName.Length = cpu_to_le16(ln); | ||
3347 | } | ||
3348 | /* BB fill in our workstation name if known BB */ | ||
3349 | |||
3350 | strcpy(bcc_ptr, "Linux version "); | ||
3351 | bcc_ptr += strlen("Linux version "); | ||
3352 | strcpy(bcc_ptr, utsname()->release); | ||
3353 | bcc_ptr += strlen(utsname()->release) + 1; | ||
3354 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
3355 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
3356 | bcc_ptr++; /* null domain */ | ||
3357 | *bcc_ptr = 0; | ||
3358 | } | ||
3359 | SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); | ||
3360 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
3361 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
3362 | smb_buffer->smb_buf_length += count; | ||
3363 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
3364 | |||
3365 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
3366 | &bytes_returned, CIFS_LONG_OP); | ||
3367 | if (rc) { | 2590 | if (rc) { |
3368 | /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ | 2591 | if (mount_data != mount_data_global) |
3369 | } else if ((smb_buffer_response->WordCount == 3) || | 2592 | kfree(mount_data); |
3370 | (smb_buffer_response->WordCount == 4)) { | 2593 | /* If find_unc succeeded then rc == 0 so we can not end */ |
3371 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | 2594 | /* up accidently freeing someone elses tcon struct */ |
3372 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | 2595 | if (tcon) |
3373 | if (action & GUEST_LOGIN) | 2596 | cifs_put_tcon(tcon); |
3374 | cFYI(1, ("Guest login")); /* BB Should we set anything | 2597 | else if (pSesInfo) |
3375 | in SesInfo struct ? */ | 2598 | cifs_put_smb_ses(pSesInfo); |
3376 | /* if (SecurityBlob2->MessageType != NtLm??) { | 2599 | else |
3377 | cFYI("Unexpected message type on auth response is %d")); | 2600 | cifs_put_tcp_session(srvTcp); |
3378 | } */ | 2601 | goto out; |
3379 | |||
3380 | if (ses) { | ||
3381 | cFYI(1, | ||
3382 | ("Check challenge UID %d vs auth response UID %d", | ||
3383 | ses->Suid, smb_buffer_response->Uid)); | ||
3384 | /* UID left in wire format */ | ||
3385 | ses->Suid = smb_buffer_response->Uid; | ||
3386 | bcc_ptr = pByteArea(smb_buffer_response); | ||
3387 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
3388 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
3389 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
3390 | && (blob_len < | ||
3391 | pSMBr->resp.ByteCount))) { | ||
3392 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
3393 | bcc_ptr += | ||
3394 | blob_len; | ||
3395 | cFYI(1, | ||
3396 | ("Security Blob Length %d ", | ||
3397 | blob_len)); | ||
3398 | } | ||
3399 | |||
3400 | cFYI(1, | ||
3401 | ("NTLMSSP response to Authenticate ")); | ||
3402 | |||
3403 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
3404 | if ((long) (bcc_ptr) % 2) { | ||
3405 | remaining_words = | ||
3406 | (BCC(smb_buffer_response) | ||
3407 | - 1) / 2; | ||
3408 | bcc_ptr++; /* Unicode strings must be word aligned */ | ||
3409 | } else { | ||
3410 | remaining_words = BCC(smb_buffer_response) / 2; | ||
3411 | } | ||
3412 | len = UniStrnlen((wchar_t *) bcc_ptr, | ||
3413 | remaining_words - 1); | ||
3414 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
3415 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
3416 | terminating last Unicode string in response */ | ||
3417 | if (ses->serverOS) | ||
3418 | kfree(ses->serverOS); | ||
3419 | ses->serverOS = | ||
3420 | kzalloc(2 * (len + 1), GFP_KERNEL); | ||
3421 | cifs_strfromUCS_le(ses->serverOS, | ||
3422 | (__le16 *) | ||
3423 | bcc_ptr, len, | ||
3424 | nls_codepage); | ||
3425 | bcc_ptr += 2 * (len + 1); | ||
3426 | remaining_words -= len + 1; | ||
3427 | ses->serverOS[2 * len] = 0; | ||
3428 | ses->serverOS[1 + (2 * len)] = 0; | ||
3429 | if (remaining_words > 0) { | ||
3430 | len = UniStrnlen((wchar_t *) | ||
3431 | bcc_ptr, | ||
3432 | remaining_words | ||
3433 | - 1); | ||
3434 | kfree(ses->serverNOS); | ||
3435 | ses->serverNOS = | ||
3436 | kzalloc(2 * (len + 1), | ||
3437 | GFP_KERNEL); | ||
3438 | cifs_strfromUCS_le(ses-> | ||
3439 | serverNOS, | ||
3440 | (__le16 *) | ||
3441 | bcc_ptr, | ||
3442 | len, | ||
3443 | nls_codepage); | ||
3444 | bcc_ptr += 2 * (len + 1); | ||
3445 | ses->serverNOS[2 * len] = 0; | ||
3446 | ses->serverNOS[1+(2*len)] = 0; | ||
3447 | remaining_words -= len + 1; | ||
3448 | if (remaining_words > 0) { | ||
3449 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
3450 | /* last string not always null terminated (e.g. for Windows XP & 2000) */ | ||
3451 | if (ses->serverDomain) | ||
3452 | kfree(ses->serverDomain); | ||
3453 | ses->serverDomain = | ||
3454 | kzalloc(2 * | ||
3455 | (len + | ||
3456 | 1), | ||
3457 | GFP_KERNEL); | ||
3458 | cifs_strfromUCS_le | ||
3459 | (ses-> | ||
3460 | serverDomain, | ||
3461 | (__le16 *) | ||
3462 | bcc_ptr, len, | ||
3463 | nls_codepage); | ||
3464 | bcc_ptr += | ||
3465 | 2 * (len + 1); | ||
3466 | ses-> | ||
3467 | serverDomain[2 | ||
3468 | * len] | ||
3469 | = 0; | ||
3470 | ses-> | ||
3471 | serverDomain[1 | ||
3472 | + | ||
3473 | (2 | ||
3474 | * | ||
3475 | len)] | ||
3476 | = 0; | ||
3477 | } /* else no more room so create dummy domain string */ | ||
3478 | else { | ||
3479 | if (ses->serverDomain) | ||
3480 | kfree(ses->serverDomain); | ||
3481 | ses->serverDomain = kzalloc(2,GFP_KERNEL); | ||
3482 | } | ||
3483 | } else { /* no room so create dummy domain and NOS string */ | ||
3484 | if (ses->serverDomain) | ||
3485 | kfree(ses->serverDomain); | ||
3486 | ses->serverDomain = kzalloc(2, GFP_KERNEL); | ||
3487 | kfree(ses->serverNOS); | ||
3488 | ses->serverNOS = kzalloc(2, GFP_KERNEL); | ||
3489 | } | ||
3490 | } else { /* ASCII */ | ||
3491 | len = strnlen(bcc_ptr, 1024); | ||
3492 | if (((long) bcc_ptr + len) - | ||
3493 | (long) pByteArea(smb_buffer_response) | ||
3494 | <= BCC(smb_buffer_response)) { | ||
3495 | if (ses->serverOS) | ||
3496 | kfree(ses->serverOS); | ||
3497 | ses->serverOS = kzalloc(len + 1, GFP_KERNEL); | ||
3498 | strncpy(ses->serverOS,bcc_ptr, len); | ||
3499 | |||
3500 | bcc_ptr += len; | ||
3501 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
3502 | bcc_ptr++; | ||
3503 | |||
3504 | len = strnlen(bcc_ptr, 1024); | ||
3505 | kfree(ses->serverNOS); | ||
3506 | ses->serverNOS = kzalloc(len+1, | ||
3507 | GFP_KERNEL); | ||
3508 | strncpy(ses->serverNOS, | ||
3509 | bcc_ptr, len); | ||
3510 | bcc_ptr += len; | ||
3511 | bcc_ptr[0] = 0; | ||
3512 | bcc_ptr++; | ||
3513 | |||
3514 | len = strnlen(bcc_ptr, 1024); | ||
3515 | if (ses->serverDomain) | ||
3516 | kfree(ses->serverDomain); | ||
3517 | ses->serverDomain = | ||
3518 | kzalloc(len+1, | ||
3519 | GFP_KERNEL); | ||
3520 | strncpy(ses->serverDomain, | ||
3521 | bcc_ptr, len); | ||
3522 | bcc_ptr += len; | ||
3523 | bcc_ptr[0] = 0; | ||
3524 | bcc_ptr++; | ||
3525 | } else | ||
3526 | cFYI(1, ("field of length %d " | ||
3527 | "extends beyond end of smb ", | ||
3528 | len)); | ||
3529 | } | ||
3530 | } else { | ||
3531 | cERROR(1, ("Security Blob extends beyond end " | ||
3532 | "of SMB")); | ||
3533 | } | ||
3534 | } else { | ||
3535 | cERROR(1, ("No session structure passed in.")); | ||
3536 | } | ||
3537 | } else { | ||
3538 | cERROR(1, ("Invalid Word count %d: ", | ||
3539 | smb_buffer_response->WordCount)); | ||
3540 | rc = -EIO; | ||
3541 | } | 2602 | } |
3542 | 2603 | ||
3543 | cifs_buf_release(smb_buffer); | 2604 | /* volume_info->password is freed above when existing session found |
3544 | 2605 | (in which case it is not needed anymore) but when new sesion is created | |
2606 | the password ptr is put in the new session structure (in which case the | ||
2607 | password will be freed at unmount time) */ | ||
2608 | out: | ||
2609 | /* zero out password before freeing */ | ||
2610 | cleanup_volume_info(&volume_info); | ||
2611 | FreeXid(xid); | ||
3545 | return rc; | 2612 | return rc; |
3546 | } | 2613 | } |
3547 | 2614 | ||
@@ -3556,7 +2623,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3556 | TCONX_RSP *pSMBr; | 2623 | TCONX_RSP *pSMBr; |
3557 | unsigned char *bcc_ptr; | 2624 | unsigned char *bcc_ptr; |
3558 | int rc = 0; | 2625 | int rc = 0; |
3559 | int length; | 2626 | int length, bytes_left; |
3560 | __u16 count; | 2627 | __u16 count; |
3561 | 2628 | ||
3562 | if (ses == NULL) | 2629 | if (ses == NULL) |
@@ -3644,14 +2711,22 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3644 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, | 2711 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
3645 | CIFS_STD_OP); | 2712 | CIFS_STD_OP); |
3646 | 2713 | ||
3647 | /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ | ||
3648 | /* above now done in SendReceive */ | 2714 | /* above now done in SendReceive */ |
3649 | if ((rc == 0) && (tcon != NULL)) { | 2715 | if ((rc == 0) && (tcon != NULL)) { |
2716 | bool is_unicode; | ||
2717 | |||
3650 | tcon->tidStatus = CifsGood; | 2718 | tcon->tidStatus = CifsGood; |
3651 | tcon->need_reconnect = false; | 2719 | tcon->need_reconnect = false; |
3652 | tcon->tid = smb_buffer_response->Tid; | 2720 | tcon->tid = smb_buffer_response->Tid; |
3653 | bcc_ptr = pByteArea(smb_buffer_response); | 2721 | bcc_ptr = pByteArea(smb_buffer_response); |
3654 | length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); | 2722 | bytes_left = BCC(smb_buffer_response); |
2723 | length = strnlen(bcc_ptr, bytes_left - 2); | ||
2724 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) | ||
2725 | is_unicode = true; | ||
2726 | else | ||
2727 | is_unicode = false; | ||
2728 | |||
2729 | |||
3655 | /* skip service field (NB: this field is always ASCII) */ | 2730 | /* skip service field (NB: this field is always ASCII) */ |
3656 | if (length == 3) { | 2731 | if (length == 3) { |
3657 | if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && | 2732 | if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && |
@@ -3666,40 +2741,16 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3666 | } | 2741 | } |
3667 | } | 2742 | } |
3668 | bcc_ptr += length + 1; | 2743 | bcc_ptr += length + 1; |
2744 | bytes_left -= (length + 1); | ||
3669 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); | 2745 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); |
3670 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | 2746 | |
3671 | length = UniStrnlen((wchar_t *) bcc_ptr, 512); | 2747 | /* mostly informational -- no need to fail on error here */ |
3672 | if ((bcc_ptr + (2 * length)) - | 2748 | tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr, |
3673 | pByteArea(smb_buffer_response) <= | 2749 | bytes_left, is_unicode, |
3674 | BCC(smb_buffer_response)) { | 2750 | nls_codepage); |
3675 | kfree(tcon->nativeFileSystem); | 2751 | |
3676 | tcon->nativeFileSystem = | 2752 | cFYI(1, ("nativeFileSystem=%s", tcon->nativeFileSystem)); |
3677 | kzalloc(2*(length + 1), GFP_KERNEL); | 2753 | |
3678 | if (tcon->nativeFileSystem) | ||
3679 | cifs_strfromUCS_le( | ||
3680 | tcon->nativeFileSystem, | ||
3681 | (__le16 *) bcc_ptr, | ||
3682 | length, nls_codepage); | ||
3683 | bcc_ptr += 2 * length; | ||
3684 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
3685 | bcc_ptr[1] = 0; | ||
3686 | bcc_ptr += 2; | ||
3687 | } | ||
3688 | /* else do not bother copying these information fields*/ | ||
3689 | } else { | ||
3690 | length = strnlen(bcc_ptr, 1024); | ||
3691 | if ((bcc_ptr + length) - | ||
3692 | pByteArea(smb_buffer_response) <= | ||
3693 | BCC(smb_buffer_response)) { | ||
3694 | kfree(tcon->nativeFileSystem); | ||
3695 | tcon->nativeFileSystem = | ||
3696 | kzalloc(length + 1, GFP_KERNEL); | ||
3697 | if (tcon->nativeFileSystem) | ||
3698 | strncpy(tcon->nativeFileSystem, bcc_ptr, | ||
3699 | length); | ||
3700 | } | ||
3701 | /* else do not bother copying these information fields*/ | ||
3702 | } | ||
3703 | if ((smb_buffer_response->WordCount == 3) || | 2754 | if ((smb_buffer_response->WordCount == 3) || |
3704 | (smb_buffer_response->WordCount == 7)) | 2755 | (smb_buffer_response->WordCount == 7)) |
3705 | /* field is in same location */ | 2756 | /* field is in same location */ |
@@ -3738,8 +2789,6 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3738 | struct nls_table *nls_info) | 2789 | struct nls_table *nls_info) |
3739 | { | 2790 | { |
3740 | int rc = 0; | 2791 | int rc = 0; |
3741 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
3742 | bool ntlmv2_flag = false; | ||
3743 | int first_time = 0; | 2792 | int first_time = 0; |
3744 | struct TCP_Server_Info *server = pSesInfo->server; | 2793 | struct TCP_Server_Info *server = pSesInfo->server; |
3745 | 2794 | ||
@@ -3771,83 +2820,19 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3771 | pSesInfo->capabilities = server->capabilities; | 2820 | pSesInfo->capabilities = server->capabilities; |
3772 | if (linuxExtEnabled == 0) | 2821 | if (linuxExtEnabled == 0) |
3773 | pSesInfo->capabilities &= (~CAP_UNIX); | 2822 | pSesInfo->capabilities &= (~CAP_UNIX); |
3774 | /* pSesInfo->sequence_number = 0;*/ | 2823 | |
3775 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", | 2824 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", |
3776 | server->secMode, server->capabilities, server->timeAdj)); | 2825 | server->secMode, server->capabilities, server->timeAdj)); |
3777 | 2826 | ||
3778 | if (experimEnabled < 2) | 2827 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); |
3779 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); | ||
3780 | else if (extended_security | ||
3781 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
3782 | && (server->secType == NTLMSSP)) { | ||
3783 | rc = -EOPNOTSUPP; | ||
3784 | } else if (extended_security | ||
3785 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
3786 | && (server->secType == RawNTLMSSP)) { | ||
3787 | cFYI(1, ("NTLMSSP sesssetup")); | ||
3788 | rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag, | ||
3789 | nls_info); | ||
3790 | if (!rc) { | ||
3791 | if (ntlmv2_flag) { | ||
3792 | char *v2_response; | ||
3793 | cFYI(1, ("more secure NTLM ver2 hash")); | ||
3794 | if (CalcNTLMv2_partial_mac_key(pSesInfo, | ||
3795 | nls_info)) { | ||
3796 | rc = -ENOMEM; | ||
3797 | goto ss_err_exit; | ||
3798 | } else | ||
3799 | v2_response = kmalloc(16 + 64 /* blob*/, | ||
3800 | GFP_KERNEL); | ||
3801 | if (v2_response) { | ||
3802 | CalcNTLMv2_response(pSesInfo, | ||
3803 | v2_response); | ||
3804 | /* if (first_time) | ||
3805 | cifs_calculate_ntlmv2_mac_key */ | ||
3806 | kfree(v2_response); | ||
3807 | /* BB Put dummy sig in SessSetup PDU? */ | ||
3808 | } else { | ||
3809 | rc = -ENOMEM; | ||
3810 | goto ss_err_exit; | ||
3811 | } | ||
3812 | |||
3813 | } else { | ||
3814 | SMBNTencrypt(pSesInfo->password, | ||
3815 | server->cryptKey, | ||
3816 | ntlm_session_key); | ||
3817 | |||
3818 | if (first_time) | ||
3819 | cifs_calculate_mac_key( | ||
3820 | &server->mac_signing_key, | ||
3821 | ntlm_session_key, | ||
3822 | pSesInfo->password); | ||
3823 | } | ||
3824 | /* for better security the weaker lanman hash not sent | ||
3825 | in AuthSessSetup so we no longer calculate it */ | ||
3826 | |||
3827 | rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo, | ||
3828 | ntlm_session_key, | ||
3829 | ntlmv2_flag, | ||
3830 | nls_info); | ||
3831 | } | ||
3832 | } else { /* old style NTLM 0.12 session setup */ | ||
3833 | SMBNTencrypt(pSesInfo->password, server->cryptKey, | ||
3834 | ntlm_session_key); | ||
3835 | |||
3836 | if (first_time) | ||
3837 | cifs_calculate_mac_key(&server->mac_signing_key, | ||
3838 | ntlm_session_key, | ||
3839 | pSesInfo->password); | ||
3840 | |||
3841 | rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info); | ||
3842 | } | ||
3843 | if (rc) { | 2828 | if (rc) { |
3844 | cERROR(1, ("Send error in SessSetup = %d", rc)); | 2829 | cERROR(1, ("Send error in SessSetup = %d", rc)); |
3845 | } else { | 2830 | } else { |
3846 | cFYI(1, ("CIFS Session Established successfully")); | 2831 | cFYI(1, ("CIFS Session Established successfully")); |
3847 | spin_lock(&GlobalMid_Lock); | 2832 | spin_lock(&GlobalMid_Lock); |
3848 | pSesInfo->status = CifsGood; | 2833 | pSesInfo->status = CifsGood; |
3849 | pSesInfo->need_reconnect = false; | 2834 | pSesInfo->need_reconnect = false; |
3850 | spin_unlock(&GlobalMid_Lock); | 2835 | spin_unlock(&GlobalMid_Lock); |
3851 | } | 2836 | } |
3852 | 2837 | ||
3853 | ss_err_exit: | 2838 | ss_err_exit: |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 54dce78fbb73..11431ed72a7f 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -129,12 +129,62 @@ cifs_bp_rename_retry: | |||
129 | return full_path; | 129 | return full_path; |
130 | } | 130 | } |
131 | 131 | ||
132 | static void | ||
133 | cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, | ||
134 | struct cifsTconInfo *tcon, bool write_only) | ||
135 | { | ||
136 | int oplock = 0; | ||
137 | struct cifsFileInfo *pCifsFile; | ||
138 | struct cifsInodeInfo *pCifsInode; | ||
139 | |||
140 | pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | ||
141 | |||
142 | if (pCifsFile == NULL) | ||
143 | return; | ||
144 | |||
145 | if (oplockEnabled) | ||
146 | oplock = REQ_OPLOCK; | ||
147 | |||
148 | pCifsFile->netfid = fileHandle; | ||
149 | pCifsFile->pid = current->tgid; | ||
150 | pCifsFile->pInode = newinode; | ||
151 | pCifsFile->invalidHandle = false; | ||
152 | pCifsFile->closePend = false; | ||
153 | mutex_init(&pCifsFile->fh_mutex); | ||
154 | mutex_init(&pCifsFile->lock_mutex); | ||
155 | INIT_LIST_HEAD(&pCifsFile->llist); | ||
156 | atomic_set(&pCifsFile->wrtPending, 0); | ||
157 | |||
158 | /* set the following in open now | ||
159 | pCifsFile->pfile = file; */ | ||
160 | write_lock(&GlobalSMBSeslock); | ||
161 | list_add(&pCifsFile->tlist, &tcon->openFileList); | ||
162 | pCifsInode = CIFS_I(newinode); | ||
163 | if (pCifsInode) { | ||
164 | /* if readable file instance put first in list*/ | ||
165 | if (write_only) | ||
166 | list_add_tail(&pCifsFile->flist, | ||
167 | &pCifsInode->openFileList); | ||
168 | else | ||
169 | list_add(&pCifsFile->flist, &pCifsInode->openFileList); | ||
170 | |||
171 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
172 | pCifsInode->clientCanCacheAll = true; | ||
173 | pCifsInode->clientCanCacheRead = true; | ||
174 | cFYI(1, ("Exclusive Oplock inode %p", newinode)); | ||
175 | } else if ((oplock & 0xF) == OPLOCK_READ) | ||
176 | pCifsInode->clientCanCacheRead = true; | ||
177 | } | ||
178 | write_unlock(&GlobalSMBSeslock); | ||
179 | } | ||
180 | |||
132 | int cifs_posix_open(char *full_path, struct inode **pinode, | 181 | int cifs_posix_open(char *full_path, struct inode **pinode, |
133 | struct super_block *sb, int mode, int oflags, | 182 | struct super_block *sb, int mode, int oflags, |
134 | int *poplock, __u16 *pnetfid, int xid) | 183 | int *poplock, __u16 *pnetfid, int xid) |
135 | { | 184 | { |
136 | int rc; | 185 | int rc; |
137 | __u32 oplock; | 186 | __u32 oplock; |
187 | bool write_only = false; | ||
138 | FILE_UNIX_BASIC_INFO *presp_data; | 188 | FILE_UNIX_BASIC_INFO *presp_data; |
139 | __u32 posix_flags = 0; | 189 | __u32 posix_flags = 0; |
140 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 190 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
@@ -172,6 +222,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
172 | if (oflags & O_DIRECT) | 222 | if (oflags & O_DIRECT) |
173 | posix_flags |= SMB_O_DIRECT; | 223 | posix_flags |= SMB_O_DIRECT; |
174 | 224 | ||
225 | if (!(oflags & FMODE_READ)) | ||
226 | write_only = true; | ||
175 | 227 | ||
176 | rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, | 228 | rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, |
177 | pnetfid, presp_data, &oplock, full_path, | 229 | pnetfid, presp_data, &oplock, full_path, |
@@ -187,8 +239,10 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
187 | if (!pinode) | 239 | if (!pinode) |
188 | goto posix_open_ret; /* caller does not need info */ | 240 | goto posix_open_ret; /* caller does not need info */ |
189 | 241 | ||
190 | if (*pinode == NULL) | 242 | if (*pinode == NULL) { |
191 | *pinode = cifs_new_inode(sb, &presp_data->UniqueId); | 243 | __u64 unique_id = le64_to_cpu(presp_data->UniqueId); |
244 | *pinode = cifs_new_inode(sb, &unique_id); | ||
245 | } | ||
192 | /* else an inode was passed in. Update its info, don't create one */ | 246 | /* else an inode was passed in. Update its info, don't create one */ |
193 | 247 | ||
194 | /* We do not need to close the file if new_inode fails since | 248 | /* We do not need to close the file if new_inode fails since |
@@ -198,6 +252,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
198 | 252 | ||
199 | posix_fill_in_inode(*pinode, presp_data, 1); | 253 | posix_fill_in_inode(*pinode, presp_data, 1); |
200 | 254 | ||
255 | cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); | ||
256 | |||
201 | posix_open_ret: | 257 | posix_open_ret: |
202 | kfree(presp_data); | 258 | kfree(presp_data); |
203 | return rc; | 259 | return rc; |
@@ -225,6 +281,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
225 | int create_options = CREATE_NOT_DIR; | 281 | int create_options = CREATE_NOT_DIR; |
226 | int oplock = 0; | 282 | int oplock = 0; |
227 | int oflags; | 283 | int oflags; |
284 | bool posix_create = false; | ||
228 | /* | 285 | /* |
229 | * BB below access is probably too much for mknod to request | 286 | * BB below access is probably too much for mknod to request |
230 | * but we have to do query and setpathinfo so requesting | 287 | * but we have to do query and setpathinfo so requesting |
@@ -239,7 +296,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
239 | char *full_path = NULL; | 296 | char *full_path = NULL; |
240 | FILE_ALL_INFO *buf = NULL; | 297 | FILE_ALL_INFO *buf = NULL; |
241 | struct inode *newinode = NULL; | 298 | struct inode *newinode = NULL; |
242 | struct cifsInodeInfo *pCifsInode; | ||
243 | int disposition = FILE_OVERWRITE_IF; | 299 | int disposition = FILE_OVERWRITE_IF; |
244 | bool write_only = false; | 300 | bool write_only = false; |
245 | 301 | ||
@@ -273,11 +329,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
273 | negotation. EREMOTE indicates DFS junction, which is not | 329 | negotation. EREMOTE indicates DFS junction, which is not |
274 | handled in posix open */ | 330 | handled in posix open */ |
275 | 331 | ||
276 | if ((rc == 0) && (newinode == NULL)) | 332 | if (rc == 0) { |
277 | goto cifs_create_get_file_info; /* query inode info */ | 333 | posix_create = true; |
278 | else if (rc == 0) /* success, no need to query */ | 334 | if (newinode == NULL) /* query inode info */ |
279 | goto cifs_create_set_dentry; | 335 | goto cifs_create_get_file_info; |
280 | else if ((rc != -EIO) && (rc != -EREMOTE) && | 336 | else /* success, no need to query */ |
337 | goto cifs_create_set_dentry; | ||
338 | } else if ((rc != -EIO) && (rc != -EREMOTE) && | ||
281 | (rc != -EOPNOTSUPP)) /* path not found or net err */ | 339 | (rc != -EOPNOTSUPP)) /* path not found or net err */ |
282 | goto cifs_create_out; | 340 | goto cifs_create_out; |
283 | /* else fallthrough to retry, using older open call, this is | 341 | /* else fallthrough to retry, using older open call, this is |
@@ -409,45 +467,9 @@ cifs_create_set_dentry: | |||
409 | if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) { | 467 | if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) { |
410 | /* mknod case - do not leave file open */ | 468 | /* mknod case - do not leave file open */ |
411 | CIFSSMBClose(xid, tcon, fileHandle); | 469 | CIFSSMBClose(xid, tcon, fileHandle); |
412 | } else if (newinode) { | 470 | } else if (!(posix_create) && (newinode)) { |
413 | struct cifsFileInfo *pCifsFile = | 471 | cifs_fill_fileinfo(newinode, fileHandle, |
414 | kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 472 | cifs_sb->tcon, write_only); |
415 | |||
416 | if (pCifsFile == NULL) | ||
417 | goto cifs_create_out; | ||
418 | pCifsFile->netfid = fileHandle; | ||
419 | pCifsFile->pid = current->tgid; | ||
420 | pCifsFile->pInode = newinode; | ||
421 | pCifsFile->invalidHandle = false; | ||
422 | pCifsFile->closePend = false; | ||
423 | init_MUTEX(&pCifsFile->fh_sem); | ||
424 | mutex_init(&pCifsFile->lock_mutex); | ||
425 | INIT_LIST_HEAD(&pCifsFile->llist); | ||
426 | atomic_set(&pCifsFile->wrtPending, 0); | ||
427 | |||
428 | /* set the following in open now | ||
429 | pCifsFile->pfile = file; */ | ||
430 | write_lock(&GlobalSMBSeslock); | ||
431 | list_add(&pCifsFile->tlist, &tcon->openFileList); | ||
432 | pCifsInode = CIFS_I(newinode); | ||
433 | if (pCifsInode) { | ||
434 | /* if readable file instance put first in list*/ | ||
435 | if (write_only) { | ||
436 | list_add_tail(&pCifsFile->flist, | ||
437 | &pCifsInode->openFileList); | ||
438 | } else { | ||
439 | list_add(&pCifsFile->flist, | ||
440 | &pCifsInode->openFileList); | ||
441 | } | ||
442 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
443 | pCifsInode->clientCanCacheAll = true; | ||
444 | pCifsInode->clientCanCacheRead = true; | ||
445 | cFYI(1, ("Exclusive Oplock inode %p", | ||
446 | newinode)); | ||
447 | } else if ((oplock & 0xF) == OPLOCK_READ) | ||
448 | pCifsInode->clientCanCacheRead = true; | ||
449 | } | ||
450 | write_unlock(&GlobalSMBSeslock); | ||
451 | } | 473 | } |
452 | cifs_create_out: | 474 | cifs_create_out: |
453 | kfree(buf); | 475 | kfree(buf); |
@@ -580,17 +602,21 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
580 | return rc; | 602 | return rc; |
581 | } | 603 | } |
582 | 604 | ||
583 | |||
584 | struct dentry * | 605 | struct dentry * |
585 | cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | 606 | cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, |
586 | struct nameidata *nd) | 607 | struct nameidata *nd) |
587 | { | 608 | { |
588 | int xid; | 609 | int xid; |
589 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ | 610 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ |
611 | int oplock = 0; | ||
612 | int mode; | ||
613 | __u16 fileHandle = 0; | ||
614 | bool posix_open = false; | ||
590 | struct cifs_sb_info *cifs_sb; | 615 | struct cifs_sb_info *cifs_sb; |
591 | struct cifsTconInfo *pTcon; | 616 | struct cifsTconInfo *pTcon; |
592 | struct inode *newInode = NULL; | 617 | struct inode *newInode = NULL; |
593 | char *full_path = NULL; | 618 | char *full_path = NULL; |
619 | struct file *filp; | ||
594 | 620 | ||
595 | xid = GetXid(); | 621 | xid = GetXid(); |
596 | 622 | ||
@@ -632,12 +658,37 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
632 | } | 658 | } |
633 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); | 659 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); |
634 | 660 | ||
635 | if (pTcon->unix_ext) | 661 | if (pTcon->unix_ext) { |
636 | rc = cifs_get_inode_info_unix(&newInode, full_path, | 662 | if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && |
637 | parent_dir_inode->i_sb, xid); | 663 | (nd->flags & LOOKUP_OPEN)) { |
638 | else | 664 | if (!((nd->intent.open.flags & O_CREAT) && |
665 | (nd->intent.open.flags & O_EXCL))) { | ||
666 | mode = nd->intent.open.create_mode & | ||
667 | ~current_umask(); | ||
668 | rc = cifs_posix_open(full_path, &newInode, | ||
669 | parent_dir_inode->i_sb, mode, | ||
670 | nd->intent.open.flags, &oplock, | ||
671 | &fileHandle, xid); | ||
672 | /* | ||
673 | * This code works around a bug in | ||
674 | * samba posix open in samba versions 3.3.1 | ||
675 | * and earlier where create works | ||
676 | * but open fails with invalid parameter. | ||
677 | * If either of these error codes are | ||
678 | * returned, follow the normal lookup. | ||
679 | * Otherwise, the error during posix open | ||
680 | * is handled. | ||
681 | */ | ||
682 | if ((rc != -EINVAL) && (rc != -EOPNOTSUPP)) | ||
683 | posix_open = true; | ||
684 | } | ||
685 | } | ||
686 | if (!posix_open) | ||
687 | rc = cifs_get_inode_info_unix(&newInode, full_path, | ||
688 | parent_dir_inode->i_sb, xid); | ||
689 | } else | ||
639 | rc = cifs_get_inode_info(&newInode, full_path, NULL, | 690 | rc = cifs_get_inode_info(&newInode, full_path, NULL, |
640 | parent_dir_inode->i_sb, xid, NULL); | 691 | parent_dir_inode->i_sb, xid, NULL); |
641 | 692 | ||
642 | if ((rc == 0) && (newInode != NULL)) { | 693 | if ((rc == 0) && (newInode != NULL)) { |
643 | if (pTcon->nocase) | 694 | if (pTcon->nocase) |
@@ -645,7 +696,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
645 | else | 696 | else |
646 | direntry->d_op = &cifs_dentry_ops; | 697 | direntry->d_op = &cifs_dentry_ops; |
647 | d_add(direntry, newInode); | 698 | d_add(direntry, newInode); |
648 | 699 | if (posix_open) | |
700 | filp = lookup_instantiate_filp(nd, direntry, NULL); | ||
649 | /* since paths are not looked up by component - the parent | 701 | /* since paths are not looked up by component - the parent |
650 | directories are presumed to be good here */ | 702 | directories are presumed to be good here */ |
651 | renew_parental_timestamps(direntry); | 703 | renew_parental_timestamps(direntry); |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 1e0c1bd8f2e4..df4a306f697e 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c | |||
@@ -78,7 +78,7 @@ dns_resolver_instantiate(struct key *key, const void *data, | |||
78 | } | 78 | } |
79 | 79 | ||
80 | key->type_data.x[0] = datalen; | 80 | key->type_data.x[0] = datalen; |
81 | rcu_assign_pointer(key->payload.data, ip); | 81 | key->payload.data = ip; |
82 | 82 | ||
83 | return rc; | 83 | return rc; |
84 | } | 84 | } |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 81747acca4c4..38c06f826575 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -46,7 +46,7 @@ static inline struct cifsFileInfo *cifs_init_private( | |||
46 | memset(private_data, 0, sizeof(struct cifsFileInfo)); | 46 | memset(private_data, 0, sizeof(struct cifsFileInfo)); |
47 | private_data->netfid = netfid; | 47 | private_data->netfid = netfid; |
48 | private_data->pid = current->tgid; | 48 | private_data->pid = current->tgid; |
49 | init_MUTEX(&private_data->fh_sem); | 49 | mutex_init(&private_data->fh_mutex); |
50 | mutex_init(&private_data->lock_mutex); | 50 | mutex_init(&private_data->lock_mutex); |
51 | INIT_LIST_HEAD(&private_data->llist); | 51 | INIT_LIST_HEAD(&private_data->llist); |
52 | private_data->pfile = file; /* needed for writepage */ | 52 | private_data->pfile = file; /* needed for writepage */ |
@@ -129,15 +129,12 @@ static inline int cifs_posix_open_inode_helper(struct inode *inode, | |||
129 | struct file *file, struct cifsInodeInfo *pCifsInode, | 129 | struct file *file, struct cifsInodeInfo *pCifsInode, |
130 | struct cifsFileInfo *pCifsFile, int oplock, u16 netfid) | 130 | struct cifsFileInfo *pCifsFile, int oplock, u16 netfid) |
131 | { | 131 | { |
132 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
133 | /* struct timespec temp; */ /* BB REMOVEME BB */ | ||
134 | 132 | ||
135 | file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 133 | file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); |
136 | if (file->private_data == NULL) | 134 | if (file->private_data == NULL) |
137 | return -ENOMEM; | 135 | return -ENOMEM; |
138 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); | 136 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); |
139 | write_lock(&GlobalSMBSeslock); | 137 | write_lock(&GlobalSMBSeslock); |
140 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); | ||
141 | 138 | ||
142 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | 139 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); |
143 | if (pCifsInode == NULL) { | 140 | if (pCifsInode == NULL) { |
@@ -145,17 +142,6 @@ static inline int cifs_posix_open_inode_helper(struct inode *inode, | |||
145 | return -EINVAL; | 142 | return -EINVAL; |
146 | } | 143 | } |
147 | 144 | ||
148 | /* want handles we can use to read with first | ||
149 | in the list so we do not have to walk the | ||
150 | list to search for one in write_begin */ | ||
151 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | ||
152 | list_add_tail(&pCifsFile->flist, | ||
153 | &pCifsInode->openFileList); | ||
154 | } else { | ||
155 | list_add(&pCifsFile->flist, | ||
156 | &pCifsInode->openFileList); | ||
157 | } | ||
158 | |||
159 | if (pCifsInode->clientCanCacheRead) { | 145 | if (pCifsInode->clientCanCacheRead) { |
160 | /* we have the inode open somewhere else | 146 | /* we have the inode open somewhere else |
161 | no need to discard cache data */ | 147 | no need to discard cache data */ |
@@ -284,35 +270,32 @@ int cifs_open(struct inode *inode, struct file *file) | |||
284 | cifs_sb = CIFS_SB(inode->i_sb); | 270 | cifs_sb = CIFS_SB(inode->i_sb); |
285 | tcon = cifs_sb->tcon; | 271 | tcon = cifs_sb->tcon; |
286 | 272 | ||
287 | if (file->f_flags & O_CREAT) { | 273 | /* search inode for this file and fill in file->private_data */ |
288 | /* search inode for this file and fill in file->private_data */ | 274 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); |
289 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | 275 | read_lock(&GlobalSMBSeslock); |
290 | read_lock(&GlobalSMBSeslock); | 276 | list_for_each(tmp, &pCifsInode->openFileList) { |
291 | list_for_each(tmp, &pCifsInode->openFileList) { | 277 | pCifsFile = list_entry(tmp, struct cifsFileInfo, |
292 | pCifsFile = list_entry(tmp, struct cifsFileInfo, | 278 | flist); |
293 | flist); | 279 | if ((pCifsFile->pfile == NULL) && |
294 | if ((pCifsFile->pfile == NULL) && | 280 | (pCifsFile->pid == current->tgid)) { |
295 | (pCifsFile->pid == current->tgid)) { | 281 | /* mode set in cifs_create */ |
296 | /* mode set in cifs_create */ | 282 | |
297 | 283 | /* needed for writepage */ | |
298 | /* needed for writepage */ | 284 | pCifsFile->pfile = file; |
299 | pCifsFile->pfile = file; | 285 | |
300 | 286 | file->private_data = pCifsFile; | |
301 | file->private_data = pCifsFile; | 287 | break; |
302 | break; | ||
303 | } | ||
304 | } | ||
305 | read_unlock(&GlobalSMBSeslock); | ||
306 | if (file->private_data != NULL) { | ||
307 | rc = 0; | ||
308 | FreeXid(xid); | ||
309 | return rc; | ||
310 | } else { | ||
311 | if (file->f_flags & O_EXCL) | ||
312 | cERROR(1, ("could not find file instance for " | ||
313 | "new file %p", file)); | ||
314 | } | 288 | } |
315 | } | 289 | } |
290 | read_unlock(&GlobalSMBSeslock); | ||
291 | |||
292 | if (file->private_data != NULL) { | ||
293 | rc = 0; | ||
294 | FreeXid(xid); | ||
295 | return rc; | ||
296 | } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL)) | ||
297 | cERROR(1, ("could not find file instance for " | ||
298 | "new file %p", file)); | ||
316 | 299 | ||
317 | full_path = build_path_from_dentry(file->f_path.dentry); | 300 | full_path = build_path_from_dentry(file->f_path.dentry); |
318 | if (full_path == NULL) { | 301 | if (full_path == NULL) { |
@@ -500,9 +483,9 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
500 | return -EBADF; | 483 | return -EBADF; |
501 | 484 | ||
502 | xid = GetXid(); | 485 | xid = GetXid(); |
503 | down(&pCifsFile->fh_sem); | 486 | mutex_unlock(&pCifsFile->fh_mutex); |
504 | if (!pCifsFile->invalidHandle) { | 487 | if (!pCifsFile->invalidHandle) { |
505 | up(&pCifsFile->fh_sem); | 488 | mutex_lock(&pCifsFile->fh_mutex); |
506 | FreeXid(xid); | 489 | FreeXid(xid); |
507 | return 0; | 490 | return 0; |
508 | } | 491 | } |
@@ -533,7 +516,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
533 | if (full_path == NULL) { | 516 | if (full_path == NULL) { |
534 | rc = -ENOMEM; | 517 | rc = -ENOMEM; |
535 | reopen_error_exit: | 518 | reopen_error_exit: |
536 | up(&pCifsFile->fh_sem); | 519 | mutex_lock(&pCifsFile->fh_mutex); |
537 | FreeXid(xid); | 520 | FreeXid(xid); |
538 | return rc; | 521 | return rc; |
539 | } | 522 | } |
@@ -575,14 +558,14 @@ reopen_error_exit: | |||
575 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 558 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
576 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 559 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
577 | if (rc) { | 560 | if (rc) { |
578 | up(&pCifsFile->fh_sem); | 561 | mutex_lock(&pCifsFile->fh_mutex); |
579 | cFYI(1, ("cifs_open returned 0x%x", rc)); | 562 | cFYI(1, ("cifs_open returned 0x%x", rc)); |
580 | cFYI(1, ("oplock: %d", oplock)); | 563 | cFYI(1, ("oplock: %d", oplock)); |
581 | } else { | 564 | } else { |
582 | reopen_success: | 565 | reopen_success: |
583 | pCifsFile->netfid = netfid; | 566 | pCifsFile->netfid = netfid; |
584 | pCifsFile->invalidHandle = false; | 567 | pCifsFile->invalidHandle = false; |
585 | up(&pCifsFile->fh_sem); | 568 | mutex_lock(&pCifsFile->fh_mutex); |
586 | pCifsInode = CIFS_I(inode); | 569 | pCifsInode = CIFS_I(inode); |
587 | if (pCifsInode) { | 570 | if (pCifsInode) { |
588 | if (can_flush) { | 571 | if (can_flush) { |
@@ -971,6 +954,40 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
971 | return rc; | 954 | return rc; |
972 | } | 955 | } |
973 | 956 | ||
957 | /* | ||
958 | * Set the timeout on write requests past EOF. For some servers (Windows) | ||
959 | * these calls can be very long. | ||
960 | * | ||
961 | * If we're writing >10M past the EOF we give a 180s timeout. Anything less | ||
962 | * than that gets a 45s timeout. Writes not past EOF get 15s timeouts. | ||
963 | * The 10M cutoff is totally arbitrary. A better scheme for this would be | ||
964 | * welcome if someone wants to suggest one. | ||
965 | * | ||
966 | * We may be able to do a better job with this if there were some way to | ||
967 | * declare that a file should be sparse. | ||
968 | */ | ||
969 | static int | ||
970 | cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset) | ||
971 | { | ||
972 | if (offset <= cifsi->server_eof) | ||
973 | return CIFS_STD_OP; | ||
974 | else if (offset > (cifsi->server_eof + (10 * 1024 * 1024))) | ||
975 | return CIFS_VLONG_OP; | ||
976 | else | ||
977 | return CIFS_LONG_OP; | ||
978 | } | ||
979 | |||
980 | /* update the file size (if needed) after a write */ | ||
981 | static void | ||
982 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | ||
983 | unsigned int bytes_written) | ||
984 | { | ||
985 | loff_t end_of_write = offset + bytes_written; | ||
986 | |||
987 | if (end_of_write > cifsi->server_eof) | ||
988 | cifsi->server_eof = end_of_write; | ||
989 | } | ||
990 | |||
974 | ssize_t cifs_user_write(struct file *file, const char __user *write_data, | 991 | ssize_t cifs_user_write(struct file *file, const char __user *write_data, |
975 | size_t write_size, loff_t *poffset) | 992 | size_t write_size, loff_t *poffset) |
976 | { | 993 | { |
@@ -981,6 +998,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
981 | struct cifsTconInfo *pTcon; | 998 | struct cifsTconInfo *pTcon; |
982 | int xid, long_op; | 999 | int xid, long_op; |
983 | struct cifsFileInfo *open_file; | 1000 | struct cifsFileInfo *open_file; |
1001 | struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode); | ||
984 | 1002 | ||
985 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1003 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
986 | 1004 | ||
@@ -1000,11 +1018,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
1000 | 1018 | ||
1001 | xid = GetXid(); | 1019 | xid = GetXid(); |
1002 | 1020 | ||
1003 | if (*poffset > file->f_path.dentry->d_inode->i_size) | 1021 | long_op = cifs_write_timeout(cifsi, *poffset); |
1004 | long_op = CIFS_VLONG_OP; /* writes past EOF take long time */ | ||
1005 | else | ||
1006 | long_op = CIFS_LONG_OP; | ||
1007 | |||
1008 | for (total_written = 0; write_size > total_written; | 1022 | for (total_written = 0; write_size > total_written; |
1009 | total_written += bytes_written) { | 1023 | total_written += bytes_written) { |
1010 | rc = -EAGAIN; | 1024 | rc = -EAGAIN; |
@@ -1048,8 +1062,10 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
1048 | FreeXid(xid); | 1062 | FreeXid(xid); |
1049 | return rc; | 1063 | return rc; |
1050 | } | 1064 | } |
1051 | } else | 1065 | } else { |
1066 | cifs_update_eof(cifsi, *poffset, bytes_written); | ||
1052 | *poffset += bytes_written; | 1067 | *poffset += bytes_written; |
1068 | } | ||
1053 | long_op = CIFS_STD_OP; /* subsequent writes fast - | 1069 | long_op = CIFS_STD_OP; /* subsequent writes fast - |
1054 | 15 seconds is plenty */ | 1070 | 15 seconds is plenty */ |
1055 | } | 1071 | } |
@@ -1085,6 +1101,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
1085 | struct cifsTconInfo *pTcon; | 1101 | struct cifsTconInfo *pTcon; |
1086 | int xid, long_op; | 1102 | int xid, long_op; |
1087 | struct cifsFileInfo *open_file; | 1103 | struct cifsFileInfo *open_file; |
1104 | struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode); | ||
1088 | 1105 | ||
1089 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1106 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
1090 | 1107 | ||
@@ -1099,11 +1116,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
1099 | 1116 | ||
1100 | xid = GetXid(); | 1117 | xid = GetXid(); |
1101 | 1118 | ||
1102 | if (*poffset > file->f_path.dentry->d_inode->i_size) | 1119 | long_op = cifs_write_timeout(cifsi, *poffset); |
1103 | long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */ | ||
1104 | else | ||
1105 | long_op = CIFS_LONG_OP; | ||
1106 | |||
1107 | for (total_written = 0; write_size > total_written; | 1120 | for (total_written = 0; write_size > total_written; |
1108 | total_written += bytes_written) { | 1121 | total_written += bytes_written) { |
1109 | rc = -EAGAIN; | 1122 | rc = -EAGAIN; |
@@ -1166,8 +1179,10 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
1166 | FreeXid(xid); | 1179 | FreeXid(xid); |
1167 | return rc; | 1180 | return rc; |
1168 | } | 1181 | } |
1169 | } else | 1182 | } else { |
1183 | cifs_update_eof(cifsi, *poffset, bytes_written); | ||
1170 | *poffset += bytes_written; | 1184 | *poffset += bytes_written; |
1185 | } | ||
1171 | long_op = CIFS_STD_OP; /* subsequent writes fast - | 1186 | long_op = CIFS_STD_OP; /* subsequent writes fast - |
1172 | 15 seconds is plenty */ | 1187 | 15 seconds is plenty */ |
1173 | } | 1188 | } |
@@ -1380,11 +1395,12 @@ static int cifs_writepages(struct address_space *mapping, | |||
1380 | int nr_pages; | 1395 | int nr_pages; |
1381 | __u64 offset = 0; | 1396 | __u64 offset = 0; |
1382 | struct cifsFileInfo *open_file; | 1397 | struct cifsFileInfo *open_file; |
1398 | struct cifsInodeInfo *cifsi = CIFS_I(mapping->host); | ||
1383 | struct page *page; | 1399 | struct page *page; |
1384 | struct pagevec pvec; | 1400 | struct pagevec pvec; |
1385 | int rc = 0; | 1401 | int rc = 0; |
1386 | int scanned = 0; | 1402 | int scanned = 0; |
1387 | int xid; | 1403 | int xid, long_op; |
1388 | 1404 | ||
1389 | cifs_sb = CIFS_SB(mapping->host->i_sb); | 1405 | cifs_sb = CIFS_SB(mapping->host->i_sb); |
1390 | 1406 | ||
@@ -1528,12 +1544,15 @@ retry: | |||
1528 | cERROR(1, ("No writable handles for inode")); | 1544 | cERROR(1, ("No writable handles for inode")); |
1529 | rc = -EBADF; | 1545 | rc = -EBADF; |
1530 | } else { | 1546 | } else { |
1547 | long_op = cifs_write_timeout(cifsi, offset); | ||
1531 | rc = CIFSSMBWrite2(xid, cifs_sb->tcon, | 1548 | rc = CIFSSMBWrite2(xid, cifs_sb->tcon, |
1532 | open_file->netfid, | 1549 | open_file->netfid, |
1533 | bytes_to_write, offset, | 1550 | bytes_to_write, offset, |
1534 | &bytes_written, iov, n_iov, | 1551 | &bytes_written, iov, n_iov, |
1535 | CIFS_LONG_OP); | 1552 | long_op); |
1536 | atomic_dec(&open_file->wrtPending); | 1553 | atomic_dec(&open_file->wrtPending); |
1554 | cifs_update_eof(cifsi, offset, bytes_written); | ||
1555 | |||
1537 | if (rc || bytes_written < bytes_to_write) { | 1556 | if (rc || bytes_written < bytes_to_write) { |
1538 | cERROR(1, ("Write2 ret %d, wrote %d", | 1557 | cERROR(1, ("Write2 ret %d, wrote %d", |
1539 | rc, bytes_written)); | 1558 | rc, bytes_written)); |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index f121a80fdd6f..9c869a6dcba1 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -143,6 +143,7 @@ static void cifs_unix_info_to_inode(struct inode *inode, | |||
143 | 143 | ||
144 | inode->i_nlink = le64_to_cpu(info->Nlinks); | 144 | inode->i_nlink = le64_to_cpu(info->Nlinks); |
145 | 145 | ||
146 | cifsInfo->server_eof = end_of_file; | ||
146 | spin_lock(&inode->i_lock); | 147 | spin_lock(&inode->i_lock); |
147 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | 148 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { |
148 | /* | 149 | /* |
@@ -276,7 +277,8 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
276 | 277 | ||
277 | /* get new inode */ | 278 | /* get new inode */ |
278 | if (*pinode == NULL) { | 279 | if (*pinode == NULL) { |
279 | *pinode = cifs_new_inode(sb, &find_data.UniqueId); | 280 | __u64 unique_id = le64_to_cpu(find_data.UniqueId); |
281 | *pinode = cifs_new_inode(sb, &unique_id); | ||
280 | if (*pinode == NULL) { | 282 | if (*pinode == NULL) { |
281 | rc = -ENOMEM; | 283 | rc = -ENOMEM; |
282 | goto cgiiu_exit; | 284 | goto cgiiu_exit; |
@@ -605,12 +607,12 @@ int cifs_get_inode_info(struct inode **pinode, | |||
605 | inode->i_mode |= S_IFREG; | 607 | inode->i_mode |= S_IFREG; |
606 | } | 608 | } |
607 | 609 | ||
610 | cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile); | ||
608 | spin_lock(&inode->i_lock); | 611 | spin_lock(&inode->i_lock); |
609 | if (is_size_safe_to_change(cifsInfo, | 612 | if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) { |
610 | le64_to_cpu(pfindData->EndOfFile))) { | ||
611 | /* can not safely shrink the file size here if the | 613 | /* can not safely shrink the file size here if the |
612 | client is writing to it due to potential races */ | 614 | client is writing to it due to potential races */ |
613 | i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); | 615 | i_size_write(inode, cifsInfo->server_eof); |
614 | 616 | ||
615 | /* 512 bytes (2**9) is the fake blocksize that must be | 617 | /* 512 bytes (2**9) is the fake blocksize that must be |
616 | used for this calculation */ | 618 | used for this calculation */ |
@@ -960,13 +962,21 @@ undo_setattr: | |||
960 | goto out_close; | 962 | goto out_close; |
961 | } | 963 | } |
962 | 964 | ||
965 | |||
966 | /* | ||
967 | * If dentry->d_inode is null (usually meaning the cached dentry | ||
968 | * is a negative dentry) then we would attempt a standard SMB delete, but | ||
969 | * if that fails we can not attempt the fall back mechanisms on EACESS | ||
970 | * but will return the EACESS to the caller. Note that the VFS does not call | ||
971 | * unlink on negative dentries currently. | ||
972 | */ | ||
963 | int cifs_unlink(struct inode *dir, struct dentry *dentry) | 973 | int cifs_unlink(struct inode *dir, struct dentry *dentry) |
964 | { | 974 | { |
965 | int rc = 0; | 975 | int rc = 0; |
966 | int xid; | 976 | int xid; |
967 | char *full_path = NULL; | 977 | char *full_path = NULL; |
968 | struct inode *inode = dentry->d_inode; | 978 | struct inode *inode = dentry->d_inode; |
969 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | 979 | struct cifsInodeInfo *cifs_inode; |
970 | struct super_block *sb = dir->i_sb; | 980 | struct super_block *sb = dir->i_sb; |
971 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 981 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
972 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 982 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
@@ -1010,7 +1020,7 @@ psx_del_no_retry: | |||
1010 | rc = cifs_rename_pending_delete(full_path, dentry, xid); | 1020 | rc = cifs_rename_pending_delete(full_path, dentry, xid); |
1011 | if (rc == 0) | 1021 | if (rc == 0) |
1012 | drop_nlink(inode); | 1022 | drop_nlink(inode); |
1013 | } else if (rc == -EACCES && dosattr == 0) { | 1023 | } else if ((rc == -EACCES) && (dosattr == 0) && inode) { |
1014 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); | 1024 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); |
1015 | if (attrs == NULL) { | 1025 | if (attrs == NULL) { |
1016 | rc = -ENOMEM; | 1026 | rc = -ENOMEM; |
@@ -1018,7 +1028,8 @@ psx_del_no_retry: | |||
1018 | } | 1028 | } |
1019 | 1029 | ||
1020 | /* try to reset dos attributes */ | 1030 | /* try to reset dos attributes */ |
1021 | origattr = cifsInode->cifsAttrs; | 1031 | cifs_inode = CIFS_I(inode); |
1032 | origattr = cifs_inode->cifsAttrs; | ||
1022 | if (origattr == 0) | 1033 | if (origattr == 0) |
1023 | origattr |= ATTR_NORMAL; | 1034 | origattr |= ATTR_NORMAL; |
1024 | dosattr = origattr & ~ATTR_READONLY; | 1035 | dosattr = origattr & ~ATTR_READONLY; |
@@ -1039,13 +1050,13 @@ psx_del_no_retry: | |||
1039 | 1050 | ||
1040 | out_reval: | 1051 | out_reval: |
1041 | if (inode) { | 1052 | if (inode) { |
1042 | cifsInode = CIFS_I(inode); | 1053 | cifs_inode = CIFS_I(inode); |
1043 | cifsInode->time = 0; /* will force revalidate to get info | 1054 | cifs_inode->time = 0; /* will force revalidate to get info |
1044 | when needed */ | 1055 | when needed */ |
1045 | inode->i_ctime = current_fs_time(sb); | 1056 | inode->i_ctime = current_fs_time(sb); |
1046 | } | 1057 | } |
1047 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); | 1058 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); |
1048 | cifsInode = CIFS_I(dir); | 1059 | cifs_inode = CIFS_I(dir); |
1049 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ | 1060 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ |
1050 | 1061 | ||
1051 | kfree(full_path); | 1062 | kfree(full_path); |
@@ -1138,6 +1149,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1138 | cFYI(1, ("posix mkdir returned 0x%x", rc)); | 1149 | cFYI(1, ("posix mkdir returned 0x%x", rc)); |
1139 | d_drop(direntry); | 1150 | d_drop(direntry); |
1140 | } else { | 1151 | } else { |
1152 | __u64 unique_id; | ||
1141 | if (pInfo->Type == cpu_to_le32(-1)) { | 1153 | if (pInfo->Type == cpu_to_le32(-1)) { |
1142 | /* no return info, go query for it */ | 1154 | /* no return info, go query for it */ |
1143 | kfree(pInfo); | 1155 | kfree(pInfo); |
@@ -1151,8 +1163,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1151 | else | 1163 | else |
1152 | direntry->d_op = &cifs_dentry_ops; | 1164 | direntry->d_op = &cifs_dentry_ops; |
1153 | 1165 | ||
1154 | newinode = cifs_new_inode(inode->i_sb, | 1166 | unique_id = le64_to_cpu(pInfo->UniqueId); |
1155 | &pInfo->UniqueId); | 1167 | newinode = cifs_new_inode(inode->i_sb, &unique_id); |
1156 | if (newinode == NULL) { | 1168 | if (newinode == NULL) { |
1157 | kfree(pInfo); | 1169 | kfree(pInfo); |
1158 | goto mkdir_get_info; | 1170 | goto mkdir_get_info; |
@@ -1450,7 +1462,8 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, | |||
1450 | checking the UniqueId via FILE_INTERNAL_INFO */ | 1462 | checking the UniqueId via FILE_INTERNAL_INFO */ |
1451 | 1463 | ||
1452 | unlink_target: | 1464 | unlink_target: |
1453 | if ((rc == -EACCES) || (rc == -EEXIST)) { | 1465 | /* Try unlinking the target dentry if it's not negative */ |
1466 | if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) { | ||
1454 | tmprc = cifs_unlink(target_dir, target_dentry); | 1467 | tmprc = cifs_unlink(target_dir, target_dentry); |
1455 | if (tmprc) | 1468 | if (tmprc) |
1456 | goto cifs_rename_exit; | 1469 | goto cifs_rename_exit; |
@@ -1753,6 +1766,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
1753 | } | 1766 | } |
1754 | 1767 | ||
1755 | if (rc == 0) { | 1768 | if (rc == 0) { |
1769 | cifsInode->server_eof = attrs->ia_size; | ||
1756 | rc = cifs_vmtruncate(inode, attrs->ia_size); | 1770 | rc = cifs_vmtruncate(inode, attrs->ia_size); |
1757 | cifs_truncate_page(inode->i_mapping, inode->i_size); | 1771 | cifs_truncate_page(inode->i_mapping, inode->i_size); |
1758 | } | 1772 | } |
@@ -1792,20 +1806,21 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1792 | goto out; | 1806 | goto out; |
1793 | } | 1807 | } |
1794 | 1808 | ||
1795 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | 1809 | /* |
1796 | /* | 1810 | * Attempt to flush data before changing attributes. We need to do |
1797 | Flush data before changing file size or changing the last | 1811 | * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the |
1798 | write time of the file on the server. If the | 1812 | * ownership or mode then we may also need to do this. Here, we take |
1799 | flush returns error, store it to report later and continue. | 1813 | * the safe way out and just do the flush on all setattr requests. If |
1800 | BB: This should be smarter. Why bother flushing pages that | 1814 | * the flush returns error, store it to report later and continue. |
1801 | will be truncated anyway? Also, should we error out here if | 1815 | * |
1802 | the flush returns error? | 1816 | * BB: This should be smarter. Why bother flushing pages that |
1803 | */ | 1817 | * will be truncated anyway? Also, should we error out here if |
1804 | rc = filemap_write_and_wait(inode->i_mapping); | 1818 | * the flush returns error? |
1805 | if (rc != 0) { | 1819 | */ |
1806 | cifsInode->write_behind_rc = rc; | 1820 | rc = filemap_write_and_wait(inode->i_mapping); |
1807 | rc = 0; | 1821 | if (rc != 0) { |
1808 | } | 1822 | cifsInode->write_behind_rc = rc; |
1823 | rc = 0; | ||
1809 | } | 1824 | } |
1810 | 1825 | ||
1811 | if (attrs->ia_valid & ATTR_SIZE) { | 1826 | if (attrs->ia_valid & ATTR_SIZE) { |
@@ -1903,20 +1918,21 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
1903 | return -ENOMEM; | 1918 | return -ENOMEM; |
1904 | } | 1919 | } |
1905 | 1920 | ||
1906 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | 1921 | /* |
1907 | /* | 1922 | * Attempt to flush data before changing attributes. We need to do |
1908 | Flush data before changing file size or changing the last | 1923 | * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the |
1909 | write time of the file on the server. If the | 1924 | * ownership or mode then we may also need to do this. Here, we take |
1910 | flush returns error, store it to report later and continue. | 1925 | * the safe way out and just do the flush on all setattr requests. If |
1911 | BB: This should be smarter. Why bother flushing pages that | 1926 | * the flush returns error, store it to report later and continue. |
1912 | will be truncated anyway? Also, should we error out here if | 1927 | * |
1913 | the flush returns error? | 1928 | * BB: This should be smarter. Why bother flushing pages that |
1914 | */ | 1929 | * will be truncated anyway? Also, should we error out here if |
1915 | rc = filemap_write_and_wait(inode->i_mapping); | 1930 | * the flush returns error? |
1916 | if (rc != 0) { | 1931 | */ |
1917 | cifsInode->write_behind_rc = rc; | 1932 | rc = filemap_write_and_wait(inode->i_mapping); |
1918 | rc = 0; | 1933 | if (rc != 0) { |
1919 | } | 1934 | cifsInode->write_behind_rc = rc; |
1935 | rc = 0; | ||
1920 | } | 1936 | } |
1921 | 1937 | ||
1922 | if (attrs->ia_valid & ATTR_SIZE) { | 1938 | if (attrs->ia_valid & ATTR_SIZE) { |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 63f644000ce5..ea9d11e3dcbb 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -119,16 +119,11 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
119 | full_path = build_path_from_dentry(direntry); | 119 | full_path = build_path_from_dentry(direntry); |
120 | 120 | ||
121 | if (!full_path) | 121 | if (!full_path) |
122 | goto out_no_free; | 122 | goto out; |
123 | 123 | ||
124 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); | 124 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); |
125 | cifs_sb = CIFS_SB(inode->i_sb); | 125 | cifs_sb = CIFS_SB(inode->i_sb); |
126 | pTcon = cifs_sb->tcon; | 126 | pTcon = cifs_sb->tcon; |
127 | target_path = kmalloc(PATH_MAX, GFP_KERNEL); | ||
128 | if (!target_path) { | ||
129 | target_path = ERR_PTR(-ENOMEM); | ||
130 | goto out; | ||
131 | } | ||
132 | 127 | ||
133 | /* We could change this to: | 128 | /* We could change this to: |
134 | if (pTcon->unix_ext) | 129 | if (pTcon->unix_ext) |
@@ -138,8 +133,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
138 | 133 | ||
139 | if (pTcon->ses->capabilities & CAP_UNIX) | 134 | if (pTcon->ses->capabilities & CAP_UNIX) |
140 | rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, | 135 | rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, |
141 | target_path, | 136 | &target_path, |
142 | PATH_MAX-1, | ||
143 | cifs_sb->local_nls); | 137 | cifs_sb->local_nls); |
144 | else { | 138 | else { |
145 | /* BB add read reparse point symlink code here */ | 139 | /* BB add read reparse point symlink code here */ |
@@ -148,22 +142,16 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
148 | /* BB Add MAC style xsymlink check here if enabled */ | 142 | /* BB Add MAC style xsymlink check here if enabled */ |
149 | } | 143 | } |
150 | 144 | ||
151 | if (rc == 0) { | 145 | if (rc != 0) { |
152 | |||
153 | /* BB Add special case check for Samba DFS symlinks */ | ||
154 | |||
155 | target_path[PATH_MAX-1] = 0; | ||
156 | } else { | ||
157 | kfree(target_path); | 146 | kfree(target_path); |
158 | target_path = ERR_PTR(rc); | 147 | target_path = ERR_PTR(rc); |
159 | } | 148 | } |
160 | 149 | ||
161 | out: | ||
162 | kfree(full_path); | 150 | kfree(full_path); |
163 | out_no_free: | 151 | out: |
164 | FreeXid(xid); | 152 | FreeXid(xid); |
165 | nd_set_link(nd, target_path); | 153 | nd_set_link(nd, target_path); |
166 | return NULL; /* No cookie */ | 154 | return NULL; |
167 | } | 155 | } |
168 | 156 | ||
169 | int | 157 | int |
@@ -224,98 +212,6 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
224 | return rc; | 212 | return rc; |
225 | } | 213 | } |
226 | 214 | ||
227 | int | ||
228 | cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) | ||
229 | { | ||
230 | struct inode *inode = direntry->d_inode; | ||
231 | int rc = -EACCES; | ||
232 | int xid; | ||
233 | int oplock = 0; | ||
234 | struct cifs_sb_info *cifs_sb; | ||
235 | struct cifsTconInfo *pTcon; | ||
236 | char *full_path = NULL; | ||
237 | char *tmpbuffer; | ||
238 | int len; | ||
239 | __u16 fid; | ||
240 | |||
241 | xid = GetXid(); | ||
242 | cifs_sb = CIFS_SB(inode->i_sb); | ||
243 | pTcon = cifs_sb->tcon; | ||
244 | |||
245 | /* BB would it be safe against deadlock to grab this sem | ||
246 | even though rename itself grabs the sem and calls lookup? */ | ||
247 | /* mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/ | ||
248 | full_path = build_path_from_dentry(direntry); | ||
249 | /* mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/ | ||
250 | |||
251 | if (full_path == NULL) { | ||
252 | FreeXid(xid); | ||
253 | return -ENOMEM; | ||
254 | } | ||
255 | |||
256 | cFYI(1, | ||
257 | ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", | ||
258 | full_path, inode, pBuffer, buflen)); | ||
259 | if (buflen > PATH_MAX) | ||
260 | len = PATH_MAX; | ||
261 | else | ||
262 | len = buflen; | ||
263 | tmpbuffer = kmalloc(len, GFP_KERNEL); | ||
264 | if (tmpbuffer == NULL) { | ||
265 | kfree(full_path); | ||
266 | FreeXid(xid); | ||
267 | return -ENOMEM; | ||
268 | } | ||
269 | |||
270 | /* BB add read reparse point symlink code and | ||
271 | Unix extensions symlink code here BB */ | ||
272 | /* We could disable this based on pTcon->unix_ext flag instead ... but why? */ | ||
273 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) | ||
274 | rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, | ||
275 | tmpbuffer, | ||
276 | len - 1, | ||
277 | cifs_sb->local_nls); | ||
278 | else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | ||
279 | cERROR(1, ("SFU style symlinks not implemented yet")); | ||
280 | /* add open and read as in fs/cifs/inode.c */ | ||
281 | } else { | ||
282 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, | ||
283 | OPEN_REPARSE_POINT, &fid, &oplock, NULL, | ||
284 | cifs_sb->local_nls, | ||
285 | cifs_sb->mnt_cifs_flags & | ||
286 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
287 | if (!rc) { | ||
288 | rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, | ||
289 | tmpbuffer, | ||
290 | len - 1, | ||
291 | fid, | ||
292 | cifs_sb->local_nls); | ||
293 | if (CIFSSMBClose(xid, pTcon, fid)) { | ||
294 | cFYI(1, ("Error closing junction point " | ||
295 | "(open for ioctl)")); | ||
296 | } | ||
297 | /* If it is a DFS junction earlier we would have gotten | ||
298 | PATH_NOT_COVERED returned from server so we do | ||
299 | not need to request the DFS info here */ | ||
300 | } | ||
301 | } | ||
302 | /* BB Anything else to do to handle recursive links? */ | ||
303 | /* BB Should we be using page ops here? */ | ||
304 | |||
305 | /* BB null terminate returned string in pBuffer? BB */ | ||
306 | if (rc == 0) { | ||
307 | rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer); | ||
308 | cFYI(1, | ||
309 | ("vfs_readlink called from cifs_readlink returned %d", | ||
310 | rc)); | ||
311 | } | ||
312 | |||
313 | kfree(tmpbuffer); | ||
314 | kfree(full_path); | ||
315 | FreeXid(xid); | ||
316 | return rc; | ||
317 | } | ||
318 | |||
319 | void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie) | 215 | void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie) |
320 | { | 216 | { |
321 | char *p = nd_get_link(nd); | 217 | char *p = nd_get_link(nd); |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 4c89c572891a..e079a9190ec4 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -635,77 +635,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) | |||
635 | return; | 635 | return; |
636 | } | 636 | } |
637 | 637 | ||
638 | /* Windows maps these to the user defined 16 bit Unicode range since they are | ||
639 | reserved symbols (along with \ and /), otherwise illegal to store | ||
640 | in filenames in NTFS */ | ||
641 | #define UNI_ASTERIK (__u16) ('*' + 0xF000) | ||
642 | #define UNI_QUESTION (__u16) ('?' + 0xF000) | ||
643 | #define UNI_COLON (__u16) (':' + 0xF000) | ||
644 | #define UNI_GRTRTHAN (__u16) ('>' + 0xF000) | ||
645 | #define UNI_LESSTHAN (__u16) ('<' + 0xF000) | ||
646 | #define UNI_PIPE (__u16) ('|' + 0xF000) | ||
647 | #define UNI_SLASH (__u16) ('\\' + 0xF000) | ||
648 | |||
649 | /* Convert 16 bit Unicode pathname from wire format to string in current code | ||
650 | page. Conversion may involve remapping up the seven characters that are | ||
651 | only legal in POSIX-like OS (if they are present in the string). Path | ||
652 | names are little endian 16 bit Unicode on the wire */ | ||
653 | int | ||
654 | cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, | ||
655 | const struct nls_table *cp) | ||
656 | { | ||
657 | int i, j, len; | ||
658 | __u16 src_char; | ||
659 | |||
660 | for (i = 0, j = 0; i < maxlen; i++) { | ||
661 | src_char = le16_to_cpu(source[i]); | ||
662 | switch (src_char) { | ||
663 | case 0: | ||
664 | goto cUCS_out; /* BB check this BB */ | ||
665 | case UNI_COLON: | ||
666 | target[j] = ':'; | ||
667 | break; | ||
668 | case UNI_ASTERIK: | ||
669 | target[j] = '*'; | ||
670 | break; | ||
671 | case UNI_QUESTION: | ||
672 | target[j] = '?'; | ||
673 | break; | ||
674 | /* BB We can not handle remapping slash until | ||
675 | all the calls to build_path_from_dentry | ||
676 | are modified, as they use slash as separator BB */ | ||
677 | /* case UNI_SLASH: | ||
678 | target[j] = '\\'; | ||
679 | break;*/ | ||
680 | case UNI_PIPE: | ||
681 | target[j] = '|'; | ||
682 | break; | ||
683 | case UNI_GRTRTHAN: | ||
684 | target[j] = '>'; | ||
685 | break; | ||
686 | case UNI_LESSTHAN: | ||
687 | target[j] = '<'; | ||
688 | break; | ||
689 | default: | ||
690 | len = cp->uni2char(src_char, &target[j], | ||
691 | NLS_MAX_CHARSET_SIZE); | ||
692 | if (len > 0) { | ||
693 | j += len; | ||
694 | continue; | ||
695 | } else { | ||
696 | target[j] = '?'; | ||
697 | } | ||
698 | } | ||
699 | j++; | ||
700 | /* make sure we do not overrun callers allocated temp buffer */ | ||
701 | if (j >= (2 * NAME_MAX)) | ||
702 | break; | ||
703 | } | ||
704 | cUCS_out: | ||
705 | target[j] = 0; | ||
706 | return j; | ||
707 | } | ||
708 | |||
709 | /* Convert 16 bit Unicode pathname to wire format from string in current code | 638 | /* Convert 16 bit Unicode pathname to wire format from string in current code |
710 | page. Conversion may involve remapping up the seven characters that are | 639 | page. Conversion may involve remapping up the seven characters that are |
711 | only legal in POSIX-like OS (if they are present in the string). Path | 640 | only legal in POSIX-like OS (if they are present in the string). Path |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 8703d68f5b20..e2fe998989a3 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -79,6 +79,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { | |||
79 | {ErrQuota, -EDQUOT}, | 79 | {ErrQuota, -EDQUOT}, |
80 | {ErrNotALink, -ENOLINK}, | 80 | {ErrNotALink, -ENOLINK}, |
81 | {ERRnetlogonNotStarted, -ENOPROTOOPT}, | 81 | {ERRnetlogonNotStarted, -ENOPROTOOPT}, |
82 | {ERRsymlink, -EOPNOTSUPP}, | ||
82 | {ErrTooManyLinks, -EMLINK}, | 83 | {ErrTooManyLinks, -EMLINK}, |
83 | {0, 0} | 84 | {0, 0} |
84 | }; | 85 | }; |
@@ -714,6 +715,7 @@ static const struct { | |||
714 | ERRDOS, ERRnoaccess, 0xc000028f}, { | 715 | ERRDOS, ERRnoaccess, 0xc000028f}, { |
715 | ERRDOS, ERRnoaccess, 0xc0000290}, { | 716 | ERRDOS, ERRnoaccess, 0xc0000290}, { |
716 | ERRDOS, ERRbadfunc, 0xc000029c}, { | 717 | ERRDOS, ERRbadfunc, 0xc000029c}, { |
718 | ERRDOS, ERRsymlink, NT_STATUS_STOPPED_ON_SYMLINK}, { | ||
717 | ERRDOS, ERRinvlevel, 0x007c0001}, }; | 719 | ERRDOS, ERRinvlevel, 0x007c0001}, }; |
718 | 720 | ||
719 | /***************************************************************************** | 721 | /***************************************************************************** |
diff --git a/fs/cifs/nterr.h b/fs/cifs/nterr.h index 588abbb9d08c..257267367d41 100644 --- a/fs/cifs/nterr.h +++ b/fs/cifs/nterr.h | |||
@@ -35,8 +35,6 @@ struct nt_err_code_struct { | |||
35 | extern const struct nt_err_code_struct nt_errs[]; | 35 | extern const struct nt_err_code_struct nt_errs[]; |
36 | 36 | ||
37 | /* Win32 Status codes. */ | 37 | /* Win32 Status codes. */ |
38 | |||
39 | #define STATUS_BUFFER_OVERFLOW 0x80000005 | ||
40 | #define STATUS_MORE_ENTRIES 0x0105 | 38 | #define STATUS_MORE_ENTRIES 0x0105 |
41 | #define ERROR_INVALID_PARAMETER 0x0057 | 39 | #define ERROR_INVALID_PARAMETER 0x0057 |
42 | #define ERROR_INSUFFICIENT_BUFFER 0x007a | 40 | #define ERROR_INSUFFICIENT_BUFFER 0x007a |
@@ -50,6 +48,13 @@ extern const struct nt_err_code_struct nt_errs[]; | |||
50 | #define STATUS_SOME_UNMAPPED 0x0107 | 48 | #define STATUS_SOME_UNMAPPED 0x0107 |
51 | #define STATUS_BUFFER_OVERFLOW 0x80000005 | 49 | #define STATUS_BUFFER_OVERFLOW 0x80000005 |
52 | #define NT_STATUS_NO_MORE_ENTRIES 0x8000001a | 50 | #define NT_STATUS_NO_MORE_ENTRIES 0x8000001a |
51 | #define NT_STATUS_MEDIA_CHANGED 0x8000001c | ||
52 | #define NT_STATUS_END_OF_MEDIA 0x8000001e | ||
53 | #define NT_STATUS_MEDIA_CHECK 0x80000020 | ||
54 | #define NT_STATUS_NO_DATA_DETECTED 0x8000001c | ||
55 | #define NT_STATUS_STOPPED_ON_SYMLINK 0x8000002d | ||
56 | #define NT_STATUS_DEVICE_REQUIRES_CLEANING 0x80000288 | ||
57 | #define NT_STATUS_DEVICE_DOOR_OPEN 0x80000288 | ||
53 | #define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001 | 58 | #define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001 |
54 | #define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002 | 59 | #define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002 |
55 | #define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003 | 60 | #define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003 |
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index c377d8065d99..49c9a4e75319 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h | |||
@@ -27,29 +27,39 @@ | |||
27 | #define UnknownMessage cpu_to_le32(8) | 27 | #define UnknownMessage cpu_to_le32(8) |
28 | 28 | ||
29 | /* Negotiate Flags */ | 29 | /* Negotiate Flags */ |
30 | #define NTLMSSP_NEGOTIATE_UNICODE 0x01 /* Text strings are in unicode */ | 30 | #define NTLMSSP_NEGOTIATE_UNICODE 0x01 /* Text strings are unicode */ |
31 | #define NTLMSSP_NEGOTIATE_OEM 0x02 /* Text strings are in OEM */ | 31 | #define NTLMSSP_NEGOTIATE_OEM 0x02 /* Text strings are in OEM */ |
32 | #define NTLMSSP_REQUEST_TARGET 0x04 /* Server return its auth realm */ | 32 | #define NTLMSSP_REQUEST_TARGET 0x04 /* Srv returns its auth realm */ |
33 | #define NTLMSSP_NEGOTIATE_SIGN 0x0010 /* Request signature capability */ | 33 | /* define reserved9 0x08 */ |
34 | #define NTLMSSP_NEGOTIATE_SEAL 0x0020 /* Request confidentiality */ | 34 | #define NTLMSSP_NEGOTIATE_SIGN 0x0010 /* Request signing capability */ |
35 | #define NTLMSSP_NEGOTIATE_DGRAM 0x0040 | 35 | #define NTLMSSP_NEGOTIATE_SEAL 0x0020 /* Request confidentiality */ |
36 | #define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 /* Sign/seal use LM session key */ | 36 | #define NTLMSSP_NEGOTIATE_DGRAM 0x0040 |
37 | #define NTLMSSP_NEGOTIATE_NTLM 0x0200 /* NTLM authentication */ | 37 | #define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 /* Use LM session key */ |
38 | #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 | 38 | /* defined reserved 8 0x0100 */ |
39 | #define NTLMSSP_NEGOTIATE_NTLM 0x0200 /* NTLM authentication */ | ||
40 | #define NTLMSSP_NEGOTIATE_NT_ONLY 0x0400 /* Lanman not allowed */ | ||
41 | #define NTLMSSP_ANONYMOUS 0x0800 | ||
42 | #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 /* reserved6 */ | ||
39 | #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 | 43 | #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 |
40 | #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 /* client/server on same machine */ | 44 | #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 /* client/server same machine */ |
41 | #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign for all security levels */ | 45 | #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign. All security levels */ |
42 | #define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 | 46 | #define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 |
43 | #define NTLMSSP_TARGET_TYPE_SERVER 0x20000 | 47 | #define NTLMSSP_TARGET_TYPE_SERVER 0x20000 |
44 | #define NTLMSSP_TARGET_TYPE_SHARE 0x40000 | 48 | #define NTLMSSP_TARGET_TYPE_SHARE 0x40000 |
45 | #define NTLMSSP_NEGOTIATE_NTLMV2 0x80000 | 49 | #define NTLMSSP_NEGOTIATE_EXTENDED_SEC 0x80000 /* NB:not related to NTLMv2 pwd*/ |
46 | #define NTLMSSP_REQUEST_INIT_RESP 0x100000 | 50 | /* #define NTLMSSP_REQUEST_INIT_RESP 0x100000 */ |
47 | #define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 | 51 | #define NTLMSSP_NEGOTIATE_IDENTIFY 0x100000 |
48 | #define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000 | 52 | #define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 /* reserved5 */ |
53 | #define NTLMSSP_REQUEST_NON_NT_KEY 0x400000 | ||
49 | #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 | 54 | #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 |
50 | #define NTLMSSP_NEGOTIATE_128 0x20000000 | 55 | /* #define reserved4 0x1000000 */ |
51 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 | 56 | #define NTLMSSP_NEGOTIATE_VERSION 0x2000000 /* we do not set */ |
52 | #define NTLMSSP_NEGOTIATE_56 0x80000000 | 57 | /* #define reserved3 0x4000000 */ |
58 | /* #define reserved2 0x8000000 */ | ||
59 | /* #define reserved1 0x10000000 */ | ||
60 | #define NTLMSSP_NEGOTIATE_128 0x20000000 | ||
61 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 | ||
62 | #define NTLMSSP_NEGOTIATE_56 0x80000000 | ||
53 | 63 | ||
54 | /* Although typedefs are not commonly used for structure definitions */ | 64 | /* Although typedefs are not commonly used for structure definitions */ |
55 | /* in the Linux kernel, in this particular case they are useful */ | 65 | /* in the Linux kernel, in this particular case they are useful */ |
@@ -60,32 +70,36 @@ | |||
60 | typedef struct _SECURITY_BUFFER { | 70 | typedef struct _SECURITY_BUFFER { |
61 | __le16 Length; | 71 | __le16 Length; |
62 | __le16 MaximumLength; | 72 | __le16 MaximumLength; |
63 | __le32 Buffer; /* offset to buffer */ | 73 | __le32 BufferOffset; /* offset to buffer */ |
64 | } __attribute__((packed)) SECURITY_BUFFER; | 74 | } __attribute__((packed)) SECURITY_BUFFER; |
65 | 75 | ||
66 | typedef struct _NEGOTIATE_MESSAGE { | 76 | typedef struct _NEGOTIATE_MESSAGE { |
67 | __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; | 77 | __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; |
68 | __le32 MessageType; /* 1 */ | 78 | __le32 MessageType; /* NtLmNegotiate = 1 */ |
69 | __le32 NegotiateFlags; | 79 | __le32 NegotiateFlags; |
70 | SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ | 80 | SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ |
71 | SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ | 81 | SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ |
82 | /* SECURITY_BUFFER for version info not present since we | ||
83 | do not set the version is present flag */ | ||
72 | char DomainString[0]; | 84 | char DomainString[0]; |
73 | /* followed by WorkstationString */ | 85 | /* followed by WorkstationString */ |
74 | } __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; | 86 | } __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; |
75 | 87 | ||
76 | typedef struct _CHALLENGE_MESSAGE { | 88 | typedef struct _CHALLENGE_MESSAGE { |
77 | __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; | 89 | __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; |
78 | __le32 MessageType; /* 2 */ | 90 | __le32 MessageType; /* NtLmChallenge = 2 */ |
79 | SECURITY_BUFFER TargetName; | 91 | SECURITY_BUFFER TargetName; |
80 | __le32 NegotiateFlags; | 92 | __le32 NegotiateFlags; |
81 | __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; | 93 | __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; |
82 | __u8 Reserved[8]; | 94 | __u8 Reserved[8]; |
83 | SECURITY_BUFFER TargetInfoArray; | 95 | SECURITY_BUFFER TargetInfoArray; |
96 | /* SECURITY_BUFFER for version info not present since we | ||
97 | do not set the version is present flag */ | ||
84 | } __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; | 98 | } __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; |
85 | 99 | ||
86 | typedef struct _AUTHENTICATE_MESSAGE { | 100 | typedef struct _AUTHENTICATE_MESSAGE { |
87 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | 101 | __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; |
88 | __le32 MessageType; /* 3 */ | 102 | __le32 MessageType; /* NtLmsAuthenticate = 3 */ |
89 | SECURITY_BUFFER LmChallengeResponse; | 103 | SECURITY_BUFFER LmChallengeResponse; |
90 | SECURITY_BUFFER NtChallengeResponse; | 104 | SECURITY_BUFFER NtChallengeResponse; |
91 | SECURITY_BUFFER DomainName; | 105 | SECURITY_BUFFER DomainName; |
@@ -93,5 +107,7 @@ typedef struct _AUTHENTICATE_MESSAGE { | |||
93 | SECURITY_BUFFER WorkstationName; | 107 | SECURITY_BUFFER WorkstationName; |
94 | SECURITY_BUFFER SessionKey; | 108 | SECURITY_BUFFER SessionKey; |
95 | __le32 NegotiateFlags; | 109 | __le32 NegotiateFlags; |
110 | /* SECURITY_BUFFER for version info not present since we | ||
111 | do not set the version is present flag */ | ||
96 | char UserString[0]; | 112 | char UserString[0]; |
97 | } __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; | 113 | } __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index c2c01ff4c32c..964e097c8203 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -31,6 +31,13 @@ | |||
31 | #include "cifs_fs_sb.h" | 31 | #include "cifs_fs_sb.h" |
32 | #include "cifsfs.h" | 32 | #include "cifsfs.h" |
33 | 33 | ||
34 | /* | ||
35 | * To be safe - for UCS to UTF-8 with strings loaded with the rare long | ||
36 | * characters alloc more to account for such multibyte target UTF-8 | ||
37 | * characters. | ||
38 | */ | ||
39 | #define UNICODE_NAME_MAX ((4 * NAME_MAX) + 2) | ||
40 | |||
34 | #ifdef CONFIG_CIFS_DEBUG2 | 41 | #ifdef CONFIG_CIFS_DEBUG2 |
35 | static void dump_cifs_file_struct(struct file *file, char *label) | 42 | static void dump_cifs_file_struct(struct file *file, char *label) |
36 | { | 43 | { |
@@ -239,6 +246,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, | |||
239 | if (atomic_read(&cifsInfo->inUse) == 0) | 246 | if (atomic_read(&cifsInfo->inUse) == 0) |
240 | atomic_set(&cifsInfo->inUse, 1); | 247 | atomic_set(&cifsInfo->inUse, 1); |
241 | 248 | ||
249 | cifsInfo->server_eof = end_of_file; | ||
242 | spin_lock(&tmp_inode->i_lock); | 250 | spin_lock(&tmp_inode->i_lock); |
243 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | 251 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { |
244 | /* can not safely change the file size here if the | 252 | /* can not safely change the file size here if the |
@@ -375,6 +383,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
375 | tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); | 383 | tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); |
376 | tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); | 384 | tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); |
377 | 385 | ||
386 | cifsInfo->server_eof = end_of_file; | ||
378 | spin_lock(&tmp_inode->i_lock); | 387 | spin_lock(&tmp_inode->i_lock); |
379 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | 388 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { |
380 | /* can not safely change the file size here if the | 389 | /* can not safely change the file size here if the |
@@ -436,6 +445,38 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
436 | } | 445 | } |
437 | } | 446 | } |
438 | 447 | ||
448 | /* BB eventually need to add the following helper function to | ||
449 | resolve NT_STATUS_STOPPED_ON_SYMLINK return code when | ||
450 | we try to do FindFirst on (NTFS) directory symlinks */ | ||
451 | /* | ||
452 | int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, | ||
453 | int xid) | ||
454 | { | ||
455 | __u16 fid; | ||
456 | int len; | ||
457 | int oplock = 0; | ||
458 | int rc; | ||
459 | struct cifsTconInfo *ptcon = cifs_sb->tcon; | ||
460 | char *tmpbuffer; | ||
461 | |||
462 | rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, | ||
463 | OPEN_REPARSE_POINT, &fid, &oplock, NULL, | ||
464 | cifs_sb->local_nls, | ||
465 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
466 | if (!rc) { | ||
467 | tmpbuffer = kmalloc(maxpath); | ||
468 | rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path, | ||
469 | tmpbuffer, | ||
470 | maxpath -1, | ||
471 | fid, | ||
472 | cifs_sb->local_nls); | ||
473 | if (CIFSSMBClose(xid, ptcon, fid)) { | ||
474 | cFYI(1, ("Error closing temporary reparsepoint open)")); | ||
475 | } | ||
476 | } | ||
477 | } | ||
478 | */ | ||
479 | |||
439 | static int initiate_cifs_search(const int xid, struct file *file) | 480 | static int initiate_cifs_search(const int xid, struct file *file) |
440 | { | 481 | { |
441 | int rc = 0; | 482 | int rc = 0; |
@@ -491,7 +532,10 @@ ffirst_retry: | |||
491 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); | 532 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); |
492 | if (rc == 0) | 533 | if (rc == 0) |
493 | cifsFile->invalidHandle = false; | 534 | cifsFile->invalidHandle = false; |
494 | if ((rc == -EOPNOTSUPP) && | 535 | /* BB add following call to handle readdir on new NTFS symlink errors |
536 | else if STATUS_STOPPED_ON_SYMLINK | ||
537 | call get_symlink_reparse_path and retry with new path */ | ||
538 | else if ((rc == -EOPNOTSUPP) && | ||
495 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { | 539 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { |
496 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; | 540 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; |
497 | goto ffirst_retry; | 541 | goto ffirst_retry; |
@@ -820,7 +864,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
820 | /* inode num, inode type and filename returned */ | 864 | /* inode num, inode type and filename returned */ |
821 | static int cifs_get_name_from_search_buf(struct qstr *pqst, | 865 | static int cifs_get_name_from_search_buf(struct qstr *pqst, |
822 | char *current_entry, __u16 level, unsigned int unicode, | 866 | char *current_entry, __u16 level, unsigned int unicode, |
823 | struct cifs_sb_info *cifs_sb, int max_len, __u64 *pinum) | 867 | struct cifs_sb_info *cifs_sb, unsigned int max_len, __u64 *pinum) |
824 | { | 868 | { |
825 | int rc = 0; | 869 | int rc = 0; |
826 | unsigned int len = 0; | 870 | unsigned int len = 0; |
@@ -840,7 +884,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
840 | len = strnlen(filename, PATH_MAX); | 884 | len = strnlen(filename, PATH_MAX); |
841 | } | 885 | } |
842 | 886 | ||
843 | *pinum = pFindData->UniqueId; | 887 | *pinum = le64_to_cpu(pFindData->UniqueId); |
844 | } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { | 888 | } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { |
845 | FILE_DIRECTORY_INFO *pFindData = | 889 | FILE_DIRECTORY_INFO *pFindData = |
846 | (FILE_DIRECTORY_INFO *)current_entry; | 890 | (FILE_DIRECTORY_INFO *)current_entry; |
@@ -856,7 +900,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
856 | (SEARCH_ID_FULL_DIR_INFO *)current_entry; | 900 | (SEARCH_ID_FULL_DIR_INFO *)current_entry; |
857 | filename = &pFindData->FileName[0]; | 901 | filename = &pFindData->FileName[0]; |
858 | len = le32_to_cpu(pFindData->FileNameLength); | 902 | len = le32_to_cpu(pFindData->FileNameLength); |
859 | *pinum = pFindData->UniqueId; | 903 | *pinum = le64_to_cpu(pFindData->UniqueId); |
860 | } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { | 904 | } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { |
861 | FILE_BOTH_DIRECTORY_INFO *pFindData = | 905 | FILE_BOTH_DIRECTORY_INFO *pFindData = |
862 | (FILE_BOTH_DIRECTORY_INFO *)current_entry; | 906 | (FILE_BOTH_DIRECTORY_INFO *)current_entry; |
@@ -879,14 +923,12 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
879 | } | 923 | } |
880 | 924 | ||
881 | if (unicode) { | 925 | if (unicode) { |
882 | /* BB fixme - test with long names */ | 926 | pqst->len = cifs_from_ucs2((char *) pqst->name, |
883 | /* Note converted filename can be longer than in unicode */ | 927 | (__le16 *) filename, |
884 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) | 928 | UNICODE_NAME_MAX, |
885 | pqst->len = cifs_convertUCSpath((char *)pqst->name, | 929 | min(len, max_len), nlt, |
886 | (__le16 *)filename, len/2, nlt); | 930 | cifs_sb->mnt_cifs_flags & |
887 | else | 931 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
888 | pqst->len = cifs_strfromUCS_le((char *)pqst->name, | ||
889 | (__le16 *)filename, len/2, nlt); | ||
890 | } else { | 932 | } else { |
891 | pqst->name = filename; | 933 | pqst->name = filename; |
892 | pqst->len = len; | 934 | pqst->len = len; |
@@ -896,8 +938,8 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
896 | return rc; | 938 | return rc; |
897 | } | 939 | } |
898 | 940 | ||
899 | static int cifs_filldir(char *pfindEntry, struct file *file, | 941 | static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, |
900 | filldir_t filldir, void *direntry, char *scratch_buf, int max_len) | 942 | void *direntry, char *scratch_buf, unsigned int max_len) |
901 | { | 943 | { |
902 | int rc = 0; | 944 | int rc = 0; |
903 | struct qstr qstring; | 945 | struct qstr qstring; |
@@ -994,7 +1036,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
994 | int num_to_fill = 0; | 1036 | int num_to_fill = 0; |
995 | char *tmp_buf = NULL; | 1037 | char *tmp_buf = NULL; |
996 | char *end_of_smb; | 1038 | char *end_of_smb; |
997 | int max_len; | 1039 | unsigned int max_len; |
998 | 1040 | ||
999 | xid = GetXid(); | 1041 | xid = GetXid(); |
1000 | 1042 | ||
@@ -1068,11 +1110,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
1068 | cifsFile->srch_inf.ntwrk_buf_start); | 1110 | cifsFile->srch_inf.ntwrk_buf_start); |
1069 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; | 1111 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; |
1070 | 1112 | ||
1071 | /* To be safe - for UCS to UTF-8 with strings loaded | 1113 | tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL); |
1072 | with the rare long characters alloc more to account for | ||
1073 | such multibyte target UTF-8 characters. cifs_unicode.c, | ||
1074 | which actually does the conversion, has the same limit */ | ||
1075 | tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); | ||
1076 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { | 1114 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { |
1077 | if (current_entry == NULL) { | 1115 | if (current_entry == NULL) { |
1078 | /* evaluate whether this case is an error */ | 1116 | /* evaluate whether this case is an error */ |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 5c68b4282be9..897a052270f9 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SMB/CIFS session setup handling routines | 4 | * SMB/CIFS session setup handling routines |
5 | * | 5 | * |
6 | * Copyright (c) International Business Machines Corp., 2006, 2007 | 6 | * Copyright (c) International Business Machines Corp., 2006, 2009 |
7 | * Author(s): Steve French (sfrench@us.ibm.com) | 7 | * Author(s): Steve French (sfrench@us.ibm.com) |
8 | * | 8 | * |
9 | * This library is free software; you can redistribute it and/or modify | 9 | * This library is free software; you can redistribute it and/or modify |
@@ -111,7 +111,7 @@ static __le16 get_next_vcnum(struct cifsSesInfo *ses) | |||
111 | get_vc_num_exit: | 111 | get_vc_num_exit: |
112 | write_unlock(&cifs_tcp_ses_lock); | 112 | write_unlock(&cifs_tcp_ses_lock); |
113 | 113 | ||
114 | return le16_to_cpu(vcnum); | 114 | return cpu_to_le16(vcnum); |
115 | } | 115 | } |
116 | 116 | ||
117 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) | 117 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) |
@@ -277,85 +277,51 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
277 | *pbcc_area = bcc_ptr; | 277 | *pbcc_area = bcc_ptr; |
278 | } | 278 | } |
279 | 279 | ||
280 | static int decode_unicode_ssetup(char **pbcc_area, int bleft, | 280 | static void |
281 | struct cifsSesInfo *ses, | 281 | decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, |
282 | const struct nls_table *nls_cp) | 282 | const struct nls_table *nls_cp) |
283 | { | 283 | { |
284 | int rc = 0; | 284 | int len; |
285 | int words_left, len; | ||
286 | char *data = *pbcc_area; | 285 | char *data = *pbcc_area; |
287 | 286 | ||
288 | |||
289 | |||
290 | cFYI(1, ("bleft %d", bleft)); | 287 | cFYI(1, ("bleft %d", bleft)); |
291 | 288 | ||
292 | 289 | /* | |
293 | /* SMB header is unaligned, so cifs servers word align start of | 290 | * Windows servers do not always double null terminate their final |
294 | Unicode strings */ | 291 | * Unicode string. Check to see if there are an uneven number of bytes |
295 | data++; | 292 | * left. If so, then add an extra NULL pad byte to the end of the |
296 | bleft--; /* Windows servers do not always double null terminate | 293 | * response. |
297 | their final Unicode string - in which case we | 294 | * |
298 | now will not attempt to decode the byte of junk | 295 | * See section 2.7.2 in "Implementing CIFS" for details |
299 | which follows it */ | 296 | */ |
300 | 297 | if (bleft % 2) { | |
301 | words_left = bleft / 2; | 298 | data[bleft] = 0; |
302 | 299 | ++bleft; | |
303 | /* save off server operating system */ | 300 | } |
304 | len = UniStrnlen((wchar_t *) data, words_left); | ||
305 | |||
306 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
307 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
308 | terminating last Unicode string in response */ | ||
309 | if (len >= words_left) | ||
310 | return rc; | ||
311 | 301 | ||
312 | kfree(ses->serverOS); | 302 | kfree(ses->serverOS); |
313 | /* UTF-8 string will not grow more than four times as big as UCS-16 */ | 303 | ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
314 | ses->serverOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); | 304 | cFYI(1, ("serverOS=%s", ses->serverOS)); |
315 | if (ses->serverOS != NULL) | 305 | len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; |
316 | cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); | 306 | data += len; |
317 | data += 2 * (len + 1); | 307 | bleft -= len; |
318 | words_left -= len + 1; | 308 | if (bleft <= 0) |
319 | 309 | return; | |
320 | /* save off server network operating system */ | ||
321 | len = UniStrnlen((wchar_t *) data, words_left); | ||
322 | |||
323 | if (len >= words_left) | ||
324 | return rc; | ||
325 | 310 | ||
326 | kfree(ses->serverNOS); | 311 | kfree(ses->serverNOS); |
327 | ses->serverNOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); | 312 | ses->serverNOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
328 | if (ses->serverNOS != NULL) { | 313 | cFYI(1, ("serverNOS=%s", ses->serverNOS)); |
329 | cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, | 314 | len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; |
330 | nls_cp); | 315 | data += len; |
331 | if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) { | 316 | bleft -= len; |
332 | cFYI(1, ("NT4 server")); | 317 | if (bleft <= 0) |
333 | ses->flags |= CIFS_SES_NT4; | 318 | return; |
334 | } | ||
335 | } | ||
336 | data += 2 * (len + 1); | ||
337 | words_left -= len + 1; | ||
338 | |||
339 | /* save off server domain */ | ||
340 | len = UniStrnlen((wchar_t *) data, words_left); | ||
341 | |||
342 | if (len > words_left) | ||
343 | return rc; | ||
344 | 319 | ||
345 | kfree(ses->serverDomain); | 320 | kfree(ses->serverDomain); |
346 | ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ | 321 | ses->serverDomain = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
347 | if (ses->serverDomain != NULL) { | 322 | cFYI(1, ("serverDomain=%s", ses->serverDomain)); |
348 | cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, | ||
349 | nls_cp); | ||
350 | ses->serverDomain[2*len] = 0; | ||
351 | ses->serverDomain[(2*len) + 1] = 0; | ||
352 | } | ||
353 | data += 2 * (len + 1); | ||
354 | words_left -= len + 1; | ||
355 | 323 | ||
356 | cFYI(1, ("words left: %d", words_left)); | 324 | return; |
357 | |||
358 | return rc; | ||
359 | } | 325 | } |
360 | 326 | ||
361 | static int decode_ascii_ssetup(char **pbcc_area, int bleft, | 327 | static int decode_ascii_ssetup(char **pbcc_area, int bleft, |
@@ -412,6 +378,186 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, | |||
412 | return rc; | 378 | return rc; |
413 | } | 379 | } |
414 | 380 | ||
381 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | ||
382 | struct cifsSesInfo *ses) | ||
383 | { | ||
384 | CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; | ||
385 | |||
386 | if (blob_len < sizeof(CHALLENGE_MESSAGE)) { | ||
387 | cERROR(1, ("challenge blob len %d too small", blob_len)); | ||
388 | return -EINVAL; | ||
389 | } | ||
390 | |||
391 | if (memcmp(pblob->Signature, "NTLMSSP", 8)) { | ||
392 | cERROR(1, ("blob signature incorrect %s", pblob->Signature)); | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | if (pblob->MessageType != NtLmChallenge) { | ||
396 | cERROR(1, ("Incorrect message type %d", pblob->MessageType)); | ||
397 | return -EINVAL; | ||
398 | } | ||
399 | |||
400 | memcpy(ses->server->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); | ||
401 | /* BB we could decode pblob->NegotiateFlags; some may be useful */ | ||
402 | /* In particular we can examine sign flags */ | ||
403 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then | ||
404 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
410 | /* BB Move to ntlmssp.c eventually */ | ||
411 | |||
412 | /* We do not malloc the blob, it is passed in pbuffer, because | ||
413 | it is fixed size, and small, making this approach cleaner */ | ||
414 | static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | ||
415 | struct cifsSesInfo *ses) | ||
416 | { | ||
417 | NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer; | ||
418 | __u32 flags; | ||
419 | |||
420 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | ||
421 | sec_blob->MessageType = NtLmNegotiate; | ||
422 | |||
423 | /* BB is NTLMV2 session security format easier to use here? */ | ||
424 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | | ||
425 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | ||
426 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; | ||
427 | if (ses->server->secMode & | ||
428 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
429 | flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
430 | if (ses->server->secMode & SECMODE_SIGN_REQUIRED) | ||
431 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | ||
432 | |||
433 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | ||
434 | |||
435 | sec_blob->WorkstationName.BufferOffset = 0; | ||
436 | sec_blob->WorkstationName.Length = 0; | ||
437 | sec_blob->WorkstationName.MaximumLength = 0; | ||
438 | |||
439 | /* Domain name is sent on the Challenge not Negotiate NTLMSSP request */ | ||
440 | sec_blob->DomainName.BufferOffset = 0; | ||
441 | sec_blob->DomainName.Length = 0; | ||
442 | sec_blob->DomainName.MaximumLength = 0; | ||
443 | } | ||
444 | |||
445 | /* We do not malloc the blob, it is passed in pbuffer, because its | ||
446 | maximum possible size is fixed and small, making this approach cleaner. | ||
447 | This function returns the length of the data in the blob */ | ||
448 | static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | ||
449 | struct cifsSesInfo *ses, | ||
450 | const struct nls_table *nls_cp, int first) | ||
451 | { | ||
452 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; | ||
453 | __u32 flags; | ||
454 | unsigned char *tmp; | ||
455 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
456 | |||
457 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | ||
458 | sec_blob->MessageType = NtLmAuthenticate; | ||
459 | |||
460 | flags = NTLMSSP_NEGOTIATE_56 | | ||
461 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | | ||
462 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | ||
463 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; | ||
464 | if (ses->server->secMode & | ||
465 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
466 | flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
467 | if (ses->server->secMode & SECMODE_SIGN_REQUIRED) | ||
468 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | ||
469 | |||
470 | tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); | ||
471 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | ||
472 | |||
473 | sec_blob->LmChallengeResponse.BufferOffset = | ||
474 | cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE)); | ||
475 | sec_blob->LmChallengeResponse.Length = 0; | ||
476 | sec_blob->LmChallengeResponse.MaximumLength = 0; | ||
477 | |||
478 | /* calculate session key, BB what about adding similar ntlmv2 path? */ | ||
479 | SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); | ||
480 | if (first) | ||
481 | cifs_calculate_mac_key(&ses->server->mac_signing_key, | ||
482 | ntlm_session_key, ses->password); | ||
483 | |||
484 | memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
485 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
486 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
487 | sec_blob->NtChallengeResponse.MaximumLength = | ||
488 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
489 | |||
490 | tmp += CIFS_SESS_KEY_SIZE; | ||
491 | |||
492 | if (ses->domainName == NULL) { | ||
493 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
494 | sec_blob->DomainName.Length = 0; | ||
495 | sec_blob->DomainName.MaximumLength = 0; | ||
496 | tmp += 2; | ||
497 | } else { | ||
498 | int len; | ||
499 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, | ||
500 | MAX_USERNAME_SIZE, nls_cp); | ||
501 | len *= 2; /* unicode is 2 bytes each */ | ||
502 | len += 2; /* trailing null */ | ||
503 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
504 | sec_blob->DomainName.Length = cpu_to_le16(len); | ||
505 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); | ||
506 | tmp += len; | ||
507 | } | ||
508 | |||
509 | if (ses->userName == NULL) { | ||
510 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
511 | sec_blob->UserName.Length = 0; | ||
512 | sec_blob->UserName.MaximumLength = 0; | ||
513 | tmp += 2; | ||
514 | } else { | ||
515 | int len; | ||
516 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, | ||
517 | MAX_USERNAME_SIZE, nls_cp); | ||
518 | len *= 2; /* unicode is 2 bytes each */ | ||
519 | len += 2; /* trailing null */ | ||
520 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
521 | sec_blob->UserName.Length = cpu_to_le16(len); | ||
522 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); | ||
523 | tmp += len; | ||
524 | } | ||
525 | |||
526 | sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
527 | sec_blob->WorkstationName.Length = 0; | ||
528 | sec_blob->WorkstationName.MaximumLength = 0; | ||
529 | tmp += 2; | ||
530 | |||
531 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
532 | sec_blob->SessionKey.Length = 0; | ||
533 | sec_blob->SessionKey.MaximumLength = 0; | ||
534 | return tmp - pbuffer; | ||
535 | } | ||
536 | |||
537 | |||
538 | static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, | ||
539 | struct cifsSesInfo *ses) | ||
540 | { | ||
541 | build_ntlmssp_negotiate_blob(&pSMB->req.SecurityBlob[0], ses); | ||
542 | pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
543 | |||
544 | return; | ||
545 | } | ||
546 | |||
547 | static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB, | ||
548 | struct cifsSesInfo *ses, | ||
549 | const struct nls_table *nls, int first_time) | ||
550 | { | ||
551 | int bloblen; | ||
552 | |||
553 | bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls, | ||
554 | first_time); | ||
555 | pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen); | ||
556 | |||
557 | return bloblen; | ||
558 | } | ||
559 | #endif | ||
560 | |||
415 | int | 561 | int |
416 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | 562 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, |
417 | const struct nls_table *nls_cp) | 563 | const struct nls_table *nls_cp) |
@@ -430,6 +576,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
430 | __u16 action; | 576 | __u16 action; |
431 | int bytes_remaining; | 577 | int bytes_remaining; |
432 | struct key *spnego_key = NULL; | 578 | struct key *spnego_key = NULL; |
579 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | ||
433 | 580 | ||
434 | if (ses == NULL) | 581 | if (ses == NULL) |
435 | return -EINVAL; | 582 | return -EINVAL; |
@@ -437,6 +584,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
437 | type = ses->server->secType; | 584 | type = ses->server->secType; |
438 | 585 | ||
439 | cFYI(1, ("sess setup type %d", type)); | 586 | cFYI(1, ("sess setup type %d", type)); |
587 | ssetup_ntlmssp_authenticate: | ||
588 | if (phase == NtLmChallenge) | ||
589 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ | ||
590 | |||
440 | if (type == LANMAN) { | 591 | if (type == LANMAN) { |
441 | #ifndef CONFIG_CIFS_WEAK_PW_HASH | 592 | #ifndef CONFIG_CIFS_WEAK_PW_HASH |
442 | /* LANMAN and plaintext are less secure and off by default. | 593 | /* LANMAN and plaintext are less secure and off by default. |
@@ -650,9 +801,53 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
650 | goto ssetup_exit; | 801 | goto ssetup_exit; |
651 | #endif /* CONFIG_CIFS_UPCALL */ | 802 | #endif /* CONFIG_CIFS_UPCALL */ |
652 | } else { | 803 | } else { |
804 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
805 | if ((experimEnabled > 1) && (type == RawNTLMSSP)) { | ||
806 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | ||
807 | cERROR(1, ("NTLMSSP requires Unicode support")); | ||
808 | rc = -ENOSYS; | ||
809 | goto ssetup_exit; | ||
810 | } | ||
811 | |||
812 | cFYI(1, ("ntlmssp session setup phase %d", phase)); | ||
813 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
814 | capabilities |= CAP_EXTENDED_SECURITY; | ||
815 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | ||
816 | if (phase == NtLmNegotiate) { | ||
817 | setup_ntlmssp_neg_req(pSMB, ses); | ||
818 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
819 | } else if (phase == NtLmAuthenticate) { | ||
820 | int blob_len; | ||
821 | blob_len = setup_ntlmssp_auth_req(pSMB, ses, | ||
822 | nls_cp, | ||
823 | first_time); | ||
824 | iov[1].iov_len = blob_len; | ||
825 | /* Make sure that we tell the server that we | ||
826 | are using the uid that it just gave us back | ||
827 | on the response (challenge) */ | ||
828 | smb_buf->Uid = ses->Suid; | ||
829 | } else { | ||
830 | cERROR(1, ("invalid phase %d", phase)); | ||
831 | rc = -ENOSYS; | ||
832 | goto ssetup_exit; | ||
833 | } | ||
834 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
835 | /* unicode strings must be word aligned */ | ||
836 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | ||
837 | *bcc_ptr = 0; | ||
838 | bcc_ptr++; | ||
839 | } | ||
840 | unicode_oslm_strings(&bcc_ptr, nls_cp); | ||
841 | } else { | ||
842 | cERROR(1, ("secType %d not supported!", type)); | ||
843 | rc = -ENOSYS; | ||
844 | goto ssetup_exit; | ||
845 | } | ||
846 | #else | ||
653 | cERROR(1, ("secType %d not supported!", type)); | 847 | cERROR(1, ("secType %d not supported!", type)); |
654 | rc = -ENOSYS; | 848 | rc = -ENOSYS; |
655 | goto ssetup_exit; | 849 | goto ssetup_exit; |
850 | #endif | ||
656 | } | 851 | } |
657 | 852 | ||
658 | iov[2].iov_base = str_area; | 853 | iov[2].iov_base = str_area; |
@@ -668,12 +863,23 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
668 | /* SMB request buf freed in SendReceive2 */ | 863 | /* SMB request buf freed in SendReceive2 */ |
669 | 864 | ||
670 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); | 865 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); |
671 | if (rc) | ||
672 | goto ssetup_exit; | ||
673 | 866 | ||
674 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | 867 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; |
675 | smb_buf = (struct smb_hdr *)iov[0].iov_base; | 868 | smb_buf = (struct smb_hdr *)iov[0].iov_base; |
676 | 869 | ||
870 | if ((type == RawNTLMSSP) && (smb_buf->Status.CifsError == | ||
871 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) { | ||
872 | if (phase != NtLmNegotiate) { | ||
873 | cERROR(1, ("Unexpected more processing error")); | ||
874 | goto ssetup_exit; | ||
875 | } | ||
876 | /* NTLMSSP Negotiate sent now processing challenge (response) */ | ||
877 | phase = NtLmChallenge; /* process ntlmssp challenge */ | ||
878 | rc = 0; /* MORE_PROC rc is not an error here, but expected */ | ||
879 | } | ||
880 | if (rc) | ||
881 | goto ssetup_exit; | ||
882 | |||
677 | if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { | 883 | if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { |
678 | rc = -EIO; | 884 | rc = -EIO; |
679 | cERROR(1, ("bad word count %d", smb_buf->WordCount)); | 885 | cERROR(1, ("bad word count %d", smb_buf->WordCount)); |
@@ -692,22 +898,33 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
692 | if (smb_buf->WordCount == 4) { | 898 | if (smb_buf->WordCount == 4) { |
693 | __u16 blob_len; | 899 | __u16 blob_len; |
694 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | 900 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); |
695 | bcc_ptr += blob_len; | ||
696 | if (blob_len > bytes_remaining) { | 901 | if (blob_len > bytes_remaining) { |
697 | cERROR(1, ("bad security blob length %d", blob_len)); | 902 | cERROR(1, ("bad security blob length %d", blob_len)); |
698 | rc = -EINVAL; | 903 | rc = -EINVAL; |
699 | goto ssetup_exit; | 904 | goto ssetup_exit; |
700 | } | 905 | } |
906 | if (phase == NtLmChallenge) { | ||
907 | rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses); | ||
908 | /* now goto beginning for ntlmssp authenticate phase */ | ||
909 | if (rc) | ||
910 | goto ssetup_exit; | ||
911 | } | ||
912 | bcc_ptr += blob_len; | ||
701 | bytes_remaining -= blob_len; | 913 | bytes_remaining -= blob_len; |
702 | } | 914 | } |
703 | 915 | ||
704 | /* BB check if Unicode and decode strings */ | 916 | /* BB check if Unicode and decode strings */ |
705 | if (smb_buf->Flags2 & SMBFLG2_UNICODE) | 917 | if (smb_buf->Flags2 & SMBFLG2_UNICODE) { |
706 | rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, | 918 | /* unicode string area must be word-aligned */ |
707 | ses, nls_cp); | 919 | if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { |
708 | else | 920 | ++bcc_ptr; |
921 | --bytes_remaining; | ||
922 | } | ||
923 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp); | ||
924 | } else { | ||
709 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, | 925 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, |
710 | ses, nls_cp); | 926 | ses, nls_cp); |
927 | } | ||
711 | 928 | ||
712 | ssetup_exit: | 929 | ssetup_exit: |
713 | if (spnego_key) { | 930 | if (spnego_key) { |
@@ -721,5 +938,9 @@ ssetup_exit: | |||
721 | } else if (resp_buf_type == CIFS_LARGE_BUFFER) | 938 | } else if (resp_buf_type == CIFS_LARGE_BUFFER) |
722 | cifs_buf_release(iov[0].iov_base); | 939 | cifs_buf_release(iov[0].iov_base); |
723 | 940 | ||
941 | /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */ | ||
942 | if ((phase == NtLmChallenge) && (rc == 0)) | ||
943 | goto ssetup_ntlmssp_authenticate; | ||
944 | |||
724 | return rc; | 945 | return rc; |
725 | } | 946 | } |
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index 7f50e8577c1c..c5084d27db7c 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h | |||
@@ -110,6 +110,7 @@ | |||
110 | 110 | ||
111 | /* Below errors are used internally (do not come over the wire) for passthrough | 111 | /* Below errors are used internally (do not come over the wire) for passthrough |
112 | from STATUS codes to POSIX only */ | 112 | from STATUS codes to POSIX only */ |
113 | #define ERRsymlink 0xFFFD | ||
113 | #define ErrTooManyLinks 0xFFFE | 114 | #define ErrTooManyLinks 0xFFFE |
114 | 115 | ||
115 | /* Following error codes may be generated with the ERRSRV error class.*/ | 116 | /* Following error codes may be generated with the ERRSRV error class.*/ |