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