Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
* 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
  ...
  • Loading branch information
Linus Torvalds committed May 8, 2009
2 parents 8c9ed89 + 90e4ee5 commit d7a5926
Show file tree
Hide file tree
Showing 22 changed files with 810 additions and 1,642 deletions.
13 changes: 13 additions & 0 deletions fs/cifs/CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
Version 1.58
------------
Guard against buffer overruns in various UCS-2 to UTF-8 string conversions
when the UTF-8 string is composed of unusually long (more than 4 byte) converted
characters. Add support for mounting root of a share which redirects immediately
to DFS target. Convert string conversion functions from Unicode to more
accurately mark string length before allocating memory (which may help the
rare cases where a UTF-8 string is much larger than the UCS2 string that
we converted from). Fix endianness of the vcnum field used during
session setup to distinguish multiple mounts to same server from different
userids. Raw NTLMSSP fixed (it requires /proc/fs/cifs/experimental
flag to be set to 2, and mount must enable krb5 to turn on extended security).

Version 1.57
------------
Improve support for multiple security contexts to the same server. We
Expand Down
10 changes: 9 additions & 1 deletion fs/cifs/README
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,15 @@ Experimental When set to 1 used to enable certain experimental
signing turned on in case buffer was modified
just before it was sent, also this flag will
be used to use the new experimental directory change
notification code).
notification code). When set to 2 enables
an additional experimental feature, "raw ntlmssp"
session establishment support (which allows
specifying "sec=ntlmssp" on mount). The Linux cifs
module will use ntlmv2 authentication encapsulated
in "raw ntlmssp" (not using SPNEGO) when
"sec=ntlmssp" is specified on mount.
This support also requires building cifs with
the CONFIG_CIFS_EXPERIMENTAL configuration flag.

These experimental features and tracing can be enabled by changing flags in
/proc/fs/cifs (after the cifs module has been installed or built into the
Expand Down
32 changes: 14 additions & 18 deletions fs/cifs/cifs_dfs_ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,28 +340,24 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);

for (i = 0; i < num_referrals; i++) {
int len;
dump_referral(referrals+i);
/* connect to a storage node */
if (referrals[i].flags & DFSREF_STORAGE_SERVER) {
int len;
len = strlen(referrals[i].node_name);
if (len < 2) {
cERROR(1, ("%s: Net Address path too short: %s",
/* connect to a node */
len = strlen(referrals[i].node_name);
if (len < 2) {
cERROR(1, ("%s: Net Address path too short: %s",
__func__, referrals[i].node_name));
rc = -EINVAL;
goto out_err;
}
mnt = cifs_dfs_do_refmount(nd->path.mnt,
nd->path.dentry,
referrals + i);
cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
__func__,
rc = -EINVAL;
goto out_err;
}
mnt = cifs_dfs_do_refmount(nd->path.mnt,
nd->path.dentry, referrals + i);
cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__,
referrals[i].node_name, mnt));

/* complete mount procedure if we accured submount */
if (!IS_ERR(mnt))
break;
}
/* complete mount procedure if we accured submount */
if (!IS_ERR(mnt))
break;
}

/* we need it cause for() above could exit without valid submount */
Expand Down
198 changes: 181 additions & 17 deletions fs/cifs/cifs_unicode.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifs_unicode.c
*
* Copyright (c) International Business Machines Corp., 2000,2005
* Copyright (c) International Business Machines Corp., 2000,2009
* Modified by Steve French (sfrench@us.ibm.com)
*
* This program is free software; you can redistribute it and/or modify
Expand All @@ -26,31 +26,157 @@
#include "cifs_debug.h"

/*
* NAME: cifs_strfromUCS()
*
* FUNCTION: Convert little-endian unicode string to character string
* cifs_ucs2_bytes - how long will a string be after conversion?
* @ucs - pointer to input string
* @maxbytes - don't go past this many bytes of input string
* @codepage - destination codepage
*
* Walk a ucs2le string and return the number of bytes that the string will
* be after being converted to the given charset, not including any null
* termination required. Don't walk past maxbytes in the source buffer.
*/
int
cifs_strfromUCS_le(char *to, const __le16 *from,
int len, const struct nls_table *codepage)
cifs_ucs2_bytes(const __le16 *from, int maxbytes,
const struct nls_table *codepage)
{
int i;
int outlen = 0;
int charlen, outlen = 0;
int maxwords = maxbytes / 2;
char tmp[NLS_MAX_CHARSET_SIZE];

for (i = 0; (i < len) && from[i]; i++) {
int charlen;
/* 2.4.0 kernel or greater */
charlen =
codepage->uni2char(le16_to_cpu(from[i]), &to[outlen],
NLS_MAX_CHARSET_SIZE);
if (charlen > 0) {
for (i = 0; from[i] && i < maxwords; i++) {
charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp,
NLS_MAX_CHARSET_SIZE);
if (charlen > 0)
outlen += charlen;
} else {
to[outlen++] = '?';
else
outlen++;
}

return outlen;
}

/*
* cifs_mapchar - convert a little-endian char to proper char in codepage
* @target - where converted character should be copied
* @src_char - 2 byte little-endian source character
* @cp - codepage to which character should be converted
* @mapchar - should character be mapped according to mapchars mount option?
*
* This function handles the conversion of a single character. It is the
* responsibility of the caller to ensure that the target buffer is large
* enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
*/
static int
cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp,
bool mapchar)
{
int len = 1;

if (!mapchar)
goto cp_convert;

/*
* BB: Cannot handle remapping UNI_SLASH until all the calls to
* build_path_from_dentry are modified, as they use slash as
* separator.
*/
switch (le16_to_cpu(src_char)) {
case UNI_COLON:
*target = ':';
break;
case UNI_ASTERIK:
*target = '*';
break;
case UNI_QUESTION:
*target = '?';
break;
case UNI_PIPE:
*target = '|';
break;
case UNI_GRTRTHAN:
*target = '>';
break;
case UNI_LESSTHAN:
*target = '<';
break;
default:
goto cp_convert;
}

out:
return len;

cp_convert:
len = cp->uni2char(le16_to_cpu(src_char), target,
NLS_MAX_CHARSET_SIZE);
if (len <= 0) {
*target = '?';
len = 1;
}
goto out;
}

