- the inactive core of the new mangling code that use tdb
[kamenim/samba.git] / source3 / smbd / mangle.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Name mangling
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /* -------------------------------------------------------------------------- **
23  * Notable problems...
24  *
25  *  March/April 1998  CRH
26  *  - Many of the functions in this module overwrite string buffers passed to
27  *    them.  This causes a variety of problems and is, generally speaking,
28  *    dangerous and scarry.  See the kludge notes in name_map_mangle()
29  *    below.
30  *  - It seems that something is calling name_map_mangle() twice.  The
31  *    first call is probably some sort of test.  Names which contain
32  *    illegal characters are being doubly mangled.  I'm not sure, but
33  *    I'm guessing the problem is in server.c.
34  *
35  * -------------------------------------------------------------------------- **
36  */
37
38 /* -------------------------------------------------------------------------- **
39  * History...
40  *
41  *  March/April 1998  CRH
42  *  Updated a bit.  Rewrote is_mangled() to be a bit more selective.
43  *  Rewrote the mangled name cache.  Added comments here and there.
44  *  &c.
45  * -------------------------------------------------------------------------- **
46  */
47
48 #include "includes.h"
49
50
51 /* -------------------------------------------------------------------------- **
52  * External Variables...
53  */
54
55 extern int DEBUGLEVEL;      /* Global debug level.                            */
56 extern int case_default;    /* Are conforming 8.3 names all upper or lower?   */
57 extern BOOL case_mangle;    /* If true, all chars in 8.3 should be same case. */
58
59 /* -------------------------------------------------------------------------- **
60  * Other stuff...
61  *
62  * magic_char     - This is the magic char used for mangling.  It's
63  *                  global.  There is a call to lp_magicchar() in server.c
64  *                  that is used to override the initial value.
65  *
66  * MANGLE_BASE    - This is the number of characters we use for name mangling.
67  *
68  * basechars      - The set characters used for name mangling.  This
69  *                  is static (scope is this file only).
70  *
71  * mangle()       - Macro used to select a character from basechars (i.e.,
72  *                  mangle(n) will return the nth digit, modulo MANGLE_BASE).
73  *
74  * chartest       - array 0..255.  The index range is the set of all possible
75  *                  values of a byte.  For each byte value, the content is a
76  *                  two nibble pair.  See BASECHAR_MASK and ILLEGAL_MASK,
77  *                  below.
78  *
79  * ct_initialized - False until the chartest array has been initialized via
80  *                  a call to init_chartest().
81  *
82  * BASECHAR_MASK  - Masks the upper nibble of a one-byte value.
83  *
84  * ILLEGAL_MASK   - Masks the lower nibble of a one-byte value.
85  *
86  * isbasecahr()   - Given a character, check the chartest array to see
87  *                  if that character is in the basechars set.  This is
88  *                  faster than using strchr_m().
89  *
90  * isillegal()    - Given a character, check the chartest array to see
91  *                  if that character is in the illegal characters set.
92  *                  This is faster than using strchr_m().
93  *
94  * mangled_cache  - Cache header used for storing mangled -> original
95  *                  reverse maps.
96  *
97  * mc_initialized - False until the mangled_cache structure has been
98  *                  initialized via a call to reset_mangled_cache().
99  *
100  * MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the
101  *                  cache.  A value of 0 indicates "infinite".
102  *
103  * MANGLED_CACHE_MAX_MEMORY  - Default maximum amount of memory for the
104  *                  cache.  When the cache was kept as an array of 256
105  *                  byte strings, the default cache size was 50 entries.
106  *                  This required a fixed 12.5Kbytes of memory.  The
107  *                  mangled stack parameter is no longer used (though
108  *                  this might change).  We're now using a fixed 16Kbyte
109  *                  maximum cache size.  This will probably be much more
110  *                  than 50 entries.
111  */
112
113 char magic_char = '~';
114
115 static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
116 #define MANGLE_BASE       ( (sizeof(basechars)/sizeof(char)) - 1 )
117
118 static unsigned char chartest[256]  = { 0 };
119 static BOOL          ct_initialized = False;
120
121 #define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
122 #define BASECHAR_MASK 0xf0
123 #define ILLEGAL_MASK  0x0f
124 #define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
125 #define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK )
126
127 static ubi_cacheRoot mangled_cache[1] = {{ { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 }};
128 static BOOL          mc_initialized   = False;
129 #define MANGLED_CACHE_MAX_ENTRIES 0
130 #define MANGLED_CACHE_MAX_MEMORY  16384
131
132
133 /* -------------------------------------------------------------------------- **
134  * Functions...
135  */
136
137 /* ************************************************************************** **
138  * Initialize the static character test array.
139  *
140  *  Input:  none
141  *
142  *  Output: none
143  *
144  *  Notes:  This function changes (loads) the contents of the <chartest>
145  *          array.  The scope of <chartest> is this file.
146  *
147  * ************************************************************************** **
148  */
149 static void init_chartest( void )
150   {
151   char          *illegalchars = "*\\/?<>|\":";
152   unsigned char *s;
153   
154   memset( (char *)chartest, '\0', 256 );
155
156   for( s = (unsigned char *)illegalchars; *s; s++ )
157     chartest[*s] = ILLEGAL_MASK;
158
159   for( s = (unsigned char *)basechars; *s; s++ )
160     chartest[*s] |= BASECHAR_MASK;
161
162   ct_initialized = True;
163   } /* init_chartest */
164
165 /* ************************************************************************** **
166  * Return True if a name is a special msdos reserved name.
167  *
168  *  Input:  fname - String containing the name to be tested.
169  *
170  *  Output: True, if the name matches one of the list of reserved names.
171  *
172  *  Notes:  This is a static function called by is_8_3(), below.
173  *
174  * ************************************************************************** **
175  */
176 static BOOL is_reserved_msdos( char *fname )
177   {
178   char upperFname[13];
179   char *p;
180
181   StrnCpy (upperFname, fname, 12);
182
183   /* lpt1.txt and con.txt etc are also illegal */
184   p = strchr_m(upperFname,'.');
185   if( p )
186     *p = '\0';
187
188   strupper( upperFname );
189   p = upperFname + 1;
190   switch( upperFname[0] )
191     {
192     case 'A':
193       if( 0 == strcmp( p, "UX" ) )
194         return( True );
195       break;
196     case 'C':
197       if( (0 == strcmp( p, "LOCK$" ))
198        || (0 == strcmp( p, "ON" ))
199        || (0 == strcmp( p, "OM1" ))
200        || (0 == strcmp( p, "OM2" ))
201        || (0 == strcmp( p, "OM3" ))
202        || (0 == strcmp( p, "OM4" ))
203         )
204         return( True );
205       break;
206     case 'L':
207       if( (0 == strcmp( p, "PT1" ))
208        || (0 == strcmp( p, "PT2" ))
209        || (0 == strcmp( p, "PT3" ))
210         )
211         return( True );
212       break;
213     case 'N':
214       if( 0 == strcmp( p, "UL" ) )
215         return( True );
216       break;
217     case 'P':
218       if( 0 == strcmp( p, "RN" ) )
219         return( True );
220       break;
221     }
222
223   return( False );
224   } /* is_reserved_msdos */
225
226 /* ************************************************************************** **
227  * Determine whether or not a given name contains illegal characters, even
228  * long names.
229  *
230  *  Input:  name  - The name to be tested.
231  *
232  *  Output: True if an illegal character was found in <name>, else False.
233  *
234  *  Notes:  This is used to test a name on the host system, long or short,
235  *          for characters that would be illegal on most client systems,
236  *          particularly DOS and Windows systems.  Unix and AmigaOS, for
237  *          example, allow a filenames which contain such oddities as
238  *          quotes (").  If a name is found which does contain an illegal
239  *          character, it is mangled even if it conforms to the 8.3
240  *          format.
241  *
242  * ************************************************************************** **
243  */
244 static BOOL is_illegal_name( char *name )
245   {
246   unsigned char *s;
247
248   if( !name )
249     return( True );
250
251   if( !ct_initialized )
252     init_chartest();
253
254   s = (unsigned char *)name;
255   while( *s )
256     {
257       if( *s>0x7F && isillegal( *s ) )
258         return( True );
259       else
260         s++;
261     }
262
263   return( False );
264   } /* is_illegal_name */
265
266 /* ************************************************************************** **
267  * Return True if the name *could be* a mangled name.
268  *
269  *  Input:  s - A path name - in UNIX pathname format.
270  *
271  *  Output: True if the name matches the pattern described below in the
272  *          notes, else False.
273  *
274  *  Notes:  The input name is *not* tested for 8.3 compliance.  This must be
275  *          done separately.  This function returns true if the name contains
276  *          a magic character followed by excactly two characters from the
277  *          basechars list (above), which in turn are followed either by the
278  *          nul (end of string) byte or a dot (extension) or by a '/' (end of
279  *          a directory name).
280  *
281  * ************************************************************************** **
282  */
283 BOOL is_mangled( char *s )
284   {
285   char *magic;
286
287   if( !ct_initialized )
288     init_chartest();
289
290   magic = strchr_m( s, magic_char );
291   while( magic && magic[1] && magic[2] )          /* 3 chars, 1st is magic. */
292     {
293     if( ('.' == magic[3] || '/' == magic[3] || !(magic[3]))          /* Ends with '.' or nul or '/' ?  */
294      && isbasechar( toupper(magic[1]) )           /* is 2nd char basechar?  */
295      && isbasechar( toupper(magic[2]) ) )         /* is 3rd char basechar?  */
296       return( True );                           /* If all above, then true, */
297     magic = strchr_m( magic+1, magic_char );      /*    else seek next magic. */
298     }
299   return( False );
300   } /* is_mangled */
301
302 /* ************************************************************************** **
303  * Return True if the name is a valid DOS name in 8.3 DOS format.
304  *
305  *  Input:  fname       - File name to be checked.
306  *          check_case  - If True, and if case_mangle is True, then the
307  *                        name will be checked to see if all characters
308  *                        are the correct case.  See case_mangle and
309  *                        case_default above.
310  *
311  *  Output: True if the name is a valid DOS name, else FALSE.
312  *
313  * ************************************************************************** **
314  */
315 BOOL is_8_3( char *fname, BOOL check_case )
316   {
317   int   len;
318   int   l;
319   char *p;
320   char *dot_pos;
321   char *slash_pos = strrchr_m( fname, '/' );
322
323   /* If there is a directory path, skip it. */
324   if( slash_pos )
325     fname = slash_pos + 1;
326   len = strlen( fname );
327
328   DEBUG( 5, ( "Checking %s for 8.3\n", fname ) );
329
330   /* Can't be 0 chars or longer than 12 chars */
331   if( (len == 0) || (len > 12) )
332     return( False );
333
334   /* Mustn't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
335   if( is_reserved_msdos( fname ) )
336     return( False );
337
338   /* Check that all characters are the correct case, if asked to do so. */
339   if( check_case && case_mangle )
340     {
341     switch( case_default )
342       {
343       case CASE_LOWER:
344         if( strhasupper( fname ) )
345           return(False);
346         break;
347       case CASE_UPPER:
348         if( strhaslower( fname ) )
349           return(False);
350         break;
351       }
352     }
353
354   /* Can't contain invalid dos chars */
355   /* Windows use the ANSI charset.
356      But filenames are translated in the PC charset.
357      This Translation may be more or less relaxed depending
358      the Windows application. */
359
360   /* %%% A nice improvment to name mangling would be to translate
361      filename to ANSI charset on the smb server host */
362
363   p       = fname;
364   dot_pos = NULL;
365   while( *p )
366     {
367       if( *p == '.' && !dot_pos )
368         dot_pos = (char *)p;
369       /*else
370         if( !isdoschar( *p ) )
371           return( False );*/
372       p++;
373     }
374
375   /* no dot and less than 9 means OK */
376   if( !dot_pos )
377     return( len <= 8 );
378         
379   l = PTR_DIFF( dot_pos, fname );
380
381   /* base must be at least 1 char except special cases . and .. */
382   if( l == 0 )
383     return( 0 == strcmp( fname, "." ) || 0 == strcmp( fname, ".." ) );
384
385   /* base can't be greater than 8 */
386   if( l > 8 )
387     return( False );
388
389   /* see smb.conf(5) for a description of the 'strip dot' parameter. */
390   if( lp_strip_dot()
391    && len - l == 1
392    && !strchr_m( dot_pos + 1, '.' ) )
393     {
394     *dot_pos = 0;
395     return( True );
396     }
397
398   /* extension must be between 1 and 3 */
399   if( (len - l < 2 ) || (len - l > 4) )
400     return( False );
401
402   /* extensions may not have a dot */
403   if( strchr_m( dot_pos+1, '.' ) )
404     return( False );
405
406   /* must be in 8.3 format */
407   return( True );
408   } /* is_8_3 */
409
410
411 /* ************************************************************************** **
412  * Compare two cache keys and return a value indicating their ordinal
413  * relationship.
414  *
415  *  Input:  ItemPtr - Pointer to a comparison key.  In this case, this will
416  *                    be a mangled name string.
417  *          NodePtr - Pointer to a node in the cache.  The node structure
418  *                    will be followed in memory by a mangled name string.
419  *
420  *  Output: A signed integer, as follows:
421  *            (x < 0)  <==> Key1 less than Key2
422  *            (x == 0) <==> Key1 equals Key2
423  *            (x > 0)  <==> Key1 greater than Key2
424  *
425  *  Notes:  This is a ubiqx-style comparison routine.  See ubi_BinTree for
426  *          more info.
427  *
428  * ************************************************************************** **
429  */
430 static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
431   {
432   char *Key1 = (char *)ItemPtr;
433   char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1);
434
435   return( StrCaseCmp( Key1, Key2 ) );
436   } /* cache_compare */
437
438 /* ************************************************************************** **
439  * Free a cache entry.
440  *
441  *  Input:  WarrenZevon - Pointer to the entry that is to be returned to
442  *                        Nirvana.
443  *  Output: none.
444  *
445  *  Notes:  This function gets around the possibility that the standard
446  *          free() function may be implemented as a macro, or other evil
447  *          subversions (oh, so much fun).
448  *
449  * ************************************************************************** **
450  */
451 static void cache_free_entry( ubi_trNodePtr WarrenZevon )
452   {
453           ZERO_STRUCTP(WarrenZevon);
454           SAFE_FREE( WarrenZevon );
455   } /* cache_free_entry */
456
457 /* ************************************************************************** **
458  * Initializes or clears the mangled cache.
459  *
460  *  Input:  none.
461  *  Output: none.
462  *
463  *  Notes:  There is a section below that is commented out.  It shows how
464  *          one might use lp_ calls to set the maximum memory and entry size
465  *          of the cache.  You might also want to remove the constants used
466  *          in ubi_cacheInit() and replace them with lp_ calls.  If so, then
467  *          the calls to ubi_cacheSetMax*() would be moved into the else
468  *          clause.  Another option would be to pass in the max_entries and
469  *          max_memory values as parameters.  crh 09-Apr-1998.
470  *
471  * ************************************************************************** **
472  */
473 void reset_mangled_cache( void )
474   {
475   if( !mc_initialized )
476     {
477     (void)ubi_cacheInit( mangled_cache,
478                          cache_compare,
479                          cache_free_entry,
480                          MANGLED_CACHE_MAX_ENTRIES,
481                          MANGLED_CACHE_MAX_MEMORY );
482     mc_initialized = True;
483     }
484   else
485     {
486     (void)ubi_cacheClear( mangled_cache );
487     }
488
489   /*
490   (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() );
491   (void)ubi_cacheSetMaxMemory(  mangled_cache, lp_mangled_cache_memory() );
492   */
493   } /* reset_mangled_cache  */
494
495
496 /* ************************************************************************** **
497  * Add a mangled name into the cache.
498  *
499  *  Notes:  If the mangled cache has not been initialized, then the
500  *          function will simply fail.  It could initialize the cache,
501  *          but that's not the way it was done before I changed the
502  *          cache mechanism, so I'm sticking with the old method.
503  *
504  *          If the extension of the raw name maps directly to the
505  *          extension of the mangled name, then we'll store both names
506  *          *without* extensions.  That way, we can provide consistent
507  *          reverse mangling for all names that match.  The test here is
508  *          a bit more careful than the one done in earlier versions of
509  *          mangle.c:
510  *
511  *            - the extension must exist on the raw name,
512  *            - it must be all lower case
513  *            - it must match the mangled extension (to prove that no
514  *              mangling occurred).
515  *
516  *  crh 07-Apr-1998
517  *
518  * ************************************************************************** **
519  */
520 static void cache_mangled_name( char *mangled_name, char *raw_name )
521   {
522   ubi_cacheEntryPtr new_entry;
523   char             *s1;
524   char             *s2;
525   size_t               mangled_len;
526   size_t               raw_len;
527   size_t               i;
528
529   /* If the cache isn't initialized, give up. */
530   if( !mc_initialized )
531     return;
532
533   /* Init the string lengths. */
534   mangled_len = strlen( mangled_name );
535   raw_len     = strlen( raw_name );
536
537   /* See if the extensions are unmangled.  If so, store the entry
538    * without the extension, thus creating a "group" reverse map.
539    */
540   s1 = strrchr_m( mangled_name, '.' );
541   if( s1 && (s2 = strrchr_m( raw_name, '.' )) )
542     {
543     i = 1;
544     while( s1[i] && (tolower( s1[1] ) == s2[i]) )
545       i++;
546     if( !s1[i] && !s2[i] )
547       {
548       mangled_len -= i;
549       raw_len     -= i;
550       }
551     }
552
553   /* Allocate a new cache entry.  If the allocation fails, just return. */
554   i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2;
555   new_entry = malloc( i );
556   if( !new_entry )
557     return;
558
559   /* Fill the new cache entry, and add it to the cache. */
560   s1 = (char *)(new_entry + 1);
561   s2 = (char *)&(s1[mangled_len + 1]);
562   (void)StrnCpy( s1, mangled_name, mangled_len );
563   (void)StrnCpy( s2, raw_name,     raw_len );
564   ubi_cachePut( mangled_cache, i, new_entry, s1 );
565   } /* cache_mangled_name */
566
567 /* ************************************************************************** **
568  * Check for a name on the mangled name stack
569  *
570  *  Input:  s - Input *and* output string buffer.
571  *
572  *  Output: True if the name was found in the cache, else False.
573  *
574  *  Notes:  If a reverse map is found, the function will overwrite the string
575  *          space indicated by the input pointer <s>.  This is frightening.
576  *          It should be rewritten to return NULL if the long name was not
577  *          found, and a pointer to the long name if it was found.
578  *
579  * ************************************************************************** **
580  */
581
582 BOOL check_mangled_cache( char *s )
583 {
584   ubi_cacheEntryPtr FoundPtr;
585   char             *ext_start = NULL;
586   char             *found_name;
587   char             *saved_ext = NULL;
588
589   /* If the cache isn't initialized, give up. */
590   if( !mc_initialized )
591     return( False );
592
593   FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
594
595   /* If we didn't find the name *with* the extension, try without. */
596   if( !FoundPtr )
597   {
598     ext_start = strrchr_m( s, '.' );
599     if( ext_start )
600     {
601       if((saved_ext = strdup(ext_start)) == NULL)
602         return False;
603
604       *ext_start = '\0';
605       FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
606       /* 
607        * At this point s is the name without the
608        * extension. We re-add the extension if saved_ext
609        * is not null, before freeing saved_ext.
610        */
611     }
612   }
613
614   /* Okay, if we haven't found it we're done. */
615   if( !FoundPtr )
616   {
617     if(saved_ext)
618     {
619       /* Replace the saved_ext as it was truncated. */
620       (void)pstrcat( s, saved_ext );
621       SAFE_FREE(saved_ext);
622     }
623     return( False );
624   }
625
626   /* If we *did* find it, we need to copy it into the string buffer. */
627   found_name = (char *)(FoundPtr + 1);
628   found_name += (strlen( found_name ) + 1);
629
630   DEBUG( 3, ("Found %s on mangled stack ", s) );
631
632   (void)pstrcpy( s, found_name );
633   if( saved_ext )
634   {
635     /* Replace the saved_ext as it was truncated. */
636     (void)pstrcat( s, saved_ext );
637     SAFE_FREE(saved_ext);
638   }
639
640   DEBUG( 3, ("as %s\n", s) );
641
642   return( True );
643 } /* check_mangled_cache */
644
645
646 /* ************************************************************************** **
647  * Used only in do_fwd_mangled_map(), below.
648  * ************************************************************************** **
649  */
650 static char *map_filename( char *s,         /* This is null terminated */
651                            char *pattern,   /* This isn't. */
652                            int len )        /* This is the length of pattern. */
653   {
654   static pstring matching_bit;  /* The bit of the string which matches */
655                                 /* a * in pattern if indeed there is a * */
656   char *sp;                     /* Pointer into s. */
657   char *pp;                     /* Pointer into p. */
658   char *match_start;            /* Where the matching bit starts. */
659   pstring pat;
660
661   StrnCpy( pat, pattern, len ); /* Get pattern into a proper string! */
662   pstrcpy( matching_bit, "" );  /* Match but no star gets this. */
663   pp = pat;                     /* Initialize the pointers. */
664   sp = s;
665
666   if( strequal(s, ".") || strequal(s, ".."))
667     {
668     return NULL;                /* Do not map '.' and '..' */
669     }
670
671   if( (len == 1) && (*pattern == '*') )
672     {
673     return NULL;                /* Impossible, too ambiguous for */
674     }                           /* words! */
675
676   while( (*sp)                  /* Not the end of the string. */
677       && (*pp)                  /* Not the end of the pattern. */
678       && (*sp == *pp)           /* The two match. */
679       && (*pp != '*') )         /* No wildcard. */
680     {
681     sp++;                       /* Keep looking. */
682     pp++;
683     }
684
685   if( !*sp && !*pp )            /* End of pattern. */
686     return( matching_bit );     /* Simple match.  Return empty string. */
687
688   if( *pp == '*' )
689     {
690     pp++;                       /* Always interrested in the chacter */
691                                 /* after the '*' */
692     if( !*pp )                  /* It is at the end of the pattern. */
693       {
694       StrnCpy( matching_bit, s, sp-s );
695       return( matching_bit );
696       }
697     else
698       {
699       /* The next character in pattern must match a character further */
700       /* along s than sp so look for that character. */
701       match_start = sp;
702       while( (*sp)              /* Not the end of s. */
703           && (*sp != *pp) )     /* Not the same  */
704         sp++;                   /* Keep looking. */
705       if( !*sp )                /* Got to the end without a match. */
706         {
707         return( NULL );
708         }                       /* Still hope for a match. */
709       else
710         {
711         /* Now sp should point to a matching character. */
712         StrnCpy(matching_bit, match_start, sp-match_start);
713         /* Back to needing a stright match again. */
714         while( (*sp)            /* Not the end of the string. */
715             && (*pp)            /* Not the end of the pattern. */
716             && (*sp == *pp) )   /* The two match. */
717           {
718           sp++;                 /* Keep looking. */
719           pp++;
720           }
721         if( !*sp && !*pp )      /* Both at end so it matched */
722           return( matching_bit );
723         else
724           return( NULL );
725         }
726       }
727     }
728   return( NULL );               /* No match. */
729   } /* map_filename */
730
731
732 /* ************************************************************************** **
733  * MangledMap is a series of name pairs in () separated by spaces.
734  * If s matches the first of the pair then the name given is the
735  * second of the pair.  A * means any number of any character and if
736  * present in the second of the pair as well as the first the
737  * matching part of the first string takes the place of the * in the
738  * second.
739  *
740  * I wanted this so that we could have RCS files which can be used
741  * by UNIX and DOS programs.  My mapping string is (RCS rcs) which
742  * converts the UNIX RCS file subdirectory to lowercase thus
743  * preventing mangling.
744  *
745  * (I think Andrew wrote the above, but I'm not sure. -- CRH)
746  *
747  * See 'mangled map' in smb.conf(5).
748  *
749  * ************************************************************************** **
750  */
751 static void do_fwd_mangled_map(char *s, char *MangledMap)
752   {
753   char *start=MangledMap;       /* Use this to search for mappings. */
754   char *end;                    /* Used to find the end of strings. */
755   char *match_string;
756   pstring new_string;           /* Make up the result here. */
757   char *np;                     /* Points into new_string. */
758
759   DEBUG( 5, ("Mangled Mapping '%s' map '%s'\n", s, MangledMap) );
760   while( *start )
761     {
762     while( (*start) && (*start != '(') )
763       start++;
764     if( !*start )
765       continue;                 /* Always check for the end. */
766     start++;                    /* Skip the ( */
767     end = start;                /* Search for the ' ' or a ')' */
768     DEBUG( 5, ("Start of first in pair '%s'\n", start) );
769     while( (*end) && !((*end == ' ') || (*end == ')')) )
770       end++;
771     if( !*end )
772       {
773       start = end;
774       continue;                 /* Always check for the end. */
775       }
776     DEBUG( 5, ("End of first in pair '%s'\n", end) );
777     if( (match_string = map_filename( s, start, end-start )) )
778       {
779       DEBUG( 5, ("Found a match\n") );
780       /* Found a match. */
781       start = end + 1;          /* Point to start of what it is to become. */
782       DEBUG( 5, ("Start of second in pair '%s'\n", start) );
783       end = start;
784       np = new_string;
785       while( (*end)             /* Not the end of string. */
786           && (*end != ')')      /* Not the end of the pattern. */
787           && (*end != '*') )    /* Not a wildcard. */
788         *np++ = *end++;
789       if( !*end )
790         {
791         start = end;
792         continue;               /* Always check for the end. */
793         }
794       if( *end == '*' )
795         {
796         pstrcpy( np, match_string );
797         np += strlen( match_string );
798         end++;                  /* Skip the '*' */
799         while( (*end)             /* Not the end of string. */
800             && (*end != ')')      /* Not the end of the pattern. */
801             && (*end != '*') )    /* Not a wildcard. */
802           *np++ = *end++;
803         }
804       if( !*end )
805         {
806         start = end;
807         continue;               /* Always check for the end. */
808         }
809       *np++ = '\0';             /* NULL terminate it. */
810       DEBUG(5,("End of second in pair '%s'\n", end));
811       pstrcpy( s, new_string );  /* Substitute with the new name. */
812       DEBUG( 5, ("s is now '%s'\n", s) );
813       }
814     start = end;              /* Skip a bit which cannot be wanted anymore. */
815     start++;
816     }
817   } /* do_fwd_mangled_map */
818
819 /*****************************************************************************
820  * do the actual mangling to 8.3 format
821  * the buffer must be able to hold 13 characters (including the null)
822  *****************************************************************************
823  */
824 void mangle_name_83( char *s)
825   {
826   int csum;
827   char *p;
828   char extension[4];
829   char base[9];
830   int baselen = 0;
831   int extlen = 0;
832
833   extension[0] = 0;
834   base[0] = 0;
835
836   p = strrchr_m(s,'.');  
837   if( p && (strlen(p+1) < (size_t)4) )
838     {
839     BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */
840
841     if( all_normal && p[1] != 0 )
842       {
843       *p = 0;
844       csum = str_checksum( s );
845       *p = '.';
846       }
847     else
848       csum = str_checksum(s);
849     }
850   else
851     csum = str_checksum(s);
852
853   strupper( s );
854
855   DEBUG( 5, ("Mangling name %s to ",s) );
856
857   if( p )
858     {
859     if( p == s )
860       safe_strcpy( extension, "___", 3 );
861     else
862       {
863       *p++ = 0;
864       while( *p && extlen < 3 )
865         {
866             if( /*isdoschar (*p) &&*/ *p != '.' )
867               extension[extlen++] = p[0];
868             p++;
869         }
870       extension[extlen] = 0;
871       }
872     }
873
874   p = s;
875
876   while( *p && baselen < 5 )
877     {
878         if( /*isdoschar( *p ) &&*/ *p != '.' )
879           base[baselen++] = p[0];
880         p++;
881     }
882   base[baselen] = 0;
883
884   csum = csum % (MANGLE_BASE*MANGLE_BASE);
885
886   (void)slprintf(s, 12, "%s%c%c%c",
887                  base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
888
889   if( *extension )
890     {
891     (void)pstrcat( s, "." );
892     (void)pstrcat( s, extension );
893     }
894
895   DEBUG( 5, ( "%s\n", s ) );
896
897   } /* mangle_name_83 */
898
899 /*****************************************************************************
900  * Convert a filename to DOS format.  Return True if successful.
901  *
902  *  Input:  OutName - Source *and* destination buffer. 
903  *
904  *                    NOTE that OutName must point to a memory space that
905  *                    is at least 13 bytes in size!
906  *
907  *          need83  - If False, name mangling will be skipped unless the
908  *                    name contains illegal characters.  Mapping will still
909  *                    be done, if appropriate.  This is probably used to
910  *                    signal that a client does not require name mangling,
911  *                    thus skipping the name mangling even on shares which
912  *                    have name-mangling turned on.
913  *          cache83 - If False, the mangled name cache will not be updated.
914  *                    This is usually used to prevent that we overwrite
915  *                    a conflicting cache entry prematurely, i.e. before
916  *                    we know whether the client is really interested in the
917  *                    current name.  (See PR#13758).  UKD.
918  *          snum    - Share number.  This identifies the share in which the
919  *                    name exists.
920  *
921  *  Output: Returns False only if the name wanted mangling but the share does
922  *          not have name mangling turned on.
923  *
924  * ****************************************************************************
925  */
926 BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
927 {
928         char *map;
929         DEBUG(5,("name_map_mangle( %s, need83 = %s, cache83 = %s, %d )\n", OutName,
930                 need83 ? "TRUE" : "FALSE", cache83 ? "TRUE" : "FALSE", snum));
931
932 #ifdef MANGLE_LONG_FILENAMES
933         if( !need83 && is_illegal_name(OutName) )
934                 need83 = True;
935 #endif  
936
937         /* apply any name mappings */
938         map = lp_mangled_map(snum);
939
940         if (map && *map) {
941                 do_fwd_mangled_map( OutName, map );
942         }
943
944         /* check if it's already in 8.3 format */
945         if (need83 && !is_8_3(OutName, True)) {
946                 char *tmp = NULL; 
947
948                 if (!lp_manglednames(snum)) {
949                         return(False);
950                 }
951
952                 /* mangle it into 8.3 */
953                 if (cache83)
954                         tmp = strdup(OutName);
955
956                 mangle_name_83(OutName);
957
958                 if(tmp != NULL) {
959                         cache_mangled_name(OutName, tmp);
960                         SAFE_FREE(tmp);
961                 }
962         }
963
964         DEBUG(5,("name_map_mangle() ==> [%s]\n", OutName));
965         return(True);
966 } /* name_map_mangle */
967
968
969
970
971
972 #if 0
973
974 #define MANGLE_TDB_VERSION              "20010830"
975 #define MANGLE_TDB_FILE_NAME            "mangle.tdb"
976 #define MANGLE_TDB_STORED_NAME          "B"
977 #define MANGLED_PREFIX                  "MANGLED_"
978 #define LONG_PREFIX                     "LONG_"
979
980 struct mt_enum_info {
981         TDB_CONTEXT     *mangle_tdb;
982         TDB_DATA        key;
983 };
984
985
986 static struct mt_enum_info      global_mt_ent = {0, 0};
987
988 static int POW10(unsigned int exp)
989 {
990         int result = 1;
991         
992         while (exp) {
993                 result *= 10;
994                 exp--;
995         }
996   
997         return result;
998 }
999
1000 static BOOL init_mangle_tdb(void)
1001 {
1002         pstring tdbfile;
1003         
1004         if (global_mt_ent.mangle_tdb == 0)
1005         {
1006                 slprintf(tdbfile, sizeof(tdbfile)-1, "%s/%s", lp_private_dir(), MANGLE_TDB_FILE_NAME);
1007
1008                 /* Open tdb */
1009                 if (!(global_mt_ent.mangle_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR, 0600)))
1010                 {
1011                         DEBUG(0, ("Unable to open Mangle TDB, trying create new!\n"));
1012                         /* create a new one if it does not exist */
1013                         if (!(global_mt_ent.mangle_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT | O_EXCL, 0600)))
1014                         {
1015                                 DEBUG(0, ("Unable to create Mangle TDB (%s) !!!", tdbfile));
1016                                 return False;
1017                         }
1018                 }
1019         }
1020
1021         return True;
1022 }
1023
1024 /* see push_ucs2 */
1025 int dos_to_ucs2(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
1026 {
1027         int len=0;
1028         int src_len = strlen(src);
1029         pstring tmpbuf;
1030
1031         /* treat a pstring as "unlimited" length */
1032         if (dest_len == -1) {
1033                 dest_len = sizeof(pstring);
1034         }
1035
1036         if (flags & STR_UPPER) {
1037                 pstrcpy(tmpbuf, src);
1038                 strupper(tmpbuf);
1039                 src = tmpbuf;
1040         }
1041
1042         if (flags & STR_TERMINATE) {
1043                 src_len++;
1044         }
1045
1046         if (ucs2_align(base_ptr, dest, flags)) {
1047                 *(char *)dest = 0;
1048                 dest = (void *)((char *)dest + 1);
1049                 if (dest_len) dest_len--;
1050                 len++;
1051         }
1052
1053         /* ucs2 is always a multiple of 2 bytes */
1054         dest_len &= ~1;
1055
1056         len += convert_string(CH_DOS, CH_UCS2, src, src_len, dest, dest_len);
1057         return len;
1058 }
1059
1060 /* see pull_ucs2 */
1061 int ucs2_to_dos(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len, int flags)
1062 {
1063         int ret;
1064
1065         if (dest_len == -1) {
1066                 dest_len = sizeof(pstring);
1067         }
1068
1069         if (ucs2_align(base_ptr, src, flags)) {
1070                 src = (const void *)((char *)src + 1);
1071                 if (src_len > 0) src_len--;
1072         }
1073
1074         if (flags & STR_TERMINATE) src_len = strlen_w(src)*2+2;
1075
1076         /* ucs2 is always a multiple of 2 bytes */
1077         src_len &= ~1;
1078         
1079         ret = convert_string(CH_UCS2, CH_DOS, src, src_len, dest, dest_len);
1080         if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
1081
1082         return src_len;
1083 }
1084
1085
1086
1087 /* the unicode string will be ZERO terminated */
1088 static smb_ucs2_t *unicode_from_buffer (uint8 *buf, uint32 size)
1089 {
1090         uint32 len = 0;
1091         uint32 lfn_len;
1092         smb_ucs2_t *long_file_name;
1093         
1094         len = tdb_unpack (buf, size, MANGLE_TDB_STORED_NAME,
1095                 &lfn_len, &long_file_name);
1096
1097         if (len == -1) return NULL;
1098         else return long_file_name;
1099 }
1100
1101 /* the unicode string MUST be ZERO terminated */
1102 static uint32 buffer_from_unicode (uint8 **buf, smb_ucs2_t *long_file_name)
1103 {
1104         uint32 buflen;
1105         uint32 len = 0;
1106         uint32 lfn_len = strlen_w(long_file_name)*sizeof(smb_ucs2_t)+1;
1107         
1108         /* one time to get the size needed */
1109         len = tdb_pack(NULL, 0,  MANGLE_TDB_STORED_NAME,
1110                 lfn_len, long_file_name);
1111
1112         /* malloc the space needed */
1113         if ((*buf=(uint8*)malloc(len)) == NULL)
1114         {
1115                 DEBUG(0,("buffer_from_longname: Unable to malloc() memory for buffer!\n"));
1116                 return (-1);
1117         }
1118         
1119         /* now for the real call to tdb_pack() */
1120         buflen = tdb_pack(*buf, 0,  MANGLE_TDB_STORED_NAME,
1121                 lfn_len, long_file_name);
1122
1123         /* check to make sure we got it correct */
1124         if (buflen != len)
1125         {
1126                 /* error */
1127                 free (*buf);
1128                 return (-1);
1129         }
1130
1131         return (buflen);
1132 }
1133
1134 /* mangled must contain only the file name, not a path.
1135    and MUST be ZERO terminated */
1136 smb_ucs2_t *unmangle(const smb_ucs2_t *mangled)
1137 {
1138         TDB_DATA data, key;
1139         fstring keystr;
1140         fstring mufname;
1141         smb_ucs2_t *retstr;
1142         smb_ucs2_t *temp;
1143
1144         if (strlen_w(mangled) > 12) return NULL;
1145         if (!strchr_wa(mangled, '~')) return NULL;
1146         if (!init_mangle_tdb()) return NULL;
1147         
1148         temp = strdup_w(mangled);
1149         if (!temp)
1150         {
1151                 DEBUG(0,("mangle: out of memory!\n"));
1152                 return NULL;
1153         }
1154         strupper_w(temp);
1155         /* set search key */
1156         pull_ucs2(NULL, mufname, temp, sizeof(mufname), 0, STR_TERMINATE);
1157         SAFE_FREE(temp);
1158         slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
1159         key.dptr = keystr;
1160         key.dsize = strlen (keystr) + 1;
1161         
1162         /* get the record */
1163         data = tdb_fetch(global_mt_ent.mangle_tdb, key);
1164         
1165         if (!data.dptr) /* not found */
1166         {
1167                 DEBUG(5,("unmangle: %s\n", tdb_errorstr(global_mt_ent.mangle_tdb)));
1168                 return NULL;
1169         }
1170         
1171         if (!(retstr = unicode_from_buffer (data.dptr, data.dsize)))
1172         {
1173                 DEBUG(0,("unmangle: bad buffer returned from database!\n"));
1174                 SAFE_FREE(data.dptr);
1175                 return NULL;
1176         }
1177
1178         SAFE_FREE(data.dptr);
1179         return retstr;
1180 }
1181
1182 /* unmangled must contain only the file name, not a path.
1183    and MUST be ZERO terminated */
1184 smb_ucs2_t *_mangle(const smb_ucs2_t *unmangled)
1185 {
1186         TDB_DATA data, key;
1187         pstring keystr;
1188         pstring longname;
1189         fstring mufname;
1190         BOOL db_free = False;
1191         smb_ucs2_t *mangled;
1192         smb_ucs2_t *um;
1193         smb_ucs2_t *ext = NULL;
1194         smb_ucs2_t *p;
1195         size_t b_len;
1196         size_t e_len;
1197         size_t um_len;
1198         uint32 n, c;
1199                         
1200
1201         /* TODO: if it is a path return a failure */
1202                         
1203         um = strdup_w(unmangled);
1204         if (!um)
1205         {
1206                 DEBUG(0,("mangle: out of memory!\n"));
1207                 goto error;
1208         }
1209         um_len = strlen_w(um);
1210         if (p = strrchr_wa(um, '.'))
1211         {
1212                 if ((um_len - ((p - um) / sizeof(smb_ucs2_t))) < 4) /* check extension */
1213                 {
1214                         *p = UCS2_CHAR('\0');
1215                         ext = p++;
1216                 }
1217         }
1218
1219         /* test if the same is yet mangled */
1220
1221         /* set search key */
1222         pull_ucs2(NULL, longname, um, sizeof(longname), 0, STR_TERMINATE);
1223         slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
1224         key.dptr = keystr;
1225         key.dsize = strlen (keystr) + 1;
1226         
1227         /* get the record */
1228         data = tdb_fetch (global_mt_ent.mangle_tdb, key);
1229         if (!data.dptr) /* not found */
1230         {
1231                 if (tdb_error(global_mt_ent.mangle_tdb) != TDB_ERR_NOEXIST)
1232                 {
1233                         DEBUG(0, ("mangle: database retrieval error: %s\n",
1234                                         tdb_errorstr(global_mt_ent.mangle_tdb)));
1235                         goto error;
1236                 }
1237         
1238                 /* if not find the first free possibile mangled name */
1239                 n = c = 1;
1240                 while (!db_free)
1241                 {
1242                         uint32 pos;
1243                         smb_ucs2_t temp[9];
1244                         char num[7];
1245                 
1246                         while ((int)POW10(n) <= c) n++;
1247                         pos = 7 - n;
1248                         if (pos == 0) goto error;
1249
1250                         strncpy_w(temp, um, pos);
1251                         strupper_w(temp);
1252                         temp[pos] = UCS2_CHAR('~');
1253                         temp[pos+1] = 0;
1254                         snprintf(num, 7, "%d", c);
1255                         strncat_wa(temp, num, n);
1256
1257                         pull_ucs2(NULL, mufname, temp, sizeof(mufname), 0, STR_TERMINATE);
1258                         if (strlen(mufname) > 8)
1259                         {
1260                                 n++;
1261                                 continue;
1262                         }
1263
1264                         slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
1265                         key.dptr = keystr;
1266                         key.dsize = strlen (keystr) + 1;
1267                         if ((data.dsize=buffer_from_unicode ((uint8 **)(&data.dptr), temp)) == -1)
1268                         {
1269                                 DEBUG(0,("mangle: ERROR - Unable to copy mangled name info buffer!\n"));
1270                                 goto error;
1271                         }
1272
1273                         if (tdb_store(global_mt_ent.mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
1274                         {
1275                                 SAFE_FREE(data.dptr);
1276                                 if (tdb_error(global_mt_ent.mangle_tdb) == TDB_ERR_EXISTS)
1277                                 {
1278                                         continue;
1279                                 }
1280                                 else
1281                                 {
1282                                         DEBUG(0, ("mangle: database retrieval error: %s\n",
1283                                                         tdb_errorstr(global_mt_ent.mangle_tdb)));
1284                                         goto error;
1285                                 }
1286                         }
1287                         else
1288                         {
1289                                 db_free = True;
1290                                 p = strdup_w(temp);
1291                         }
1292                         c++;
1293                 }
1294         }
1295         else /* FOUND */
1296         {
1297                 if (!(p = unicode_from_buffer (data.dptr, data.dsize)))
1298                 {
1299                         DEBUG(0,("mangle: bad buffer returned from database!\n"));
1300                         goto error;
1301                 }
1302         }
1303                 
1304         b_len = strlen_w(p);
1305         if (ext) e_len = strlen_w(ext);
1306         else e_len = 0;
1307         mangled = (smb_ucs2_t *)malloc((b_len+e_len+2)*sizeof(smb_ucs2_t));
1308         strncpy_w (mangled, p, b_len+1);
1309         strncat_w (mangled, ext, e_len);
1310
1311         SAFE_FREE(p);
1312         SAFE_FREE(um);
1313         SAFE_FREE(data.dptr);
1314
1315         return mangled;
1316
1317 error:
1318         DEBUG(10, ("mangle: failed to mangle <string from unicode here>!\n"));
1319         SAFE_FREE(data.dptr);
1320         SAFE_FREE(um);
1321         return NULL;
1322 }
1323
1324 #endif /* 0 */