Merge commit 'release-4-0-0alpha15' into master4-tmp
[amitay/samba.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    Copyright (C) Jeremy Allison 2007
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "smbd/smbd.h"
26 #include "smbd/globals.h"
27 #include "mangle.h"
28 #include "util_tdb.h"
29
30 /* -------------------------------------------------------------------------- **
31  * Other stuff...
32  *
33  * magic_char     - This is the magic char used for mangling.  It's
34  *                  global.  There is a call to lp_magicchar() in server.c
35  *                  that is used to override the initial value.
36  *
37  * MANGLE_BASE    - This is the number of characters we use for name mangling.
38  *
39  * basechars      - The set characters used for name mangling.  This
40  *                  is static (scope is this file only).
41  *
42  * mangle()       - Macro used to select a character from basechars (i.e.,
43  *                  mangle(n) will return the nth digit, modulo MANGLE_BASE).
44  *
45  * chartest       - array 0..255.  The index range is the set of all possible
46  *                  values of a byte.  For each byte value, the content is a
47  *                  two nibble pair.  See BASECHAR_MASK below.
48  *
49  * ct_initialized - False until the chartest array has been initialized via
50  *                  a call to init_chartest().
51  *
52  * BASECHAR_MASK  - Masks the upper nibble of a one-byte value.
53  *
54  * isbasecahr()   - Given a character, check the chartest array to see
55  *                  if that character is in the basechars set.  This is
56  *                  faster than using strchr_m().
57  *
58  */
59
60 static const char basechars[43]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
61 #define MANGLE_BASE       (sizeof(basechars)/sizeof(char)-1)
62
63 #define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
64 #define BASECHAR_MASK 0xf0
65 #define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
66
67 /* -------------------------------------------------------------------- */
68
69
70 /*******************************************************************
71  Determine if a character is valid in a 8.3 name.
72 ********************************************************************/
73
74 /**
75  * Load the valid character map table from <tt>valid.dat</tt> or
76  * create from the configured codepage.
77  *
78  * This function is called whenever the configuration is reloaded.
79  * However, the valid character table is not changed if it's loaded
80  * from a file, because we can't unmap files.
81  **/
82
83 static uint8 *valid_table;
84 static void init_valid_table(void)
85 {
86         if (valid_table) {
87                 return;
88         }
89
90         valid_table = (uint8 *)map_file(data_path(talloc_tos(), "valid.dat"), 0x10000);
91         if (!valid_table) {
92                 smb_panic("Could not load valid.dat file required for mangle method=hash");
93                 return;
94         }
95 }
96
97 static bool isvalid83_w(smb_ucs2_t c)
98 {
99         init_valid_table();
100         return valid_table[SVAL(&c,0)] != 0;
101 }
102
103 static NTSTATUS has_valid_83_chars(const smb_ucs2_t *s, bool allow_wildcards)
104 {
105         if (!*s) {
106                 return NT_STATUS_INVALID_PARAMETER;
107         }
108
109         if (!allow_wildcards && ms_has_wild_w(s)) {
110                 return NT_STATUS_UNSUCCESSFUL;
111         }
112
113         while (*s) {
114                 if(!isvalid83_w(*s)) {
115                         return NT_STATUS_UNSUCCESSFUL;
116                 }
117                 s++;
118         }
119
120         return NT_STATUS_OK;
121 }
122
123 static NTSTATUS has_illegal_chars(const smb_ucs2_t *s, bool allow_wildcards)
124 {
125         if (!allow_wildcards && ms_has_wild_w(s)) {
126                 return NT_STATUS_UNSUCCESSFUL;
127         }
128
129         while (*s) {
130                 if (*s <= 0x1f) {
131                         /* Control characters. */
132                         return NT_STATUS_UNSUCCESSFUL;
133                 }
134                 switch(*s) {
135                         case UCS2_CHAR('\\'):
136                         case UCS2_CHAR('/'):
137                         case UCS2_CHAR('|'):
138                         case UCS2_CHAR(':'):
139                                 return NT_STATUS_UNSUCCESSFUL;
140                 }
141                 s++;
142         }
143
144         return NT_STATUS_OK;
145 }
146
147 /*******************************************************************
148  Duplicate string.
149 ********************************************************************/
150
151 static smb_ucs2_t *strdup_w(const smb_ucs2_t *src)
152 {
153         smb_ucs2_t *dest;
154         size_t len = strlen_w(src);
155         dest = SMB_MALLOC_ARRAY(smb_ucs2_t, len + 1);
156         if (!dest) {
157                 DEBUG(0,("strdup_w: out of memory!\n"));
158                 return NULL;
159         }
160
161         memcpy(dest, src, len * sizeof(smb_ucs2_t));
162         dest[len] = 0;
163         return dest;
164 }
165
166 /* return False if something fail and
167  * return 2 alloced unicode strings that contain prefix and extension
168  */
169
170 static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix,
171                 smb_ucs2_t **extension, bool allow_wildcards)
172 {
173         size_t ext_len;
174         smb_ucs2_t *p;
175
176         *extension = 0;
177         *prefix = strdup_w(ucs2_string);
178         if (!*prefix) {
179                 return NT_STATUS_NO_MEMORY;
180         }
181         if ((p = strrchr_w(*prefix, UCS2_CHAR('.')))) {
182                 ext_len = strlen_w(p+1);
183                 if ((ext_len > 0) && (ext_len < 4) && (p != *prefix) &&
184                     (NT_STATUS_IS_OK(has_valid_83_chars(p+1,allow_wildcards)))) /* check extension */ {
185                         *p = 0;
186                         *extension = strdup_w(p+1);
187                         if (!*extension) {
188                                 SAFE_FREE(*prefix);
189                                 return NT_STATUS_NO_MEMORY;
190                         }
191                 }
192         }
193         return NT_STATUS_OK;
194 }
195
196 /* ************************************************************************** **
197  * Return NT_STATUS_UNSUCCESSFUL if a name is a special msdos reserved name.
198  * or contains illegal characters.
199  *
200  *  Input:  fname - String containing the name to be tested.
201  *
202  *  Output: NT_STATUS_UNSUCCESSFUL, if the condition above is true.
203  *
204  *  Notes:  This is a static function called by is_8_3(), below.
205  *
206  * ************************************************************************** **
207  */
208
209 static NTSTATUS is_valid_name(const smb_ucs2_t *fname, bool allow_wildcards, bool only_8_3)
210 {
211         smb_ucs2_t *str, *p;
212         size_t num_ucs2_chars;
213         NTSTATUS ret = NT_STATUS_OK;
214
215         if (!fname || !*fname)
216                 return NT_STATUS_INVALID_PARAMETER;
217
218         /* . and .. are valid names. */
219         if (strcmp_wa(fname, ".")==0 || strcmp_wa(fname, "..")==0)
220                 return NT_STATUS_OK;
221
222         if (only_8_3) {
223                 ret = has_valid_83_chars(fname, allow_wildcards);
224                 if (!NT_STATUS_IS_OK(ret))
225                         return ret;
226         }
227
228         ret = has_illegal_chars(fname, allow_wildcards);
229         if (!NT_STATUS_IS_OK(ret))
230                 return ret;
231
232         /* Name can't end in '.' or ' ' */
233         num_ucs2_chars = strlen_w(fname);
234         if (fname[num_ucs2_chars-1] == UCS2_CHAR('.') || fname[num_ucs2_chars-1] == UCS2_CHAR(' ')) {
235                 return NT_STATUS_UNSUCCESSFUL;
236         }
237
238         str = strdup_w(fname);
239
240         /* Truncate copy after the first dot. */
241         p = strchr_w(str, UCS2_CHAR('.'));
242         if (p) {
243                 *p = 0;
244         }
245
246         strupper_w(str);
247         p = &str[1];
248
249         switch(str[0])
250         {
251         case UCS2_CHAR('A'):
252                 if(strcmp_wa(p, "UX") == 0)
253                         ret = NT_STATUS_UNSUCCESSFUL;
254                 break;
255         case UCS2_CHAR('C'):
256                 if((strcmp_wa(p, "LOCK$") == 0)
257                 || (strcmp_wa(p, "ON") == 0)
258                 || (strcmp_wa(p, "OM1") == 0)
259                 || (strcmp_wa(p, "OM2") == 0)
260                 || (strcmp_wa(p, "OM3") == 0)
261                 || (strcmp_wa(p, "OM4") == 0)
262                 )
263                         ret = NT_STATUS_UNSUCCESSFUL;
264                 break;
265         case UCS2_CHAR('L'):
266                 if((strcmp_wa(p, "PT1") == 0)
267                 || (strcmp_wa(p, "PT2") == 0)
268                 || (strcmp_wa(p, "PT3") == 0)
269                 )
270                         ret = NT_STATUS_UNSUCCESSFUL;
271                 break;
272         case UCS2_CHAR('N'):
273                 if(strcmp_wa(p, "UL") == 0)
274                         ret = NT_STATUS_UNSUCCESSFUL;
275                 break;
276         case UCS2_CHAR('P'):
277                 if(strcmp_wa(p, "RN") == 0)
278                         ret = NT_STATUS_UNSUCCESSFUL;
279                 break;
280         default:
281                 break;
282         }
283
284         SAFE_FREE(str);
285         return ret;
286 }
287
288 static NTSTATUS is_8_3_w(const smb_ucs2_t *fname, bool allow_wildcards)
289 {
290         smb_ucs2_t *pref = 0, *ext = 0;
291         size_t plen;
292         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
293
294         if (!fname || !*fname)
295                 return NT_STATUS_INVALID_PARAMETER;
296
297         if (strlen_w(fname) > 12)
298                 return NT_STATUS_UNSUCCESSFUL;
299
300         if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0)
301                 return NT_STATUS_OK;
302
303         /* Name cannot start with '.' */
304         if (*fname == UCS2_CHAR('.'))
305                 return NT_STATUS_UNSUCCESSFUL;
306
307         if (!NT_STATUS_IS_OK(is_valid_name(fname, allow_wildcards, True)))
308                 goto done;
309
310         if (!NT_STATUS_IS_OK(mangle_get_prefix(fname, &pref, &ext, allow_wildcards)))
311                 goto done;
312         plen = strlen_w(pref);
313
314         if (strchr_wa(pref, '.'))
315                 goto done;
316         if (plen < 1 || plen > 8)
317                 goto done;
318         if (ext && (strlen_w(ext) > 3))
319                 goto done;
320
321         ret = NT_STATUS_OK;
322
323 done:
324         SAFE_FREE(pref);
325         SAFE_FREE(ext);
326         return ret;
327 }
328
329 static bool is_8_3(const char *fname, bool check_case, bool allow_wildcards,
330                    const struct share_params *p)
331 {
332         const char *f;
333         smb_ucs2_t *ucs2name;
334         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
335         size_t size;
336         char magic_char;
337
338         magic_char = lp_magicchar(p);
339
340         if (!fname || !*fname)
341                 return False;
342         if ((f = strrchr(fname, '/')) == NULL)
343                 f = fname;
344         else
345                 f++;
346
347         if (strlen(f) > 12)
348                 return False;
349
350         if (!push_ucs2_talloc(NULL, &ucs2name, f, &size)) {
351                 DEBUG(0,("is_8_3: internal error push_ucs2_talloc() failed!\n"));
352                 goto done;
353         }
354
355         ret = is_8_3_w(ucs2name, allow_wildcards);
356
357 done:
358         TALLOC_FREE(ucs2name);
359
360         if (!NT_STATUS_IS_OK(ret)) {
361                 return False;
362         }
363
364         return True;
365 }
366
367 /* -------------------------------------------------------------------------- **
368  * Functions...
369  */
370
371 /* ************************************************************************** **
372  * Initialize the static character test array.
373  *
374  *  Input:  none
375  *
376  *  Output: none
377  *
378  *  Notes:  This function changes (loads) the contents of the <chartest>
379  *          array.  The scope of <chartest> is this file.
380  *
381  * ************************************************************************** **
382  */
383
384 static void init_chartest( void )
385 {
386         const unsigned char *s;
387
388         chartest = SMB_MALLOC_ARRAY(unsigned char, 256);
389
390         SMB_ASSERT(chartest != NULL);
391         memset(chartest, '\0', 256);
392
393         for( s = (const unsigned char *)basechars; *s; s++ ) {
394                 chartest[*s] |= BASECHAR_MASK;
395         }
396 }
397
398 /* ************************************************************************** **
399  * Return True if the name *could be* a mangled name.
400  *
401  *  Input:  s - A path name - in UNIX pathname format.
402  *
403  *  Output: True if the name matches the pattern described below in the
404  *          notes, else False.
405  *
406  *  Notes:  The input name is *not* tested for 8.3 compliance.  This must be
407  *          done separately.  This function returns true if the name contains
408  *          a magic character followed by excactly two characters from the
409  *          basechars list (above), which in turn are followed either by the
410  *          nul (end of string) byte or a dot (extension) or by a '/' (end of
411  *          a directory name).
412  *
413  * ************************************************************************** **
414  */
415
416 static bool is_mangled(const char *s, const struct share_params *p)
417 {
418         char *magic;
419         char magic_char;
420
421         magic_char = lp_magicchar(p);
422
423         if (chartest == NULL) {
424                 init_chartest();
425         }
426
427         magic = strchr_m( s, magic_char );
428         while( magic && magic[1] && magic[2] ) {         /* 3 chars, 1st is magic. */
429                 if( ('.' == magic[3] || '/' == magic[3] || !(magic[3]))          /* Ends with '.' or nul or '/' ?  */
430                                 && isbasechar( toupper_ascii(magic[1]) )           /* is 2nd char basechar?  */
431                                 && isbasechar( toupper_ascii(magic[2]) ) )         /* is 3rd char basechar?  */
432                         return( True );                           /* If all above, then true, */
433                 magic = strchr_m( magic+1, magic_char );      /*    else seek next magic. */
434         }
435         return( False );
436 }
437
438 /***************************************************************************
439  Initializes or clears the mangled cache.
440 ***************************************************************************/
441
442 static void mangle_reset( void )
443 {
444         /* We could close and re-open the tdb here... should we ? The old code did
445            the equivalent... JRA. */
446 }
447
448 /***************************************************************************
449  Add a mangled name into the cache.
450  If the extension of the raw name maps directly to the
451  extension of the mangled name, then we'll store both names
452  *without* extensions.  That way, we can provide consistent
453  reverse mangling for all names that match.  The test here is
454  a bit more careful than the one done in earlier versions of
455  mangle.c:
456
457     - the extension must exist on the raw name,
458     - it must be all lower case
459     - it must match the mangled extension (to prove that no
460       mangling occurred).
461   crh 07-Apr-1998
462 **************************************************************************/
463
464 static void cache_mangled_name( const char mangled_name[13],
465                                 const char *raw_name )
466 {
467         TDB_DATA data_val;
468         char mangled_name_key[13];
469         char *s1 = NULL;
470         char *s2 = NULL;
471
472         /* If the cache isn't initialized, give up. */
473         if( !tdb_mangled_cache )
474                 return;
475
476         /* Init the string lengths. */
477         strlcpy(mangled_name_key, mangled_name, sizeof(mangled_name_key));
478
479         /* See if the extensions are unmangled.  If so, store the entry
480          * without the extension, thus creating a "group" reverse map.
481          */
482         s1 = strrchr( mangled_name_key, '.' );
483         if( s1 && (s2 = strrchr( raw_name, '.' )) ) {
484                 size_t i = 1;
485                 while( s1[i] && (tolower_ascii( s1[i] ) == s2[i]) )
486                         i++;
487                 if( !s1[i] && !s2[i] ) {
488                         /* Truncate at the '.' */
489                         *s1 = '\0';
490                         /*
491                          * DANGER WILL ROBINSON - this
492                          * is changing a const string via
493                          * an aliased pointer ! Remember to
494                          * put it back once we've used it.
495                          * JRA
496                          */
497                         *s2 = '\0';
498                 }
499         }
500
501         /* Allocate a new cache entry.  If the allocation fails, just return. */
502         data_val = string_term_tdb_data(raw_name);
503         if (tdb_store_bystring(tdb_mangled_cache, mangled_name_key, data_val, TDB_REPLACE) != 0) {
504                 DEBUG(0,("cache_mangled_name: Error storing entry %s -> %s\n", mangled_name_key, raw_name));
505         } else {
506                 DEBUG(5,("cache_mangled_name: Stored entry %s -> %s\n", mangled_name_key, raw_name));
507         }
508         /* Restore the change we made to the const string. */
509         if (s2) {
510                 *s2 = '.';
511         }
512 }
513
514 /* ************************************************************************** **
515  * Check for a name on the mangled name stack
516  *
517  *  Input:  s - Input *and* output string buffer.
518  *          maxlen - space in i/o string buffer.
519  *  Output: True if the name was found in the cache, else False.
520  *
521  *  Notes:  If a reverse map is found, the function will overwrite the string
522  *          space indicated by the input pointer <s>.  This is frightening.
523  *          It should be rewritten to return NULL if the long name was not
524  *          found, and a pointer to the long name if it was found.
525  *
526  * ************************************************************************** **
527  */
528
529 static bool lookup_name_from_8_3(TALLOC_CTX *ctx,
530                                 const char *in,
531                                 char **out, /* talloced on the given context. */
532                                 const struct share_params *p)
533 {
534         TDB_DATA data_val;
535         char *saved_ext = NULL;
536         char *s = talloc_strdup(ctx, in);
537         char magic_char;
538
539         magic_char = lp_magicchar(p);
540
541         /* If the cache isn't initialized, give up. */
542         if(!s || !tdb_mangled_cache ) {
543                 TALLOC_FREE(s);
544                 return False;
545         }
546
547         data_val = tdb_fetch_bystring(tdb_mangled_cache, s);
548
549         /* If we didn't find the name *with* the extension, try without. */
550         if(data_val.dptr == NULL || data_val.dsize == 0) {
551                 char *ext_start = strrchr( s, '.' );
552                 if( ext_start ) {
553                         if((saved_ext = talloc_strdup(ctx,ext_start)) == NULL) {
554                                 TALLOC_FREE(s);
555                                 return False;
556                         }
557
558                         *ext_start = '\0';
559                         data_val = tdb_fetch_bystring(tdb_mangled_cache, s);
560                         /*
561                          * At this point s is the name without the
562                          * extension. We re-add the extension if saved_ext
563                          * is not null, before freeing saved_ext.
564                          */
565                 }
566         }
567
568         /* Okay, if we haven't found it we're done. */
569         if(data_val.dptr == NULL || data_val.dsize == 0) {
570                 TALLOC_FREE(saved_ext);
571                 TALLOC_FREE(s);
572                 return False;
573         }
574
575         /* If we *did* find it, we need to talloc it on the given ctx. */
576         if (saved_ext) {
577                 *out = talloc_asprintf(ctx, "%s%s",
578                                         (char *)data_val.dptr,
579                                         saved_ext);
580         } else {
581                 *out = talloc_strdup(ctx, (char *)data_val.dptr);
582         }
583
584         TALLOC_FREE(s);
585         TALLOC_FREE(saved_ext);
586         SAFE_FREE(data_val.dptr);
587
588         return *out ? True : False;
589 }
590
591 /**
592  Check if a string is in "normal" case.
593 **/
594
595 static bool strisnormal(const char *s, int case_default)
596 {
597         if (case_default == CASE_UPPER)
598                 return(!strhaslower(s));
599
600         return(!strhasupper(s));
601 }
602
603
604 /*****************************************************************************
605  Do the actual mangling to 8.3 format.
606 *****************************************************************************/
607
608 static bool to_8_3(char magic_char, const char *in, char out[13], int default_case)
609 {
610         int csum;
611         char *p;
612         char extension[4];
613         char base[9];
614         int baselen = 0;
615         int extlen = 0;
616         char *s = SMB_STRDUP(in);
617
618         extension[0] = 0;
619         base[0] = 0;
620
621         if (!s) {
622                 return False;
623         }
624
625         p = strrchr(s,'.');
626         if( p && (strlen(p+1) < (size_t)4) ) {
627                 bool all_normal = ( strisnormal(p+1, default_case) ); /* XXXXXXXXX */
628
629                 if( all_normal && p[1] != 0 ) {
630                         *p = 0;
631                         csum = str_checksum( s );
632                         *p = '.';
633                 } else
634                         csum = str_checksum(s);
635         } else
636                 csum = str_checksum(s);
637
638         strupper_m( s );
639
640         if( p ) {
641                 if( p == s )
642                         strlcpy( extension, "___", 4);
643                 else {
644                         *p++ = 0;
645                         while( *p && extlen < 3 ) {
646                                 if ( *p != '.') {
647                                         extension[extlen++] = p[0];
648                                 }
649                                 p++;
650                         }
651                         extension[extlen] = 0;
652                 }
653         }
654
655         p = s;
656
657         while( *p && baselen < 5 ) {
658                 if (isbasechar(*p)) {
659                         base[baselen++] = p[0];
660                 }
661                 p++;
662         }
663         base[baselen] = 0;
664
665         csum = csum % (MANGLE_BASE*MANGLE_BASE);
666
667         memcpy(out, base, baselen);
668         out[baselen] = magic_char;
669         out[baselen+1] = mangle( csum/MANGLE_BASE );
670         out[baselen+2] = mangle( csum );
671
672         if( *extension ) {
673                 out[baselen+3] = '.';
674                 strlcpy(&out[baselen+4], extension, 4);
675         }
676
677         SAFE_FREE(s);
678         return True;
679 }
680
681 static bool must_mangle(const char *name,
682                         const struct share_params *p)
683 {
684         smb_ucs2_t *name_ucs2 = NULL;
685         NTSTATUS status;
686         size_t converted_size;
687         char magic_char;
688
689         magic_char = lp_magicchar(p);
690
691         if (!push_ucs2_talloc(NULL, &name_ucs2, name, &converted_size)) {
692                 DEBUG(0, ("push_ucs2_talloc failed!\n"));
693                 return False;
694         }
695         status = is_valid_name(name_ucs2, False, False);
696         TALLOC_FREE(name_ucs2);
697         /* We return true if we *must* mangle, so if it's
698          * a valid name (status == OK) then we must return
699          * false. Bug #6939. */
700         return !NT_STATUS_IS_OK(status);
701 }
702
703 /*****************************************************************************
704  * Convert a filename to DOS format.  Return True if successful.
705  *  Input:  in        Incoming name.
706  *
707  *          out       8.3 DOS name.
708  *
709  *          cache83 - If False, the mangled name cache will not be updated.
710  *                    This is usually used to prevent that we overwrite
711  *                    a conflicting cache entry prematurely, i.e. before
712  *                    we know whether the client is really interested in the
713  *                    current name.  (See PR#13758).  UKD.
714  *
715  * ****************************************************************************
716  */
717
718 static bool hash_name_to_8_3(const char *in,
719                         char out[13],
720                         bool cache83,
721                         int default_case,
722                         const struct share_params *p)
723 {
724         smb_ucs2_t *in_ucs2 = NULL;
725         size_t converted_size;
726         char magic_char;
727
728         magic_char = lp_magicchar(p);
729
730         DEBUG(5,("hash_name_to_8_3( %s, cache83 = %s)\n", in,
731                  cache83 ? "True" : "False"));
732
733         if (!push_ucs2_talloc(NULL, &in_ucs2, in, &converted_size)) {
734                 DEBUG(0, ("push_ucs2_talloc failed!\n"));
735                 return False;
736         }
737
738         /* If it's already 8.3, just copy. */
739         if (NT_STATUS_IS_OK(is_valid_name(in_ucs2, False, False)) &&
740                                 NT_STATUS_IS_OK(is_8_3_w(in_ucs2, False))) {
741                 TALLOC_FREE(in_ucs2);
742                 strlcpy(out, in, 13);
743                 return True;
744         }
745
746         TALLOC_FREE(in_ucs2);
747         if (!to_8_3(magic_char, in, out, default_case)) {
748                 return False;
749         }
750
751         cache_mangled_name(out, in);
752
753         DEBUG(5,("hash_name_to_8_3(%s) ==> [%s]\n", in, out));
754         return True;
755 }
756
757 /*
758   the following provides the abstraction layer to make it easier
759   to drop in an alternative mangling implementation
760 */
761 static const struct mangle_fns mangle_hash_fns = {
762         mangle_reset,
763         is_mangled,
764         must_mangle,
765         is_8_3,
766         lookup_name_from_8_3,
767         hash_name_to_8_3
768 };
769
770 /* return the methods for this mangling implementation */
771 const struct mangle_fns *mangle_hash_init(void)
772 {
773         mangle_reset();
774
775         /* Create the in-memory tdb using our custom hash function. */
776 #ifndef BUILD_TDB2
777         tdb_mangled_cache = tdb_open_ex("mangled_cache", 1031, TDB_INTERNAL,
778                                 (O_RDWR|O_CREAT), 0644, NULL, fast_string_hash);
779 #else
780         /* FIXME: We should *never* open a tdb without logging! */
781         tdb_mangled_cache = tdb_open("mangled_cache", TDB_INTERNAL, 0, 0, NULL);
782 #endif
783
784         return &mangle_hash_fns;
785 }