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