first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[mimir/samba.git] / source3 / smbd / mangle.c
index 0a3d3f54eb7f1135b95c59ae159364692781f8d1..48e16e533222b12e8f6bb5d8a7daa8a38e40f09c 100644 (file)
@@ -63,11 +63,13 @@ extern BOOL case_mangle;    /* If true, all chars in 8.3 should be same case. */
  *                  global.  There is a call to lp_magicchar() in server.c
  *                  that is used to override the initial value.
  *
- * basechars      - The set of 36 characters used for name mangling.  This
+ * MANGLE_BASE    - This is the number of characters we use for name mangling.
+ *
+ * basechars      - The set characters used for name mangling.  This
  *                  is static (scope is this file only).
  *
- * base36()       - Macro used to select a character from basechars (i.e.,
- *                  base36(n) will return the nth digit, modulo 36).
+ * mangle()       - Macro used to select a character from basechars (i.e.,
+ *                  mangle(n) will return the nth digit, modulo MANGLE_BASE).
  *
  * chartest       - array 0..255.  The index range is the set of all possible
  *                  values of a byte.  For each byte value, the content is a
@@ -110,12 +112,13 @@ extern BOOL case_mangle;    /* If true, all chars in 8.3 should be same case. */
 
 char magic_char = '~';
 
-static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
+#define MANGLE_BASE       (sizeof(basechars)/sizeof(char)-1)
 
 static unsigned char chartest[256]  = { 0 };
 static BOOL          ct_initialized = False;
 
-#define base36(V) ((char)(basechars[(V) % 36]))
+#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
 #define BASECHAR_MASK 0xf0
 #define ILLEGAL_MASK  0x0f
 #define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
@@ -148,7 +151,7 @@ static void init_chartest( void )
   char          *illegalchars = "*\\/?<>|\":";
   unsigned char *s;
   
-  bzero( (char *)chartest, 256 );
+  memset( (char *)chartest, '\0', 256 );
 
   for( s = (unsigned char *)illegalchars; *s; s++ )
     chartest[*s] = ILLEGAL_MASK;
@@ -272,7 +275,7 @@ static BOOL is_illegal_name( char *name )
 /* ************************************************************************** **
  * Return True if the name *could be* a mangled name.
  *
- *  Input:  s - A file name.
+ *  Input:  s - A path name - in UNIX pathname format.
  *
  *  Output: True if the name matches the pattern described below in the
  *          notes, else False.
@@ -281,7 +284,8 @@ static BOOL is_illegal_name( char *name )
  *          done separately.  This function returns true if the name contains
  *          a magic character followed by excactly two characters from the
  *          basechars list (above), which in turn are followed either by the
- *          nul (end of string) byte or a dot (extension).
+ *          nul (end of string) byte or a dot (extension) or by a '/' (end of
+ *          a directory name).
  *
  * ************************************************************************** **
  */
@@ -295,7 +299,7 @@ BOOL is_mangled( char *s )
   magic = strchr( s, magic_char );
   while( magic && magic[1] && magic[2] )          /* 3 chars, 1st is magic. */
     {
-    if( ('.' == magic[3] || !(magic[3]))          /* Ends with '.' or nul?  */
+    if( ('.' == magic[3] || '/' == magic[3] || !(magic[3]))          /* Ends with '.' or nul or '/' ?  */
      && isbasechar( toupper(magic[1]) )           /* is 2nd char basechar?  */
      && isbasechar( toupper(magic[2]) ) )         /* is 3rd char basechar?  */
       return( True );                           /* If all above, then true, */
@@ -513,7 +517,7 @@ void reset_mangled_cache( void )
  *
  *          If the extension of the raw name maps directly to the
  *          extension of the mangled name, then we'll store both names
- *          *without* extensions.  That way, we can provide consistant
+ *          *without* extensions.  That way, we can provide consistent
  *          reverse mangling for all names that match.  The test here is
  *          a bit more careful than the one done in earlier versions of
  *          mangle.c:
@@ -532,9 +536,9 @@ static void cache_mangled_name( char *mangled_name, char *raw_name )
   ubi_cacheEntryPtr new_entry;
   char             *s1;
   char             *s2;
-  int               mangled_len;
-  int               raw_len;
-  int               i;
+  size_t               mangled_len;
+  size_t               raw_len;
+  size_t               i;
 
   /* If the cache isn't initialized, give up. */
   if( !mc_initialized )
@@ -560,7 +564,7 @@ static void cache_mangled_name( char *mangled_name, char *raw_name )
       }
     }
 
-  /* Allocate a new cache entry.  If the allcoation fails, just return. */
+  /* Allocate a new cache entry.  If the allocation fails, just return. */
   i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2;
   new_entry = malloc( i );
   if( !new_entry )
@@ -588,11 +592,13 @@ static void cache_mangled_name( char *mangled_name, char *raw_name )
  *
  * ************************************************************************** **
  */
+
 BOOL check_mangled_cache( char *s )
