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