s3-param: Rename loadparm_s3_context -> loadparm_s3_helpers
[kai/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
337         if (!fname || !*fname)
338                 return False;
339         if ((f = strrchr(fname, '/')) == NULL)
340                 f = fname;
341         else
342                 f++;
343
344         if (strlen(f) > 12)
345                 return False;
346
347         if (!push_ucs2_talloc(NULL, &ucs2name, f, &size)) {
348                 DEBUG(0,("is_8_3: internal error push_ucs2_talloc() failed!\n"));
349                 goto done;
350         }
351
352         ret = is_8_3_w(ucs2name, allow_wildcards);
353
354 done:
355         TALLOC_FREE(ucs2name);
356
357         if (!NT_STATUS_IS_OK(ret)) {
358                 return False;
359         }
360
361         return True;
362 }
363
364 /* -------------------------------------------------------------------------- **
365  * Functions...
366  */
367
368 /* ************************************************************************** **
369  * Initialize the static character test array.
370  *
371  *  Input:  none
372  *
373  *  Output: none
374  *
375  *  Notes:  This function changes (loads) the contents of the <chartest>
376  *          array.  The scope of <chartest> is this file.
377  *
378  * ************************************************************************** **
379  */
380
381 static void init_chartest( void )
382 {
383         const unsigned char *s;
384
385         chartest = SMB_MALLOC_ARRAY(unsigned char, 256);
386
387         SMB_ASSERT(chartest != NULL);
388         memset(chartest, '\0', 256);
389
390         for( s = (const unsigned char *)basechars; *s; s++ ) {
391                 chartest[*s] |= BASECHAR_MASK;
392         }
393 }
394
395 /* ************************************************************************** **
396  * Return True if the name *could be* a mangled name.
397  *
398  *  Input:  s - A path name - in UNIX pathname format.
399  *
400  *  Output: True if the name matches the pattern described below in the
401  *          notes, else False.
402  *
403  *  Notes:  The input name is *not* tested for 8.3 compliance.  This must be
404  *          done separately.  This function returns true if the name contains
405  *          a magic character followed by excactly two characters from the
406  *          basechars list (above), which in turn are followed either by the
407  *          nul (end of string) byte or a dot (extension) or by a '/' (end of
408  *          a directory name).
409  *
410  * ************************************************************************** **
411  */
412
413 static bool is_mangled(const char *s, const struct share_params *p)
414 {
415         char *magic;
416         char magic_char;
417
418         magic_char = lp_magicchar(p);
419
420         if (chartest == NULL) {
421                 init_chartest();
422         }
423
424         magic = strchr_m( s, magic_char );
425         while( magic && magic[1] && magic[2] ) {         /* 3 chars, 1st is magic. */
426                 if( ('.' == magic[3] || '/' == magic[3] || !(magic[3]))          /* Ends with '.' or nul or '/' ?  */
427                                 && isbasechar( toupper_m(magic[1]) )           /* is 2nd char basechar?  */
428                                 && isbasechar( toupper_m(magic[2]) ) )         /* is 3rd char basechar?  */
429                         return( True );                           /* If all above, then true, */
430                 magic = strchr_m( magic+1, magic_char );      /*    else seek next magic. */
431         }
432         return( False );
433 }
434
435 /***************************************************************************
436  Initializes or clears the mangled cache.
437 ***************************************************************************/
438
439 static void mangle_reset( void )
440 {
441         /* We could close and re-open the tdb here... should we ? The old code did
442            the equivalent... JRA. */
443 }
444
445 /***************************************************************************
446  Add a mangled name into the cache.
447  If the extension of the raw name maps directly to the
448  extension of the mangled name, then we'll store both names
449  *without* extensions.  That way, we can provide consistent
450  reverse mangling for all names that match.  The test here is
451  a bit more careful than the one done in earlier versions of
452  mangle.c:
453
454     - the extension must exist on the raw name,
455     - it must be all lower case
456     - it must match the mangled extension (to prove that no
457       mangling occurred).
458   crh 07-Apr-1998
459 **************************************************************************/
460
461 static void cache_mangled_name( const char mangled_name[13],
462                                 const char *raw_name )
463 {
464         TDB_DATA data_val;
465         char mangled_name_key[13];
466         char *s1 = NULL;
467         char *s2 = NULL;
468
469         /* If the cache isn't initialized, give up. */
470         if( !tdb_mangled_cache )
471                 return;
472
473         /* Init the string lengths. */
474         strlcpy(mangled_name_key, mangled_name, sizeof(mangled_name_key));
475
476         /* See if the extensions are unmangled.  If so, store the entry
477          * without the extension, thus creating a "group" reverse map.
478          */
479         s1 = strrchr( mangled_name_key, '.' );
480         if( s1 && (s2 = strrchr( raw_name, '.' )) ) {
481                 size_t i = 1;
482                 while( s1[i] && (tolower_m( s1[i] ) == s2[i]) )
483                         i++;
484                 if( !s1[i] && !s2[i] ) {
485                         /* Truncate at the '.' */
486                         *s1 = '\0';
487                         /*
488                          * DANGER WILL ROBINSON - this
489                          * is changing a const string via
490                          * an aliased pointer ! Remember to
491                          * put it back once we've used it.
492                          * JRA
493                          */
494                         *s2 = '\0';
495                 }
496         }
497
498         /* Allocate a new cache entry.  If the allocation fails, just return. */
499         data_val = string_term_tdb_data(raw_name);
500         if (tdb_store_bystring(tdb_mangled_cache, mangled_name_key, data_val, TDB_REPLACE) != 0) {
501                 DEBUG(0,("cache_mangled_name: Error storing entry %s -> %s\n", mangled_name_key, raw_name));
502         } else {
503                 DEBUG(5,("cache_mangled_name: Stored entry %s -> %s\n", mangled_name_key, raw_name));
504         }
505         /* Restore the change we made to the const string. */
506         if (s2) {
507                 *s2 = '.';
508         }
509 }
510
511 /* ************************************************************************** **
512  * Check for a name on the mangled name stack
513  *
514  *  Input:  s - Input *and* output string buffer.
515  *          maxlen - space in i/o string buffer.
516  *  Output: True if the name was found in the cache, else False.
517  *
518  *  Notes:  If a reverse map is found, the function will overwrite the string
519  *          space indicated by the input pointer <s>.  This is frightening.
520  *          It should be rewritten to return NULL if the long name was not
521  *          found, and a pointer to the long name if it was found.
522  *
523  * ************************************************************************** **
524  */
525
526 static bool lookup_name_from_8_3(TALLOC_CTX *ctx,
527                                 const char *in,
528                                 char **out, /* talloced on the given context. */
529                                 const struct share_params *p)
530 {
531         TDB_DATA data_val;
532         char *saved_ext = NULL;
533         char *s = talloc_strdup(ctx, in);
534
535         /* If the cache isn't initialized, give up. */
536         if(!s || !tdb_mangled_cache ) {
537                 TALLOC_FREE(s);
538                 return False;
539         }
540
541         data_val = tdb_fetch_bystring(tdb_mangled_cache, s);
542
543         /* If we didn't find the name *with* the extension, try without. */
544         if(data_val.dptr == NULL || data_val.dsize == 0) {
545                 char *ext_start = strrchr( s, '.' );
546                 if( ext_start ) {
547                         if((saved_ext = talloc_strdup(ctx,ext_start)) == NULL) {
548                                 TALLOC_FREE(s);
549                                 return False;
550                         }
551
552                         *ext_start = '\0';
553                         data_val = tdb_fetch_bystring(tdb_mangled_cache, s);
554                         /*
555                          * At this point s is the name without the
556                          * extension. We re-add the extension if saved_ext
557                          * is not null, before freeing saved_ext.
558                          */
559                 }
560         }
561
562         /* Okay, if we haven't found it we're done. */
563         if(data_val.dptr == NULL || data_val.dsize == 0) {
564                 TALLOC_FREE(saved_ext);
565                 TALLOC_FREE(s);
566                 return False;
567         }
568
569         /* If we *did* find it, we need to talloc it on the given ctx. */
570         if (saved_ext) {
571                 *out = talloc_asprintf(ctx, "%s%s",
572                                         (char *)data_val.dptr,
573                                         saved_ext);
574         } else {
575                 *out = talloc_strdup(ctx, (char *)data_val.dptr);
576         }
577
578         TALLOC_FREE(s);
579         TALLOC_FREE(saved_ext);
580         SAFE_FREE(data_val.dptr);
581
582         return *out ? True : False;
583 }
584
585 /**
586  Check if a string is in "normal" case.
587 **/
588
589 static bool strisnormal(const char *s, int case_default)
590 {
591         if (case_default == CASE_UPPER)
592                 return(!strhaslower(s));
593
594         return(!strhasupper(s));
595 }
596
597
598 /*****************************************************************************
599  Do the actual mangling to 8.3 format.
600 *****************************************************************************/
601
602 static bool to_8_3(char magic_char, const char *in, char out[13], int default_case)
603 {
604         int csum;
605         char *p;
606         char extension[4];
607         char base[9];
608         int baselen = 0;
609         int extlen = 0;
610         char *s = SMB_STRDUP(in);
611
612         extension[0] = 0;
613         base[0] = 0;
614
615         if (!s) {
616                 return False;
617         }
618
619         p = strrchr(s,'.');
620         if( p && (strlen(p+1) < (size_t)4) ) {
621                 bool all_normal = ( strisnormal(p+1, default_case) ); /* XXXXXXXXX */
622
623                 if( all_normal && p[1] != 0 ) {
624                         *p = 0;
625                         csum = str_checksum( s );
626                         *p = '.';
627                 } else
628                         csum = str_checksum(s);
629         } else
630                 csum = str_checksum(s);
631
632         strupper_m( s );
633
634         if( p ) {
635                 if( p == s )
636                         strlcpy( extension, "___", 4);
637                 else {
638                         *p++ = 0;
639                         while( *p && extlen < 3 ) {
640                                 if ( *p != '.') {
641                                         extension[extlen++] = p[0];
642                                 }
643                                 p++;
644                         }
645                         extension[extlen] = 0;
646                 }
647         }
648
649         p = s;
650
651         while( *p && baselen < 5 ) {
652                 if (isbasechar(*p)) {
653                         base[baselen++] = p[0];
654                 }
655                 p++;
656         }
657         base[baselen] = 0;
658
659         csum = csum % (MANGLE_BASE*MANGLE_BASE);
660
661         memcpy(out, base, baselen);
662         out[baselen] = magic_char;
663         out[baselen+1] = mangle( csum/MANGLE_BASE );
664         out[baselen+2] = mangle( csum );
665
666         if( *extension ) {
667                 out[baselen+3] = '.';
668                 strlcpy(&out[baselen+4], extension, 4);
669         }
670
671         SAFE_FREE(s);
672         return True;
673 }
674
675 static bool must_mangle(const char *name,
676                         const struct share_params *p)
677 {
678         smb_ucs2_t *name_ucs2 = NULL;
679         NTSTATUS status;
680         size_t converted_size;
681
682         if (!push_ucs2_talloc(NULL, &name_ucs2, name, &converted_size)) {
683                 DEBUG(0, ("push_ucs2_talloc failed!\n"));
684                 return False;
685         }
686         status = is_valid_name(name_ucs2, False, False);
687         TALLOC_FREE(name_ucs2);
688         /* We return true if we *must* mangle, so if it's
689          * a valid name (status == OK) then we must return
690          * false. Bug #6939. */
691         return !NT_STATUS_IS_OK(status);
692 }
693
694 /*****************************************************************************
695  * Convert a filename to DOS format.  Return True if successful.
696  *  Input:  in        Incoming name.
697  *
698  *          out       8.3 DOS name.
699  *
700  *          cache83 - If False, the mangled name cache will not be updated.
701  *                    This is usually used to prevent that we overwrite
702  *                    a conflicting cache entry prematurely, i.e. before
703  *                    we know whether the client is really interested in the
704  *                    current name.  (See PR#13758).  UKD.
705  *
706  * ****************************************************************************
707  */
708
709 static bool hash_name_to_8_3(const char *in,
710                         char out[13],
711                         bool cache83,
712                         int default_case,
713                         const struct share_params *p)
714 {
715         smb_ucs2_t *in_ucs2 = NULL;
716         size_t converted_size;
717         char magic_char;
718
719         magic_char = lp_magicchar(p);
720
721         DEBUG(5,("hash_name_to_8_3( %s, cache83 = %s)\n", in,
722                  cache83 ? "True" : "False"));
723
724         if (!push_ucs2_talloc(NULL, &in_ucs2, in, &converted_size)) {
725                 DEBUG(0, ("push_ucs2_talloc failed!\n"));
726                 return False;
727         }
728
729         /* If it's already 8.3, just copy. */
730         if (NT_STATUS_IS_OK(is_valid_name(in_ucs2, False, False)) &&
731                                 NT_STATUS_IS_OK(is_8_3_w(in_ucs2, False))) {
732                 TALLOC_FREE(in_ucs2);
733                 strlcpy(out, in, 13);
734                 return True;
735         }
736
737         TALLOC_FREE(in_ucs2);
738         if (!to_8_3(magic_char, in, out, default_case)) {
739                 return False;
740         }
741
742         cache_mangled_name(out, in);
743
744         DEBUG(5,("hash_name_to_8_3(%s) ==> [%s]\n", in, out));
745         return True;
746 }
747
748 /*
749   the following provides the abstraction layer to make it easier
750   to drop in an alternative mangling implementation
751 */
752 static const struct mangle_fns mangle_hash_fns = {
753         mangle_reset,
754         is_mangled,
755         must_mangle,
756         is_8_3,
757         lookup_name_from_8_3,
758         hash_name_to_8_3
759 };
760
761 /* return the methods for this mangling implementation */
762 const struct mangle_fns *mangle_hash_init(void)
763 {
764         mangle_reset();
765
766         /* Create the in-memory tdb using our custom hash function. */
767         tdb_mangled_cache = tdb_open_ex("mangled_cache", 1031, TDB_INTERNAL,
768                                 (O_RDWR|O_CREAT), 0644, NULL, fast_string_hash);
769
770         return &mangle_hash_fns;
771 }