-  {
+{
   ubi_cacheEntryPtr FoundPtr;
   char             *ext_start = NULL;
   char             *found_name;
+  char             *saved_ext = NULL;
 
   /* If the cache isn't initialized, give up. */
   if( !mc_initialized )
@@ -602,19 +608,34 @@ BOOL check_mangled_cache( char *s )
 
   /* If we didn't find the name *with* the extension, try without. */
   if( !FoundPtr )
-    {
+  {
     ext_start = strrchr( s, '.' );
     if( ext_start )
-      {
+    {
+      if((saved_ext = strdup(ext_start)) == NULL)
+        return False;
+
       *ext_start = '\0';
       FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
-      *ext_start = '.';
-      }
+      /* 
+       * At this point s is the name without the
+       * extension. We re-add the extension if saved_ext
+       * is not null, before freeing saved_ext.
+       */
     }
+  }
 
   /* Okay, if we haven't found it we're done. */
   if( !FoundPtr )
+  {
+    if(saved_ext)
+    {
+      /* Replace the saved_ext as it was truncated. */
+      (void)pstrcat( s, saved_ext );
+      free(saved_ext);
+    }
     return( False );
+  }
 
   /* If we *did* find it, we need to copy it into the string buffer. */
   found_name = (char *)(FoundPtr + 1);
@@ -623,13 +644,17 @@ BOOL check_mangled_cache( char *s )
   DEBUG( 3, ("Found %s on mangled stack ", s) );
 
   (void)pstrcpy( s, found_name );
-  if( ext_start )
-    (void)pstrcat( s, ext_start );
+  if( saved_ext )
+  {
+    /* Replace the saved_ext as it was truncated. */
+    (void)pstrcat( s, saved_ext );
+    free(saved_ext);
+  }
 
   DEBUG( 3, ("as %s\n", s) );
 
   return( True );
-  } /* check_mangled_cache */
+} /* check_mangled_cache */
 
 
 /* ************************************************************************** **
@@ -651,6 +676,12 @@ static char *map_filename( char *s,         /* This is null terminated */
   pstrcpy( matching_bit, "" );  /* Match but no star gets this. */
   pp = pat;                     /* Initialize the pointers. */
   sp = s;
+
+  if( strequal(s, ".") || strequal(s, ".."))
+    {
+    return NULL;                /* Do not map '.' and '..' */
+    }
+
   if( (len == 1) && (*pattern == '*') )
     {
     return NULL;                /* Impossible, too ambiguous for */
@@ -806,7 +837,7 @@ static void do_fwd_mangled_map(char *s, char *MangledMap)
  */
 void mangle_name_83( char *s)
   {
-  int csum = str_checksum(s);
+  int csum;
   char *p;
   char extension[4];
   char base[9];
@@ -828,7 +859,11 @@ void mangle_name_83( char *s)
       csum = str_checksum( s );
       *p = '.';
       }
+    else
+      csum = str_checksum(s);
     }
+  else
+    csum = str_checksum(s);
 
   strupper( s );
 
@@ -854,7 +889,7 @@ void mangle_name_83( char *s)
               }
             else 
               {
-              extension[extlen++] = base36( (unsigned char)*p );
+              extension[extlen++] = mangle( (unsigned char)*p );
               }
             p += 2;
             break;
@@ -888,7 +923,7 @@ void mangle_name_83( char *s)
           }
         else 
           {
-          base[baselen++] = base36( (unsigned char)*p );
+          base[baselen++] = mangle( (unsigned char)*p );
           }
         p += 2;
         break;
@@ -905,10 +940,10 @@ void mangle_name_83( char *s)
     }
   base[baselen] = 0;
 
-  csum = csum % (36*36);
+  csum = csum % (MANGLE_BASE*MANGLE_BASE);
 
   (void)slprintf(s, 12, "%s%c%c%c",
-                 base, magic_char, base36( csum/36 ), base36( csum ) );
+                 base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
 
   if( *extension )
     {
@@ -934,6 +969,11 @@ void mangle_name_83( char *s)
  *                    signal that a client does not require name mangling,
  *                    thus skipping the name mangling even on shares which
  *                    have name-mangling turned on.
+ *          cache83 - If False, the mangled name cache will not be updated.
+ *                    This is usually used to prevent that we overwrite
+ *                    a conflicting cache entry prematurely, i.e. before
+ *                    we know whether the client is really interested in the
+ *                    current name.  (See PR#13758).  UKD.
  *          snum    - Share number.  This identifies the share in which the
  *                    name exists.
  *
@@ -942,11 +982,11 @@ void mangle_name_83( char *s)
  *
  * ****************************************************************************
  */
-BOOL name_map_mangle(char *OutName, BOOL need83, int snum)
+BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
 {
        char *map;
-       DEBUG(5,("name_map_mangle( %s, %s, %d )\n", 
-                OutName, need83?"TRUE":"FALSE", snum));
+       DEBUG(5,("name_map_mangle( %s, need83 = %s, cache83 = %s, %d )\n", OutName,
+               need83 ? "TRUE" : "FALSE", cache83 ? "TRUE" : "FALSE", snum));
 
 #ifdef MANGLE_LONG_FILENAMES
        if( !need83 && is_illegal_name(OutName) )
@@ -962,17 +1002,19 @@ BOOL name_map_mangle(char *OutName, BOOL need83, int snum)
 
        /* check if it's already in 8.3 format */
        if (need83 && !is_8_3(OutName, True)) {
-               char *tmp; 
+               char *tmp = NULL
 
                if (!lp_manglednames(snum)) {
                        return(False);
                }
 
                /* mangle it into 8.3 */
-               tmp = strdup(OutName);
+               if (cache83)
+                       tmp = strdup(OutName);
+
                mangle_name_83(OutName);
 
-               if(tmp) {
+               if(tmp != NULL) {
                        cache_mangled_name(OutName, tmp);
                        free(tmp);
                }
@@ -982,4 +1024,3 @@ BOOL name_map_mangle(char *OutName, BOOL need83, int snum)
        return(True);
 } /* name_map_mangle */
 
-/* ========================================================================== */