move to SAFE_FREE()
[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