diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-05-08 00:13:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-05-08 00:13:24 -0400 |
commit | d7a5926978cb109b2db5985c65086483caf9e226 (patch) | |
tree | 0431ca74aec312ed69dea21a7039b4c734307723 | |
parent | 8c9ed899b44c19e81859fbb0e9d659fe2f8630fc (diff) | |
parent | 90e4ee5d311d4e0729daa676b1d7f754265b5874 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (32 commits)
[CIFS] Fix double list addition in cifs posix open code
[CIFS] Allow raw ntlmssp code to be enabled with sec=ntlmssp
[CIFS] Fix SMB uid in NTLMSSP authenticate request
[CIFS] NTLMSSP reenabled after move from connect.c to sess.c
[CIFS] Remove sparse warning
[CIFS] remove checkpatch warning
[CIFS] Fix final user of old string conversion code
[CIFS] remove cifs_strfromUCS_le
[CIFS] NTLMSSP support moving into new file, old dead code removed
[CIFS] Fix endian conversion of vcnum field
[CIFS] Remove trailing whitespace
[CIFS] Remove sparse endian warnings
[CIFS] Add remaining ntlmssp flags and standardize field names
[CIFS] Fix build warning
cifs: fix length handling in cifs_get_name_from_search_buf
[CIFS] Remove unneeded QuerySymlink call and fix mapping for unmapped status
[CIFS] rename cifs_strndup to cifs_strndup_from_ucs
Added loop check when mounting DFS tree.
Enable dfs submounts to handle remote referrals.
[CIFS] Remove older session setup implementation
...
-rw-r--r-- | fs/cifs/CHANGES | 13 | ||||
-rw-r--r-- | fs/cifs/README | 10 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 32 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.c | 198 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.h | 23 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 16 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 217 | ||||
-rw-r--r-- | fs/cifs/connect.c | 1190 | ||||
-rw-r--r-- | fs/cifs/dir.c | 15 | ||||
-rw-r--r-- | fs/cifs/file.c | 14 | ||||
-rw-r--r-- | fs/cifs/inode.c | 21 | ||||
-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 | 72 | ||||
-rw-r--r-- | fs/cifs/sess.c | 340 | ||||
-rw-r--r-- | fs/cifs/smberr.h | 1 | ||||
-rw-r--r-- | include/linux/nls.h | 19 |
22 files changed, 810 insertions, 1642 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 9d1fb6ec8a5a..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 |
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_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.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 df40ab64cd95..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 | }; |
@@ -531,6 +531,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
531 | #define CIFSSEC_MAY_PLNTXT 0 | 531 | #define CIFSSEC_MAY_PLNTXT 0 |
532 | #endif /* weak passwords */ | 532 | #endif /* weak passwords */ |
533 | #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 */ | ||
534 | 535 | ||
535 | #define CIFSSEC_MUST_SIGN 0x01001 | 536 | #define CIFSSEC_MUST_SIGN 0x01001 |
536 | /* 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 |
@@ -543,22 +544,23 @@ require use of the stronger protocol */ | |||
543 | #define CIFSSEC_MUST_LANMAN 0x10010 | 544 | #define CIFSSEC_MUST_LANMAN 0x10010 |
544 | #define CIFSSEC_MUST_PLNTXT 0x20020 | 545 | #define CIFSSEC_MUST_PLNTXT 0x20020 |
545 | #ifdef CONFIG_CIFS_UPCALL | 546 | #ifdef CONFIG_CIFS_UPCALL |
546 | #define CIFSSEC_MASK 0x3F03F /* allows weak security but also krb5 */ | 547 | #define CIFSSEC_MASK 0xAF0AF /* allows weak security but also krb5 */ |
547 | #else | 548 | #else |
548 | #define CIFSSEC_MASK 0x37037 /* current flags supported if weak */ | 549 | #define CIFSSEC_MASK 0xA70A7 /* current flags supported if weak */ |
549 | #endif /* UPCALL */ | 550 | #endif /* UPCALL */ |
550 | #else /* do not allow weak pw hash */ | 551 | #else /* do not allow weak pw hash */ |
551 | #ifdef CONFIG_CIFS_UPCALL | 552 | #ifdef CONFIG_CIFS_UPCALL |
552 | #define CIFSSEC_MASK 0x0F00F /* flags supported if no weak allowed */ | 553 | #define CIFSSEC_MASK 0x8F08F /* flags supported if no weak allowed */ |
553 | #else | 554 | #else |
554 | #define CIFSSEC_MASK 0x07007 /* flags supported if no weak allowed */ | 555 | #define CIFSSEC_MASK 0x87087 /* flags supported if no weak allowed */ |
555 | #endif /* UPCALL */ | 556 | #endif /* UPCALL */ |
556 | #endif /* WEAK_PW_HASH */ | 557 | #endif /* WEAK_PW_HASH */ |
557 | #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 */ | ||
558 | 560 | ||
559 | #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) |
560 | #define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) | 562 | #define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) |
561 | #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) |
562 | /* | 564 | /* |
563 | ***************************************************************** | 565 | ***************************************************************** |
564 | * All constants go here | 566 | * All constants go here |
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 a0845dc7b8a9..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 |
@@ -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 | ||
@@ -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 bacdef1546b7..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; |
@@ -2278,6 +2286,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2278 | #ifdef CONFIG_CIFS_DFS_UPCALL | 2286 | #ifdef CONFIG_CIFS_DFS_UPCALL |
2279 | struct dfs_info3_param *referrals = NULL; | 2287 | struct dfs_info3_param *referrals = NULL; |
2280 | unsigned int num_referrals = 0; | 2288 | unsigned int num_referrals = 0; |
2289 | int referral_walks_count = 0; | ||
2281 | try_mount_again: | 2290 | try_mount_again: |
2282 | #endif | 2291 | #endif |
2283 | full_path = NULL; | 2292 | full_path = NULL; |
@@ -2525,6 +2534,16 @@ remote_path_check: | |||
2525 | /* get referral if needed */ | 2534 | /* get referral if needed */ |
2526 | if (rc == -EREMOTE) { | 2535 | if (rc == -EREMOTE) { |
2527 | #ifdef CONFIG_CIFS_DFS_UPCALL | 2536 | #ifdef CONFIG_CIFS_DFS_UPCALL |
2537 | if (referral_walks_count > MAX_NESTED_LINKS) { | ||
2538 | /* | ||
2539 | * BB: when we implement proper loop detection, | ||
2540 | * we will remove this check. But now we need it | ||
2541 | * to prevent an indefinite loop if 'DFS tree' is | ||
2542 | * misconfigured (i.e. has loops). | ||
2543 | */ | ||
2544 | rc = -ELOOP; | ||
2545 | goto mount_fail_check; | ||
2546 | } | ||
2528 | /* convert forward to back slashes in prepath here if needed */ | 2547 | /* convert forward to back slashes in prepath here if needed */ |
2529 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) | 2548 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) |
2530 | convert_delimiter(cifs_sb->prepath, | 2549 | convert_delimiter(cifs_sb->prepath, |
@@ -2558,6 +2577,7 @@ remote_path_check: | |||
2558 | cleanup_volume_info(&volume_info); | 2577 | cleanup_volume_info(&volume_info); |
2559 | FreeXid(xid); | 2578 | FreeXid(xid); |
2560 | kfree(full_path); | 2579 | kfree(full_path); |
2580 | referral_walks_count++; | ||
2561 | goto try_mount_again; | 2581 | goto try_mount_again; |
2562 | } | 2582 | } |
2563 | #else /* No DFS support, return error on mount */ | 2583 | #else /* No DFS support, return error on mount */ |
@@ -2592,1041 +2612,6 @@ out: | |||
2592 | return rc; | 2612 | return rc; |
2593 | } | 2613 | } |
2594 | 2614 | ||
2595 | static int | ||
2596 | CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
2597 | char session_key[CIFS_SESS_KEY_SIZE], | ||
2598 | const struct nls_table *nls_codepage) | ||
2599 | { | ||
2600 | struct smb_hdr *smb_buffer; | ||
2601 | struct smb_hdr *smb_buffer_response; | ||
2602 | SESSION_SETUP_ANDX *pSMB; | ||
2603 | SESSION_SETUP_ANDX *pSMBr; | ||
2604 | char *bcc_ptr; | ||
2605 | char *user; | ||
2606 | char *domain; | ||
2607 | int rc = 0; | ||
2608 | int remaining_words = 0; | ||
2609 | int bytes_returned = 0; | ||
2610 | int len; | ||
2611 | __u32 capabilities; | ||
2612 | __u16 count; | ||
2613 | |||
2614 | cFYI(1, ("In sesssetup")); | ||
2615 | if (ses == NULL) | ||
2616 | return -EINVAL; | ||
2617 | user = ses->userName; | ||
2618 | domain = ses->domainName; | ||
2619 | smb_buffer = cifs_buf_get(); | ||
2620 | |||
2621 | if (smb_buffer == NULL) | ||
2622 | return -ENOMEM; | ||
2623 | |||
2624 | smb_buffer_response = smb_buffer; | ||
2625 | pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
2626 | |||
2627 | /* send SMBsessionSetup here */ | ||
2628 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
2629 | NULL /* no tCon exists yet */ , 13 /* wct */ ); | ||
2630 | |||
2631 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2632 | pSMB->req_no_secext.AndXCommand = 0xFF; | ||
2633 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
2634 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
2635 | |||
2636 | if (ses->server->secMode & | ||
2637 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
2638 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
2639 | |||
2640 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
2641 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; | ||
2642 | if (ses->capabilities & CAP_UNICODE) { | ||
2643 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
2644 | capabilities |= CAP_UNICODE; | ||
2645 | } | ||
2646 | if (ses->capabilities & CAP_STATUS32) { | ||
2647 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
2648 | capabilities |= CAP_STATUS32; | ||
2649 | } | ||
2650 | if (ses->capabilities & CAP_DFS) { | ||
2651 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
2652 | capabilities |= CAP_DFS; | ||
2653 | } | ||
2654 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
2655 | |||
2656 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | ||
2657 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
2658 | |||
2659 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
2660 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
2661 | bcc_ptr = pByteArea(smb_buffer); | ||
2662 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); | ||
2663 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
2664 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); | ||
2665 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
2666 | |||
2667 | if (ses->capabilities & CAP_UNICODE) { | ||
2668 | if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ | ||
2669 | *bcc_ptr = 0; | ||
2670 | bcc_ptr++; | ||
2671 | } | ||
2672 | if (user == NULL) | ||
2673 | bytes_returned = 0; /* skip null user */ | ||
2674 | else | ||
2675 | bytes_returned = | ||
2676 | cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, | ||
2677 | nls_codepage); | ||
2678 | /* convert number of 16 bit words to bytes */ | ||
2679 | bcc_ptr += 2 * bytes_returned; | ||
2680 | bcc_ptr += 2; /* trailing null */ | ||
2681 | if (domain == NULL) | ||
2682 | bytes_returned = | ||
2683 | cifs_strtoUCS((__le16 *) bcc_ptr, | ||
2684 | "CIFS_LINUX_DOM", 32, nls_codepage); | ||
2685 | else | ||
2686 | bytes_returned = | ||
2687 | cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, | ||
2688 | nls_codepage); | ||
2689 | bcc_ptr += 2 * bytes_returned; | ||
2690 | bcc_ptr += 2; | ||
2691 | bytes_returned = | ||
2692 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
2693 | 32, nls_codepage); | ||
2694 | bcc_ptr += 2 * bytes_returned; | ||
2695 | bytes_returned = | ||
2696 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, | ||
2697 | 32, nls_codepage); | ||
2698 | bcc_ptr += 2 * bytes_returned; | ||
2699 | bcc_ptr += 2; | ||
2700 | bytes_returned = | ||
2701 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
2702 | 64, nls_codepage); | ||
2703 | bcc_ptr += 2 * bytes_returned; | ||
2704 | bcc_ptr += 2; | ||
2705 | } else { | ||
2706 | if (user != NULL) { | ||
2707 | strncpy(bcc_ptr, user, 200); | ||
2708 | bcc_ptr += strnlen(user, 200); | ||
2709 | } | ||
2710 | *bcc_ptr = 0; | ||
2711 | bcc_ptr++; | ||
2712 | if (domain == NULL) { | ||
2713 | strcpy(bcc_ptr, "CIFS_LINUX_DOM"); | ||
2714 | bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; | ||
2715 | } else { | ||
2716 | strncpy(bcc_ptr, domain, 64); | ||
2717 | bcc_ptr += strnlen(domain, 64); | ||
2718 | *bcc_ptr = 0; | ||
2719 | bcc_ptr++; | ||
2720 | } | ||
2721 | strcpy(bcc_ptr, "Linux version "); | ||
2722 | bcc_ptr += strlen("Linux version "); | ||
2723 | strcpy(bcc_ptr, utsname()->release); | ||
2724 | bcc_ptr += strlen(utsname()->release) + 1; | ||
2725 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
2726 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
2727 | } | ||
2728 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
2729 | smb_buffer->smb_buf_length += count; | ||
2730 | pSMB->req_no_secext.ByteCount = cpu_to_le16(count); | ||
2731 | |||
2732 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
2733 | &bytes_returned, CIFS_LONG_OP); | ||
2734 | if (rc) { | ||
2735 | /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ | ||
2736 | } else if ((smb_buffer_response->WordCount == 3) | ||
2737 | || (smb_buffer_response->WordCount == 4)) { | ||
2738 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
2739 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
2740 | if (action & GUEST_LOGIN) | ||
2741 | cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ | ||
2742 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format | ||
2743 | (little endian) */ | ||
2744 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
2745 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
2746 | bcc_ptr = pByteArea(smb_buffer_response); | ||
2747 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
2748 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
2749 | && (blob_len < pSMBr->resp.ByteCount))) { | ||
2750 | if (pSMBr->resp.hdr.WordCount == 4) | ||
2751 | bcc_ptr += blob_len; | ||
2752 | |||
2753 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
2754 | if ((long) (bcc_ptr) % 2) { | ||
2755 | remaining_words = | ||
2756 | (BCC(smb_buffer_response) - 1) / 2; | ||
2757 | /* Unicode strings must be word | ||
2758 | aligned */ | ||
2759 | bcc_ptr++; | ||
2760 | } else { | ||
2761 | remaining_words = | ||
2762 | BCC(smb_buffer_response) / 2; | ||
2763 | } | ||
2764 | len = | ||
2765 | UniStrnlen((wchar_t *) bcc_ptr, | ||
2766 | remaining_words - 1); | ||
2767 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
2768 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
2769 | terminating last Unicode string in response */ | ||
2770 | kfree(ses->serverOS); | ||
2771 | ses->serverOS = kzalloc(2 * (len + 1), | ||
2772 | GFP_KERNEL); | ||
2773 | if (ses->serverOS == NULL) | ||
2774 | goto sesssetup_nomem; | ||
2775 | cifs_strfromUCS_le(ses->serverOS, | ||
2776 | (__le16 *)bcc_ptr, | ||
2777 | len, nls_codepage); | ||
2778 | bcc_ptr += 2 * (len + 1); | ||
2779 | remaining_words -= len + 1; | ||
2780 | ses->serverOS[2 * len] = 0; | ||
2781 | ses->serverOS[1 + (2 * len)] = 0; | ||
2782 | if (remaining_words > 0) { | ||
2783 | len = UniStrnlen((wchar_t *)bcc_ptr, | ||
2784 | remaining_words-1); | ||
2785 | kfree(ses->serverNOS); | ||
2786 | ses->serverNOS = kzalloc(2 * (len + 1), | ||
2787 | GFP_KERNEL); | ||
2788 | if (ses->serverNOS == NULL) | ||
2789 | goto sesssetup_nomem; | ||
2790 | cifs_strfromUCS_le(ses->serverNOS, | ||
2791 | (__le16 *)bcc_ptr, | ||
2792 | len, nls_codepage); | ||
2793 | bcc_ptr += 2 * (len + 1); | ||
2794 | ses->serverNOS[2 * len] = 0; | ||
2795 | ses->serverNOS[1 + (2 * len)] = 0; | ||
2796 | if (strncmp(ses->serverNOS, | ||
2797 | "NT LAN Manager 4", 16) == 0) { | ||
2798 | cFYI(1, ("NT4 server")); | ||
2799 | ses->flags |= CIFS_SES_NT4; | ||
2800 | } | ||
2801 | remaining_words -= len + 1; | ||
2802 | if (remaining_words > 0) { | ||
2803 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
2804 | /* last string is not always null terminated | ||
2805 | (for e.g. for Windows XP & 2000) */ | ||
2806 | kfree(ses->serverDomain); | ||
2807 | ses->serverDomain = | ||
2808 | kzalloc(2*(len+1), | ||
2809 | GFP_KERNEL); | ||
2810 | if (ses->serverDomain == NULL) | ||
2811 | goto sesssetup_nomem; | ||
2812 | cifs_strfromUCS_le(ses->serverDomain, | ||
2813 | (__le16 *)bcc_ptr, | ||
2814 | len, nls_codepage); | ||
2815 | bcc_ptr += 2 * (len + 1); | ||
2816 | ses->serverDomain[2*len] = 0; | ||
2817 | ses->serverDomain[1+(2*len)] = 0; | ||
2818 | } else { /* else no more room so create | ||
2819 | dummy domain string */ | ||
2820 | kfree(ses->serverDomain); | ||
2821 | ses->serverDomain = | ||
2822 | kzalloc(2, GFP_KERNEL); | ||
2823 | } | ||
2824 | } else { /* no room so create dummy domain | ||
2825 | and NOS string */ | ||
2826 | |||
2827 | /* if these kcallocs fail not much we | ||
2828 | can do, but better to not fail the | ||
2829 | sesssetup itself */ | ||
2830 | kfree(ses->serverDomain); | ||
2831 | ses->serverDomain = | ||
2832 | kzalloc(2, GFP_KERNEL); | ||
2833 | kfree(ses->serverNOS); | ||
2834 | ses->serverNOS = | ||
2835 | kzalloc(2, GFP_KERNEL); | ||
2836 | } | ||
2837 | } else { /* ASCII */ | ||
2838 | len = strnlen(bcc_ptr, 1024); | ||
2839 | if (((long) bcc_ptr + len) - (long) | ||
2840 | pByteArea(smb_buffer_response) | ||
2841 | <= BCC(smb_buffer_response)) { | ||
2842 | kfree(ses->serverOS); | ||
2843 | ses->serverOS = kzalloc(len + 1, | ||
2844 | GFP_KERNEL); | ||
2845 | if (ses->serverOS == NULL) | ||
2846 | goto sesssetup_nomem; | ||
2847 | strncpy(ses->serverOS, bcc_ptr, len); | ||
2848 | |||
2849 | bcc_ptr += len; | ||
2850 | /* null terminate the string */ | ||
2851 | bcc_ptr[0] = 0; | ||
2852 | bcc_ptr++; | ||
2853 | |||
2854 | len = strnlen(bcc_ptr, 1024); | ||
2855 | kfree(ses->serverNOS); | ||
2856 | ses->serverNOS = kzalloc(len + 1, | ||
2857 | GFP_KERNEL); | ||
2858 | if (ses->serverNOS == NULL) | ||
2859 | goto sesssetup_nomem; | ||
2860 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
2861 | bcc_ptr += len; | ||
2862 | bcc_ptr[0] = 0; | ||
2863 | bcc_ptr++; | ||
2864 | |||
2865 | len = strnlen(bcc_ptr, 1024); | ||
2866 | kfree(ses->serverDomain); | ||
2867 | ses->serverDomain = kzalloc(len + 1, | ||
2868 | GFP_KERNEL); | ||
2869 | if (ses->serverDomain == NULL) | ||
2870 | goto sesssetup_nomem; | ||
2871 | strncpy(ses->serverDomain, bcc_ptr, | ||
2872 | len); | ||
2873 | bcc_ptr += len; | ||
2874 | bcc_ptr[0] = 0; | ||
2875 | bcc_ptr++; | ||
2876 | } else | ||
2877 | cFYI(1, | ||
2878 | ("Variable field of length %d " | ||
2879 | "extends beyond end of smb ", | ||
2880 | len)); | ||
2881 | } | ||
2882 | } else { | ||
2883 | cERROR(1, ("Security Blob Length extends beyond " | ||
2884 | "end of SMB")); | ||
2885 | } | ||
2886 | } else { | ||
2887 | cERROR(1, ("Invalid Word count %d: ", | ||
2888 | smb_buffer_response->WordCount)); | ||
2889 | rc = -EIO; | ||
2890 | } | ||
2891 | sesssetup_nomem: /* do not return an error on nomem for the info strings, | ||
2892 | since that could make reconnection harder, and | ||
2893 | reconnection might be needed to free memory */ | ||
2894 | cifs_buf_release(smb_buffer); | ||
2895 | |||
2896 | return rc; | ||
2897 | } | ||
2898 | |||
2899 | static int | ||
2900 | CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | ||
2901 | struct cifsSesInfo *ses, bool *pNTLMv2_flag, | ||
2902 | const struct nls_table *nls_codepage) | ||
2903 | { | ||
2904 | struct smb_hdr *smb_buffer; | ||
2905 | struct smb_hdr *smb_buffer_response; | ||
2906 | SESSION_SETUP_ANDX *pSMB; | ||
2907 | SESSION_SETUP_ANDX *pSMBr; | ||
2908 | char *bcc_ptr; | ||
2909 | char *domain; | ||
2910 | int rc = 0; | ||
2911 | int remaining_words = 0; | ||
2912 | int bytes_returned = 0; | ||
2913 | int len; | ||
2914 | int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE); | ||
2915 | PNEGOTIATE_MESSAGE SecurityBlob; | ||
2916 | PCHALLENGE_MESSAGE SecurityBlob2; | ||
2917 | __u32 negotiate_flags, capabilities; | ||
2918 | __u16 count; | ||
2919 | |||
2920 | cFYI(1, ("In NTLMSSP sesssetup (negotiate)")); | ||
2921 | if (ses == NULL) | ||
2922 | return -EINVAL; | ||
2923 | domain = ses->domainName; | ||
2924 | *pNTLMv2_flag = false; | ||
2925 | smb_buffer = cifs_buf_get(); | ||
2926 | if (smb_buffer == NULL) { | ||
2927 | return -ENOMEM; | ||
2928 | } | ||
2929 | smb_buffer_response = smb_buffer; | ||
2930 | pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
2931 | pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; | ||
2932 | |||
2933 | /* send SMBsessionSetup here */ | ||
2934 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
2935 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
2936 | |||
2937 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2938 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
2939 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | ||
2940 | |||
2941 | pSMB->req.AndXCommand = 0xFF; | ||
2942 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
2943 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
2944 | |||
2945 | if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
2946 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
2947 | |||
2948 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
2949 | CAP_EXTENDED_SECURITY; | ||
2950 | if (ses->capabilities & CAP_UNICODE) { | ||
2951 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
2952 | capabilities |= CAP_UNICODE; | ||
2953 | } | ||
2954 | if (ses->capabilities & CAP_STATUS32) { | ||
2955 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
2956 | capabilities |= CAP_STATUS32; | ||
2957 | } | ||
2958 | if (ses->capabilities & CAP_DFS) { | ||
2959 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
2960 | capabilities |= CAP_DFS; | ||
2961 | } | ||
2962 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
2963 | |||
2964 | bcc_ptr = (char *) &pSMB->req.SecurityBlob; | ||
2965 | SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; | ||
2966 | strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); | ||
2967 | SecurityBlob->MessageType = NtLmNegotiate; | ||
2968 | negotiate_flags = | ||
2969 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | | ||
2970 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | | ||
2971 | NTLMSSP_NEGOTIATE_56 | | ||
2972 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; | ||
2973 | if (sign_CIFS_PDUs) | ||
2974 | negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
2975 | /* if (ntlmv2_support) | ||
2976 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/ | ||
2977 | /* setup pointers to domain name and workstation name */ | ||
2978 | bcc_ptr += SecurityBlobLength; | ||
2979 | |||
2980 | SecurityBlob->WorkstationName.Buffer = 0; | ||
2981 | SecurityBlob->WorkstationName.Length = 0; | ||
2982 | SecurityBlob->WorkstationName.MaximumLength = 0; | ||
2983 | |||
2984 | /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent | ||
2985 | along with username on auth request (ie the response to challenge) */ | ||
2986 | SecurityBlob->DomainName.Buffer = 0; | ||
2987 | SecurityBlob->DomainName.Length = 0; | ||
2988 | SecurityBlob->DomainName.MaximumLength = 0; | ||
2989 | if (ses->capabilities & CAP_UNICODE) { | ||
2990 | if ((long) bcc_ptr % 2) { | ||
2991 | *bcc_ptr = 0; | ||
2992 | bcc_ptr++; | ||
2993 | } | ||
2994 | |||
2995 | bytes_returned = | ||
2996 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
2997 | 32, nls_codepage); | ||
2998 | bcc_ptr += 2 * bytes_returned; | ||
2999 | bytes_returned = | ||
3000 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, | ||
3001 | nls_codepage); | ||
3002 | bcc_ptr += 2 * bytes_returned; | ||
3003 | bcc_ptr += 2; /* null terminate Linux version */ | ||
3004 | bytes_returned = | ||
3005 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
3006 | 64, nls_codepage); | ||
3007 | bcc_ptr += 2 * bytes_returned; | ||
3008 | *(bcc_ptr + 1) = 0; | ||
3009 | *(bcc_ptr + 2) = 0; | ||
3010 | bcc_ptr += 2; /* null terminate network opsys string */ | ||
3011 | *(bcc_ptr + 1) = 0; | ||
3012 | *(bcc_ptr + 2) = 0; | ||
3013 | bcc_ptr += 2; /* null domain */ | ||
3014 | } else { /* ASCII */ | ||
3015 | strcpy(bcc_ptr, "Linux version "); | ||
3016 | bcc_ptr += strlen("Linux version "); | ||
3017 | strcpy(bcc_ptr, utsname()->release); | ||
3018 | bcc_ptr += strlen(utsname()->release) + 1; | ||
3019 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
3020 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
3021 | bcc_ptr++; /* empty domain field */ | ||
3022 | *bcc_ptr = 0; | ||
3023 | } | ||
3024 | SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); | ||
3025 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
3026 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
3027 | smb_buffer->smb_buf_length += count; | ||
3028 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
3029 | |||
3030 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
3031 | &bytes_returned, CIFS_LONG_OP); | ||
3032 | |||
3033 | if (smb_buffer_response->Status.CifsError == | ||
3034 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) | ||
3035 | rc = 0; | ||
3036 | |||
3037 | if (rc) { | ||
3038 | /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ | ||
3039 | } else if ((smb_buffer_response->WordCount == 3) | ||
3040 | || (smb_buffer_response->WordCount == 4)) { | ||
3041 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
3042 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
3043 | |||
3044 | if (action & GUEST_LOGIN) | ||
3045 | cFYI(1, ("Guest login")); | ||
3046 | /* Do we want to set anything in SesInfo struct when guest login? */ | ||
3047 | |||
3048 | bcc_ptr = pByteArea(smb_buffer_response); | ||
3049 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
3050 | |||
3051 | SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; | ||
3052 | if (SecurityBlob2->MessageType != NtLmChallenge) { | ||
3053 | cFYI(1, ("Unexpected NTLMSSP message type received %d", | ||
3054 | SecurityBlob2->MessageType)); | ||
3055 | } else if (ses) { | ||
3056 | ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ | ||
3057 | cFYI(1, ("UID = %d", ses->Suid)); | ||
3058 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
3059 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
3060 | && (blob_len < | ||
3061 | pSMBr->resp.ByteCount))) { | ||
3062 | |||
3063 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
3064 | bcc_ptr += blob_len; | ||
3065 | cFYI(1, ("Security Blob Length %d", | ||
3066 | blob_len)); | ||
3067 | } | ||
3068 | |||
3069 | cFYI(1, ("NTLMSSP Challenge rcvd")); | ||
3070 | |||
3071 | memcpy(ses->server->cryptKey, | ||
3072 | SecurityBlob2->Challenge, | ||
3073 | CIFS_CRYPTO_KEY_SIZE); | ||
3074 | if (SecurityBlob2->NegotiateFlags & | ||
3075 | cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2)) | ||
3076 | *pNTLMv2_flag = true; | ||
3077 | |||
3078 | if ((SecurityBlob2->NegotiateFlags & | ||
3079 | cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) | ||
3080 | || (sign_CIFS_PDUs > 1)) | ||
3081 | ses->server->secMode |= | ||
3082 | SECMODE_SIGN_REQUIRED; | ||
3083 | if ((SecurityBlob2->NegotiateFlags & | ||
3084 | cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs)) | ||
3085 | ses->server->secMode |= | ||
3086 | SECMODE_SIGN_ENABLED; | ||
3087 | |||
3088 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
3089 | if ((long) (bcc_ptr) % 2) { | ||
3090 | remaining_words = | ||
3091 | (BCC(smb_buffer_response) | ||
3092 | - 1) / 2; | ||
3093 | /* Must word align unicode strings */ | ||
3094 | bcc_ptr++; | ||
3095 | } else { | ||
3096 | remaining_words = | ||
3097 | BCC | ||
3098 | (smb_buffer_response) / 2; | ||
3099 | } | ||
3100 | len = | ||
3101 | UniStrnlen((wchar_t *) bcc_ptr, | ||
3102 | remaining_words - 1); | ||
3103 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
3104 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
3105 | terminating last Unicode string in response */ | ||
3106 | kfree(ses->serverOS); | ||
3107 | ses->serverOS = | ||
3108 | kzalloc(2 * (len + 1), GFP_KERNEL); | ||
3109 | cifs_strfromUCS_le(ses->serverOS, | ||
3110 | (__le16 *) | ||
3111 | bcc_ptr, len, | ||
3112 | nls_codepage); | ||
3113 | bcc_ptr += 2 * (len + 1); | ||
3114 | remaining_words -= len + 1; | ||
3115 | ses->serverOS[2 * len] = 0; | ||
3116 | ses->serverOS[1 + (2 * len)] = 0; | ||
3117 | if (remaining_words > 0) { | ||
3118 | len = UniStrnlen((wchar_t *) | ||
3119 | bcc_ptr, | ||
3120 | remaining_words | ||
3121 | - 1); | ||
3122 | kfree(ses->serverNOS); | ||
3123 | ses->serverNOS = | ||
3124 | kzalloc(2 * (len + 1), | ||
3125 | GFP_KERNEL); | ||
3126 | cifs_strfromUCS_le(ses-> | ||
3127 | serverNOS, | ||
3128 | (__le16 *) | ||
3129 | bcc_ptr, | ||
3130 | len, | ||
3131 | nls_codepage); | ||
3132 | bcc_ptr += 2 * (len + 1); | ||
3133 | ses->serverNOS[2 * len] = 0; | ||
3134 | ses->serverNOS[1 + | ||
3135 | (2 * len)] = 0; | ||
3136 | remaining_words -= len + 1; | ||
3137 | if (remaining_words > 0) { | ||
3138 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
3139 | /* last string not always null terminated | ||
3140 | (for e.g. for Windows XP & 2000) */ | ||
3141 | kfree(ses->serverDomain); | ||
3142 | ses->serverDomain = | ||
3143 | kzalloc(2 * | ||
3144 | (len + | ||
3145 | 1), | ||
3146 | GFP_KERNEL); | ||
3147 | cifs_strfromUCS_le | ||
3148 | (ses->serverDomain, | ||
3149 | (__le16 *)bcc_ptr, | ||
3150 | len, nls_codepage); | ||
3151 | bcc_ptr += | ||
3152 | 2 * (len + 1); | ||
3153 | ses->serverDomain[2*len] | ||
3154 | = 0; | ||
3155 | ses->serverDomain | ||
3156 | [1 + (2 * len)] | ||
3157 | = 0; | ||
3158 | } /* else no more room so create dummy domain string */ | ||
3159 | else { | ||
3160 | kfree(ses->serverDomain); | ||
3161 | ses->serverDomain = | ||
3162 | kzalloc(2, | ||
3163 | GFP_KERNEL); | ||
3164 | } | ||
3165 | } else { /* no room so create dummy domain and NOS string */ | ||
3166 | kfree(ses->serverDomain); | ||
3167 | ses->serverDomain = | ||
3168 | kzalloc(2, GFP_KERNEL); | ||
3169 | kfree(ses->serverNOS); | ||
3170 | ses->serverNOS = | ||
3171 | kzalloc(2, GFP_KERNEL); | ||
3172 | } | ||
3173 | } else { /* ASCII */ | ||
3174 | len = strnlen(bcc_ptr, 1024); | ||
3175 | if (((long) bcc_ptr + len) - (long) | ||
3176 | pByteArea(smb_buffer_response) | ||
3177 | <= BCC(smb_buffer_response)) { | ||
3178 | kfree(ses->serverOS); | ||
3179 | ses->serverOS = | ||
3180 | kzalloc(len + 1, | ||
3181 | GFP_KERNEL); | ||
3182 | strncpy(ses->serverOS, | ||
3183 | bcc_ptr, len); | ||
3184 | |||
3185 | bcc_ptr += len; | ||
3186 | bcc_ptr[0] = 0; /* null terminate string */ | ||
3187 | bcc_ptr++; | ||
3188 | |||
3189 | len = strnlen(bcc_ptr, 1024); | ||
3190 | kfree(ses->serverNOS); | ||
3191 | ses->serverNOS = | ||
3192 | kzalloc(len + 1, | ||
3193 | GFP_KERNEL); | ||
3194 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
3195 | bcc_ptr += len; | ||
3196 | bcc_ptr[0] = 0; | ||
3197 | bcc_ptr++; | ||
3198 | |||
3199 | len = strnlen(bcc_ptr, 1024); | ||
3200 | kfree(ses->serverDomain); | ||
3201 | ses->serverDomain = | ||
3202 | kzalloc(len + 1, | ||
3203 | GFP_KERNEL); | ||
3204 | strncpy(ses->serverDomain, | ||
3205 | bcc_ptr, len); | ||
3206 | bcc_ptr += len; | ||
3207 | bcc_ptr[0] = 0; | ||
3208 | bcc_ptr++; | ||
3209 | } else | ||
3210 | cFYI(1, | ||
3211 | ("field of length %d " | ||
3212 | "extends beyond end of smb", | ||
3213 | len)); | ||
3214 | } | ||
3215 | } else { | ||
3216 | cERROR(1, ("Security Blob Length extends beyond" | ||
3217 | " end of SMB")); | ||
3218 | } | ||
3219 | } else { | ||
3220 | cERROR(1, ("No session structure passed in.")); | ||
3221 | } | ||
3222 | } else { | ||
3223 | cERROR(1, ("Invalid Word count %d:", | ||
3224 | smb_buffer_response->WordCount)); | ||
3225 | rc = -EIO; | ||
3226 | } | ||
3227 | |||
3228 | cifs_buf_release(smb_buffer); | ||
3229 | |||
3230 | return rc; | ||
3231 | } | ||
3232 | static int | ||
3233 | CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
3234 | char *ntlm_session_key, bool ntlmv2_flag, | ||
3235 | const struct nls_table *nls_codepage) | ||
3236 | { | ||
3237 | struct smb_hdr *smb_buffer; | ||
3238 | struct smb_hdr *smb_buffer_response; | ||
3239 | SESSION_SETUP_ANDX *pSMB; | ||
3240 | SESSION_SETUP_ANDX *pSMBr; | ||
3241 | char *bcc_ptr; | ||
3242 | char *user; | ||
3243 | char *domain; | ||
3244 | int rc = 0; | ||
3245 | int remaining_words = 0; | ||
3246 | int bytes_returned = 0; | ||
3247 | int len; | ||
3248 | int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE); | ||
3249 | PAUTHENTICATE_MESSAGE SecurityBlob; | ||
3250 | __u32 negotiate_flags, capabilities; | ||
3251 | __u16 count; | ||
3252 | |||
3253 | cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); | ||
3254 | if (ses == NULL) | ||
3255 | return -EINVAL; | ||
3256 | user = ses->userName; | ||
3257 | domain = ses->domainName; | ||
3258 | smb_buffer = cifs_buf_get(); | ||
3259 | if (smb_buffer == NULL) { | ||
3260 | return -ENOMEM; | ||
3261 | } | ||
3262 | smb_buffer_response = smb_buffer; | ||
3263 | pSMB = (SESSION_SETUP_ANDX *)smb_buffer; | ||
3264 | pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response; | ||
3265 | |||
3266 | /* send SMBsessionSetup here */ | ||
3267 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
3268 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
3269 | |||
3270 | smb_buffer->Mid = GetNextMid(ses->server); | ||
3271 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | ||
3272 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
3273 | pSMB->req.AndXCommand = 0xFF; | ||
3274 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
3275 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
3276 | |||
3277 | pSMB->req.hdr.Uid = ses->Suid; | ||
3278 | |||
3279 | if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
3280 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
3281 | |||
3282 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
3283 | CAP_EXTENDED_SECURITY; | ||
3284 | if (ses->capabilities & CAP_UNICODE) { | ||
3285 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
3286 | capabilities |= CAP_UNICODE; | ||
3287 | } | ||
3288 | if (ses->capabilities & CAP_STATUS32) { | ||
3289 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
3290 | capabilities |= CAP_STATUS32; | ||
3291 | } | ||
3292 | if (ses->capabilities & CAP_DFS) { | ||
3293 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
3294 | capabilities |= CAP_DFS; | ||
3295 | } | ||
3296 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
3297 | |||
3298 | bcc_ptr = (char *)&pSMB->req.SecurityBlob; | ||
3299 | SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr; | ||
3300 | strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); | ||
3301 | SecurityBlob->MessageType = NtLmAuthenticate; | ||
3302 | bcc_ptr += SecurityBlobLength; | ||
3303 | negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | | ||
3304 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | | ||
3305 | 0x80000000 | NTLMSSP_NEGOTIATE_128; | ||
3306 | if (sign_CIFS_PDUs) | ||
3307 | negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; | ||
3308 | if (ntlmv2_flag) | ||
3309 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; | ||
3310 | |||
3311 | /* setup pointers to domain name and workstation name */ | ||
3312 | |||
3313 | SecurityBlob->WorkstationName.Buffer = 0; | ||
3314 | SecurityBlob->WorkstationName.Length = 0; | ||
3315 | SecurityBlob->WorkstationName.MaximumLength = 0; | ||
3316 | SecurityBlob->SessionKey.Length = 0; | ||
3317 | SecurityBlob->SessionKey.MaximumLength = 0; | ||
3318 | SecurityBlob->SessionKey.Buffer = 0; | ||
3319 | |||
3320 | SecurityBlob->LmChallengeResponse.Length = 0; | ||
3321 | SecurityBlob->LmChallengeResponse.MaximumLength = 0; | ||
3322 | SecurityBlob->LmChallengeResponse.Buffer = 0; | ||
3323 | |||
3324 | SecurityBlob->NtChallengeResponse.Length = | ||
3325 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
3326 | SecurityBlob->NtChallengeResponse.MaximumLength = | ||
3327 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
3328 | memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
3329 | SecurityBlob->NtChallengeResponse.Buffer = | ||
3330 | cpu_to_le32(SecurityBlobLength); | ||
3331 | SecurityBlobLength += CIFS_SESS_KEY_SIZE; | ||
3332 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
3333 | |||
3334 | if (ses->capabilities & CAP_UNICODE) { | ||
3335 | if (domain == NULL) { | ||
3336 | SecurityBlob->DomainName.Buffer = 0; | ||
3337 | SecurityBlob->DomainName.Length = 0; | ||
3338 | SecurityBlob->DomainName.MaximumLength = 0; | ||
3339 | } else { | ||
3340 | __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, | ||
3341 | nls_codepage); | ||
3342 | ln *= 2; | ||
3343 | SecurityBlob->DomainName.MaximumLength = | ||
3344 | cpu_to_le16(ln); | ||
3345 | SecurityBlob->DomainName.Buffer = | ||
3346 | cpu_to_le32(SecurityBlobLength); | ||
3347 | bcc_ptr += ln; | ||
3348 | SecurityBlobLength += ln; | ||
3349 | SecurityBlob->DomainName.Length = cpu_to_le16(ln); | ||
3350 | } | ||
3351 | if (user == NULL) { | ||
3352 | SecurityBlob->UserName.Buffer = 0; | ||
3353 | SecurityBlob->UserName.Length = 0; | ||
3354 | SecurityBlob->UserName.MaximumLength = 0; | ||
3355 | } else { | ||
3356 | __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, | ||
3357 | nls_codepage); | ||
3358 | ln *= 2; | ||
3359 | SecurityBlob->UserName.MaximumLength = | ||
3360 | cpu_to_le16(ln); | ||
3361 | SecurityBlob->UserName.Buffer = | ||
3362 | cpu_to_le32(SecurityBlobLength); | ||
3363 | bcc_ptr += ln; | ||
3364 | SecurityBlobLength += ln; | ||
3365 | SecurityBlob->UserName.Length = cpu_to_le16(ln); | ||
3366 | } | ||
3367 | |||
3368 | /* SecurityBlob->WorkstationName.Length = | ||
3369 | cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); | ||
3370 | SecurityBlob->WorkstationName.Length *= 2; | ||
3371 | SecurityBlob->WorkstationName.MaximumLength = | ||
3372 | cpu_to_le16(SecurityBlob->WorkstationName.Length); | ||
3373 | SecurityBlob->WorkstationName.Buffer = | ||
3374 | cpu_to_le32(SecurityBlobLength); | ||
3375 | bcc_ptr += SecurityBlob->WorkstationName.Length; | ||
3376 | SecurityBlobLength += SecurityBlob->WorkstationName.Length; | ||
3377 | SecurityBlob->WorkstationName.Length = | ||
3378 | cpu_to_le16(SecurityBlob->WorkstationName.Length); */ | ||
3379 | |||
3380 | if ((long) bcc_ptr % 2) { | ||
3381 | *bcc_ptr = 0; | ||
3382 | bcc_ptr++; | ||
3383 | } | ||
3384 | bytes_returned = | ||
3385 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
3386 | 32, nls_codepage); | ||
3387 | bcc_ptr += 2 * bytes_returned; | ||
3388 | bytes_returned = | ||
3389 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, | ||
3390 | nls_codepage); | ||
3391 | bcc_ptr += 2 * bytes_returned; | ||
3392 | bcc_ptr += 2; /* null term version string */ | ||
3393 | bytes_returned = | ||
3394 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
3395 | 64, nls_codepage); | ||
3396 | bcc_ptr += 2 * bytes_returned; | ||
3397 | *(bcc_ptr + 1) = 0; | ||
3398 | *(bcc_ptr + 2) = 0; | ||
3399 | bcc_ptr += 2; /* null terminate network opsys string */ | ||
3400 | *(bcc_ptr + 1) = 0; | ||
3401 | *(bcc_ptr + 2) = 0; | ||
3402 | bcc_ptr += 2; /* null domain */ | ||
3403 | } else { /* ASCII */ | ||
3404 | if (domain == NULL) { | ||
3405 | SecurityBlob->DomainName.Buffer = 0; | ||
3406 | SecurityBlob->DomainName.Length = 0; | ||
3407 | SecurityBlob->DomainName.MaximumLength = 0; | ||
3408 | } else { | ||
3409 | __u16 ln; | ||
3410 | negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; | ||
3411 | strncpy(bcc_ptr, domain, 63); | ||
3412 | ln = strnlen(domain, 64); | ||
3413 | SecurityBlob->DomainName.MaximumLength = | ||
3414 | cpu_to_le16(ln); | ||
3415 | SecurityBlob->DomainName.Buffer = | ||
3416 | cpu_to_le32(SecurityBlobLength); | ||
3417 | bcc_ptr += ln; | ||
3418 | SecurityBlobLength += ln; | ||
3419 | SecurityBlob->DomainName.Length = cpu_to_le16(ln); | ||
3420 | } | ||
3421 | if (user == NULL) { | ||
3422 | SecurityBlob->UserName.Buffer = 0; | ||
3423 | SecurityBlob->UserName.Length = 0; | ||
3424 | SecurityBlob->UserName.MaximumLength = 0; | ||
3425 | } else { | ||
3426 | __u16 ln; | ||
3427 | strncpy(bcc_ptr, user, 63); | ||
3428 | ln = strnlen(user, 64); | ||
3429 | SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); | ||
3430 | SecurityBlob->UserName.Buffer = | ||
3431 | cpu_to_le32(SecurityBlobLength); | ||
3432 | bcc_ptr += ln; | ||
3433 | SecurityBlobLength += ln; | ||
3434 | SecurityBlob->UserName.Length = cpu_to_le16(ln); | ||
3435 | } | ||
3436 | /* BB fill in our workstation name if known BB */ | ||
3437 | |||
3438 | strcpy(bcc_ptr, "Linux version "); | ||
3439 | bcc_ptr += strlen("Linux version "); | ||
3440 | strcpy(bcc_ptr, utsname()->release); | ||
3441 | bcc_ptr += strlen(utsname()->release) + 1; | ||
3442 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
3443 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
3444 | bcc_ptr++; /* null domain */ | ||
3445 | *bcc_ptr = 0; | ||
3446 | } | ||
3447 | SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); | ||
3448 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
3449 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
3450 | smb_buffer->smb_buf_length += count; | ||
3451 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
3452 | |||
3453 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
3454 | &bytes_returned, CIFS_LONG_OP); | ||
3455 | if (rc) { | ||
3456 | /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ | ||
3457 | } else if ((smb_buffer_response->WordCount == 3) || | ||
3458 | (smb_buffer_response->WordCount == 4)) { | ||
3459 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
3460 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
3461 | if (action & GUEST_LOGIN) | ||
3462 | cFYI(1, ("Guest login")); /* BB Should we set anything | ||
3463 | in SesInfo struct ? */ | ||
3464 | /* if (SecurityBlob2->MessageType != NtLm??) { | ||
3465 | cFYI("Unexpected message type on auth response is %d")); | ||
3466 | } */ | ||
3467 | |||
3468 | if (ses) { | ||
3469 | cFYI(1, | ||
3470 | ("Check challenge UID %d vs auth response UID %d", | ||
3471 | ses->Suid, smb_buffer_response->Uid)); | ||
3472 | /* UID left in wire format */ | ||
3473 | ses->Suid = smb_buffer_response->Uid; | ||
3474 | bcc_ptr = pByteArea(smb_buffer_response); | ||
3475 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
3476 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
3477 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
3478 | && (blob_len < | ||
3479 | pSMBr->resp.ByteCount))) { | ||
3480 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
3481 | bcc_ptr += | ||
3482 | blob_len; | ||
3483 | cFYI(1, | ||
3484 | ("Security Blob Length %d ", | ||
3485 | blob_len)); | ||
3486 | } | ||
3487 | |||
3488 | cFYI(1, | ||
3489 | ("NTLMSSP response to Authenticate ")); | ||
3490 | |||
3491 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
3492 | if ((long) (bcc_ptr) % 2) { | ||
3493 | remaining_words = | ||
3494 | (BCC(smb_buffer_response) | ||
3495 | - 1) / 2; | ||
3496 | bcc_ptr++; /* Unicode strings must be word aligned */ | ||
3497 | } else { | ||
3498 | remaining_words = BCC(smb_buffer_response) / 2; | ||
3499 | } | ||
3500 | len = UniStrnlen((wchar_t *) bcc_ptr, | ||
3501 | remaining_words - 1); | ||
3502 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
3503 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
3504 | terminating last Unicode string in response */ | ||
3505 | kfree(ses->serverOS); | ||
3506 | ses->serverOS = | ||
3507 | kzalloc(2 * (len + 1), GFP_KERNEL); | ||
3508 | cifs_strfromUCS_le(ses->serverOS, | ||
3509 | (__le16 *) | ||
3510 | bcc_ptr, len, | ||
3511 | nls_codepage); | ||
3512 | bcc_ptr += 2 * (len + 1); | ||
3513 | remaining_words -= len + 1; | ||
3514 | ses->serverOS[2 * len] = 0; | ||
3515 | ses->serverOS[1 + (2 * len)] = 0; | ||
3516 | if (remaining_words > 0) { | ||
3517 | len = UniStrnlen((wchar_t *) | ||
3518 | bcc_ptr, | ||
3519 | remaining_words | ||
3520 | - 1); | ||
3521 | kfree(ses->serverNOS); | ||
3522 | ses->serverNOS = | ||
3523 | kzalloc(2 * (len + 1), | ||
3524 | GFP_KERNEL); | ||
3525 | cifs_strfromUCS_le(ses-> | ||
3526 | serverNOS, | ||
3527 | (__le16 *) | ||
3528 | bcc_ptr, | ||
3529 | len, | ||
3530 | nls_codepage); | ||
3531 | bcc_ptr += 2 * (len + 1); | ||
3532 | ses->serverNOS[2 * len] = 0; | ||
3533 | ses->serverNOS[1+(2*len)] = 0; | ||
3534 | remaining_words -= len + 1; | ||
3535 | if (remaining_words > 0) { | ||
3536 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
3537 | /* last string not always null terminated (e.g. for Windows XP & 2000) */ | ||
3538 | kfree(ses->serverDomain); | ||
3539 | ses->serverDomain = | ||
3540 | kzalloc(2 * | ||
3541 | (len + | ||
3542 | 1), | ||
3543 | GFP_KERNEL); | ||
3544 | cifs_strfromUCS_le | ||
3545 | (ses-> | ||
3546 | serverDomain, | ||
3547 | (__le16 *) | ||
3548 | bcc_ptr, len, | ||
3549 | nls_codepage); | ||
3550 | bcc_ptr += | ||
3551 | 2 * (len + 1); | ||
3552 | ses-> | ||
3553 | serverDomain[2 | ||
3554 | * len] | ||
3555 | = 0; | ||
3556 | ses-> | ||
3557 | serverDomain[1 | ||
3558 | + | ||
3559 | (2 | ||
3560 | * | ||
3561 | len)] | ||
3562 | = 0; | ||
3563 | } /* else no more room so create dummy domain string */ | ||
3564 | else { | ||
3565 | kfree(ses->serverDomain); | ||
3566 | ses->serverDomain = kzalloc(2,GFP_KERNEL); | ||
3567 | } | ||
3568 | } else { /* no room so create dummy domain and NOS string */ | ||
3569 | kfree(ses->serverDomain); | ||
3570 | ses->serverDomain = kzalloc(2, GFP_KERNEL); | ||
3571 | kfree(ses->serverNOS); | ||
3572 | ses->serverNOS = kzalloc(2, GFP_KERNEL); | ||
3573 | } | ||
3574 | } else { /* ASCII */ | ||
3575 | len = strnlen(bcc_ptr, 1024); | ||
3576 | if (((long) bcc_ptr + len) - | ||
3577 | (long) pByteArea(smb_buffer_response) | ||
3578 | <= BCC(smb_buffer_response)) { | ||
3579 | kfree(ses->serverOS); | ||
3580 | ses->serverOS = kzalloc(len + 1, GFP_KERNEL); | ||
3581 | strncpy(ses->serverOS,bcc_ptr, len); | ||
3582 | |||
3583 | bcc_ptr += len; | ||
3584 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
3585 | bcc_ptr++; | ||
3586 | |||
3587 | len = strnlen(bcc_ptr, 1024); | ||
3588 | kfree(ses->serverNOS); | ||
3589 | ses->serverNOS = kzalloc(len+1, | ||
3590 | GFP_KERNEL); | ||
3591 | strncpy(ses->serverNOS, | ||
3592 | bcc_ptr, len); | ||
3593 | bcc_ptr += len; | ||
3594 | bcc_ptr[0] = 0; | ||
3595 | bcc_ptr++; | ||
3596 | |||
3597 | len = strnlen(bcc_ptr, 1024); | ||
3598 | kfree(ses->serverDomain); | ||
3599 | ses->serverDomain = | ||
3600 | kzalloc(len+1, | ||
3601 | GFP_KERNEL); | ||
3602 | strncpy(ses->serverDomain, | ||
3603 | bcc_ptr, len); | ||
3604 | bcc_ptr += len; | ||
3605 | bcc_ptr[0] = 0; | ||
3606 | bcc_ptr++; | ||
3607 | } else | ||
3608 | cFYI(1, ("field of length %d " | ||
3609 | "extends beyond end of smb ", | ||
3610 | len)); | ||
3611 | } | ||
3612 | } else { | ||
3613 | cERROR(1, ("Security Blob extends beyond end " | ||
3614 | "of SMB")); | ||
3615 | } | ||
3616 | } else { | ||
3617 | cERROR(1, ("No session structure passed in.")); | ||
3618 | } | ||
3619 | } else { | ||
3620 | cERROR(1, ("Invalid Word count %d: ", | ||
3621 | smb_buffer_response->WordCount)); | ||
3622 | rc = -EIO; | ||
3623 | } | ||
3624 | |||
3625 | cifs_buf_release(smb_buffer); | ||
3626 | |||
3627 | return rc; | ||
3628 | } | ||
3629 | |||
3630 | int | 2615 | int |
3631 | CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | 2616 | CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, |
3632 | const char *tree, struct cifsTconInfo *tcon, | 2617 | const char *tree, struct cifsTconInfo *tcon, |
@@ -3638,7 +2623,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3638 | TCONX_RSP *pSMBr; | 2623 | TCONX_RSP *pSMBr; |
3639 | unsigned char *bcc_ptr; | 2624 | unsigned char *bcc_ptr; |
3640 | int rc = 0; | 2625 | int rc = 0; |
3641 | int length; | 2626 | int length, bytes_left; |
3642 | __u16 count; | 2627 | __u16 count; |
3643 | 2628 | ||
3644 | if (ses == NULL) | 2629 | if (ses == NULL) |
@@ -3726,14 +2711,22 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3726 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, | 2711 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
3727 | CIFS_STD_OP); | 2712 | CIFS_STD_OP); |
3728 | 2713 | ||
3729 | /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ | ||
3730 | /* above now done in SendReceive */ | 2714 | /* above now done in SendReceive */ |
3731 | if ((rc == 0) && (tcon != NULL)) { | 2715 | if ((rc == 0) && (tcon != NULL)) { |
2716 | bool is_unicode; | ||
2717 | |||
3732 | tcon->tidStatus = CifsGood; | 2718 | tcon->tidStatus = CifsGood; |
3733 | tcon->need_reconnect = false; | 2719 | tcon->need_reconnect = false; |
3734 | tcon->tid = smb_buffer_response->Tid; | 2720 | tcon->tid = smb_buffer_response->Tid; |
3735 | bcc_ptr = pByteArea(smb_buffer_response); | 2721 | bcc_ptr = pByteArea(smb_buffer_response); |
3736 | 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 | |||
3737 | /* skip service field (NB: this field is always ASCII) */ | 2730 | /* skip service field (NB: this field is always ASCII) */ |
3738 | if (length == 3) { | 2731 | if (length == 3) { |
3739 | if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && | 2732 | if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && |
@@ -3748,39 +2741,16 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3748 | } | 2741 | } |
3749 | } | 2742 | } |
3750 | bcc_ptr += length + 1; | 2743 | bcc_ptr += length + 1; |
2744 | bytes_left -= (length + 1); | ||
3751 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); | 2745 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); |
3752 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | 2746 | |
3753 | length = UniStrnlen((wchar_t *) bcc_ptr, 512); | 2747 | /* mostly informational -- no need to fail on error here */ |
3754 | if ((bcc_ptr + (2 * length)) - | 2748 | tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr, |
3755 | pByteArea(smb_buffer_response) <= | 2749 | bytes_left, is_unicode, |
3756 | BCC(smb_buffer_response)) { | 2750 | nls_codepage); |
3757 | kfree(tcon->nativeFileSystem); | 2751 | |
3758 | tcon->nativeFileSystem = | 2752 | cFYI(1, ("nativeFileSystem=%s", tcon->nativeFileSystem)); |
3759 | kzalloc((4 * length) + 2, GFP_KERNEL); | 2753 | |
3760 | if (tcon->nativeFileSystem) { | ||
3761 | cifs_strfromUCS_le( | ||
3762 | tcon->nativeFileSystem, | ||
3763 | (__le16 *) bcc_ptr, | ||
3764 | length, nls_codepage); | ||
3765 | cFYI(1, ("nativeFileSystem=%s", | ||
3766 | tcon->nativeFileSystem)); | ||
3767 | } | ||
3768 | } | ||
3769 | /* else do not bother copying these information fields*/ | ||
3770 | } else { | ||
3771 | length = strnlen(bcc_ptr, 1024); | ||
3772 | if ((bcc_ptr + length) - | ||
3773 | pByteArea(smb_buffer_response) <= | ||
3774 | BCC(smb_buffer_response)) { | ||
3775 | kfree(tcon->nativeFileSystem); | ||
3776 | tcon->nativeFileSystem = | ||
3777 | kzalloc(length + 1, GFP_KERNEL); | ||
3778 | if (tcon->nativeFileSystem) | ||
3779 | strncpy(tcon->nativeFileSystem, bcc_ptr, | ||
3780 | length); | ||
3781 | } | ||
3782 | /* else do not bother copying these information fields*/ | ||
3783 | } | ||
3784 | if ((smb_buffer_response->WordCount == 3) || | 2754 | if ((smb_buffer_response->WordCount == 3) || |
3785 | (smb_buffer_response->WordCount == 7)) | 2755 | (smb_buffer_response->WordCount == 7)) |
3786 | /* field is in same location */ | 2756 | /* field is in same location */ |
@@ -3819,8 +2789,6 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3819 | struct nls_table *nls_info) | 2789 | struct nls_table *nls_info) |
3820 | { | 2790 | { |
3821 | int rc = 0; | 2791 | int rc = 0; |
3822 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
3823 | bool ntlmv2_flag = false; | ||
3824 | int first_time = 0; | 2792 | int first_time = 0; |
3825 | struct TCP_Server_Info *server = pSesInfo->server; | 2793 | struct TCP_Server_Info *server = pSesInfo->server; |
3826 | 2794 | ||
@@ -3852,83 +2820,19 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3852 | pSesInfo->capabilities = server->capabilities; | 2820 | pSesInfo->capabilities = server->capabilities; |
3853 | if (linuxExtEnabled == 0) | 2821 | if (linuxExtEnabled == 0) |
3854 | pSesInfo->capabilities &= (~CAP_UNIX); | 2822 | pSesInfo->capabilities &= (~CAP_UNIX); |
3855 | /* pSesInfo->sequence_number = 0;*/ | 2823 | |
3856 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", | 2824 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", |
3857 | server->secMode, server->capabilities, server->timeAdj)); | 2825 | server->secMode, server->capabilities, server->timeAdj)); |
3858 | 2826 | ||
3859 | if (experimEnabled < 2) | 2827 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); |
3860 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); | ||
3861 | else if (extended_security | ||
3862 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
3863 | && (server->secType == NTLMSSP)) { | ||
3864 | rc = -EOPNOTSUPP; | ||
3865 | } else if (extended_security | ||
3866 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
3867 | && (server->secType == RawNTLMSSP)) { | ||
3868 | cFYI(1, ("NTLMSSP sesssetup")); | ||
3869 | rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag, | ||
3870 | nls_info); | ||
3871 | if (!rc) { | ||
3872 | if (ntlmv2_flag) { | ||
3873 | char *v2_response; | ||
3874 | cFYI(1, ("more secure NTLM ver2 hash")); | ||
3875 | if (CalcNTLMv2_partial_mac_key(pSesInfo, | ||
3876 | nls_info)) { | ||
3877 | rc = -ENOMEM; | ||
3878 | goto ss_err_exit; | ||
3879 | } else | ||
3880 | v2_response = kmalloc(16 + 64 /* blob*/, | ||
3881 | GFP_KERNEL); | ||
3882 | if (v2_response) { | ||
3883 | CalcNTLMv2_response(pSesInfo, | ||
3884 | v2_response); | ||
3885 | /* if (first_time) | ||
3886 | cifs_calculate_ntlmv2_mac_key */ | ||
3887 | kfree(v2_response); | ||
3888 | /* BB Put dummy sig in SessSetup PDU? */ | ||
3889 | } else { | ||
3890 | rc = -ENOMEM; | ||
3891 | goto ss_err_exit; | ||
3892 | } | ||
3893 | |||
3894 | } else { | ||
3895 | SMBNTencrypt(pSesInfo->password, | ||
3896 | server->cryptKey, | ||
3897 | ntlm_session_key); | ||
3898 | |||
3899 | if (first_time) | ||
3900 | cifs_calculate_mac_key( | ||
3901 | &server->mac_signing_key, | ||
3902 | ntlm_session_key, | ||
3903 | pSesInfo->password); | ||
3904 | } | ||
3905 | /* for better security the weaker lanman hash not sent | ||
3906 | in AuthSessSetup so we no longer calculate it */ | ||
3907 | |||
3908 | rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo, | ||
3909 | ntlm_session_key, | ||
3910 | ntlmv2_flag, | ||
3911 | nls_info); | ||
3912 | } | ||
3913 | } else { /* old style NTLM 0.12 session setup */ | ||
3914 | SMBNTencrypt(pSesInfo->password, server->cryptKey, | ||
3915 | ntlm_session_key); | ||
3916 | |||
3917 | if (first_time) | ||
3918 | cifs_calculate_mac_key(&server->mac_signing_key, | ||
3919 | ntlm_session_key, | ||
3920 | pSesInfo->password); | ||
3921 | |||
3922 | rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info); | ||
3923 | } | ||
3924 | if (rc) { | 2828 | if (rc) { |
3925 | cERROR(1, ("Send error in SessSetup = %d", rc)); | 2829 | cERROR(1, ("Send error in SessSetup = %d", rc)); |
3926 | } else { | 2830 | } else { |
3927 | cFYI(1, ("CIFS Session Established successfully")); | 2831 | cFYI(1, ("CIFS Session Established successfully")); |
3928 | spin_lock(&GlobalMid_Lock); | 2832 | spin_lock(&GlobalMid_Lock); |
3929 | pSesInfo->status = CifsGood; | 2833 | pSesInfo->status = CifsGood; |
3930 | pSesInfo->need_reconnect = false; | 2834 | pSesInfo->need_reconnect = false; |
3931 | spin_unlock(&GlobalMid_Lock); | 2835 | spin_unlock(&GlobalMid_Lock); |
3932 | } | 2836 | } |
3933 | 2837 | ||
3934 | ss_err_exit: | 2838 | ss_err_exit: |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 461750e01364..11431ed72a7f 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -281,6 +281,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
281 | int create_options = CREATE_NOT_DIR; | 281 | int create_options = CREATE_NOT_DIR; |
282 | int oplock = 0; | 282 | int oplock = 0; |
283 | int oflags; | 283 | int oflags; |
284 | bool posix_create = false; | ||
284 | /* | 285 | /* |
285 | * BB below access is probably too much for mknod to request | 286 | * BB below access is probably too much for mknod to request |
286 | * but we have to do query and setpathinfo so requesting | 287 | * but we have to do query and setpathinfo so requesting |
@@ -328,11 +329,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
328 | negotation. EREMOTE indicates DFS junction, which is not | 329 | negotation. EREMOTE indicates DFS junction, which is not |
329 | handled in posix open */ | 330 | handled in posix open */ |
330 | 331 | ||
331 | if ((rc == 0) && (newinode == NULL)) | 332 | if (rc == 0) { |
332 | goto cifs_create_get_file_info; /* query inode info */ | 333 | posix_create = true; |
333 | else if (rc == 0) /* success, no need to query */ | 334 | if (newinode == NULL) /* query inode info */ |
334 | goto cifs_create_set_dentry; | 335 | goto cifs_create_get_file_info; |
335 | 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) && | ||
336 | (rc != -EOPNOTSUPP)) /* path not found or net err */ | 339 | (rc != -EOPNOTSUPP)) /* path not found or net err */ |
337 | goto cifs_create_out; | 340 | goto cifs_create_out; |
338 | /* else fallthrough to retry, using older open call, this is | 341 | /* else fallthrough to retry, using older open call, this is |
@@ -464,7 +467,7 @@ cifs_create_set_dentry: | |||
464 | if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) { | 467 | if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) { |
465 | /* mknod case - do not leave file open */ | 468 | /* mknod case - do not leave file open */ |
466 | CIFSSMBClose(xid, tcon, fileHandle); | 469 | CIFSSMBClose(xid, tcon, fileHandle); |
467 | } else if (newinode) { | 470 | } else if (!(posix_create) && (newinode)) { |
468 | cifs_fill_fileinfo(newinode, fileHandle, | 471 | cifs_fill_fileinfo(newinode, fileHandle, |
469 | cifs_sb->tcon, write_only); | 472 | cifs_sb->tcon, write_only); |
470 | } | 473 | } |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 50ca088d8860..38c06f826575 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -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 */ |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index f36b4e40e443..9c869a6dcba1 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -962,13 +962,21 @@ undo_setattr: | |||
962 | goto out_close; | 962 | goto out_close; |
963 | } | 963 | } |
964 | 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 | */ | ||
965 | int cifs_unlink(struct inode *dir, struct dentry *dentry) | 973 | int cifs_unlink(struct inode *dir, struct dentry *dentry) |
966 | { | 974 | { |
967 | int rc = 0; | 975 | int rc = 0; |
968 | int xid; | 976 | int xid; |
969 | char *full_path = NULL; | 977 | char *full_path = NULL; |
970 | struct inode *inode = dentry->d_inode; | 978 | struct inode *inode = dentry->d_inode; |
971 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | 979 | struct cifsInodeInfo *cifs_inode; |
972 | struct super_block *sb = dir->i_sb; | 980 | struct super_block *sb = dir->i_sb; |
973 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 981 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
974 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 982 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
@@ -1012,7 +1020,7 @@ psx_del_no_retry: | |||
1012 | rc = cifs_rename_pending_delete(full_path, dentry, xid); | 1020 | rc = cifs_rename_pending_delete(full_path, dentry, xid); |
1013 | if (rc == 0) | 1021 | if (rc == 0) |
1014 | drop_nlink(inode); | 1022 | drop_nlink(inode); |
1015 | } else if (rc == -EACCES && dosattr == 0) { | 1023 | } else if ((rc == -EACCES) && (dosattr == 0) && inode) { |
1016 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); | 1024 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); |
1017 | if (attrs == NULL) { | 1025 | if (attrs == NULL) { |
1018 | rc = -ENOMEM; | 1026 | rc = -ENOMEM; |
@@ -1020,7 +1028,8 @@ psx_del_no_retry: | |||
1020 | } | 1028 | } |
1021 | 1029 | ||
1022 | /* try to reset dos attributes */ | 1030 | /* try to reset dos attributes */ |
1023 | origattr = cifsInode->cifsAttrs; | 1031 | cifs_inode = CIFS_I(inode); |
1032 | origattr = cifs_inode->cifsAttrs; | ||
1024 | if (origattr == 0) | 1033 | if (origattr == 0) |
1025 | origattr |= ATTR_NORMAL; | 1034 | origattr |= ATTR_NORMAL; |
1026 | dosattr = origattr & ~ATTR_READONLY; | 1035 | dosattr = origattr & ~ATTR_READONLY; |
@@ -1041,13 +1050,13 @@ psx_del_no_retry: | |||
1041 | 1050 | ||
1042 | out_reval: | 1051 | out_reval: |
1043 | if (inode) { | 1052 | if (inode) { |
1044 | cifsInode = CIFS_I(inode); | 1053 | cifs_inode = CIFS_I(inode); |
1045 | cifsInode->time = 0; /* will force revalidate to get info | 1054 | cifs_inode->time = 0; /* will force revalidate to get info |
1046 | when needed */ | 1055 | when needed */ |
1047 | inode->i_ctime = current_fs_time(sb); | 1056 | inode->i_ctime = current_fs_time(sb); |
1048 | } | 1057 | } |
1049 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); | 1058 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); |
1050 | cifsInode = CIFS_I(dir); | 1059 | cifs_inode = CIFS_I(dir); |
1051 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ | 1060 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ |
1052 | 1061 | ||
1053 | kfree(full_path); | 1062 | kfree(full_path); |
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 1a8be6228333..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 | { |
@@ -438,6 +445,38 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
438 | } | 445 | } |
439 | } | 446 | } |
440 | 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 | |||
441 | static int initiate_cifs_search(const int xid, struct file *file) | 480 | static int initiate_cifs_search(const int xid, struct file *file) |
442 | { | 481 | { |
443 | int rc = 0; | 482 | int rc = 0; |
@@ -493,7 +532,10 @@ ffirst_retry: | |||
493 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); | 532 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); |
494 | if (rc == 0) | 533 | if (rc == 0) |
495 | cifsFile->invalidHandle = false; | 534 | cifsFile->invalidHandle = false; |
496 | 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) && | ||
497 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { | 539 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { |
498 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; | 540 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; |
499 | goto ffirst_retry; | 541 | goto ffirst_retry; |
@@ -822,7 +864,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
822 | /* inode num, inode type and filename returned */ | 864 | /* inode num, inode type and filename returned */ |
823 | static int cifs_get_name_from_search_buf(struct qstr *pqst, | 865 | static int cifs_get_name_from_search_buf(struct qstr *pqst, |
824 | char *current_entry, __u16 level, unsigned int unicode, | 866 | char *current_entry, __u16 level, unsigned int unicode, |
825 | struct cifs_sb_info *cifs_sb, int max_len, __u64 *pinum) | 867 | struct cifs_sb_info *cifs_sb, unsigned int max_len, __u64 *pinum) |
826 | { | 868 | { |
827 | int rc = 0; | 869 | int rc = 0; |
828 | unsigned int len = 0; | 870 | unsigned int len = 0; |
@@ -881,14 +923,12 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
881 | } | 923 | } |
882 | 924 | ||
883 | if (unicode) { | 925 | if (unicode) { |
884 | /* BB fixme - test with long names */ | 926 | pqst->len = cifs_from_ucs2((char *) pqst->name, |
885 | /* Note converted filename can be longer than in unicode */ | 927 | (__le16 *) filename, |
886 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) | 928 | UNICODE_NAME_MAX, |
887 | pqst->len = cifs_convertUCSpath((char *)pqst->name, | 929 | min(len, max_len), nlt, |
888 | (__le16 *)filename, len/2, nlt); | 930 | cifs_sb->mnt_cifs_flags & |
889 | else | 931 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
890 | pqst->len = cifs_strfromUCS_le((char *)pqst->name, | ||
891 | (__le16 *)filename, len/2, nlt); | ||
892 | } else { | 932 | } else { |
893 | pqst->name = filename; | 933 | pqst->name = filename; |
894 | pqst->len = len; | 934 | pqst->len = len; |
@@ -898,8 +938,8 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
898 | return rc; | 938 | return rc; |
899 | } | 939 | } |
900 | 940 | ||
901 | static int cifs_filldir(char *pfindEntry, struct file *file, | 941 | static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, |
902 | filldir_t filldir, void *direntry, char *scratch_buf, int max_len) | 942 | void *direntry, char *scratch_buf, unsigned int max_len) |
903 | { | 943 | { |
904 | int rc = 0; | 944 | int rc = 0; |
905 | struct qstr qstring; | 945 | struct qstr qstring; |
@@ -996,7 +1036,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
996 | int num_to_fill = 0; | 1036 | int num_to_fill = 0; |
997 | char *tmp_buf = NULL; | 1037 | char *tmp_buf = NULL; |
998 | char *end_of_smb; | 1038 | char *end_of_smb; |
999 | int max_len; | 1039 | unsigned int max_len; |
1000 | 1040 | ||
1001 | xid = GetXid(); | 1041 | xid = GetXid(); |
1002 | 1042 | ||
@@ -1070,11 +1110,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
1070 | cifsFile->srch_inf.ntwrk_buf_start); | 1110 | cifsFile->srch_inf.ntwrk_buf_start); |
1071 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; | 1111 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; |
1072 | 1112 | ||
1073 | /* To be safe - for UCS to UTF-8 with strings loaded | 1113 | tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL); |
1074 | with the rare long characters alloc more to account for | ||
1075 | such multibyte target UTF-8 characters. cifs_unicode.c, | ||
1076 | which actually does the conversion, has the same limit */ | ||
1077 | tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); | ||
1078 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { | 1114 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { |
1079 | if (current_entry == NULL) { | 1115 | if (current_entry == NULL) { |
1080 | /* 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 c652c73760dd..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,12 +277,11 @@ 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 | cFYI(1, ("bleft %d", bleft)); | 287 | cFYI(1, ("bleft %d", bleft)); |
@@ -300,63 +299,29 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, | |||
300 | ++bleft; | 299 | ++bleft; |
301 | } | 300 | } |
302 | 301 | ||
303 | words_left = bleft / 2; | ||
304 | |||
305 | /* save off server operating system */ | ||
306 | len = UniStrnlen((wchar_t *) data, words_left); | ||
307 | |||
308 | if (len >= words_left) | ||
309 | return rc; | ||
310 | |||
311 | kfree(ses->serverOS); | 302 | kfree(ses->serverOS); |
312 | /* 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); |
313 | ses->serverOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); | 304 | cFYI(1, ("serverOS=%s", ses->serverOS)); |
314 | if (ses->serverOS != NULL) { | 305 | len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; |
315 | cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); | 306 | data += len; |
316 | cFYI(1, ("serverOS=%s", ses->serverOS)); | 307 | bleft -= len; |
317 | } | 308 | if (bleft <= 0) |
318 | data += 2 * (len + 1); | 309 | return; |
319 | words_left -= len + 1; | ||
320 | |||
321 | /* save off server network operating system */ | ||
322 | len = UniStrnlen((wchar_t *) data, words_left); | ||
323 | |||
324 | if (len >= words_left) | ||
325 | return rc; | ||
326 | 310 | ||
327 | kfree(ses->serverNOS); | 311 | kfree(ses->serverNOS); |
328 | ses->serverNOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); | 312 | ses->serverNOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
329 | if (ses->serverNOS != NULL) { | 313 | cFYI(1, ("serverNOS=%s", ses->serverNOS)); |
330 | cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, | 314 | len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; |
331 | nls_cp); | 315 | data += len; |
332 | cFYI(1, ("serverNOS=%s", ses->serverNOS)); | 316 | bleft -= len; |
333 | if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) { | 317 | if (bleft <= 0) |
334 | cFYI(1, ("NT4 server")); | 318 | return; |
335 | ses->flags |= CIFS_SES_NT4; | ||
336 | } | ||
337 | } | ||
338 | data += 2 * (len + 1); | ||
339 | words_left -= len + 1; | ||
340 | |||
341 | /* save off server domain */ | ||
342 | len = UniStrnlen((wchar_t *) data, words_left); | ||
343 | |||
344 | if (len > words_left) | ||
345 | return rc; | ||
346 | 319 | ||
347 | kfree(ses->serverDomain); | 320 | kfree(ses->serverDomain); |
348 | ses->serverDomain = kzalloc((4 * len) + 2, GFP_KERNEL); | 321 | ses->serverDomain = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
349 | if (ses->serverDomain != NULL) { | 322 | cFYI(1, ("serverDomain=%s", ses->serverDomain)); |
350 | cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, | ||
351 | nls_cp); | ||
352 | cFYI(1, ("serverDomain=%s", ses->serverDomain)); | ||
353 | } | ||
354 | data += 2 * (len + 1); | ||
355 | words_left -= len + 1; | ||
356 | |||
357 | cFYI(1, ("words left: %d", words_left)); | ||
358 | 323 | ||
359 | return rc; | 324 | return; |
360 | } | 325 | } |
361 | 326 | ||
362 | static int decode_ascii_ssetup(char **pbcc_area, int bleft, | 327 | static int decode_ascii_ssetup(char **pbcc_area, int bleft, |
@@ -413,6 +378,186 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, | |||
413 | return rc; | 378 | return rc; |
414 | } | 379 | } |
415 | 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 | |||
416 | int | 561 | int |
417 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | 562 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, |
418 | const struct nls_table *nls_cp) | 563 | const struct nls_table *nls_cp) |
@@ -431,6 +576,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
431 | __u16 action; | 576 | __u16 action; |
432 | int bytes_remaining; | 577 | int bytes_remaining; |
433 | struct key *spnego_key = NULL; | 578 | struct key *spnego_key = NULL; |
579 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | ||
434 | 580 | ||
435 | if (ses == NULL) | 581 | if (ses == NULL) |
436 | return -EINVAL; | 582 | return -EINVAL; |
@@ -438,6 +584,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
438 | type = ses->server->secType; | 584 | type = ses->server->secType; |
439 | 585 | ||
440 | 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 | |||
441 | if (type == LANMAN) { | 591 | if (type == LANMAN) { |
442 | #ifndef CONFIG_CIFS_WEAK_PW_HASH | 592 | #ifndef CONFIG_CIFS_WEAK_PW_HASH |
443 | /* LANMAN and plaintext are less secure and off by default. | 593 | /* LANMAN and plaintext are less secure and off by default. |
@@ -651,9 +801,53 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
651 | goto ssetup_exit; | 801 | goto ssetup_exit; |
652 | #endif /* CONFIG_CIFS_UPCALL */ | 802 | #endif /* CONFIG_CIFS_UPCALL */ |
653 | } 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 | ||
654 | cERROR(1, ("secType %d not supported!", type)); | 847 | cERROR(1, ("secType %d not supported!", type)); |
655 | rc = -ENOSYS; | 848 | rc = -ENOSYS; |
656 | goto ssetup_exit; | 849 | goto ssetup_exit; |
850 | #endif | ||
657 | } | 851 | } |
658 | 852 | ||
659 | iov[2].iov_base = str_area; | 853 | iov[2].iov_base = str_area; |
@@ -669,12 +863,23 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
669 | /* SMB request buf freed in SendReceive2 */ | 863 | /* SMB request buf freed in SendReceive2 */ |
670 | 864 | ||
671 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); | 865 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); |
672 | if (rc) | ||
673 | goto ssetup_exit; | ||
674 | 866 | ||
675 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | 867 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; |
676 | smb_buf = (struct smb_hdr *)iov[0].iov_base; | 868 | smb_buf = (struct smb_hdr *)iov[0].iov_base; |
677 | 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 | |||
678 | if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { | 883 | if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { |
679 | rc = -EIO; | 884 | rc = -EIO; |
680 | cERROR(1, ("bad word count %d", smb_buf->WordCount)); | 885 | cERROR(1, ("bad word count %d", smb_buf->WordCount)); |
@@ -693,12 +898,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
693 | if (smb_buf->WordCount == 4) { | 898 | if (smb_buf->WordCount == 4) { |
694 | __u16 blob_len; | 899 | __u16 blob_len; |
695 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | 900 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); |
696 | bcc_ptr += blob_len; | ||
697 | if (blob_len > bytes_remaining) { | 901 | if (blob_len > bytes_remaining) { |
698 | cERROR(1, ("bad security blob length %d", blob_len)); | 902 | cERROR(1, ("bad security blob length %d", blob_len)); |
699 | rc = -EINVAL; | 903 | rc = -EINVAL; |
700 | goto ssetup_exit; | 904 | goto ssetup_exit; |
701 | } | 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; | ||
702 | bytes_remaining -= blob_len; | 913 | bytes_remaining -= blob_len; |
703 | } | 914 | } |
704 | 915 | ||
@@ -709,8 +920,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
709 | ++bcc_ptr; | 920 | ++bcc_ptr; |
710 | --bytes_remaining; | 921 | --bytes_remaining; |
711 | } | 922 | } |
712 | rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, | 923 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp); |
713 | ses, nls_cp); | ||
714 | } else { | 924 | } else { |
715 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, | 925 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, |
716 | ses, nls_cp); | 926 | ses, nls_cp); |
@@ -728,5 +938,9 @@ ssetup_exit: | |||
728 | } else if (resp_buf_type == CIFS_LARGE_BUFFER) | 938 | } else if (resp_buf_type == CIFS_LARGE_BUFFER) |
729 | cifs_buf_release(iov[0].iov_base); | 939 | cifs_buf_release(iov[0].iov_base); |
730 | 940 | ||
941 | /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */ | ||
942 | if ((phase == NtLmChallenge) && (rc == 0)) | ||
943 | goto ssetup_ntlmssp_authenticate; | ||
944 | |||
731 | return rc; | 945 | return rc; |
732 | } | 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.*/ |
diff --git a/include/linux/nls.h b/include/linux/nls.h index 6a882208301a..52b1a76c1b43 100644 --- a/include/linux/nls.h +++ b/include/linux/nls.h | |||
@@ -58,6 +58,25 @@ static inline int nls_strnicmp(struct nls_table *t, const unsigned char *s1, | |||
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
60 | 60 | ||
61 | /* | ||
62 | * nls_nullsize - return length of null character for codepage | ||
63 | * @codepage - codepage for which to return length of NULL terminator | ||
64 | * | ||
65 | * Since we can't guarantee that the null terminator will be a particular | ||
66 | * length, we have to check against the codepage. If there's a problem | ||
67 | * determining it, assume a single-byte NULL terminator. | ||
68 | */ | ||
69 | static inline int | ||
70 | nls_nullsize(const struct nls_table *codepage) | ||
71 | { | ||
72 | int charlen; | ||
73 | char tmp[NLS_MAX_CHARSET_SIZE]; | ||
74 | |||
75 | charlen = codepage->uni2char(0, tmp, NLS_MAX_CHARSET_SIZE); | ||
76 | |||
77 | return charlen > 0 ? charlen : 1; | ||
78 | } | ||
79 | |||
61 | #define MODULE_ALIAS_NLS(name) MODULE_ALIAS("nls_" __stringify(name)) | 80 | #define MODULE_ALIAS_NLS(name) MODULE_ALIAS("nls_" __stringify(name)) |
62 | 81 | ||
63 | #endif /* _LINUX_NLS_H */ | 82 | #endif /* _LINUX_NLS_H */ |