1/* 2 Unix SMB/Netbios implementation. 3 Version 1.9. 4 Name mangling 5 Copyright (C) Andrew Tridgell 1992-1998 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 * Notable problems... 24 * 25 * March/April 1998 CRH 26 * - Many of the functions in this module overwrite string buffers passed to 27 * them. This causes a variety of problems and is, generally speaking, 28 * dangerous and scarry. See the kludge notes in name_map_mangle() 29 * below. 30 * - It seems that something is calling name_map_mangle() twice. The 31 * first call is probably some sort of test. Names which contain 32 * illegal characters are being doubly mangled. I'm not sure, but 33 * I'm guessing the problem is in server.c. 34 * 35 * -------------------------------------------------------------------------- ** 36 */ 37 38/* -------------------------------------------------------------------------- ** 39 * History... 40 * 41 * March/April 1998 CRH 42 * Updated a bit. Rewrote is_mangled() to be a bit more selective. 43 * Rewrote the mangled name cache. Added comments here and there. 44 * &c. 45 * -------------------------------------------------------------------------- ** 46 */ 47 48#include "includes.h" 49 50 51/* -------------------------------------------------------------------------- ** 52 * External Variables... 53 */ 54 55extern int DEBUGLEVEL; /* Global debug level. */ 56extern int case_default; /* Are conforming 8.3 names all upper or lower? */ 57extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */ 58 59/* -------------------------------------------------------------------------- ** 60 * Other stuff... 61 * 62 * magic_char - This is the magic char used for mangling. It's 63 * global. There is a call to lp_magicchar() in server.c 64 * that is used to override the initial value. 65 * 66 * MANGLE_BASE - This is the number of characters we use for name mangling. 67 * 68 * basechars - The set characters used for name mangling. This 69 * is static (scope is this file only). 70 * 71 * mangle() - Macro used to select a character from basechars (i.e., 72 * mangle(n) will return the nth digit, modulo MANGLE_BASE). 73 * 74 * chartest - array 0..255. The index range is the set of all possible 75 * values of a byte. For each byte value, the content is a 76 * two nibble pair. See BASECHAR_MASK and ILLEGAL_MASK, 77 * below. 78 * 79 * ct_initialized - False until the chartest array has been initialized via 80 * a call to init_chartest(). 81 * 82 * BASECHAR_MASK - Masks the upper nibble of a one-byte value. 83 * 84 * ILLEGAL_MASK - Masks the lower nibble of a one-byte value. 85 * 86 * isbasecahr() - Given a character, check the chartest array to see 87 * if that character is in the basechars set. This is 88 * faster than using strchr(). 89 * 90 * isillegal() - Given a character, check the chartest array to see 91 * if that character is in the illegal characters set. 92 * This is faster than using strchr(). 93 * 94 * mangled_cache - Cache header used for storing mangled -> original 95 * reverse maps. 96 * 97 * mc_initialized - False until the mangled_cache structure has been 98 * initialized via a call to reset_mangled_cache(). 99 * 100 * MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the 101 * cache. A value of 0 indicates "infinite". 102 * 103 * MANGLED_CACHE_MAX_MEMORY - Default maximum amount of memory for the 104 * cache. When the cache was kept as an array of 256 105 * byte strings, the default cache size was 50 entries. 106 * This required a fixed 12.5Kbytes of memory. The 107 * mangled stack parameter is no longer used (though 108 * this might change). We're now using a fixed 16Kbyte 109 * maximum cache size. This will probably be much more 110 * than 50 entries. 111 */ 112 113char magic_char = '~'; 114 115static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%"; 116#define MANGLE_BASE (sizeof(basechars)/sizeof(char)-1) 117 118static unsigned char chartest[256] = { 0 }; 119static BOOL ct_initialized = False; 120 121#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE])) 122#define BASECHAR_MASK 0xf0 123#define ILLEGAL_MASK 0x0f 124#define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK ) 125#define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK ) 126 127static ubi_cacheRoot mangled_cache[1] = { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } }; 128static BOOL mc_initialized = False; 129#define MANGLED_CACHE_MAX_ENTRIES 0 130#define MANGLED_CACHE_MAX_MEMORY 16384 131 132 133/* -------------------------------------------------------------------------- ** 134 * Functions... 135 */ 136 137/* ************************************************************************** ** 138 * Initialize the static character test array. 139 * 140 * Input: none 141 * 142 * Output: none 143 * 144 * Notes: This function changes (loads) the contents of the <chartest> 145 * array. The scope of <chartest> is this file. 146 * 147 * ************************************************************************** ** 148 */ 149static void init_chartest( void ) 150 { 151 char *illegalchars = "*\\/?<>|\":"; 152 unsigned char *s; 153 154 memset( (char *)chartest, '\0', 256 ); 155 156 for( s = (unsigned char *)illegalchars; *s; s++ ) 157 chartest[*s] = ILLEGAL_MASK; 158 159 for( s = (unsigned char *)basechars; *s; s++ ) 160 chartest[*s] |= BASECHAR_MASK; 161 162 ct_initialized = True; 163 } /* init_chartest */ 164 165/* ************************************************************************** ** 166 * Return True if a name is a special msdos reserved name. 167 * 168 * Input: fname - String containing the name to be tested. 169 * 170 * Output: True, if the name matches one of the list of reserved names. 171 * 172 * Notes: This is a static function called by is_8_3(), below. 173 * 174 * ************************************************************************** ** 175 */ 176static BOOL is_reserved_msdos( char *fname ) 177 { 178 char upperFname[13]; 179 char *p; 180 181 StrnCpy (upperFname, fname, 12); 182 183 /* lpt1.txt and con.txt etc are also illegal */ 184 p = strchr(upperFname,'.'); 185 if( p ) 186 *p = '\0'; 187 188 strupper( upperFname ); 189 p = upperFname + 1; 190 switch( upperFname[0] ) 191 { 192 case 'A': 193 if( 0 == strcmp( p, "UX" ) ) 194 return( True ); 195 break; 196 case 'C': 197 if( (0 == strcmp( p, "LOCK$" )) 198 || (0 == strcmp( p, "ON" )) 199 || (0 == strcmp( p, "OM1" )) 200 || (0 == strcmp( p, "OM2" )) 201 || (0 == strcmp( p, "OM3" )) 202 || (0 == strcmp( p, "OM4" )) 203 ) 204 return( True ); 205 break; 206 case 'L': 207 if( (0 == strcmp( p, "PT1" )) 208 || (0 == strcmp( p, "PT2" )) 209 || (0 == strcmp( p, "PT3" )) 210 ) 211 return( True ); 212 break; 213 case 'N': 214 if( 0 == strcmp( p, "UL" ) ) 215 return( True ); 216 break; 217 case 'P': 218 if( 0 == strcmp( p, "RN" ) ) 219 return( True ); 220 break; 221 } 222 223 return( False ); 224 } /* is_reserved_msdos */ 225 226/* ************************************************************************** ** 227 * Determine whether or not a given name contains illegal characters, even 228 * long names. 229 * 230 * Input: name - The name to be tested. 231 * 232 * Output: True if an illegal character was found in <name>, else False. 233 * 234 * Notes: This is used to test a name on the host system, long or short, 235 * for characters that would be illegal on most client systems, 236 * particularly DOS and Windows systems. Unix and AmigaOS, for 237 * example, allow a filenames which contain such oddities as 238 * quotes ("). If a name is found which does contain an illegal 239 * character, it is mangled even if it conforms to the 8.3 240 * format. 241 * 242 * ************************************************************************** ** 243 */ 244static BOOL is_illegal_name( char *name ) 245 { 246 unsigned char *s; 247 int skip; 248 249 if( !name ) 250 return( True ); 251 252 if( !ct_initialized ) 253 init_chartest(); 254 255 s = (unsigned char *)name; 256 while( *s ) 257 { 258 skip = get_character_len( *s ); 259 if( skip != 0 ) 260 { 261 s += skip; 262 } 263 else 264 { 265 if( isillegal( *s ) ) 266 return( True ); 267 else 268 s++; 269 } 270 } 271 272 return( False ); 273 } /* is_illegal_name */ 274 275/* ************************************************************************** ** 276 * Return True if the name *could be* a mangled name. 277 * 278 * Input: s - A path name - in UNIX pathname format. 279 * 280 * Output: True if the name matches the pattern described below in the 281 * notes, else False. 282 * 283 * Notes: The input name is *not* tested for 8.3 compliance. This must be 284 * done separately. This function returns true if the name contains 285 * a magic character followed by excactly two characters from the 286 * basechars list (above), which in turn are followed either by the 287 * nul (end of string) byte or a dot (extension) or by a '/' (end of 288 * a directory name). 289 * 290 * ************************************************************************** ** 291 */ 292BOOL is_mangled( char *s ) 293 { 294 char *magic; 295 296 if( !ct_initialized ) 297 init_chartest(); 298 299 magic = strchr( s, magic_char ); 300 while( magic && magic[1] && magic[2] ) /* 3 chars, 1st is magic. */ 301 { 302 if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */ 303 && isbasechar( toupper(magic[1]) ) /* is 2nd char basechar? */ 304 && isbasechar( toupper(magic[2]) ) ) /* is 3rd char basechar? */ 305 return( True ); /* If all above, then true, */ 306 magic = strchr( magic+1, magic_char ); /* else seek next magic. */ 307 } 308 return( False ); 309 } /* is_mangled */ 310 311/* ************************************************************************** ** 312 * Return True if the name is a valid DOS name in 8.3 DOS format. 313 * 314 * Input: fname - File name to be checked. 315 * check_case - If True, and if case_mangle is True, then the 316 * name will be checked to see if all characters 317 * are the correct case. See case_mangle and 318 * case_default above. 319 * 320 * Output: True if the name is a valid DOS name, else FALSE. 321 * 322 * ************************************************************************** ** 323 */ 324BOOL is_8_3( char *fname, BOOL check_case ) 325 { 326 int len; 327 int l; 328 int skip; 329 char *p; 330 char *dot_pos; 331 char *slash_pos = strrchr( fname, '/' ); 332 333 /* If there is a directory path, skip it. */ 334 if( slash_pos ) 335 fname = slash_pos + 1; 336 len = strlen( fname ); 337 338 DEBUG( 5, ( "Checking %s for 8.3\n", fname ) ); 339 340 /* Can't be 0 chars or longer than 12 chars */ 341 if( (len == 0) || (len > 12) ) 342 return( False ); 343 344 /* Mustn't be an MS-DOS Special file such as lpt1 or even lpt1.txt */ 345 if( is_reserved_msdos( fname ) ) 346 return( False ); 347 348 /* Check that all characters are the correct case, if asked to do so. */ 349 if( check_case && case_mangle ) 350 { 351 switch( case_default ) 352 { 353 case CASE_LOWER: 354 if( strhasupper( fname ) ) 355 return(False); 356 break; 357 case CASE_UPPER: 358 if( strhaslower( fname ) ) 359 return(False); 360 break; 361 } 362 } 363 364 /* Can't contain invalid dos chars */ 365 /* Windows use the ANSI charset. 366 But filenames are translated in the PC charset. 367 This Translation may be more or less relaxed depending 368 the Windows application. */ 369 370 /* %%% A nice improvment to name mangling would be to translate 371 filename to ANSI charset on the smb server host */ 372 373 p = fname; 374 dot_pos = NULL; 375 while( *p ) 376 { 377 if( (skip = get_character_len( *p )) != 0 ) 378 p += skip; 379 else 380 { 381 if( *p == '.' && !dot_pos ) 382 dot_pos = (char *)p; 383 else 384 if( !isdoschar( *p ) ) 385 return( False ); 386 p++; 387 } 388 } 389 390 /* no dot and less than 9 means OK */ 391 if( !dot_pos ) 392 return( len <= 8 ); 393 394 l = PTR_DIFF( dot_pos, fname ); 395 396 /* base must be at least 1 char except special cases . and .. */ 397 if( l == 0 ) 398 return( 0 == strcmp( fname, "." ) || 0 == strcmp( fname, ".." ) ); 399 400 /* base can't be greater than 8 */ 401 if( l > 8 ) 402 return( False ); 403 404 /* see smb.conf(5) for a description of the 'strip dot' parameter. */ 405 if( lp_strip_dot() 406 && len - l == 1 407 && !strchr( dot_pos + 1, '.' ) ) 408 { 409 *dot_pos = 0; 410 return( True ); 411 } 412 413 /* extension must be between 1 and 3 */ 414 if( (len - l < 2 ) || (len - l > 4) ) 415 return( False ); 416 417 /* extensions may not have a dot */ 418 if( strchr( dot_pos+1, '.' ) ) 419 return( False ); 420 421 /* must be in 8.3 format */ 422 return( True ); 423 } /* is_8_3 */ 424 425 426/* ************************************************************************** ** 427 * Compare two cache keys and return a value indicating their ordinal 428 * relationship. 429 * 430 * Input: ItemPtr - Pointer to a comparison key. In this case, this will 431 * be a mangled name string. 432 * NodePtr - Pointer to a node in the cache. The node structure 433 * will be followed in memory by a mangled name string. 434 * 435 * Output: A signed integer, as follows: 436 * (x < 0) <==> Key1 less than Key2 437 * (x == 0) <==> Key1 equals Key2 438 * (x > 0) <==> Key1 greater than Key2 439 * 440 * Notes: This is a ubiqx-style comparison routine. See ubi_BinTree for 441 * more info. 442 * 443 * ************************************************************************** ** 444 */ 445static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr ) 446 { 447 char *Key1 = (char *)ItemPtr; 448 char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1); 449 450 return( StrCaseCmp( Key1, Key2 ) ); 451 } /* cache_compare */ 452 453/* ************************************************************************** ** 454 * Free a cache entry. 455 * 456 * Input: WarrenZevon - Pointer to the entry that is to be returned to 457 * Nirvana. 458 * Output: none. 459 * 460 * Notes: This function gets around the possibility that the standard 461 * free() function may be implemented as a macro, or other evil 462 * subversions (oh, so much fun). 463 * 464 * ************************************************************************** ** 465 */ 466static void cache_free_entry( ubi_trNodePtr WarrenZevon ) 467 { 468 ZERO_STRUCTP(WarrenZevon); 469 free( WarrenZevon ); 470 } /* cache_free_entry */ 471 472/* ************************************************************************** ** 473 * Initializes or clears the mangled cache. 474 * 475 * Input: none. 476 * Output: none. 477 * 478 * Notes: There is a section below that is commented out. It shows how 479 * one might use lp_ calls to set the maximum memory and entry size 480 * of the cache. You might also want to remove the constants used 481 * in ubi_cacheInit() and replace them with lp_ calls. If so, then 482 * the calls to ubi_cacheSetMax*() would be moved into the else 483 * clause. Another option would be to pass in the max_entries and 484 * max_memory values as parameters. crh 09-Apr-1998. 485 * 486 * ************************************************************************** ** 487 */ 488void reset_mangled_cache( void ) 489 { 490 if( !mc_initialized ) 491 { 492 (void)ubi_cacheInit( mangled_cache, 493 cache_compare, 494 cache_free_entry, 495 MANGLED_CACHE_MAX_ENTRIES, 496 MANGLED_CACHE_MAX_MEMORY ); 497 mc_initialized = True; 498 } 499 else 500 { 501 (void)ubi_cacheClear( mangled_cache ); 502 } 503 504 /* 505 (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() ); 506 (void)ubi_cacheSetMaxMemory( mangled_cache, lp_mangled_cache_memory() ); 507 */ 508 } /* reset_mangled_cache */ 509 510 511/* ************************************************************************** ** 512 * Add a mangled name into the cache. 513 * 514 * Notes: If the mangled cache has not been initialized, then the 515 * function will simply fail. It could initialize the cache, 516 * but that's not the way it was done before I changed the 517 * cache mechanism, so I'm sticking with the old method. 518 * 519 * If the extension of the raw name maps directly to the 520 * extension of the mangled name, then we'll store both names 521 * *without* extensions. That way, we can provide consistent 522 * reverse mangling for all names that match. The test here is 523 * a bit more careful than the one done in earlier versions of 524 * mangle.c: 525 * 526 * - the extension must exist on the raw name, 527 * - it must be all lower case 528 * - it must match the mangled extension (to prove that no 529 * mangling occurred). 530 * 531 * crh 07-Apr-1998 532 * 533 * ************************************************************************** ** 534 */ 535static void cache_mangled_name( char *mangled_name, char *raw_name ) 536 { 537 ubi_cacheEntryPtr new_entry; 538 char *s1; 539 char *s2; 540 size_t mangled_len; 541 size_t raw_len; 542 size_t i; 543 544 /* If the cache isn't initialized, give up. */ 545 if( !mc_initialized ) 546 return; 547 548 /* Init the string lengths. */ 549 mangled_len = strlen( mangled_name ); 550 raw_len = strlen( raw_name ); 551 552 /* See if the extensions are unmangled. If so, store the entry 553 * without the extension, thus creating a "group" reverse map. 554 */ 555 s1 = strrchr( mangled_name, '.' ); 556 if( s1 && (s2 = strrchr( raw_name, '.' )) ) 557 { 558 i = 1; 559 while( s1[i] && (tolower( s1[1] ) == s2[i]) ) 560 i++; 561 if( !s1[i] && !s2[i] ) 562 { 563 mangled_len -= i; 564 raw_len -= i; 565 } 566 } 567 568 /* Allocate a new cache entry. If the allocation fails, just return. */ 569 i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2; 570 new_entry = malloc( i ); 571 if( !new_entry ) 572 return; 573 574 /* Fill the new cache entry, and add it to the cache. */ 575 s1 = (char *)(new_entry + 1); 576 s2 = (char *)&(s1[mangled_len + 1]); 577 (void)StrnCpy( s1, mangled_name, mangled_len ); 578 (void)StrnCpy( s2, raw_name, raw_len ); 579 580 /* possibly delete an old entry - this avoids a memory leak in the 581 ubi code to do with overwriting existing entries. 582 583 remove this test when ubi gets fixed */ 584 if (ubi_cacheGet(mangled_cache, s1)) { 585 ubi_cacheDelete(mangled_cache, s1); 586 } 587 588 ubi_cachePut( mangled_cache, i, new_entry, s1 ); 589 } /* cache_mangled_name */ 590 591/* ************************************************************************** ** 592 * Check for a name on the mangled name stack 593 * 594 * Input: s - Input *and* output string buffer. 595 * 596 * Output: True if the name was found in the cache, else False. 597 * 598 * Notes: If a reverse map is found, the function will overwrite the string 599 * space indicated by the input pointer <s>. This is frightening. 600 * It should be rewritten to return NULL if the long name was not 601 * found, and a pointer to the long name if it was found. 602 * 603 * ************************************************************************** ** 604 */ 605 606BOOL check_mangled_cache( char *s ) 607{ 608 ubi_cacheEntryPtr FoundPtr; 609 char *ext_start = NULL; 610 char *found_name; 611 char *saved_ext = NULL; 612 613 /* If the cache isn't initialized, give up. */ 614 if( !mc_initialized ) 615 return( False ); 616 617 FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s ); 618 619 /* If we didn't find the name *with* the extension, try without. */ 620 if( !FoundPtr ) 621 { 622 ext_start = strrchr( s, '.' ); 623 if( ext_start ) 624 { 625 if((saved_ext = strdup(ext_start)) == NULL) 626 return False; 627 628 *ext_start = '\0'; 629 FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s ); 630 /* 631 * At this point s is the name without the 632 * extension. We re-add the extension if saved_ext 633 * is not null, before freeing saved_ext. 634 */ 635 } 636 } 637 638 /* Okay, if we haven't found it we're done. */ 639 if( !FoundPtr ) 640 { 641 if(saved_ext) 642 { 643 /* Replace the saved_ext as it was truncated. */ 644 (void)pstrcat( s, saved_ext ); 645 free(saved_ext); 646 } 647 return( False ); 648 } 649 650 /* If we *did* find it, we need to copy it into the string buffer. */ 651 found_name = (char *)(FoundPtr + 1); 652 found_name += (strlen( found_name ) + 1); 653 654 DEBUG( 3, ("Found %s on mangled stack ", s) ); 655 656 (void)pstrcpy( s, found_name ); 657 if( saved_ext ) 658 { 659 /* Replace the saved_ext as it was truncated. */ 660 (void)pstrcat( s, saved_ext ); 661 free(saved_ext); 662 } 663 664 DEBUG( 3, ("as %s\n", s) ); 665 666 return( True ); 667} /* check_mangled_cache */ 668 669 670/* ************************************************************************** ** 671 * Used only in do_fwd_mangled_map(), below. 672 * ************************************************************************** ** 673 */ 674static char *map_filename( char *s, /* This is null terminated */ 675 char *pattern, /* This isn't. */ 676 int len ) /* This is the length of pattern. */ 677 { 678 static pstring matching_bit; /* The bit of the string which matches */ 679 /* a * in pattern if indeed there is a * */ 680 char *sp; /* Pointer into s. */ 681 char *pp; /* Pointer into p. */ 682 char *match_start; /* Where the matching bit starts. */ 683 pstring pat; 684 685 StrnCpy( pat, pattern, len ); /* Get pattern into a proper string! */ 686 pstrcpy( matching_bit, "" ); /* Match but no star gets this. */ 687 pp = pat; /* Initialize the pointers. */ 688 sp = s; 689 690 if( strequal(s, ".") || strequal(s, "..")) 691 { 692 return NULL; /* Do not map '.' and '..' */ 693 } 694 695 if( (len == 1) && (*pattern == '*') ) 696 { 697 return NULL; /* Impossible, too ambiguous for */ 698 } /* words! */ 699 700 while( (*sp) /* Not the end of the string. */ 701 && (*pp) /* Not the end of the pattern. */ 702 && (*sp == *pp) /* The two match. */ 703 && (*pp != '*') ) /* No wildcard. */ 704 { 705 sp++; /* Keep looking. */ 706 pp++; 707 } 708 709 if( !*sp && !*pp ) /* End of pattern. */ 710 return( matching_bit ); /* Simple match. Return empty string. */ 711 712 if( *pp == '*' ) 713 { 714 pp++; /* Always interrested in the chacter */ 715 /* after the '*' */ 716 if( !*pp ) /* It is at the end of the pattern. */ 717 { 718 StrnCpy( matching_bit, s, sp-s ); 719 return( matching_bit ); 720 } 721 else 722 { 723 /* The next character in pattern must match a character further */ 724 /* along s than sp so look for that character. */ 725 match_start = sp; 726 while( (*sp) /* Not the end of s. */ 727 && (*sp != *pp) ) /* Not the same */ 728 sp++; /* Keep looking. */ 729 if( !*sp ) /* Got to the end without a match. */ 730 { 731 return( NULL ); 732 } /* Still hope for a match. */ 733 else 734 { 735 /* Now sp should point to a matching character. */ 736 StrnCpy(matching_bit, match_start, sp-match_start); 737 /* Back to needing a stright match again. */ 738 while( (*sp) /* Not the end of the string. */ 739 && (*pp) /* Not the end of the pattern. */ 740 && (*sp == *pp) ) /* The two match. */ 741 { 742 sp++; /* Keep looking. */ 743 pp++; 744 } 745 if( !*sp && !*pp ) /* Both at end so it matched */ 746 return( matching_bit ); 747 else 748 return( NULL ); 749 } 750 } 751 } 752 return( NULL ); /* No match. */ 753 } /* map_filename */ 754 755 756/* ************************************************************************** ** 757 * MangledMap is a series of name pairs in () separated by spaces. 758 * If s matches the first of the pair then the name given is the 759 * second of the pair. A * means any number of any character and if 760 * present in the second of the pair as well as the first the 761 * matching part of the first string takes the place of the * in the 762 * second. 763 * 764 * I wanted this so that we could have RCS files which can be used 765 * by UNIX and DOS programs. My mapping string is (RCS rcs) which 766 * converts the UNIX RCS file subdirectory to lowercase thus 767 * preventing mangling. 768 * 769 * (I think Andrew wrote the above, but I'm not sure. -- CRH) 770 * 771 * See 'mangled map' in smb.conf(5). 772 * 773 * ************************************************************************** ** 774 */ 775static void do_fwd_mangled_map(char *s, char *MangledMap) 776 { 777 char *start=MangledMap; /* Use this to search for mappings. */ 778 char *end; /* Used to find the end of strings. */ 779 char *match_string; 780 pstring new_string; /* Make up the result here. */ 781 char *np; /* Points into new_string. */ 782 783 DEBUG( 5, ("Mangled Mapping '%s' map '%s'\n", s, MangledMap) ); 784 while( *start ) 785 { 786 while( (*start) && (*start != '(') ) 787 start++; 788 if( !*start ) 789 continue; /* Always check for the end. */ 790 start++; /* Skip the ( */ 791 end = start; /* Search for the ' ' or a ')' */ 792 DEBUG( 5, ("Start of first in pair '%s'\n", start) ); 793 while( (*end) && !((*end == ' ') || (*end == ')')) ) 794 end++; 795 if( !*end ) 796 { 797 start = end; 798 continue; /* Always check for the end. */ 799 } 800 DEBUG( 5, ("End of first in pair '%s'\n", end) ); 801 if( (match_string = map_filename( s, start, end-start )) ) 802 { 803 DEBUG( 5, ("Found a match\n") ); 804 /* Found a match. */ 805 start = end + 1; /* Point to start of what it is to become. */ 806 DEBUG( 5, ("Start of second in pair '%s'\n", start) ); 807 end = start; 808 np = new_string; 809 while( (*end) /* Not the end of string. */ 810 && (*end != ')') /* Not the end of the pattern. */ 811 && (*end != '*') ) /* Not a wildcard. */ 812 *np++ = *end++; 813 if( !*end ) 814 { 815 start = end; 816 continue; /* Always check for the end. */ 817 } 818 if( *end == '*' ) 819 { 820 pstrcpy( np, match_string ); 821 np += strlen( match_string ); 822 end++; /* Skip the '*' */ 823 while( (*end) /* Not the end of string. */ 824 && (*end != ')') /* Not the end of the pattern. */ 825 && (*end != '*') ) /* Not a wildcard. */ 826 *np++ = *end++; 827 } 828 if( !*end ) 829 { 830 start = end; 831 continue; /* Always check for the end. */ 832 } 833 *np++ = '\0'; /* NULL terminate it. */ 834 DEBUG(5,("End of second in pair '%s'\n", end)); 835 pstrcpy( s, new_string ); /* Substitute with the new name. */ 836 DEBUG( 5, ("s is now '%s'\n", s) ); 837 } 838 start = end; /* Skip a bit which cannot be wanted anymore. */ 839 start++; 840 } 841 } /* do_fwd_mangled_map */ 842 843/***************************************************************************** 844 * do the actual mangling to 8.3 format 845 * the buffer must be able to hold 13 characters (including the null) 846 ***************************************************************************** 847 */ 848void mangle_name_83( char *s) 849 { 850 int csum; 851 char *p; 852 char extension[4]; 853 char base[9]; 854 int baselen = 0; 855 int extlen = 0; 856 int skip; 857 858 extension[0] = 0; 859 base[0] = 0; 860 861 p = strrchr(s,'.'); 862 if( p && (strlen(p+1) < (size_t)4) ) 863 { 864 BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */ 865 866 if( all_normal && p[1] != 0 ) 867 { 868 *p = 0; 869 csum = str_checksum( s ); 870 *p = '.'; 871 } 872 else 873 csum = str_checksum(s); 874 } 875 else 876 csum = str_checksum(s); 877 878 strupper( s ); 879 880 DEBUG( 5, ("Mangling name %s to ",s) ); 881 882 if( p ) 883 { 884 if( p == s ) 885 safe_strcpy( extension, "___", 3 ); 886 else 887 { 888 *p++ = 0; 889 while( *p && extlen < 3 ) 890 { 891 skip = get_character_len( *p ); 892 switch( skip ) 893 { 894 case 2: 895 if( extlen < 2 ) 896 { 897 extension[extlen++] = p[0]; 898 extension[extlen++] = p[1]; 899 } 900 else 901 { 902 extension[extlen++] = mangle( (unsigned char)*p ); 903 } 904 p += 2; 905 break; 906 case 1: 907 extension[extlen++] = p[0]; 908 p++; 909 break; 910 default: 911 if( isdoschar (*p) && *p != '.' ) 912 extension[extlen++] = p[0]; 913 p++; 914 break; 915 } 916 } 917 extension[extlen] = 0; 918 } 919 } 920 921 p = s; 922 923 while( *p && baselen < 5 ) 924 { 925 skip = get_character_len(*p); 926 switch( skip ) 927 { 928 case 2: 929 if( baselen < 4 ) 930 { 931 base[baselen++] = p[0]; 932 base[baselen++] = p[1]; 933 } 934 else 935 { 936 base[baselen++] = mangle( (unsigned char)*p ); 937 } 938 p += 2; 939 break; 940 case 1: 941 base[baselen++] = p[0]; 942 p++; 943 break; 944 default: 945 if( isdoschar( *p ) && *p != '.' ) 946 base[baselen++] = p[0]; 947 p++; 948 break; 949 } 950 } 951 base[baselen] = 0; 952 953 csum = csum % (MANGLE_BASE*MANGLE_BASE); 954 955 (void)slprintf(s, 12, "%s%c%c%c", 956 base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) ); 957 958 if( *extension ) 959 { 960 (void)pstrcat( s, "." ); 961 (void)pstrcat( s, extension ); 962 } 963 964 DEBUG( 5, ( "%s\n", s ) ); 965 966 } /* mangle_name_83 */ 967 968/***************************************************************************** 969 * Convert a filename to DOS format. Return True if successful. 970 * 971 * Input: OutName - Source *and* destination buffer. 972 * 973 * NOTE that OutName must point to a memory space that 974 * is at least 13 bytes in size! 975 * 976 * need83 - If False, name mangling will be skipped unless the 977 * name contains illegal characters. Mapping will still 978 * be done, if appropriate. This is probably used to 979 * signal that a client does not require name mangling, 980 * thus skipping the name mangling even on shares which 981 * have name-mangling turned on. 982 * cache83 - If False, the mangled name cache will not be updated. 983 * This is usually used to prevent that we overwrite 984 * a conflicting cache entry prematurely, i.e. before 985 * we know whether the client is really interested in the 986 * current name. (See PR#13758). UKD. 987 * snum - Share number. This identifies the share in which the 988 * name exists. 989 * 990 * Output: Returns False only if the name wanted mangling but the share does 991 * not have name mangling turned on. 992 * 993 * **************************************************************************** 994 */ 995BOOL name_map_mangle(char *OutName, BOOL need83, BOOL cache83, int snum) 996{ 997 char *map; 998 DEBUG(5,("name_map_mangle( %s, need83 = %s, cache83 = %s, %d )\n", OutName, 999 need83 ? "TRUE" : "FALSE", cache83 ? "TRUE" : "FALSE", snum)); 1000 1001#ifdef MANGLE_LONG_FILENAMES 1002 if( !need83 && is_illegal_name(OutName) ) 1003 need83 = True; 1004#endif 1005 1006 /* apply any name mappings */ 1007 map = lp_mangled_map(snum); 1008 1009 if (map && *map) { 1010 do_fwd_mangled_map( OutName, map ); 1011 } 1012 1013 /* check if it's already in 8.3 format */ 1014 if (need83 && !is_8_3(OutName, True)) { 1015 char *tmp = NULL; 1016 1017 if (!lp_manglednames(snum)) { 1018 return(False); 1019 } 1020 1021 /* mangle it into 8.3 */ 1022 if (cache83) 1023 tmp = strdup(OutName); 1024 1025 mangle_name_83(OutName); 1026 1027 if(tmp != NULL) { 1028 cache_mangled_name(OutName, tmp); 1029 free(tmp); 1030 } 1031 } 1032 1033 DEBUG(5,("name_map_mangle() ==> [%s]\n", OutName)); 1034 return(True); 1035} /* name_map_mangle */ 1036 1037