/*
* cifs_from_ucs2 - convert utf16le string to local charset
* @to - destination buffer
* @from - source buffer
* @tolen - destination buffer size (in bytes)
* @fromlen - source buffer size (in bytes)
* @codepage - codepage to which characters should be converted
* @mapchar - should characters be remapped according to the mapchars option?
*
* Convert a little-endian ucs2le string (as sent by the server) to a string
* in the provided codepage. The tolen and fromlen parameters are to ensure
* that the code doesn't walk off of the end of the buffer (which is always
* a danger if the alignment of the source buffer is off). The destination
* string is always properly null terminated and fits in the destination
* buffer. Returns the length of the destination string in bytes (including
* null terminator).
*
* Note that some windows versions actually send multiword UTF-16 characters
* instead of straight UCS-2. The linux nls routines however aren't able to
* deal with those characters properly. In the event that we get some of
* those characters, they won't be translated properly.
*/
int
cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
const struct nls_table *codepage, bool mapchar)
{
int i, charlen, safelen;
int outlen = 0;
int nullsize = nls_nullsize(codepage);
int fromwords = fromlen / 2;
char tmp[NLS_MAX_CHARSET_SIZE];

/*
* because the chars can be of varying widths, we need to take care
* not to overflow the destination buffer when we get close to the
* end of it. Until we get to this offset, we don't need to check
* for overflow however.
*/
safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);

for (i = 0; i < fromwords && from[i]; i++) {
/*
* check to see if converting this character might make the
* conversion bleed into the null terminator
*/
if (outlen >= safelen) {
charlen = cifs_mapchar(tmp, from[i], codepage, mapchar);
if ((outlen + charlen) > (tolen - nullsize))
break;
}

/* put converted char into 'to' buffer */
charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar);
outlen += charlen;
}
to[outlen] = 0;

/* properly null-terminate string */
for (i = 0; i < nullsize; i++)
to[outlen++] = 0;

return outlen;
}

Expand Down Expand Up @@ -88,3 +214,41 @@ cifs_strtoUCS(__le16 *to, const char *from, int len,
return i;
}

/*
* cifs_strndup_from_ucs - copy a string from wire format to the local codepage
* @src - source string
* @maxlen - don't walk past this many bytes in the source string
* @is_unicode - is this a unicode string?
* @codepage - destination codepage
*
* Take a string given by the server, convert it to the local codepage and
* put it in a new buffer. Returns a pointer to the new string or NULL on
* error.
*/
char *
cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode,
const struct nls_table *codepage)
{
int len;
char *dst;

if (is_unicode) {
len = cifs_ucs2_bytes((__le16 *) src, maxlen, codepage);
len += nls_nullsize(codepage);
dst = kmalloc(len, GFP_KERNEL);
if (!dst)
return NULL;
cifs_from_ucs2(dst, (__le16 *) src, len, maxlen, codepage,
false);
} else {
len = strnlen(src, maxlen);
len++;
dst = kmalloc(len, GFP_KERNEL);
if (!dst)
return NULL;
strlcpy(dst, src, len);
}

return dst;
}

23 changes: 21 additions & 2 deletions fs/cifs/cifs_unicode.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Convert a unicode character to upper or lower case using
* compressed tables.
*
* Copyright (c) International Business Machines Corp., 2000,2007
* Copyright (c) International Business Machines Corp., 2000,2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -37,6 +37,19 @@

#define UNIUPR_NOLOWER /* Example to not expand lower case tables */

/*
* Windows maps these to the user defined 16 bit Unicode range since they are
* reserved symbols (along with \ and /), otherwise illegal to store
* in filenames in NTFS
*/
#define UNI_ASTERIK (__u16) ('*' + 0xF000)
#define UNI_QUESTION (__u16) ('?' + 0xF000)
#define UNI_COLON (__u16) (':' + 0xF000)
#define UNI_GRTRTHAN (__u16) ('>' + 0xF000)
#define UNI_LESSTHAN (__u16) ('<' + 0xF000)
#define UNI_PIPE (__u16) ('|' + 0xF000)
#define UNI_SLASH (__u16) ('\\' + 0xF000)

/* Just define what we want from uniupr.h. We don't want to define the tables
* in each source file.
*/
Expand All @@ -59,8 +72,14 @@ extern struct UniCaseRange UniLowerRange[];
#endif /* UNIUPR_NOLOWER */

#ifdef __KERNEL__
int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *);
int cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
const struct nls_table *codepage, bool mapchar);
int cifs_ucs2_bytes(const __le16 *from, int maxbytes,
const struct nls_table *codepage);
int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *);
char *cifs_strndup_from_ucs(const char *src, const int maxlen,
const bool is_unicode,
const struct nls_table *codepage);
#endif

/*
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */

#define CIFS_VERSION "1.57"
#define CIFS_VERSION "1.58"
#endif /* _CIFSFS_H */
Loading

0 comments on commit d7a5926

Please sign in to comment.