00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "includes.h"
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 char magic_char = '~';
00056
00057 static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
00058 #define MANGLE_BASE (sizeof(basechars)/sizeof(char)-1)
00059
00060 static unsigned char chartest[256] = { 0 };
00061 static BOOL ct_initialized = False;
00062
00063 #define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
00064 #define BASECHAR_MASK 0xf0
00065 #define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
00066
00067 static TDB_CONTEXT *tdb_mangled_cache;
00068
00069
00070
00071 static NTSTATUS has_valid_83_chars(const smb_ucs2_t *s, BOOL allow_wildcards)
00072 {
00073 if (!*s) {
00074 return NT_STATUS_INVALID_PARAMETER;
00075 }
00076
00077 if (!allow_wildcards && ms_has_wild_w(s)) {
00078 return NT_STATUS_UNSUCCESSFUL;
00079 }
00080
00081 while (*s) {
00082 if(!isvalid83_w(*s)) {
00083 return NT_STATUS_UNSUCCESSFUL;
00084 }
00085 s++;
00086 }
00087
00088 return NT_STATUS_OK;
00089 }
00090
00091 static NTSTATUS has_illegal_chars(const smb_ucs2_t *s, BOOL allow_wildcards)
00092 {
00093 if (!allow_wildcards && ms_has_wild_w(s)) {
00094 return NT_STATUS_UNSUCCESSFUL;
00095 }
00096
00097 while (*s) {
00098 if (*s <= 0x1f) {
00099
00100 return NT_STATUS_UNSUCCESSFUL;
00101 }
00102 switch(*s) {
00103 case UCS2_CHAR('\\'):
00104 case UCS2_CHAR('/'):
00105 case UCS2_CHAR('|'):
00106 case UCS2_CHAR(':'):
00107 return NT_STATUS_UNSUCCESSFUL;
00108 }
00109 s++;
00110 }
00111
00112 return NT_STATUS_OK;
00113 }
00114
00115
00116
00117
00118
00119 static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix,
00120 smb_ucs2_t **extension, BOOL allow_wildcards)
00121 {
00122 size_t ext_len;
00123 smb_ucs2_t *p;
00124
00125 *extension = 0;
00126 *prefix = strdup_w(ucs2_string);
00127 if (!*prefix) {
00128 return NT_STATUS_NO_MEMORY;
00129 }
00130 if ((p = strrchr_w(*prefix, UCS2_CHAR('.')))) {
00131 ext_len = strlen_w(p+1);
00132 if ((ext_len > 0) && (ext_len < 4) && (p != *prefix) &&
00133 (NT_STATUS_IS_OK(has_valid_83_chars(p+1,allow_wildcards)))) {
00134 *p = 0;
00135 *extension = strdup_w(p+1);
00136 if (!*extension) {
00137 SAFE_FREE(*prefix);
00138 return NT_STATUS_NO_MEMORY;
00139 }
00140 }
00141 }
00142 return NT_STATUS_OK;
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 static NTSTATUS is_valid_name(const smb_ucs2_t *fname, BOOL allow_wildcards, BOOL only_8_3)
00159 {
00160 smb_ucs2_t *str, *p;
00161 size_t num_ucs2_chars;
00162 NTSTATUS ret = NT_STATUS_OK;
00163
00164 if (!fname || !*fname)
00165 return NT_STATUS_INVALID_PARAMETER;
00166
00167
00168 if (strcmp_wa(fname, ".")==0 || strcmp_wa(fname, "..")==0)
00169 return NT_STATUS_OK;
00170
00171 if (only_8_3) {
00172 ret = has_valid_83_chars(fname, allow_wildcards);
00173 if (!NT_STATUS_IS_OK(ret))
00174 return ret;
00175 }
00176
00177 ret = has_illegal_chars(fname, allow_wildcards);
00178 if (!NT_STATUS_IS_OK(ret))
00179 return ret;
00180
00181
00182 num_ucs2_chars = strlen_w(fname);
00183 if (fname[num_ucs2_chars-1] == UCS2_CHAR('.') || fname[num_ucs2_chars-1] == UCS2_CHAR(' ')) {
00184 return NT_STATUS_UNSUCCESSFUL;
00185 }
00186
00187 str = strdup_w(fname);
00188
00189
00190 p = strchr_w(str, UCS2_CHAR('.'));
00191 if (p) {
00192 *p = 0;
00193 }
00194
00195 strupper_w(str);
00196 p = &str[1];
00197
00198 switch(str[0])
00199 {
00200 case UCS2_CHAR('A'):
00201 if(strcmp_wa(p, "UX") == 0)
00202 ret = NT_STATUS_UNSUCCESSFUL;
00203 break;
00204 case UCS2_CHAR('C'):
00205 if((strcmp_wa(p, "LOCK$") == 0)
00206 || (strcmp_wa(p, "ON") == 0)
00207 || (strcmp_wa(p, "OM1") == 0)
00208 || (strcmp_wa(p, "OM2") == 0)
00209 || (strcmp_wa(p, "OM3") == 0)
00210 || (strcmp_wa(p, "OM4") == 0)
00211 )
00212 ret = NT_STATUS_UNSUCCESSFUL;
00213 break;
00214 case UCS2_CHAR('L'):
00215 if((strcmp_wa(p, "PT1") == 0)
00216 || (strcmp_wa(p, "PT2") == 0)
00217 || (strcmp_wa(p, "PT3") == 0)
00218 )
00219 ret = NT_STATUS_UNSUCCESSFUL;
00220 break;
00221 case UCS2_CHAR('N'):
00222 if(strcmp_wa(p, "UL") == 0)
00223 ret = NT_STATUS_UNSUCCESSFUL;
00224 break;
00225 case UCS2_CHAR('P'):
00226 if(strcmp_wa(p, "RN") == 0)
00227 ret = NT_STATUS_UNSUCCESSFUL;
00228 break;
00229 default:
00230 break;
00231 }
00232
00233 SAFE_FREE(str);
00234 return ret;
00235 }
00236
00237 static NTSTATUS is_8_3_w(const smb_ucs2_t *fname, BOOL allow_wildcards)
00238 {
00239 smb_ucs2_t *pref = 0, *ext = 0;
00240 size_t plen;
00241 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
00242
00243 if (!fname || !*fname)
00244 return NT_STATUS_INVALID_PARAMETER;
00245
00246 if (strlen_w(fname) > 12)
00247 return NT_STATUS_UNSUCCESSFUL;
00248
00249 if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0)
00250 return NT_STATUS_OK;
00251
00252
00253 if (*fname == UCS2_CHAR('.'))
00254 return NT_STATUS_UNSUCCESSFUL;
00255
00256 if (!NT_STATUS_IS_OK(is_valid_name(fname, allow_wildcards, True)))
00257 goto done;
00258
00259 if (!NT_STATUS_IS_OK(mangle_get_prefix(fname, &pref, &ext, allow_wildcards)))
00260 goto done;
00261 plen = strlen_w(pref);
00262
00263 if (strchr_wa(pref, '.'))
00264 goto done;
00265 if (plen < 1 || plen > 8)
00266 goto done;
00267 if (ext && (strlen_w(ext) > 3))
00268 goto done;
00269
00270 ret = NT_STATUS_OK;
00271
00272 done:
00273 SAFE_FREE(pref);
00274 SAFE_FREE(ext);
00275 return ret;
00276 }
00277
00278 static BOOL is_8_3(const char *fname, BOOL check_case, BOOL allow_wildcards,
00279 const struct share_params *p)
00280 {
00281 const char *f;
00282 smb_ucs2_t *ucs2name;
00283 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
00284 size_t size;
00285
00286 magic_char = lp_magicchar(p);
00287
00288 if (!fname || !*fname)
00289 return False;
00290 if ((f = strrchr(fname, '/')) == NULL)
00291 f = fname;
00292 else
00293 f++;
00294
00295 if (strlen(f) > 12)
00296 return False;
00297
00298 size = push_ucs2_allocate(&ucs2name, f);
00299 if (size == (size_t)-1) {
00300 DEBUG(0,("is_8_3: internal error push_ucs2_allocate() failed!\n"));
00301 goto done;
00302 }
00303
00304 ret = is_8_3_w(ucs2name, allow_wildcards);
00305
00306 done:
00307 SAFE_FREE(ucs2name);
00308
00309 if (!NT_STATUS_IS_OK(ret)) {
00310 return False;
00311 }
00312
00313 return True;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 static void init_chartest( void )
00335 {
00336 const unsigned char *s;
00337
00338 memset( (char *)chartest, '\0', 256 );
00339
00340 for( s = (const unsigned char *)basechars; *s; s++ ) {
00341 chartest[*s] |= BASECHAR_MASK;
00342 }
00343
00344 ct_initialized = True;
00345 }
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 static BOOL is_mangled(const char *s, const struct share_params *p)
00365 {
00366 char *magic;
00367
00368 magic_char = lp_magicchar(p);
00369
00370 if( !ct_initialized )
00371 init_chartest();
00372
00373 magic = strchr_m( s, magic_char );
00374 while( magic && magic[1] && magic[2] ) {
00375 if( ('.' == magic[3] || '/' == magic[3] || !(magic[3]))
00376 && isbasechar( toupper_ascii(magic[1]) )
00377 && isbasechar( toupper_ascii(magic[2]) ) )
00378 return( True );
00379 magic = strchr_m( magic+1, magic_char );
00380 }
00381 return( False );
00382 }
00383
00384
00385
00386
00387
00388 static void mangle_reset( void )
00389 {
00390
00391
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410 static void cache_mangled_name( const char mangled_name[13], char *raw_name )
00411 {
00412 TDB_DATA data_val;
00413 char mangled_name_key[13];
00414 char *s1;
00415 char *s2;
00416
00417
00418 if( !tdb_mangled_cache )
00419 return;
00420
00421
00422 safe_strcpy(mangled_name_key, mangled_name, sizeof(mangled_name_key)-1);
00423
00424
00425
00426
00427 s1 = strrchr( mangled_name_key, '.' );
00428 if( s1 && (s2 = strrchr( raw_name, '.' )) ) {
00429 size_t i = 1;
00430 while( s1[i] && (tolower_ascii( s1[i] ) == s2[i]) )
00431 i++;
00432 if( !s1[i] && !s2[i] ) {
00433
00434 *s1 = '\0';
00435 *s2 = '\0';
00436 }
00437 }
00438
00439
00440 data_val.dptr = raw_name;
00441 data_val.dsize = strlen(raw_name)+1;
00442 if (tdb_store_bystring(tdb_mangled_cache, mangled_name_key, data_val, TDB_REPLACE) != 0) {
00443 DEBUG(0,("cache_mangled_name: Error storing entry %s -> %s\n", mangled_name_key, raw_name));
00444 } else {
00445 DEBUG(5,("cache_mangled_name: Stored entry %s -> %s\n", mangled_name_key, raw_name));
00446 }
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 static BOOL check_cache( char *s, size_t maxlen, const struct share_params *p )
00465 {
00466 TDB_DATA data_val;
00467 char *ext_start = NULL;
00468 char *saved_ext = NULL;
00469
00470 magic_char = lp_magicchar(p);
00471
00472
00473 if( !tdb_mangled_cache )
00474 return( False );
00475
00476 data_val = tdb_fetch_bystring(tdb_mangled_cache, s);
00477
00478
00479 if(data_val.dptr == NULL || data_val.dsize == 0) {
00480 ext_start = strrchr( s, '.' );
00481 if( ext_start ) {
00482 if((saved_ext = SMB_STRDUP(ext_start)) == NULL)
00483 return False;
00484
00485 *ext_start = '\0';
00486 data_val = tdb_fetch_bystring(tdb_mangled_cache, s);
00487
00488
00489
00490
00491
00492 }
00493 }
00494
00495
00496 if(data_val.dptr == NULL || data_val.dsize == 0) {
00497 if(saved_ext) {
00498
00499 (void)safe_strcat( s, saved_ext, maxlen );
00500 SAFE_FREE(saved_ext);
00501 }
00502 return( False );
00503 }
00504
00505
00506 (void)safe_strcpy( s, data_val.dptr, maxlen );
00507 if( saved_ext ) {
00508
00509 (void)safe_strcat( s, saved_ext, maxlen );
00510 SAFE_FREE(saved_ext);
00511 }
00512 SAFE_FREE(data_val.dptr);
00513 return( True );
00514 }
00515
00516
00517
00518
00519
00520
00521 static void to_8_3(char *s, int default_case)
00522 {
00523 int csum;
00524 char *p;
00525 char extension[4];
00526 char base[9];
00527 int baselen = 0;
00528 int extlen = 0;
00529
00530 extension[0] = 0;
00531 base[0] = 0;
00532
00533 p = strrchr(s,'.');
00534 if( p && (strlen(p+1) < (size_t)4) ) {
00535 BOOL all_normal = ( strisnormal(p+1, default_case) );
00536
00537 if( all_normal && p[1] != 0 ) {
00538 *p = 0;
00539 csum = str_checksum( s );
00540 *p = '.';
00541 } else
00542 csum = str_checksum(s);
00543 } else
00544 csum = str_checksum(s);
00545
00546 strupper_m( s );
00547
00548 if( p ) {
00549 if( p == s )
00550 safe_strcpy( extension, "___", 3 );
00551 else {
00552 *p++ = 0;
00553 while( *p && extlen < 3 ) {
00554 if ( *p != '.') {
00555 extension[extlen++] = p[0];
00556 }
00557 p++;
00558 }
00559 extension[extlen] = 0;
00560 }
00561 }
00562
00563 p = s;
00564
00565 while( *p && baselen < 5 ) {
00566 if (isbasechar(*p)) {
00567 base[baselen++] = p[0];
00568 }
00569 p++;
00570 }
00571 base[baselen] = 0;
00572
00573 csum = csum % (MANGLE_BASE*MANGLE_BASE);
00574
00575 (void)slprintf(s, 12, "%s%c%c%c",
00576 base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
00577
00578 if( *extension ) {
00579 (void)pstrcat( s, "." );
00580 (void)pstrcat( s, extension );
00581 }
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610 static void name_map(char *OutName, BOOL need83, BOOL cache83,
00611 int default_case, const struct share_params *p)
00612 {
00613 smb_ucs2_t *OutName_ucs2;
00614 magic_char = lp_magicchar(p);
00615
00616 DEBUG(5,("name_map( %s, need83 = %s, cache83 = %s)\n", OutName,
00617 need83 ? "True" : "False", cache83 ? "True" : "False"));
00618
00619 if (push_ucs2_allocate(&OutName_ucs2, OutName) == (size_t)-1) {
00620 DEBUG(0, ("push_ucs2_allocate failed!\n"));
00621 return;
00622 }
00623
00624 if( !need83 && !NT_STATUS_IS_OK(is_valid_name(OutName_ucs2, False, False)))
00625 need83 = True;
00626
00627
00628 if (need83 && !NT_STATUS_IS_OK(is_8_3_w(OutName_ucs2, False))) {
00629 char *tmp = NULL;
00630
00631
00632 if (cache83)
00633 tmp = SMB_STRDUP(OutName);
00634
00635 to_8_3(OutName, default_case);
00636
00637 if(tmp != NULL) {
00638 cache_mangled_name(OutName, tmp);
00639 SAFE_FREE(tmp);
00640 }
00641 }
00642
00643 DEBUG(5,("name_map() ==> [%s]\n", OutName));
00644 SAFE_FREE(OutName_ucs2);
00645 }
00646
00647
00648
00649
00650
00651 static struct mangle_fns mangle_fns = {
00652 mangle_reset,
00653 is_mangled,
00654 is_8_3,
00655 check_cache,
00656 name_map
00657 };
00658
00659
00660 struct mangle_fns *mangle_hash_init(void)
00661 {
00662 mangle_reset();
00663
00664
00665 tdb_mangled_cache = tdb_open_ex("mangled_cache", 1031, TDB_INTERNAL,
00666 (O_RDWR|O_CREAT), 0644, NULL, fast_string_hash);
00667
00668 return &mangle_fns;
00669 }