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 /fs | |
| 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
...
Diffstat (limited to 'fs')
| -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 |
21 files changed, 791 insertions, 1642 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 9d1fb6ec8a5..f20c4069c22 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 07434181623..db208ddb989 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 5fdbf8a1447..83d62759c7c 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 7d75272a6b3..60e3c4253de 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 14eb9a2395d..650638275a6 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 77e190dc288..051b71cfdea 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 df40ab64cd9..a61ab772c6f 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 4167716d32f..fae083930ee 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 a0845dc7b8a..75e6623a863 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 bacdef1546b..4aa81a507b7 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 461750e0136..11431ed72a7 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 50ca088d886..38c06f82657 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 f36b4e40e44..9c869a6dcba 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 63f644000ce..ea9d11e3dcb 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 4c89c572891..e079a9190ec 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 8703d68f5b2..e2fe998989a 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 588abbb9d08..257267367d4 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 c377d8065d9..49c9a4e7531 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 1a8be622833..964e097c820 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 c652c73760d..897a052270f 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 7f50e8577c1..c5084d27db7 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.*/ |
