lib: strings: Fix the behavior of strcasecmp_m_handle() in the face of bad conversions.
authorJeremy Allison <jra@samba.org>
Sat, 2 Aug 2014 04:29:21 +0000 (21:29 -0700)
committerKarolin Seeger <kseeger@samba.org>
Mon, 1 Sep 2014 19:34:11 +0000 (21:34 +0200)
When either string has a bad conversion, we fall back to
doing raw ascii byte comparisons using strcasecmp().

The problem is we've already stepped past the character
that failed the conversion, so we're not re-testing those
characters for comparison. This can have the effect of
causing strcasecmp_m_handle() to report that two strings
are identical when they are not, if the failed conversion
takes place at the end of the string.

The correct behavior is to step back to the point of
the string(s) that failed the conversion, and continue
the test from there.

Found by <lev@zadarastorage.com> when investigating bug
10716 - smbd constantly crashes when filename contains non-ascii character.

Given the normal character set of utf-8, and an on
disk filename of ISO-8859-1 of file-é on disk hex
value: 66 69 6c 65 2d e9, an incoming open given the
correct utf8 name of file-é will collide when it
should not.

Fixes:

Bug 10716 - smbd constantly crashes when filename contains non-ascii character

https://bugzilla.samba.org/show_bug.cgi?id=10716

Signed-off-by: Jeremy Allison <jra@samba.org>
lib/util/charset/util_str.c

index 688ab5a0a1c11b8b1a02a421060eb0d8767c50e9..1810e2429f85d6238965b08e448d43aeed84dc9b 100644 (file)
@@ -56,7 +56,17 @@ _PUBLIC_ int strcasecmp_m_handle(struct smb_iconv_handle *iconv_handle,
 
                if (c1 == INVALID_CODEPOINT ||
                    c2 == INVALID_CODEPOINT) {
-                       /* what else can we do?? */
+                       /*
+                        * Fall back to byte
+                        * comparison. We must
+                        * step back by the codepoint
+                        * length we just incremented
+                        * - otherwise we are not
+                        * checking the bytes that
+                        * failed the conversion.
+                        */
+                       s1 -= size1;
+                       s2 -= size2;
                        return strcasecmp(s1, s2);
                }