Fix bug #7154 - mangling method = hash can crash storing a name not containing a '.'
[abartlet/samba.git/.git] / source3 / smbd / mangle_hash.c
index ebd93ff5d0d0e9d880e1137eb45fa6b69e4451f3..1482d10b7a240388b8c1d739cda0d76c36cf1c07 100644 (file)
@@ -53,7 +53,7 @@
  *
  */
 
-static const char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
+static const char basechars[43]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
 #define MANGLE_BASE       (sizeof(basechars)/sizeof(char)-1)
 
 #define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
@@ -290,15 +290,15 @@ static bool is_8_3(const char *fname, bool check_case, bool allow_wildcards,
        if (strlen(f) > 12)
                return False;
 
-       if (!push_ucs2_allocate(&ucs2name, f, &size)) {
-               DEBUG(0,("is_8_3: internal error push_ucs2_allocate() failed!\n"));
+       if (!push_ucs2_talloc(NULL, &ucs2name, f, &size)) {
+               DEBUG(0,("is_8_3: internal error push_ucs2_talloc() failed!\n"));
                goto done;
        }
 
        ret = is_8_3_w(ucs2name, allow_wildcards);
 
 done:
-       SAFE_FREE(ucs2name);
+       TALLOC_FREE(ucs2name);
 
        if (!NT_STATUS_IS_OK(ret)) {
                return False;
@@ -408,8 +408,8 @@ static void cache_mangled_name( const char mangled_name[13],
 {
        TDB_DATA data_val;
        char mangled_name_key[13];
-       char *s1;
-       char *s2;
+       char *s1 = NULL;
+       char *s2 = NULL;
 
        /* If the cache isn't initialized, give up. */
        if( !tdb_mangled_cache )
@@ -429,6 +429,13 @@ static void cache_mangled_name( const char mangled_name[13],
                if( !s1[i] && !s2[i] ) {
                        /* Truncate at the '.' */
                        *s1 = '\0';
+                       /*
+                        * DANGER WILL ROBINSON - this
+                        * is changing a const string via
+                        * an aliased pointer ! Remember to
+                        * put it back once we've used it.
+                        * JRA
+                        */
                        *s2 = '\0';
                }
        }
@@ -440,6 +447,10 @@ static void cache_mangled_name( const char mangled_name[13],
        } else {
                DEBUG(5,("cache_mangled_name: Stored entry %s -> %s\n", mangled_name_key, raw_name));
        }
+       /* Restore the change we made to the const string. */
+       if (s2) {
+               *s2 = '.';
+       }
 }
 
 /* ************************************************************************** **
@@ -606,13 +617,16 @@ static bool must_mangle(const char *name,
 
        magic_char = lp_magicchar(p);
 
-       if (!push_ucs2_allocate(&name_ucs2, name, &converted_size)) {
-               DEBUG(0, ("push_ucs2_allocate failed!\n"));
+       if (!push_ucs2_talloc(NULL, &name_ucs2, name, &converted_size)) {
+               DEBUG(0, ("push_ucs2_talloc failed!\n"));
                return False;
        }
        status = is_valid_name(name_ucs2, False, False);
-       SAFE_FREE(name_ucs2);
-       return NT_STATUS_IS_OK(status);
+       TALLOC_FREE(name_ucs2);
+       /* We return true if we *must* mangle, so if it's
+        * a valid name (status == OK) then we must return
+        * false. Bug #6939. */
+       return !NT_STATUS_IS_OK(status);
 }
 
 /*****************************************************************************
@@ -645,20 +659,20 @@ static bool hash_name_to_8_3(const char *in,
        DEBUG(5,("hash_name_to_8_3( %s, cache83 = %s)\n", in,
                 cache83 ? "True" : "False"));
 
-       if (!push_ucs2_allocate(&in_ucs2, in, &converted_size)) {
-               DEBUG(0, ("push_ucs2_allocate failed!\n"));
+       if (!push_ucs2_talloc(NULL, &in_ucs2, in, &converted_size)) {
+               DEBUG(0, ("push_ucs2_talloc failed!\n"));
                return False;
        }
 
        /* If it's already 8.3, just copy. */
        if (NT_STATUS_IS_OK(is_valid_name(in_ucs2, False, False)) &&
                                NT_STATUS_IS_OK(is_8_3_w(in_ucs2, False))) {
-               SAFE_FREE(in_ucs2);
+               TALLOC_FREE(in_ucs2);
                safe_strcpy(out, in, 12);
                return True;
        }
 
-       SAFE_FREE(in_ucs2);
+       TALLOC_FREE(in_ucs2);
        if (!to_8_3(magic_char, in, out, default_case)) {
                return False;
        }