r570: Remove lots of globals to handle case issues - move them
[ira/wip.git] / source3 / smbd / mangle_hash.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Name mangling
4    Copyright (C) Andrew Tridgell 1992-2002
5    Copyright (C) Simo Sorce 2001
6    Copyright (C) Andrew Bartlett 2002
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 /* -------------------------------------------------------------------------- **
25  * Notable problems...
26  *
27  *  March/April 1998  CRH
28  *  - Many of the functions in this module overwrite string buffers passed to
29  *    them.  This causes a variety of problems and is, generally speaking,
30  *    dangerous and scarry.  See the kludge notes in name_map()
31  *    below.
32  *  - It seems that something is calling name_map() twice.  The
33  *    first call is probably some sort of test.  Names which contain
34  *    illegal characters are being doubly mangled.  I'm not sure, but
35  *    I'm guessing the problem is in server.c.
36  *
37  * -------------------------------------------------------------------------- **
38  */
39
40 /* -------------------------------------------------------------------------- **
41  * History...
42  *
43  *  March/April 1998  CRH
44  *  Updated a bit.  Rewrote is_mangled() to be a bit more selective.
45  *  Rewrote the mangled name cache.  Added comments here and there.
46  *  &c.
47  * -------------------------------------------------------------------------- **
48  */
49
50 #include "includes.h"
51
52
53 /* -------------------------------------------------------------------------- **
54  * Other stuff...
55  *
56  * magic_char     - This is the magic char used for mangling.  It's
57  *                  global.  There is a call to lp_magicchar() in server.c
58  *                  that is used to override the initial value.
59  *
60  * MANGLE_BASE    - This is the number of characters we use for name mangling.
61  *
62  * basechars      - The set characters used for name mangling.  This
63  *                  is static (scope is this file only).
64  *
65  * mangle()       - Macro used to select a character from basechars (i.e.,
66  *                  mangle(n) will return the nth digit, modulo MANGLE_BASE).
67  *
68  * chartest       - array 0..255.  The index range is the set of all possible
69  *                  values of a byte.  For each byte value, the content is a
70  *                  two nibble pair.  See BASECHAR_MASK and ILLEGAL_MASK,
71  *                  below.
72  *
73  * ct_initialized - False until the chartest array has been initialized via
74  *                  a call to init_chartest().
75  *
76  * BASECHAR_MASK  - Masks the upper nibble of a one-byte value.
77  *
78  * ILLEGAL_MASK   - Masks the lower nibble of a one-byte value.
79  *
80  * isbasecahr()   - Given a character, check the chartest array to see
81  *                  if that character is in the basechars set.  This is
82  *                  faster than using strchr_m().
83  *
84  * isillegal()    - Given a character, check the chartest array to see
85  *                  if that character is in the illegal characters set.
86  *                  This is faster than using strchr_m().
87  *
88  * mangled_cache  - Cache header used for storing mangled -> original
89  *                  reverse maps.
90  *
91  * mc_initialized - False until the mangled_cache structure has been
92  *                  initialized via a call to reset_mangled_cache().
93  *
94  * MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the
95  *                  cache.  A value of 0 indicates "infinite".
96  *
97  * MANGLED_CACHE_MAX_MEMORY  - Default maximum amount of memory for the
98  *                  cache.  When the cache was kept as an array of 256
99  *                  byte strings, the default cache size was 50 entries.
100  *                  This required a fixed 12.5Kbytes of memory.  The
101  *                  mangled stack parameter is no longer used (though
102  *                  this might change).  We're now using a fixed 16Kbyte
103  *                  maximum cache size.  This will probably be much more
104  *                  than 50 entries.
105  */
106
107 char magic_char = '~';
108
109 static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
110 #define MANGLE_BASE       (sizeof(basechars)/sizeof(char)-1)
111
112 static unsigned char chartest[256]  = { 0 };
113 static BOOL          ct_initialized = False;
114
115 #define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
116 #define BASECHAR_MASK 0xf0
117 #define ILLEGAL_MASK  0x0f
118 #define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
119 #define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK )
120
121 static ubi_cacheRoot mangled_cache[1] =  { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } };
122 static BOOL          mc_initialized   = False;
123 #define MANGLED_CACHE_MAX_ENTRIES 1024
124 #define MANGLED_CACHE_MAX_MEMORY 0
125
126 /* -------------------------------------------------------------------- */
127
128 static NTSTATUS has_valid_83_chars(const smb_ucs2_t *s, BOOL allow_wildcards)
129 {
130         if (!s || !*s)
131                 return NT_STATUS_INVALID_PARAMETER;
132
133         /* CHECK: this should not be necessary if the ms wild chars
134            are not valid in valid.dat  --- simo */
135         if (!allow_wildcards && ms_has_wild_w(s))
136                 return NT_STATUS_UNSUCCESSFUL;
137
138         while (*s) {
139                 if(!isvalid83_w(*s))
140                         return NT_STATUS_UNSUCCESSFUL;
141                 s++;
142         }
143
144         return NT_STATUS_OK;
145 }
146
147 /* return False if something fail and
148  * return 2 alloced unicode strings that contain prefix and extension
149  */
150
151 static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix,
152                 smb_ucs2_t **extension, BOOL allow_wildcards)
153 {
154         size_t ext_len;
155         smb_ucs2_t *p;
156
157         *extension = 0;
158         *prefix = strdup_w(ucs2_string);
159         if (!*prefix) {
160                 return NT_STATUS_NO_MEMORY;
161         }
162         if ((p = strrchr_w(*prefix, UCS2_CHAR('.')))) {
163                 ext_len = strlen_w(p+1);
164                 if ((ext_len > 0) && (ext_len < 4) && (p != *prefix) &&
165                     (NT_STATUS_IS_OK(has_valid_83_chars(p+1,allow_wildcards)))) /* check extension */ {
166                         *p = 0;
167                         *extension = strdup_w(p+1);
168                         if (!*extension) {
169                                 SAFE_FREE(*prefix);
170                                 return NT_STATUS_NO_MEMORY;
171                         }
172                 }
173         }
174         return NT_STATUS_OK;
175 }
176
177 /* ************************************************************************** **
178  * Return NT_STATUS_UNSUCCESSFUL if a name is a special msdos reserved name.
179  *
180  *  Input:  fname - String containing the name to be tested.
181  *
182  *  Output: NT_STATUS_UNSUCCESSFUL, if the name matches one of the list of reserved names.
183  *
184  *  Notes:  This is a static function called by is_8_3(), below.
185  *
186  * ************************************************************************** **
187  */
188
189 static NTSTATUS is_valid_name(const smb_ucs2_t *fname, BOOL allow_wildcards, BOOL only_8_3)
190 {
191         smb_ucs2_t *str, *p;
192         NTSTATUS ret = NT_STATUS_OK;
193
194         if (!fname || !*fname)
195                 return NT_STATUS_INVALID_PARAMETER;
196
197         /* . and .. are valid names. */
198         if (strcmp_wa(fname, ".")==0 || strcmp_wa(fname, "..")==0)
199                 return NT_STATUS_OK;
200
201         /* Name cannot start with '.' */
202         if (*fname == UCS2_CHAR('.'))
203                 return NT_STATUS_UNSUCCESSFUL;
204         
205         if (only_8_3) {
206                 ret = has_valid_83_chars(fname, allow_wildcards);
207                 if (!NT_STATUS_IS_OK(ret))
208                         return ret;
209         }
210
211         str = strdup_w(fname);
212         p = strchr_w(str, UCS2_CHAR('.'));
213         if (p && p[1] == UCS2_CHAR(0)) {
214                 /* Name cannot end in '.' */
215                 SAFE_FREE(str);
216                 return NT_STATUS_UNSUCCESSFUL;
217         }
218         if (p)
219                 *p = 0;
220         strupper_w(str);
221         p = &(str[1]);
222
223         switch(str[0])
224         {
225         case UCS2_CHAR('A'):
226                 if(strcmp_wa(p, "UX") == 0)
227                         ret = NT_STATUS_UNSUCCESSFUL;
228                 break;
229         case UCS2_CHAR('C'):
230                 if((strcmp_wa(p, "LOCK$") == 0)
231                 || (strcmp_wa(p, "ON") == 0)
232                 || (strcmp_wa(p, "OM1") == 0)
233                 || (strcmp_wa(p, "OM2") == 0)
234                 || (strcmp_wa(p, "OM3") == 0)
235                 || (strcmp_wa(p, "OM4") == 0)
236                 )
237                         ret = NT_STATUS_UNSUCCESSFUL;
238                 break;
239         case UCS2_CHAR('L'):
240                 if((strcmp_wa(p, "PT1") == 0)
241                 || (strcmp_wa(p, "PT2") == 0)
242                 || (strcmp_wa(p, "PT3") == 0)
243                 )
244                         ret = NT_STATUS_UNSUCCESSFUL;
245                 break;
246         case UCS2_CHAR('N'):
247                 if(strcmp_wa(p, "UL") == 0)
248                         ret = NT_STATUS_UNSUCCESSFUL;
249                 break;
250         case UCS2_CHAR('P'):
251                 if(strcmp_wa(p, "RN") == 0)
252                         ret = NT_STATUS_UNSUCCESSFUL;
253                 break;
254         default:
255                 break;
256         }
257
258         SAFE_FREE(str);
259         return ret;
260 }
261
262 static NTSTATUS is_8_3_w(const smb_ucs2_t *fname, BOOL allow_wildcards)
263 {
264         smb_ucs2_t *pref = 0, *ext = 0;
265         size_t plen;
266         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
267
268         if (!fname || !*fname)
269                 return NT_STATUS_INVALID_PARAMETER;
270
271         if (strlen_w(fname) > 12)
272                 return NT_STATUS_UNSUCCESSFUL;
273         
274         if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0)
275                 return NT_STATUS_OK;
276
277         if (!NT_STATUS_IS_OK(is_valid_name(fname, allow_wildcards, True)))
278                 goto done;
279
280         if (!NT_STATUS_IS_OK(mangle_get_prefix(fname, &pref, &ext, allow_wildcards)))
281                 goto done;
282         plen = strlen_w(pref);
283
284         if (strchr_wa(pref, '.'))
285                 goto done;
286         if (plen < 1 || plen > 8)
287                 goto done;
288         if (ext && (strlen_w(ext) > 3))
289                 goto done;
290
291         ret = NT_STATUS_OK;
292
293 done:
294         SAFE_FREE(pref);
295         SAFE_FREE(ext);
296         return ret;
297 }
298
299 static BOOL is_8_3(const char *fname, BOOL check_case, BOOL allow_wildcards)
300 {
301         const char *f;
302         smb_ucs2_t *ucs2name;
303         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
304         size_t size;
305
306         if (!fname || !*fname)
307                 return False;
308         if ((f = strrchr(fname, '/')) == NULL)
309                 f = fname;
310         else
311                 f++;
312
313         if (strlen(f) > 12)
314                 return False;
315         
316         size = push_ucs2_allocate(&ucs2name, f);
317         if (size == (size_t)-1) {
318                 DEBUG(0,("is_8_3: internal error push_ucs2_allocate() failed!\n"));
319                 goto done;
320         }
321
322         ret = is_8_3_w(ucs2name, allow_wildcards);
323
324 done:
325         SAFE_FREE(ucs2name);
326
327         if (!NT_STATUS_IS_OK(ret)) { 
328                 return False;
329         }
330         
331         return True;
332 }
333
334
335
336 /* -------------------------------------------------------------------------- **
337  * Functions...
338  */
339
340 /* ************************************************************************** **
341  * Initialize the static character test array.
342  *
343  *  Input:  none
344  *
345  *  Output: none
346  *
347  *  Notes:  This function changes (loads) the contents of the <chartest>
348  *          array.  The scope of <chartest> is this file.
349  *
350  * ************************************************************************** **
351  */
352 static void init_chartest( void )
353 {
354         const char          *illegalchars = "*\\/?<>|\":";
355         const unsigned char *s;
356   
357         memset( (char *)chartest, '\0', 256 );
358
359         for( s = (const unsigned char *)illegalchars; *s; s++ )
360                 chartest[*s] = ILLEGAL_MASK;
361
362         for( s = (const unsigned char *)basechars; *s; s++ )
363                 chartest[*s] |= BASECHAR_MASK;
364
365         ct_initialized = True;
366 }
367
368 /* ************************************************************************** **
369  * Return True if the name *could be* a mangled name.
370  *
371  *  Input:  s - A path name - in UNIX pathname format.
372  *
373  *  Output: True if the name matches the pattern described below in the
374  *          notes, else False.
375  *
376  *  Notes:  The input name is *not* tested for 8.3 compliance.  This must be
377  *          done separately.  This function returns true if the name contains
378  *          a magic character followed by excactly two characters from the
379  *          basechars list (above), which in turn are followed either by the
380  *          nul (end of string) byte or a dot (extension) or by a '/' (end of
381  *          a directory name).
382  *
383  * ************************************************************************** **
384  */
385 static BOOL is_mangled(const char *s)
386 {
387         char *magic;
388
389         if( !ct_initialized )
390                 init_chartest();
391
392         magic = strchr_m( s, magic_char );
393         while( magic && magic[1] && magic[2] ) {         /* 3 chars, 1st is magic. */
394                 if( ('.' == magic[3] || '/' == magic[3] || !(magic[3]))          /* Ends with '.' or nul or '/' ?  */
395                                 && isbasechar( toupper(magic[1]) )           /* is 2nd char basechar?  */
396                                 && isbasechar( toupper(magic[2]) ) )         /* is 3rd char basechar?  */
397                         return( True );                           /* If all above, then true, */
398                 magic = strchr_m( magic+1, magic_char );      /*    else seek next magic. */
399         }
400         return( False );
401 }
402
403 /* ************************************************************************** **
404  * Compare two cache keys and return a value indicating their ordinal
405  * relationship.
406  *
407  *  Input:  ItemPtr - Pointer to a comparison key.  In this case, this will
408  *                    be a mangled name string.
409  *          NodePtr - Pointer to a node in the cache.  The node structure
410  *                    will be followed in memory by a mangled name string.
411  *
412  *  Output: A signed integer, as follows:
413  *            (x < 0)  <==> Key1 less than Key2
414  *            (x == 0) <==> Key1 equals Key2
415  *            (x > 0)  <==> Key1 greater than Key2
416  *
417  *  Notes:  This is a ubiqx-style comparison routine.  See ubi_BinTree for
418  *          more info.
419  *
420  * ************************************************************************** **
421  */
422 static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
423 {
424         char *Key1 = (char *)ItemPtr;
425         char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1);
426
427         return( StrCaseCmp( Key1, Key2 ) );
428 }
429
430 /* ************************************************************************** **
431  * Free a cache entry.
432  *
433  *  Input:  WarrenZevon - Pointer to the entry that is to be returned to
434  *                        Nirvana.
435  *  Output: none.
436  *
437  *  Notes:  This function gets around the possibility that the standard
438  *          free() function may be implemented as a macro, or other evil
439  *          subversions (oh, so much fun).
440  *
441  * ************************************************************************** **
442  */
443 static void cache_free_entry( ubi_trNodePtr WarrenZevon )
444 {
445         ZERO_STRUCTP(WarrenZevon);
446         SAFE_FREE( WarrenZevon );
447 }
448
449 /* ************************************************************************** **
450  * Initializes or clears the mangled cache.
451  *
452  *  Input:  none.
453  *  Output: none.
454  *
455  *  Notes:  There is a section below that is commented out.  It shows how
456  *          one might use lp_ calls to set the maximum memory and entry size
457  *          of the cache.  You might also want to remove the constants used
458  *          in ubi_cacheInit() and replace them with lp_ calls.  If so, then
459  *          the calls to ubi_cacheSetMax*() would be moved into the else
460  *          clause.  Another option would be to pass in the max_entries and
461  *          max_memory values as parameters.  crh 09-Apr-1998.
462  *
463  * ************************************************************************** **
464  */
465
466 static void mangle_reset( void )
467 {
468         if( !mc_initialized ) {
469                 (void)ubi_cacheInit( mangled_cache,
470                                 cache_compare,
471                                 cache_free_entry,
472                                 MANGLED_CACHE_MAX_ENTRIES,
473                                 MANGLED_CACHE_MAX_MEMORY );
474                 mc_initialized = True;
475         } else {
476                 (void)ubi_cacheClear( mangled_cache );
477         }
478
479         /*
480         (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() );
481         (void)ubi_cacheSetMaxMemory(  mangled_cache, lp_mangled_cache_memory() );
482         */
483 }
484
485 /* ************************************************************************** **
486  * Add a mangled name into the cache.
487  *
488  *  Notes:  If the mangled cache has not been initialized, then the
489  *          function will simply fail.  It could initialize the cache,
490  *          but that's not the way it was done before I changed the
491  *          cache mechanism, so I'm sticking with the old method.
492  *
493  *          If the extension of the raw name maps directly to the
494  *          extension of the mangled name, then we'll store both names
495  *          *without* extensions.  That way, we can provide consistent
496  *          reverse mangling for all names that match.  The test here is
497  *          a bit more careful than the one done in earlier versions of
498  *          mangle.c:
499  *
500  *            - the extension must exist on the raw name,
501  *            - it must be all lower case
502  *            - it must match the mangled extension (to prove that no
503  *              mangling occurred).
504  *
505  *  crh 07-Apr-1998
506  *
507  * ************************************************************************** **
508  */
509 static void cache_mangled_name( char *mangled_name, char *raw_name )
510 {
511         ubi_cacheEntryPtr new_entry;
512         char             *s1;
513         char             *s2;
514         size_t               mangled_len;
515         size_t               raw_len;
516         size_t               i;
517
518         /* If the cache isn't initialized, give up. */
519         if( !mc_initialized )
520                 return;
521
522         /* Init the string lengths. */
523         mangled_len = strlen( mangled_name );
524         raw_len     = strlen( raw_name );
525
526         /* See if the extensions are unmangled.  If so, store the entry
527          * without the extension, thus creating a "group" reverse map.
528          */
529         s1 = strrchr( mangled_name, '.' );
530         if( s1 && (s2 = strrchr( raw_name, '.' )) ) {
531                 i = 1;
532                 while( s1[i] && (tolower( s1[i] ) == s2[i]) )
533                         i++;
534                 if( !s1[i] && !s2[i] ) {
535                         mangled_len -= i;
536                         raw_len     -= i;
537                 }
538         }
539
540         /* Allocate a new cache entry.  If the allocation fails, just return. */
541         i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2;
542         new_entry = malloc( i );
543         if( !new_entry )
544                 return;
545
546         /* Fill the new cache entry, and add it to the cache. */
547         s1 = (char *)(new_entry + 1);
548         s2 = (char *)&(s1[mangled_len + 1]);
549         safe_strcpy( s1, mangled_name, mangled_len );
550         safe_strcpy( s2, raw_name,     raw_len );
551         ubi_cachePut( mangled_cache, i, new_entry, s1 );
552 }
553
554 /* ************************************************************************** **
555  * Check for a name on the mangled name stack
556  *
557  *  Input:  s - Input *and* output string buffer.
558  *
559  *  Output: True if the name was found in the cache, else False.
560  *
561  *  Notes:  If a reverse map is found, the function will overwrite the string
562  *          space indicated by the input pointer <s>.  This is frightening.
563  *          It should be rewritten to return NULL if the long name was not
564  *          found, and a pointer to the long name if it was found.
565  *
566  * ************************************************************************** **
567  */
568
569 static BOOL check_cache( char *s )
570 {
571         ubi_cacheEntryPtr FoundPtr;
572         char             *ext_start = NULL;
573         char             *found_name;
574         char             *saved_ext = NULL;
575
576         /* If the cache isn't initialized, give up. */
577         if( !mc_initialized )
578                 return( False );
579
580         FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
581
582         /* If we didn't find the name *with* the extension, try without. */
583         if( !FoundPtr ) {
584                 ext_start = strrchr( s, '.' );
585                 if( ext_start ) {
586                         if((saved_ext = strdup(ext_start)) == NULL)
587                                 return False;
588
589                         *ext_start = '\0';
590                         FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
591                         /* 
592                          * At this point s is the name without the
593                          * extension. We re-add the extension if saved_ext
594                          * is not null, before freeing saved_ext.
595                          */
596                 }
597         }
598
599         /* Okay, if we haven't found it we're done. */
600         if( !FoundPtr ) {
601                 if(saved_ext) {
602                         /* Replace the saved_ext as it was truncated. */
603                         (void)pstrcat( s, saved_ext );
604                         SAFE_FREE(saved_ext);
605                 }
606                 return( False );
607         }
608
609         /* If we *did* find it, we need to copy it into the string buffer. */
610         found_name = (char *)(FoundPtr + 1);
611         found_name += (strlen( found_name ) + 1);
612
613         (void)pstrcpy( s, found_name );
614         if( saved_ext ) {
615                 /* Replace the saved_ext as it was truncated. */
616                 (void)pstrcat( s, saved_ext );
617                 SAFE_FREE(saved_ext);
618         }
619
620         return( True );
621 }
622
623 /*****************************************************************************
624  * do the actual mangling to 8.3 format
625  * the buffer must be able to hold 13 characters (including the null)
626  *****************************************************************************
627  */
628 static void to_8_3(char *s, int default_case)
629 {
630         int csum;
631         char *p;
632         char extension[4];
633         char base[9];
634         int baselen = 0;
635         int extlen = 0;
636
637         extension[0] = 0;
638         base[0] = 0;
639
640         p = strrchr(s,'.');  
641         if( p && (strlen(p+1) < (size_t)4) ) {
642                 BOOL all_normal = ( strisnormal(p+1, default_case) ); /* XXXXXXXXX */
643
644                 if( all_normal && p[1] != 0 ) {
645                         *p = 0;
646                         csum = str_checksum( s );
647                         *p = '.';
648                 } else
649                         csum = str_checksum(s);
650         } else
651                 csum = str_checksum(s);
652
653         strupper_m( s );
654
655         if( p ) {
656                 if( p == s )
657                         safe_strcpy( extension, "___", 3 );
658                 else {
659                         *p++ = 0;
660                         while( *p && extlen < 3 ) {
661                                 if ( *p != '.') {
662                                         extension[extlen++] = p[0];
663                                 }
664                                 p++;
665                         }
666                         extension[extlen] = 0;
667                 }
668         }
669   
670         p = s;
671
672         while( *p && baselen < 5 ) {
673                 if (*p != '.') {
674                         base[baselen++] = p[0];
675                 }
676                 p++;
677         }
678         base[baselen] = 0;
679   
680         csum = csum % (MANGLE_BASE*MANGLE_BASE);
681   
682         (void)slprintf(s, 12, "%s%c%c%c",
683                 base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
684   
685         if( *extension ) {
686                 (void)pstrcat( s, "." );
687                 (void)pstrcat( s, extension );
688         }
689 }
690
691 /*****************************************************************************
692  * Convert a filename to DOS format.  Return True if successful.
693  *
694  *  Input:  OutName - Source *and* destination buffer. 
695  *
696  *                    NOTE that OutName must point to a memory space that
697  *                    is at least 13 bytes in size!
698  *
699  *          need83  - If False, name mangling will be skipped unless the
700  *                    name contains illegal characters.  Mapping will still
701  *                    be done, if appropriate.  This is probably used to
702  *                    signal that a client does not require name mangling,
703  *                    thus skipping the name mangling even on shares which
704  *                    have name-mangling turned on.
705  *          cache83 - If False, the mangled name cache will not be updated.
706  *                    This is usually used to prevent that we overwrite
707  *                    a conflicting cache entry prematurely, i.e. before
708  *                    we know whether the client is really interested in the
709  *                    current name.  (See PR#13758).  UKD.
710  *
711  *  Output: Returns False only if the name wanted mangling but the share does
712  *          not have name mangling turned on.
713  *
714  * ****************************************************************************
715  */
716
717 static void name_map(char *OutName, BOOL need83, BOOL cache83, int default_case)
718 {
719         smb_ucs2_t *OutName_ucs2;
720         DEBUG(5,("name_map( %s, need83 = %s, cache83 = %s)\n", OutName,
721                  need83 ? "True" : "False", cache83 ? "True" : "False"));
722         
723         if (push_ucs2_allocate(&OutName_ucs2, OutName) == (size_t)-1) {
724                 DEBUG(0, ("push_ucs2_allocate failed!\n"));
725                 return;
726         }
727
728         if( !need83 && !NT_STATUS_IS_OK(is_valid_name(OutName_ucs2, False, False)))
729                 need83 = True;
730
731         /* check if it's already in 8.3 format */
732         if (need83 && !NT_STATUS_IS_OK(is_8_3_w(OutName_ucs2, False))) {
733                 char *tmp = NULL; 
734
735                 /* mangle it into 8.3 */
736                 if (cache83)
737                         tmp = strdup(OutName);
738
739                 to_8_3(OutName, default_case);
740
741                 if(tmp != NULL) {
742                         cache_mangled_name(OutName, tmp);
743                         SAFE_FREE(tmp);
744                 }
745         }
746
747         DEBUG(5,("name_map() ==> [%s]\n", OutName));
748         SAFE_FREE(OutName_ucs2);
749 }
750
751 /*
752   the following provides the abstraction layer to make it easier
753   to drop in an alternative mangling implementation
754 */
755 static struct mangle_fns mangle_fns = {
756         is_mangled,
757         is_8_3,
758         mangle_reset,
759         check_cache,
760         name_map
761 };
762
763 /* return the methods for this mangling implementation */
764 struct mangle_fns *mangle_hash_init(void)
765 {
766         mangle_reset();
767
768         return &mangle_fns;
769 }