Fixed compiler warnings.
[kai/samba.git] / source3 / smbd / mangle.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    Name mangling with persistent tdb
5    Copyright (C) Simo Sorce 2001
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /****************************************************************************
23   Rewritten from scrach in 2001 by Simo Sorce <idra@samba.org>
24  ****************************************************************************/
25
26 #include "includes.h"
27
28
29 /* -------------------------------------------------------------------------- **
30  * External Variables...
31  */
32
33 extern int case_default;    /* Are conforming 8.3 names all upper or lower?   */
34 extern BOOL case_mangle;    /* If true, all chars in 8.3 should be same case. */
35
36 char magic_char = '~';
37
38 /* -------------------------------------------------------------------- */
39
40 #define MANGLE_TDB_VERSION              "20010927"
41 #define MANGLE_TDB_FILE_NAME            "mangle.tdb"
42 #define MANGLED_PREFIX                  "MANGLED_"
43 #define LONG_PREFIX                     "LONG_"
44 #define COUNTER_PREFIX                  "COUNTER_"
45 #define MANGLE_COUNTER_MAX              99
46 #define MANGLE_SUFFIX_SIZE              3 /* "~XX" */
47
48
49 static TDB_CONTEXT      *mangle_tdb;
50
51 BOOL init_mangle_tdb(void)
52 {
53         char *tdbfile;
54         
55         tdbfile = lock_path(MANGLE_TDB_FILE_NAME); /* this return a static pstring do not try to free it */
56
57         /* Open tdb */
58         if (!(mangle_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600)))
59         {
60                 DEBUG(0, ("Unable to open Mangle TDB\n"));
61                 return False;
62         }
63
64         return True;
65 }
66
67 /* trasform a dos charset string in a terminated unicode string */
68 static int dos_to_ucs2(void *dest, const char *src, int dest_len)
69 {
70         int len=0;
71         int src_len = strlen(src) + 1;
72
73         /* treat a pstring as "unlimited" length */
74         if (dest_len == -1) {
75                 dest_len = sizeof(pstring);
76         }
77
78         /* ucs2 is always a multiple of 2 bytes */
79         dest_len &= ~1;
80
81         len = convert_string(CH_DOS, CH_UCS2, src, src_len, dest, dest_len);
82         return len;
83 }
84
85 /* trasform a unicode string into a dos charset string */
86 static int ucs2_to_dos(char *dest, const smb_ucs2_t *src, int dest_len)
87 {
88         int src_len, ret;
89
90         if (dest_len == -1) {
91                 dest_len = sizeof(pstring);
92         }
93
94         src_len = strlen_w(src)* sizeof(smb_ucs2_t);
95         
96         ret = convert_string(CH_UCS2, CH_DOS, src, src_len, dest, dest_len);
97         if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
98
99         return ret;
100 }
101
102 /* trasform in a string that contain only valid chars for win filenames */
103 static void strvalid(smb_ucs2_t *src)
104 {
105         if (!src || !*src) return;
106
107         while (*src) {
108                 if (!isvalid83_w(*src)) *src = UCS2_CHAR('_');
109                 src++;
110         }
111 }
112
113
114 /* return False if something fail and
115  * return 2 alloced unicode strings that contain prefix and extension
116  */
117 static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix, smb_ucs2_t **extension)
118 {
119         size_t ext_len;
120         smb_ucs2_t *p;
121
122         *extension = 0;
123         *prefix = strdup_w(ucs2_string);
124         if (!*prefix)
125         {
126                 DEBUG(0,("mangle_get_prefix: out of memory!\n"));
127                 return NT_STATUS_NO_MEMORY;
128         }
129         if ((p = strrchr_w(*prefix, UCS2_CHAR('.'))))
130         {
131                 p++;
132                 ext_len = strlen_w(p);
133                 if ((ext_len > 0) && (ext_len < 4)
134                         && (NT_STATUS_IS_OK(has_valid_chars(p)))) /* check extension */
135                 {
136                         *(p - 1) = 0;
137                         *extension = strdup_w(p);
138                         if (!*extension)
139                         {
140                                 DEBUG(0,("mangle_get_prefix: out of memory!\n"));
141                                 SAFE_FREE(*prefix);
142                                 return NT_STATUS_NO_MEMORY;
143                         }
144                 }
145         }
146         return NT_STATUS_OK;
147 }
148
149
150 /* mangled must contain only the file name, not a path.
151    and MUST be ZERO terminated */
152 smb_ucs2_t *unmangle(const smb_ucs2_t *mangled)
153 {
154         TDB_DATA data, key;
155         fstring keystr;
156         fstring mufname;
157         smb_ucs2_t *pref, *ext, *retstr;
158         size_t long_len, ext_len, muf_len;
159
160         if (strlen_w(mangled) > 12) return NULL;
161         if (!strchr_w(mangled, UCS2_CHAR('~'))) return NULL;
162
163         /* if it is a path refuse to proceed */
164         if (strchr_w(mangled, UCS2_CHAR('/'))) {
165                 DEBUG(10, ("unmangle: cannot unmangle a path\n"));
166                 return NULL;
167         }
168
169         if (NT_STATUS_IS_ERR(mangle_get_prefix(mangled, &pref, &ext)))
170                 return NULL;
171
172         /* mangled names are stored lowercase only */   
173         strlower_w(pref);
174         /* set search key */
175         muf_len = ucs2_to_dos(mufname, pref, sizeof(mufname));
176         SAFE_FREE(pref);
177         if (!muf_len) return NULL;
178         
179         slprintf(keystr, sizeof(keystr) - 1, "%s%s", MANGLED_PREFIX, mufname);
180         key.dptr = keystr;
181         key.dsize = strlen (keystr) + 1;
182         
183         /* get the record */
184         data = tdb_fetch(mangle_tdb, key);
185         
186         if (!data.dptr) /* not found */
187         {
188                 DEBUG(5,("unmangle: failed retrieve from db %s\n", tdb_errorstr(mangle_tdb)));
189                 retstr = NULL;
190                 goto done;
191         }
192
193         if (ext)
194         {
195                 long_len = (data.dsize / 2) - 1;
196                 ext_len = strlen_w(ext);
197                 retstr = (smb_ucs2_t *)malloc((long_len + ext_len + 2)*sizeof(smb_ucs2_t));
198                 if (!retstr)
199                 {
200                         DEBUG(0, ("unamngle: out of memory!\n"));
201                         goto done;
202                 }
203                 strncpy_w(retstr, (smb_ucs2_t *)data.dptr, long_len);
204                 retstr[long_len] = UCS2_CHAR('.');
205                 retstr[long_len + 1] = 0;
206                 strncat_w(retstr, ext, ext_len);
207         }
208         else
209         {
210                 retstr = strdup_w((smb_ucs2_t *)data.dptr);
211                 if (!retstr)
212                 {
213                         DEBUG(0, ("unamngle: out of memory!\n"));
214                         goto done;
215                 }
216
217         }
218
219 done:
220         SAFE_FREE(data.dptr);
221         SAFE_FREE(pref);
222         SAFE_FREE(ext);
223
224         return retstr;
225 }
226
227 /* unmangled must contain only the file name, not a path.
228    and MUST be ZERO terminated.
229    return a new allocated string if the name is yet valid 8.3
230    or is mangled successfully.
231    return null on error.
232  */
233
234 smb_ucs2_t *mangle(const smb_ucs2_t *unmangled)
235 {
236         TDB_DATA data, key, klock;
237         pstring keystr;
238         pstring longname;
239         fstring keylock;
240         fstring mufname;
241         fstring prefix;
242         BOOL tclock = False;
243         char suffix[7];
244         smb_ucs2_t *mangled = NULL;
245         smb_ucs2_t *umpref, *ext, *p = NULL;
246         size_t pref_len, ext_len, ud83_len;
247
248         /* if it is a path refuse to proceed */
249         if (strchr_w(unmangled, UCS2_CHAR('/'))) {
250                 DEBUG(10, ("mangle: cannot mangle a path\n"));
251                 return NULL;
252         }
253
254         /* if it is a valid 8_3 do not mangle again */
255         if (NT_STATUS_IS_OK(is_8_3_w(unmangled)))
256                 return strdup_w(unmangled);
257
258         if (NT_STATUS_IS_ERR(mangle_get_prefix(unmangled, &umpref, &ext)))
259                 return NULL;
260
261         /* test if the same is yet mangled */
262
263         /* set search key */
264         pull_ucs2(NULL, longname, umpref, sizeof(longname), 0, STR_TERMINATE);
265         slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
266         key.dptr = keystr;
267         key.dsize = strlen(keystr) + 1;
268
269         /* get the record */
270         data = tdb_fetch (mangle_tdb, key);
271         if (!data.dptr) /* not found */
272         {
273                 smb_ucs2_t temp[9];
274                 size_t c, pos;
275
276                 if (tdb_error(mangle_tdb) != TDB_ERR_NOEXIST)
277                 {
278                         DEBUG(0, ("mangle: database retrieval error: %s\n",
279                                         tdb_errorstr(mangle_tdb)));
280                         goto done;
281                 }
282
283                 /* if not find the first free possibile mangled name */
284
285                 pos = strlen_w(umpref);
286                 if ((8 - MANGLE_SUFFIX_SIZE) < pos)
287                         pos = 8 - MANGLE_SUFFIX_SIZE;
288                 pos++;
289                 do
290                 {
291                         pos--;
292                         if (pos == 0)
293                         {
294                                 DEBUG(0, ("mangle: unable to mangle file name!\n"));
295                                 goto done;
296                         }
297                         strncpy_w(temp, umpref, pos);
298                         temp[pos] = 0;
299                         strlower_w(temp);
300
301                         /* convert any invalid char into '_' */
302                         strvalid(temp);
303                         ud83_len = ucs2_to_dos(prefix, temp, sizeof(prefix));
304                         if (!ud83_len) goto done;
305                 }
306                 while (ud83_len > 8 - MANGLE_SUFFIX_SIZE);
307
308                 slprintf(keylock, sizeof(keylock)-1, "%s%s", COUNTER_PREFIX, prefix);
309                 klock.dptr = keylock;
310                 klock.dsize = strlen(keylock) + 1;
311
312                 c = 0;
313                 data.dptr = (char *)&c;
314                 data.dsize = sizeof(uint32);
315                 /* try to insert a new counter prefix, if it exist the call will
316                    fail (correct) otherwise it will create a new entry with counter set
317                    to 0
318                  */
319                 if(tdb_store(mangle_tdb, klock, data, TDB_INSERT) != TDB_SUCCESS)
320                 {
321                         if (tdb_error(mangle_tdb) != TDB_ERR_EXISTS)
322                         {
323                                 DEBUG(0, ("mangle: database store error: %s\n",
324                                         tdb_errorstr(mangle_tdb)));
325                                 goto done;
326                         }
327                 }
328
329                 /* lock the mangle counter for this prefix */           
330                 if (tdb_chainlock(mangle_tdb, klock))
331                 {
332                         DEBUG(0,("mangle: failed to lock database\n!"));
333                         goto done;
334                 }
335                 tclock = True;
336
337                 data = tdb_fetch(mangle_tdb, klock);
338                 if (!data.dptr)
339                 {
340                         DEBUG(0, ("mangle: database retrieval error: %s\n",
341                                         tdb_errorstr(mangle_tdb)));
342                         goto done;
343                 }
344                 c = *((uint32 *)data.dptr);
345                 c++;
346                 
347                 if (c > MANGLE_COUNTER_MAX)
348                 {
349                         DEBUG(0, ("mangle: error, counter overflow!\n"));
350                         goto done;
351                 }
352                         
353                 temp[pos] = UCS2_CHAR('~');
354                 temp[pos+1] = 0;
355                 snprintf(suffix, 7, "%.6d", c);
356                 strncat_wa(temp, &suffix[7 - MANGLE_SUFFIX_SIZE], MANGLE_SUFFIX_SIZE);
357
358                 ud83_len = ucs2_to_dos(mufname, temp, sizeof(mufname));
359                 if (!ud83_len) goto done;
360                 if (ud83_len > 8)
361                 {
362                         DEBUG(0, ("mangle: darn, logic error aborting!\n"));
363                         goto done;
364                 }
365                         
366                 /* store the long entry with mangled key */
367                 slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
368                 key.dptr = keystr;
369                 key.dsize = strlen (keystr) + 1;
370                 data.dsize = (strlen_w(umpref) + 1) * sizeof (smb_ucs2_t);
371                 data.dptr = (void *)umpref;
372
373                 if (tdb_store(mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
374                 {
375                         DEBUG(0, ("mangle: database store error: %s\n",
376                                         tdb_errorstr(mangle_tdb)));
377                         goto done;
378                 }
379
380                 /* store the mangled entry with long key*/
381                 pull_ucs2(NULL, longname, umpref, sizeof(longname), 0, STR_TERMINATE);
382                 slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
383                 key.dptr = keystr;
384                 key.dsize = strlen (keystr) + 1;
385                 data.dsize = strlen(mufname) + 1;
386                 data.dptr = mufname;
387                 if (tdb_store(mangle_tdb, key, data, TDB_INSERT) != TDB_SUCCESS)
388                 {
389                         DEBUG(0, ("mangle: database store failed: %s\n",
390                                         tdb_errorstr(mangle_tdb)));
391
392                         /* try to delete the mangled key entry to avoid later inconsistency */
393                         slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
394                         key.dptr = keystr;
395                         key.dsize = strlen (keystr) + 1;
396                         if (!tdb_delete(mangle_tdb, key))
397                         {
398                                 DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
399                         }
400                         goto done;
401                 }
402
403                 p = strdup_w(temp);
404                 if (!p)
405                 {
406                         DEBUG(0,("mangle: out of memory!\n"));
407                         goto done;
408                 }
409                 
410                 data.dptr = (char *)&c;
411                 data.dsize = sizeof(uint32);
412                 /* store the counter */
413                 if(tdb_store(mangle_tdb, klock, data, TDB_REPLACE) != TDB_SUCCESS)
414                 {
415                         DEBUG(0, ("mangle: database store failed: %s\n",
416                                         tdb_errorstr(mangle_tdb)));
417                         /* try to delete the mangled and long key entry to avoid later inconsistency */
418                         slprintf(keystr, sizeof(keystr)-1, "%s%s", MANGLED_PREFIX, mufname);
419                         key.dptr = keystr;
420                         key.dsize = strlen (keystr) + 1;
421                         if (!tdb_delete(mangle_tdb, key))
422                         {
423                                 DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
424                         }
425                         slprintf(keystr, sizeof(keystr)-1, "%s%s", LONG_PREFIX, longname);
426                         key.dptr = keystr;
427                         key.dsize = strlen (keystr) + 1;
428                         if (!tdb_delete(mangle_tdb, key))
429                         {
430                                 DEBUG(0, ("mangle: severe error, mangled tdb may be inconsistent!\n"));
431                         }
432                         goto done;
433                 }
434
435                 tclock = False;
436                 tdb_chainunlock(mangle_tdb, klock);
437         }
438         else /* FOUND */
439         {
440                 p = (smb_ucs2_t *)malloc(data.dsize*sizeof(smb_ucs2_t));
441                 if (!p)
442                 {
443                         DEBUG(0,("mangle: out of memory!\n"));
444                         goto done;
445                 }
446                 dos_to_ucs2(p, data.dptr, data.dsize*sizeof(smb_ucs2_t));
447         }
448                 
449         if (ext)
450         {
451                 pref_len = strlen_w(p);
452                 ext_len = strlen_w(ext);
453                 mangled = (smb_ucs2_t *)malloc((pref_len + ext_len + 2)*sizeof(smb_ucs2_t));
454                 if (!mangled)
455                 {
456                         DEBUG(0,("mangle: out of memory!\n"));
457                         goto done;
458                 }
459                 strncpy_w (mangled, p, pref_len);
460                 mangled[pref_len] = UCS2_CHAR('.');
461                 mangled[pref_len + 1] = 0;
462                 strncat_w (mangled, ext, ext_len);
463         }
464         else
465         {
466                 mangled = strdup_w(p);
467                 if (!mangled)
468                 {
469                         DEBUG(0,("mangle: out of memory!\n"));
470                         goto done;
471                 }
472         }
473
474         /* mangled name are returned in upper or lower case depending on
475            case_default value */
476         strnorm_w(mangled);
477
478 done:
479         if (tclock) tdb_chainunlock(mangle_tdb, klock);
480         SAFE_FREE(p);
481         SAFE_FREE(umpref);
482         SAFE_FREE(ext);
483
484         return mangled;
485 }
486
487
488 /* non unicode compatibility functions */
489
490 char *dos_mangle(const char *dos_unmangled)
491 {
492         smb_ucs2_t *in, *out;
493         char *dos_mangled;
494         size_t len;
495
496         if (!dos_unmangled || !*dos_unmangled) return NULL;
497
498         len = (strlen(dos_unmangled) + 1) * sizeof(smb_ucs2_t);
499         in = (smb_ucs2_t *)malloc(len);
500         if (!in)
501         {
502                 DEBUG(0,("dos_mangle: out of memory!\n"));
503                 return NULL;
504         }
505         dos_to_ucs2(in, dos_unmangled, len);
506
507         out = mangle(in);
508         if (!out)
509         {
510                 SAFE_FREE(in);
511                 return NULL;
512         }
513
514         dos_mangled = (char *)malloc(PSTRING_LEN);
515         if (!dos_mangled)
516         {
517                 DEBUG(0,("dos_mangle: out of memory!\n"));
518                 goto done;
519         }
520         ucs2_to_dos (dos_mangled, out, PSTRING_LEN);
521
522 done:
523         SAFE_FREE(in);
524         SAFE_FREE(out);
525         return dos_mangled;
526 }
527
528 char *dos_unmangle(const char *dos_mangled)
529 {
530         smb_ucs2_t *in, *out;
531         char *dos_unmangled;
532         size_t len;
533
534         if (!dos_mangled || !*dos_mangled) return NULL;
535
536         len = (strlen(dos_mangled) + 1) * sizeof(smb_ucs2_t);
537         in = (smb_ucs2_t *)malloc(len);
538         if (!in)
539         {
540                 DEBUG(0,("dos_unmangle: out of memory!\n"));
541                 return NULL;
542         }
543         dos_to_ucs2(in, dos_mangled, len);
544
545         out = mangle(in);
546         if (!out)
547         {
548                 SAFE_FREE(in);
549                 return NULL;
550         }
551
552         dos_unmangled = (char *)malloc(PSTRING_LEN);
553         if (!dos_unmangled)
554         {
555                 DEBUG(0,("dos_unmangle: out of memory!\n"));
556                 goto done;
557         }
558         ucs2_to_dos (dos_unmangled, out, PSTRING_LEN);
559
560 done:
561         SAFE_FREE(in);
562         SAFE_FREE(out);
563         return dos_unmangled;
564 }
565
566 BOOL is_8_3(const char *fname, BOOL check_case)
567 {
568         smb_ucs2_t *ucs2name;
569         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
570
571         if (!fname || !*fname) return False;
572
573         DEBUG(10,("is_8_3: testing [%s]\n", fname));
574
575         if (strlen(fname) > 12) return False;
576         
577         ucs2name = (smb_ucs2_t *)malloc(13 * sizeof(smb_ucs2_t));
578         if (!ucs2name)
579         {
580                 DEBUG(0,("is_8_3: out of memory!\n"));
581                 goto done;
582         }
583
584         push_ucs2(NULL, ucs2name, fname, 13, STR_TERMINATE);
585         ret = is_8_3_w(ucs2name);
586
587 done:
588         SAFE_FREE(ucs2name);
589
590         DEBUG(10,("is_8_3: returning -> %s\n", NT_STATUS_IS_OK(ret)?"True":"False"));
591
592         if (NT_STATUS_IS_ERR(ret)) return False;
593         else return True;
594 }
595
596 NTSTATUS is_8_3_w(const smb_ucs2_t *fname)
597 {
598         smb_ucs2_t *pref = 0, *ext = 0;
599         size_t plen;
600         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
601
602         if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER;
603
604         DEBUG(10,("is_8_3_w: testing\n")); /* [%s]\n", fname)); */
605
606         if (strlen_w(fname) > 12) return NT_STATUS_UNSUCCESSFUL;
607         
608         if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0)
609                 return NT_STATUS_OK;
610
611         if (NT_STATUS_IS_ERR(is_valid_name(fname))) goto done;
612
613         if (NT_STATUS_IS_ERR(mangle_get_prefix(fname, &pref, &ext))) goto done;
614         plen = strlen_w(pref);
615         if (plen < 1 || plen > 8) goto done;
616         if (ext) if (strlen_w(ext) > 3) goto done;
617
618         ret = NT_STATUS_OK;
619
620 done:
621         SAFE_FREE(pref);
622         SAFE_FREE(ext);
623         return ret;
624 }
625
626 NTSTATUS has_valid_chars(const smb_ucs2_t *s)
627 {
628         NTSTATUS ret = NT_STATUS_OK;
629
630         if (!s || !*s) return NT_STATUS_INVALID_PARAMETER;
631
632         DEBUG(10,("has_valid_chars: testing\n")); /* [%s]\n", s)); */
633         
634         /* CHECK: this should not be necessary if the ms wild chars
635            are not valid in valid.dat  --- simo */
636         if (ms_has_wild_w(s)) return NT_STATUS_UNSUCCESSFUL;
637
638         while (*s) {
639                 if(!isvalid83_w(*s)) return NT_STATUS_UNSUCCESSFUL;
640                 s++;
641         }
642
643         return ret;
644 }
645
646 NTSTATUS is_valid_name(const smb_ucs2_t *fname)
647 {
648         smb_ucs2_t *str, *p;
649         NTSTATUS ret = NT_STATUS_OK;
650
651         if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER;
652
653         DEBUG(10,("has_valid_chars: testing\n")); /* [%s]\n", s)); */
654         
655         ret = has_valid_chars(fname);
656         if (NT_STATUS_IS_ERR(ret)) return ret;
657
658         str = strdup_w(fname);
659         p = strchr_w(str, UCS2_CHAR('.'));
660         if (p) *p = 0;
661         strupper_w(str);
662         p = &(str[1]);
663
664         switch(str[0])
665         {
666         case UCS2_CHAR('A'):
667                 if(strcmp_wa(p, "UX") == 0)
668                         ret = NT_STATUS_UNSUCCESSFUL;
669                 break;
670         case UCS2_CHAR('C'):
671                 if((strcmp_wa(p, "LOCK$") == 0)
672                 || (strcmp_wa(p, "ON") == 0)
673                 || (strcmp_wa(p, "OM1") == 0)
674                 || (strcmp_wa(p, "OM2") == 0)
675                 || (strcmp_wa(p, "OM3") == 0)
676                 || (strcmp_wa(p, "OM4") == 0)
677                 )
678                         ret = NT_STATUS_UNSUCCESSFUL;
679                 break;
680         case UCS2_CHAR('L'):
681                 if((strcmp_wa(p, "PT1") == 0)
682                 || (strcmp_wa(p, "PT2") == 0)
683                 || (strcmp_wa(p, "PT3") == 0)
684                 )
685                         ret = NT_STATUS_UNSUCCESSFUL;
686                 break;
687         case UCS2_CHAR('N'):
688                 if(strcmp_wa(p, "UL") == 0)
689                         ret = NT_STATUS_UNSUCCESSFUL;
690                 break;
691         case UCS2_CHAR('P'):
692                 if(strcmp_wa(p, "RN") == 0)
693                         ret = NT_STATUS_UNSUCCESSFUL;
694                 break;
695         default:
696                 break;
697         }
698
699         SAFE_FREE(str);
700         return ret;
701 }
702
703 BOOL is_mangled(const char *s)
704 {
705         smb_ucs2_t *u2, *res;
706         size_t u2len;
707         BOOL ret = False;
708         
709         DEBUG(10,("is_mangled: testing [%s]\n", s));
710         
711         if (!s || !*s) return False;
712         if ((strlen(s) > 12) || (!strchr(s, '~'))) return False;
713         
714         u2len = (strlen(s) + 1) * sizeof(smb_ucs2_t);
715         u2 = (smb_ucs2_t *)malloc(u2len);
716         if (!u2)
717         {
718                 DEBUG(0,("is_mangled: out of memory!\n"));
719                 return ret;
720         }
721         dos_to_ucs2(u2, s, u2len);
722
723         res = unmangle(u2);
724         if (res) ret = True;
725         SAFE_FREE(res);
726         SAFE_FREE(u2);
727         DEBUG(10,("is_mangled: returning  [%s]\n", ret?"True":"False"));
728         return ret;
729 }
730
731 NTSTATUS is_mangled_w(const smb_ucs2_t *s)
732 {
733         smb_ucs2_t *res;
734         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
735         
736         res = unmangle(s);
737         if (res) ret = NT_STATUS_OK;
738         SAFE_FREE(res);
739         return ret;
740 }
741
742 NTSTATUS path_has_mangled(const smb_ucs2_t *s)
743 {
744         smb_ucs2_t *p, *f, *b;
745         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
746
747         if (!s || !*s) return NT_STATUS_INVALID_PARAMETER;
748
749         p = strdup_w(s);
750         if (!p) return NT_STATUS_NO_MEMORY;
751         trim_string_wa(p, "/", "/");
752         f = b = p;
753         while (b) {
754                 b = strchr_w(f, UCS2_CHAR('/'));
755                 if (b) *b = 0;
756                 if (NT_STATUS_IS_OK(is_mangled_w(f))) {
757                         ret = NT_STATUS_OK;
758                         goto done;
759                 }
760                 f = b + 1;
761         }
762 done:
763         SAFE_FREE(p);
764         return ret;
765 }
766
767 /* backward compatibility functions */
768
769 void reset_mangled_cache(void)
770 {
771         DEBUG(10,("reset_mangled_cache: compatibility function, remove me!\n"));
772 }
773
774 BOOL check_mangled_cache(char *s)
775 {
776         smb_ucs2_t *u2, *res;
777         size_t slen, u2len;
778         BOOL ret = False;
779
780         DEBUG(10,("check_mangled_cache: I'm so ugly, please remove me!\n"));
781         DEBUG(10,("check_mangled_cache: testing -> [%s]\n", s));
782
783         if (!s || !*s) return False;
784
785         slen = strlen(s);
786         u2len = (slen + 1) * sizeof(smb_ucs2_t);
787         u2 = (smb_ucs2_t *)malloc(u2len);
788         if (!u2)
789         {
790                 DEBUG(0,("check_mangled_cache: out of memory!\n"));
791                 return ret;
792         }
793         dos_to_ucs2(u2, s, u2len);
794
795         res = unmangle(u2);
796         if (res)
797         {
798                 
799                 ucs2_to_dos (s, res, PSTRING_LEN);
800                 /* We MUST change this brainded interface,
801                    we do not know how many chars will be used
802                    in dos so i guess they will be no more than
803                    double the size of the unicode string
804                           ---simo */
805                 DEBUG(10,("check_mangled_cache: returning -> [%s]\n", s));
806                 ret = True;
807         }
808         SAFE_FREE(res);
809         SAFE_FREE(u2);
810         DEBUG(10,("check_mangled_cache: returning -> %s\n", ret?"True":"False"));
811         return ret;
812 }
813
814 void mangle_name_83(char *s)
815 {
816         smb_ucs2_t *u2, *res;
817         size_t slen, u2len;
818
819         DEBUG(10,("mangle_name_83: I'm so ugly, please remove me!\n"));
820         DEBUG(10,("mangle_name_83: testing -> [%s]\n", s));
821
822         if (!s || !*s) return;
823         
824         slen = strlen(s);
825         u2len = (slen + 1) * sizeof(smb_ucs2_t);
826         u2 = (smb_ucs2_t *)malloc(u2len);
827         if (!u2)
828         {
829                 DEBUG(0,("mangle_name_83: out of memory!\n"));
830                 return;
831         }
832         dos_to_ucs2(u2, s, u2len);
833
834         res = mangle(u2);
835         if (res) ucs2_to_dos (s, res, 13); /* ugly, but must be done this way */
836         DEBUG(10,("mangle_name_83: returning -> [%s]\n", s));
837         SAFE_FREE(res);
838         SAFE_FREE(u2);
839 }
840
841 BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum)
842 {
843         DEBUG(10,("name_map_mangle: I'm so ugly, please remove me!\n"));
844
845         if (!need83) return True;
846         /* if (is_8_3(OutName, True)) return True; */
847         /* Warning: we should check for invalid chars in file name and mangle
848            if invalid chars found --simo*/
849
850         mangle_name_83(OutName);
851         return True;
852 }
853
854
855
856 #if 0 /* TEST_MANGLE_CODE */
857
858 #define LONG            "this_is_a_long_file_name"
859 #define LONGM           "this_~01"
860 #define SHORT           "short"
861 #define SHORTM          "short~01"
862 #define EXT1            "ex1"
863 #define EXT2            "e2"
864 #define EXT3            "3"
865 #define EXTFAIL         "longext"
866 #define EXTNULL         ""
867
868 static void unmangle_test (char *name, char *ext)
869 {
870         smb_ucs2_t ucs2_name[2048];
871         smb_ucs2_t *retstr;
872         pstring unix_name;      
873
874         push_ucs2(NULL, ucs2_name, name, sizeof(ucs2_name), STR_TERMINATE);
875         if (ext)
876         {
877                 strncat_wa(ucs2_name, ".", 1);
878                 strncat_wa(ucs2_name, ext, strlen(ext) + 1);
879         }
880         retstr = unmangle(ucs2_name);
881         if(retstr) pull_ucs2(NULL, unix_name, retstr, sizeof(unix_name), 0, STR_TERMINATE);
882         else unix_name[0] = 0;
883         if (ext) printf ("[%s.%s] ---> [%s]\n", name, ext, unix_name);
884         else printf ("[%s] ---> [%s]\n", name, unix_name);
885         SAFE_FREE(retstr);
886 }
887
888 static void mangle_test (char *name, char *ext)
889 {
890         smb_ucs2_t ucs2_name[2048];
891         smb_ucs2_t *retstr;
892         pstring unix_name;      
893
894         push_ucs2(NULL, ucs2_name, name, sizeof(ucs2_name), STR_TERMINATE);
895         if (ext)
896         {
897                 strncat_wa(ucs2_name, ".", 1);
898                 strncat_wa(ucs2_name, ext, strlen(ext) + 1);
899         }
900         retstr = mangle(ucs2_name);
901         if(retstr) pull_ucs2(NULL, unix_name, retstr, sizeof(unix_name), 0, STR_TERMINATE);
902         else unix_name[0] = 0;
903         if (ext) printf ("[%s.%s] ---> [%s]\n", name, ext, unix_name);
904         else printf ("[%s] ---> [%s]\n", name, unix_name);
905         SAFE_FREE(retstr);
906 }
907
908 void mangle_test_code(void)
909 {
910         init_mangle_tdb();
911
912         /* unmangle every */
913         printf("Unmangle test 1:\n");
914
915         unmangle_test (LONG, NULL);
916         unmangle_test (LONG, EXT1);
917         unmangle_test (LONG, EXT2);
918         unmangle_test (LONG, EXT3);
919         unmangle_test (LONG, EXTFAIL);
920         unmangle_test (LONG, EXTNULL);
921
922         unmangle_test (LONGM, NULL);
923         unmangle_test (LONGM, EXT1);
924         unmangle_test (LONGM, EXT2);
925         unmangle_test (LONGM, EXT3);
926         unmangle_test (LONGM, EXTFAIL);
927         unmangle_test (LONGM, EXTNULL);
928
929         unmangle_test (SHORT, NULL);
930         unmangle_test (SHORT, EXT1);
931         unmangle_test (SHORT, EXT2);
932         unmangle_test (SHORT, EXT3);
933         unmangle_test (SHORT, EXTFAIL);
934         unmangle_test (SHORT, EXTNULL);
935
936         unmangle_test (SHORTM, NULL);
937         unmangle_test (SHORTM, EXT1);
938         unmangle_test (SHORTM, EXT2);
939         unmangle_test (SHORTM, EXT3);
940         unmangle_test (SHORTM, EXTFAIL);
941         unmangle_test (SHORTM, EXTNULL);
942
943         /* mangle every */
944         printf("Mangle test\n");
945
946         mangle_test (LONG, NULL);
947         mangle_test (LONG, EXT1);
948         mangle_test (LONG, EXT2);
949         mangle_test (LONG, EXT3);
950         mangle_test (LONG, EXTFAIL);
951         mangle_test (LONG, EXTNULL);
952
953         mangle_test (LONGM, NULL);
954         mangle_test (LONGM, EXT1);
955         mangle_test (LONGM, EXT2);
956         mangle_test (LONGM, EXT3);
957         mangle_test (LONGM, EXTFAIL);
958         mangle_test (LONGM, EXTNULL);
959
960         mangle_test (SHORT, NULL);
961         mangle_test (SHORT, EXT1);
962         mangle_test (SHORT, EXT2);
963         mangle_test (SHORT, EXT3);
964         mangle_test (SHORT, EXTFAIL);
965         mangle_test (SHORT, EXTNULL);
966
967         mangle_test (SHORTM, NULL);
968         mangle_test (SHORTM, EXT1);
969         mangle_test (SHORTM, EXT2);
970         mangle_test (SHORTM, EXT3);
971         mangle_test (SHORTM, EXTFAIL);
972         mangle_test (SHORTM, EXTNULL);
973
974         /* unmangle again every */
975         printf("Unmangle test 2:\n");
976
977         unmangle_test (LONG, NULL);
978         unmangle_test (LONG, EXT1);
979         unmangle_test (LONG, EXT2);
980         unmangle_test (LONG, EXT3);
981         unmangle_test (LONG, EXTFAIL);
982         unmangle_test (LONG, EXTNULL);
983
984         unmangle_test (LONGM, NULL);
985         unmangle_test (LONGM, EXT1);
986         unmangle_test (LONGM, EXT2);
987         unmangle_test (LONGM, EXT3);
988         unmangle_test (LONGM, EXTFAIL);
989         unmangle_test (LONGM, EXTNULL);
990
991         unmangle_test (SHORT, NULL);
992         unmangle_test (SHORT, EXT1);
993         unmangle_test (SHORT, EXT2);
994         unmangle_test (SHORT, EXT3);
995         unmangle_test (SHORT, EXTFAIL);
996         unmangle_test (SHORT, EXTNULL);
997
998         unmangle_test (SHORTM, NULL);
999         unmangle_test (SHORTM, EXT1);
1000         unmangle_test (SHORTM, EXT2);
1001         unmangle_test (SHORTM, EXT3);
1002         unmangle_test (SHORTM, EXTFAIL);
1003         unmangle_test (SHORTM, EXTNULL);
1004 }
1005
1006 #endif /* TEST_MANGLE_CODE */