2007-09-08 00:57:01 +04:00
/*
2002-04-11 06:20:56 +04:00
Unix SMB / CIFS implementation .
Name mangling
Copyright ( C ) Andrew Tridgell 1992 - 2002
Copyright ( C ) Simo Sorce 2001
Copyright ( C ) Andrew Bartlett 2002
2007-09-08 00:57:01 +04:00
Copyright ( C ) Jeremy Allison 2007
2002-04-11 06:20:56 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2002-04-11 06:20:56 +04:00
( at your option ) any later version .
2007-09-08 00:57:01 +04:00
2002-04-11 06:20:56 +04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2007-09-08 00:57:01 +04:00
2002-04-11 06:20:56 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-04-11 06:20:56 +04:00
*/
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
2010-08-18 20:34:01 +04:00
# include "mangle.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2012-07-23 06:47:01 +04:00
# include "lib/param/loadparm.h"
2002-04-11 06:20:56 +04:00
/* -------------------------------------------------------------------------- **
* Other stuff . . .
*
* magic_char - This is the magic char used for mangling . It ' s
2014-02-03 06:16:06 +04:00
* global . There is a call to lp_mangling_char ( ) in server . c
2002-04-11 06:20:56 +04:00
* that is used to override the initial value .
*
* MANGLE_BASE - This is the number of characters we use for name mangling .
*
* basechars - The set characters used for name mangling . This
* is static ( scope is this file only ) .
*
* mangle ( ) - Macro used to select a character from basechars ( i . e . ,
* mangle ( n ) will return the nth digit , modulo MANGLE_BASE ) .
*
* chartest - array 0. .255 . The index range is the set of all possible
* values of a byte . For each byte value , the content is a
2005-05-25 04:51:39 +04:00
* two nibble pair . See BASECHAR_MASK below .
2002-04-11 06:20:56 +04:00
*
* ct_initialized - False until the chartest array has been initialized via
* a call to init_chartest ( ) .
*
* BASECHAR_MASK - Masks the upper nibble of a one - byte value .
*
* isbasecahr ( ) - Given a character , check the chartest array to see
* if that character is in the basechars set . This is
* faster than using strchr_m ( ) .
*
*/
2009-01-31 18:47:15 +03:00
static const char basechars [ 43 ] = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$% " ;
2002-04-11 06:20:56 +04:00
# define MANGLE_BASE (sizeof(basechars) / sizeof(char)-1)
# define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
# define BASECHAR_MASK 0xf0
# define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
/* -------------------------------------------------------------------- */
2011-04-12 10:23:17 +04:00
/*******************************************************************
Determine if a character is valid in a 8.3 name .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Load the valid character map table from < tt > valid . dat < / tt > or
* create from the configured codepage .
*
* This function is called whenever the configuration is reloaded .
* However , the valid character table is not changed if it ' s loaded
* from a file , because we can ' t unmap files .
* */
static uint8 * valid_table ;
static void init_valid_table ( void )
{
if ( valid_table ) {
return ;
}
2011-06-06 08:37:06 +04:00
valid_table = ( uint8 * ) map_file ( data_path ( talloc_tos ( ) , " valid.dat " ) , 0x10000 ) ;
2011-04-12 10:23:17 +04:00
if ( ! valid_table ) {
smb_panic ( " Could not load valid.dat file required for mangle method=hash " ) ;
return ;
}
}
static bool isvalid83_w ( smb_ucs2_t c )
{
init_valid_table ( ) ;
return valid_table [ SVAL ( & c , 0 ) ] ! = 0 ;
}
2007-10-19 04:40:25 +04:00
static NTSTATUS has_valid_83_chars ( const smb_ucs2_t * s , bool allow_wildcards )
2002-04-11 06:20:56 +04:00
{
2005-05-25 04:51:39 +04:00
if ( ! * s ) {
2002-07-15 14:35:28 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2005-05-25 04:51:39 +04:00
}
2002-04-11 06:20:56 +04:00
2005-05-25 04:51:39 +04:00
if ( ! allow_wildcards & & ms_has_wild_w ( s ) ) {
2002-07-15 14:35:28 +04:00
return NT_STATUS_UNSUCCESSFUL ;
2005-05-25 04:51:39 +04:00
}
2002-04-11 06:20:56 +04:00
while ( * s ) {
2005-05-25 04:51:39 +04:00
if ( ! isvalid83_w ( * s ) ) {
2002-07-15 14:35:28 +04:00
return NT_STATUS_UNSUCCESSFUL ;
2005-05-25 04:51:39 +04:00
}
s + + ;
}
return NT_STATUS_OK ;
}
2007-10-19 04:40:25 +04:00
static NTSTATUS has_illegal_chars ( const smb_ucs2_t * s , bool allow_wildcards )
2005-05-25 04:51:39 +04:00
{
if ( ! allow_wildcards & & ms_has_wild_w ( s ) ) {
return NT_STATUS_UNSUCCESSFUL ;
}
while ( * s ) {
2005-05-25 23:25:35 +04:00
if ( * s < = 0x1f ) {
/* Control characters. */
return NT_STATUS_UNSUCCESSFUL ;
}
2005-05-25 04:51:39 +04:00
switch ( * s ) {
case UCS2_CHAR ( ' \\ ' ) :
case UCS2_CHAR ( ' / ' ) :
case UCS2_CHAR ( ' | ' ) :
case UCS2_CHAR ( ' : ' ) :
return NT_STATUS_UNSUCCESSFUL ;
}
2002-04-11 06:20:56 +04:00
s + + ;
}
return NT_STATUS_OK ;
}
2011-04-12 10:55:16 +04:00
/*******************************************************************
Duplicate string .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static smb_ucs2_t * strdup_w ( const smb_ucs2_t * src )
{
smb_ucs2_t * dest ;
size_t len = strlen_w ( src ) ;
dest = SMB_MALLOC_ARRAY ( smb_ucs2_t , len + 1 ) ;
if ( ! dest ) {
DEBUG ( 0 , ( " strdup_w: out of memory! \n " ) ) ;
return NULL ;
}
memcpy ( dest , src , len * sizeof ( smb_ucs2_t ) ) ;
dest [ len ] = 0 ;
return dest ;
}
2002-04-11 06:20:56 +04:00
/* return False if something fail and
* return 2 alloced unicode strings that contain prefix and extension
*/
2002-07-15 14:35:28 +04:00
static NTSTATUS mangle_get_prefix ( const smb_ucs2_t * ucs2_string , smb_ucs2_t * * prefix ,
2007-10-19 04:40:25 +04:00
smb_ucs2_t * * extension , bool allow_wildcards )
2002-04-11 06:20:56 +04:00
{
size_t ext_len ;
smb_ucs2_t * p ;
* extension = 0 ;
* prefix = strdup_w ( ucs2_string ) ;
if ( ! * prefix ) {
return NT_STATUS_NO_MEMORY ;
}
2002-07-15 14:35:28 +04:00
if ( ( p = strrchr_w ( * prefix , UCS2_CHAR ( ' . ' ) ) ) ) {
2002-04-11 06:20:56 +04:00
ext_len = strlen_w ( p + 1 ) ;
if ( ( ext_len > 0 ) & & ( ext_len < 4 ) & & ( p ! = * prefix ) & &
2003-12-04 02:16:27 +03:00
( NT_STATUS_IS_OK ( has_valid_83_chars ( p + 1 , allow_wildcards ) ) ) ) /* check extension */ {
2002-04-11 06:20:56 +04:00
* p = 0 ;
* extension = strdup_w ( p + 1 ) ;
if ( ! * extension ) {
SAFE_FREE ( * prefix ) ;
return NT_STATUS_NO_MEMORY ;
}
}
}
return NT_STATUS_OK ;
}
/* ************************************************************************** **
* Return NT_STATUS_UNSUCCESSFUL if a name is a special msdos reserved name .
2005-05-25 04:51:39 +04:00
* or contains illegal characters .
2002-04-11 06:20:56 +04:00
*
* Input : fname - String containing the name to be tested .
*
2005-05-25 04:51:39 +04:00
* Output : NT_STATUS_UNSUCCESSFUL , if the condition above is true .
2002-04-11 06:20:56 +04:00
*
* Notes : This is a static function called by is_8_3 ( ) , below .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2002-07-15 14:35:28 +04:00
2007-10-19 04:40:25 +04:00
static NTSTATUS is_valid_name ( const smb_ucs2_t * fname , bool allow_wildcards , bool only_8_3 )
2002-04-11 06:20:56 +04:00
{
smb_ucs2_t * str , * p ;
2005-09-29 05:27:19 +04:00
size_t num_ucs2_chars ;
2002-04-11 06:20:56 +04:00
NTSTATUS ret = NT_STATUS_OK ;
2002-07-15 14:35:28 +04:00
if ( ! fname | | ! * fname )
return NT_STATUS_INVALID_PARAMETER ;
2002-04-11 06:20:56 +04:00
2002-07-15 14:35:28 +04:00
/* . and .. are valid names. */
if ( strcmp_wa ( fname , " . " ) = = 0 | | strcmp_wa ( fname , " .. " ) = = 0 )
return NT_STATUS_OK ;
2003-12-04 02:16:27 +03:00
if ( only_8_3 ) {
ret = has_valid_83_chars ( fname , allow_wildcards ) ;
if ( ! NT_STATUS_IS_OK ( ret ) )
return ret ;
}
2002-04-11 06:20:56 +04:00
2005-05-25 04:51:39 +04:00
ret = has_illegal_chars ( fname , allow_wildcards ) ;
if ( ! NT_STATUS_IS_OK ( ret ) )
return ret ;
2005-09-29 05:27:19 +04:00
/* Name can't end in '.' or ' ' */
num_ucs2_chars = strlen_w ( fname ) ;
if ( fname [ num_ucs2_chars - 1 ] = = UCS2_CHAR ( ' . ' ) | | fname [ num_ucs2_chars - 1 ] = = UCS2_CHAR ( ' ' ) ) {
2002-07-15 14:35:28 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
2005-09-29 05:27:19 +04:00
str = strdup_w ( fname ) ;
/* Truncate copy after the first dot. */
p = strchr_w ( str , UCS2_CHAR ( ' . ' ) ) ;
if ( p ) {
2003-07-03 23:11:31 +04:00
* p = 0 ;
2005-09-29 05:27:19 +04:00
}
2002-04-11 06:20:56 +04:00
strupper_w ( str ) ;
2005-09-29 05:27:19 +04:00
p = & str [ 1 ] ;
2002-04-11 06:20:56 +04:00
switch ( str [ 0 ] )
{
case UCS2_CHAR ( ' A ' ) :
if ( strcmp_wa ( p , " UX " ) = = 0 )
ret = NT_STATUS_UNSUCCESSFUL ;
break ;
case UCS2_CHAR ( ' C ' ) :
if ( ( strcmp_wa ( p , " LOCK$ " ) = = 0 )
| | ( strcmp_wa ( p , " ON " ) = = 0 )
| | ( strcmp_wa ( p , " OM1 " ) = = 0 )
| | ( strcmp_wa ( p , " OM2 " ) = = 0 )
| | ( strcmp_wa ( p , " OM3 " ) = = 0 )
| | ( strcmp_wa ( p , " OM4 " ) = = 0 )
)
ret = NT_STATUS_UNSUCCESSFUL ;
break ;
case UCS2_CHAR ( ' L ' ) :
if ( ( strcmp_wa ( p , " PT1 " ) = = 0 )
| | ( strcmp_wa ( p , " PT2 " ) = = 0 )
| | ( strcmp_wa ( p , " PT3 " ) = = 0 )
)
ret = NT_STATUS_UNSUCCESSFUL ;
break ;
case UCS2_CHAR ( ' N ' ) :
if ( strcmp_wa ( p , " UL " ) = = 0 )
ret = NT_STATUS_UNSUCCESSFUL ;
break ;
case UCS2_CHAR ( ' P ' ) :
if ( strcmp_wa ( p , " RN " ) = = 0 )
ret = NT_STATUS_UNSUCCESSFUL ;
break ;
default :
break ;
}
SAFE_FREE ( str ) ;
return ret ;
}
2007-10-19 04:40:25 +04:00
static NTSTATUS is_8_3_w ( const smb_ucs2_t * fname , bool allow_wildcards )
2002-04-11 06:20:56 +04:00
{
smb_ucs2_t * pref = 0 , * ext = 0 ;
size_t plen ;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL ;
2002-07-15 14:35:28 +04:00
if ( ! fname | | ! * fname )
return NT_STATUS_INVALID_PARAMETER ;
2002-04-11 06:20:56 +04:00
2002-07-15 14:35:28 +04:00
if ( strlen_w ( fname ) > 12 )
return NT_STATUS_UNSUCCESSFUL ;
2007-09-08 00:57:01 +04:00
2002-04-11 06:20:56 +04:00
if ( strcmp_wa ( fname , " . " ) = = 0 | | strcmp_wa ( fname , " .. " ) = = 0 )
return NT_STATUS_OK ;
2005-08-23 21:53:11 +04:00
/* Name cannot start with '.' */
if ( * fname = = UCS2_CHAR ( ' . ' ) )
return NT_STATUS_UNSUCCESSFUL ;
2007-09-08 00:57:01 +04:00
2003-12-04 02:16:27 +03:00
if ( ! NT_STATUS_IS_OK ( is_valid_name ( fname , allow_wildcards , True ) ) )
2002-07-15 14:35:28 +04:00
goto done ;
2002-04-11 06:20:56 +04:00
2003-06-22 14:09:52 +04:00
if ( ! NT_STATUS_IS_OK ( mangle_get_prefix ( fname , & pref , & ext , allow_wildcards ) ) )
2002-07-15 14:35:28 +04:00
goto done ;
2002-04-11 06:20:56 +04:00
plen = strlen_w ( pref ) ;
2002-07-15 14:35:28 +04:00
if ( strchr_wa ( pref , ' . ' ) )
goto done ;
if ( plen < 1 | | plen > 8 )
goto done ;
if ( ext & & ( strlen_w ( ext ) > 3 ) )
goto done ;
2002-04-11 06:20:56 +04:00
ret = NT_STATUS_OK ;
done :
SAFE_FREE ( pref ) ;
SAFE_FREE ( ext ) ;
return ret ;
}
2007-10-19 04:40:25 +04:00
static bool is_8_3 ( const char * fname , bool check_case , bool allow_wildcards ,
2006-07-11 22:01:26 +04:00
const struct share_params * p )
2002-04-11 06:20:56 +04:00
{
const char * f ;
smb_ucs2_t * ucs2name ;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL ;
2003-07-27 06:28:25 +04:00
size_t size ;
2005-05-06 12:07:39 +04:00
2002-07-15 14:35:28 +04:00
if ( ! fname | | ! * fname )
return False ;
if ( ( f = strrchr ( fname , ' / ' ) ) = = NULL )
f = fname ;
else
f + + ;
2002-04-11 06:20:56 +04:00
2002-07-15 14:35:28 +04:00
if ( strlen ( f ) > 12 )
return False ;
2007-09-08 00:57:01 +04:00
2009-03-19 04:20:11 +03:00
if ( ! push_ucs2_talloc ( NULL , & ucs2name , f , & size ) ) {
DEBUG ( 0 , ( " is_8_3: internal error push_ucs2_talloc() failed! \n " ) ) ;
2002-04-11 06:20:56 +04:00
goto done ;
}
2002-07-15 14:35:28 +04:00
ret = is_8_3_w ( ucs2name , allow_wildcards ) ;
2002-04-11 06:20:56 +04:00
done :
2009-03-19 04:20:11 +03:00
TALLOC_FREE ( ucs2name ) ;
2002-04-11 06:20:56 +04:00
2007-09-08 00:57:01 +04:00
if ( ! NT_STATUS_IS_OK ( ret ) ) {
2002-04-11 06:20:56 +04:00
return False ;
}
2007-09-08 00:57:01 +04:00
2002-04-11 06:20:56 +04:00
return True ;
}
/* -------------------------------------------------------------------------- **
* Functions . . .
*/
/* ************************************************************************** **
* Initialize the static character test array .
*
* Input : none
*
* Output : none
*
* Notes : This function changes ( loads ) the contents of the < chartest >
* array . The scope of < chartest > is this file .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2007-09-08 00:57:01 +04:00
2002-04-11 06:20:56 +04:00
static void init_chartest ( void )
2002-07-15 14:35:28 +04:00
{
2003-01-03 11:28:12 +03:00
const unsigned char * s ;
2007-09-08 00:57:01 +04:00
2007-12-28 19:02:07 +03:00
chartest = SMB_MALLOC_ARRAY ( unsigned char , 256 ) ;
SMB_ASSERT ( chartest ! = NULL ) ;
2010-02-18 23:21:10 +03:00
memset ( chartest , ' \0 ' , 256 ) ;
2002-04-11 06:20:56 +04:00
2005-05-25 04:51:39 +04:00
for ( s = ( const unsigned char * ) basechars ; * s ; s + + ) {
2002-07-15 14:35:28 +04:00
chartest [ * s ] | = BASECHAR_MASK ;
2005-05-25 04:51:39 +04:00
}
2002-07-15 14:35:28 +04:00
}
2002-04-11 06:20:56 +04:00
/* ************************************************************************** **
* Return True if the name * could be * a mangled name .
*
* Input : s - A path name - in UNIX pathname format .
*
* Output : True if the name matches the pattern described below in the
* notes , else False .
*
* Notes : The input name is * not * tested for 8.3 compliance . This must be
* done separately . This function returns true if the name contains
* a magic character followed by excactly two characters from the
* basechars list ( above ) , which in turn are followed either by the
* nul ( end of string ) byte or a dot ( extension ) or by a ' / ' ( end of
* a directory name ) .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2007-09-08 00:57:01 +04:00
2007-10-19 04:40:25 +04:00
static bool is_mangled ( const char * s , const struct share_params * p )
2002-07-15 14:35:28 +04:00
{
char * magic ;
2009-01-08 10:50:36 +03:00
char magic_char ;
2002-07-15 14:35:28 +04:00
2014-02-03 06:16:06 +04:00
magic_char = lp_mangling_char ( p ) ;
2005-05-06 12:07:39 +04:00
2007-12-28 19:02:07 +03:00
if ( chartest = = NULL ) {
2002-07-15 14:35:28 +04:00
init_chartest ( ) ;
2007-12-28 19:02:07 +03:00
}
2002-07-15 14:35:28 +04:00
magic = strchr_m ( s , magic_char ) ;
while ( magic & & magic [ 1 ] & & magic [ 2 ] ) { /* 3 chars, 1st is magic. */
if ( ( ' . ' = = magic [ 3 ] | | ' / ' = = magic [ 3 ] | | ! ( magic [ 3 ] ) ) /* Ends with '.' or nul or '/' ? */
2011-07-20 00:19:29 +04:00
& & isbasechar ( toupper_m ( magic [ 1 ] ) ) /* is 2nd char basechar? */
& & isbasechar ( toupper_m ( magic [ 2 ] ) ) ) /* is 3rd char basechar? */
2002-07-15 14:35:28 +04:00
return ( True ) ; /* If all above, then true, */
magic = strchr_m ( magic + 1 , magic_char ) ; /* else seek next magic. */
}
return ( False ) ;
}
2002-04-11 06:20:56 +04:00
2004-08-31 00:19:40 +04:00
/***************************************************************************
Initializes or clears the mangled cache .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-07-15 14:35:28 +04:00
2002-04-11 06:20:56 +04:00
static void mangle_reset ( void )
2002-07-15 14:35:28 +04:00
{
2004-08-31 00:19:40 +04:00
/* We could close and re-open the tdb here... should we ? The old code did
the equivalent . . . JRA . */
2002-07-15 14:35:28 +04:00
}
2002-04-11 06:20:56 +04:00
2004-08-31 00:19:40 +04:00
/***************************************************************************
Add a mangled name into the cache .
If the extension of the raw name maps directly to the
extension of the mangled name , then we ' ll store both names
* without * extensions . That way , we can provide consistent
reverse mangling for all names that match . The test here is
a bit more careful than the one done in earlier versions of
mangle . c :
- the extension must exist on the raw name ,
- it must be all lower case
- it must match the mangled extension ( to prove that no
mangling occurred ) .
crh 07 - Apr - 1998
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-09-08 00:57:01 +04:00
static void cache_mangled_name ( const char mangled_name [ 13 ] ,
const char * raw_name )
2002-07-15 14:35:28 +04:00
{
2004-08-31 00:19:40 +04:00
TDB_DATA data_val ;
char mangled_name_key [ 13 ] ;
2010-02-18 22:22:44 +03:00
char * s1 = NULL ;
char * s2 = NULL ;
2002-07-15 14:35:28 +04:00
/* If the cache isn't initialized, give up. */
2004-08-31 00:19:40 +04:00
if ( ! tdb_mangled_cache )
2002-07-15 14:35:28 +04:00
return ;
/* Init the string lengths. */
2011-05-04 00:52:06 +04:00
strlcpy ( mangled_name_key , mangled_name , sizeof ( mangled_name_key ) ) ;
2002-07-15 14:35:28 +04:00
/* See if the extensions are unmangled. If so, store the entry
* without the extension , thus creating a " group " reverse map .
*/
2004-08-31 00:19:40 +04:00
s1 = strrchr ( mangled_name_key , ' . ' ) ;
2002-07-15 14:35:28 +04:00
if ( s1 & & ( s2 = strrchr ( raw_name , ' . ' ) ) ) {
2004-08-31 00:19:40 +04:00
size_t i = 1 ;
2011-07-20 00:19:29 +04:00
while ( s1 [ i ] & & ( tolower_m ( s1 [ i ] ) = = s2 [ i ] ) )
2002-07-15 14:35:28 +04:00
i + + ;
if ( ! s1 [ i ] & & ! s2 [ i ] ) {
2004-08-31 00:19:40 +04:00
/* Truncate at the '.' */
* s1 = ' \0 ' ;
2009-12-22 04:46:32 +03:00
/*
* DANGER WILL ROBINSON - this
* is changing a const string via
* an aliased pointer ! Remember to
* put it back once we ' ve used it .
* JRA
*/
2004-08-31 00:19:40 +04:00
* s2 = ' \0 ' ;
2002-07-15 14:35:28 +04:00
}
}
/* Allocate a new cache entry. If the allocation fails, just return. */
2007-03-27 14:20:50 +04:00
data_val = string_term_tdb_data ( raw_name ) ;
2004-08-31 00:19:40 +04:00
if ( tdb_store_bystring ( tdb_mangled_cache , mangled_name_key , data_val , TDB_REPLACE ) ! = 0 ) {
DEBUG ( 0 , ( " cache_mangled_name: Error storing entry %s -> %s \n " , mangled_name_key , raw_name ) ) ;
} else {
DEBUG ( 5 , ( " cache_mangled_name: Stored entry %s -> %s \n " , mangled_name_key , raw_name ) ) ;
}
2009-12-22 04:46:32 +03:00
/* Restore the change we made to the const string. */
2010-02-18 22:22:44 +03:00
if ( s2 ) {
* s2 = ' . ' ;
}
2002-07-15 14:35:28 +04:00
}
2002-04-11 06:20:56 +04:00
/* ************************************************************************** **
* Check for a name on the mangled name stack
*
* Input : s - Input * and * output string buffer .
2004-07-22 17:39:43 +04:00
* maxlen - space in i / o string buffer .
2002-04-11 06:20:56 +04:00
* Output : True if the name was found in the cache , else False .
*
* Notes : If a reverse map is found , the function will overwrite the string
* space indicated by the input pointer < s > . This is frightening .
* It should be rewritten to return NULL if the long name was not
* found , and a pointer to the long name if it was found .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2007-10-19 04:40:25 +04:00
static bool lookup_name_from_8_3 ( TALLOC_CTX * ctx ,
2007-09-08 00:57:01 +04:00
const char * in ,
char * * out , /* talloced on the given context. */
const struct share_params * p )
2002-04-11 06:20:56 +04:00
{
2004-08-31 00:19:40 +04:00
TDB_DATA data_val ;
char * saved_ext = NULL ;
2007-09-08 00:57:01 +04:00
char * s = talloc_strdup ( ctx , in ) ;
2005-05-06 12:07:39 +04:00
2002-07-15 14:35:28 +04:00
/* If the cache isn't initialized, give up. */
2007-09-08 00:57:01 +04:00
if ( ! s | | ! tdb_mangled_cache ) {
TALLOC_FREE ( s ) ;
return False ;
}
2002-07-15 14:35:28 +04:00
2004-08-31 00:19:40 +04:00
data_val = tdb_fetch_bystring ( tdb_mangled_cache , s ) ;
2002-07-15 14:35:28 +04:00
/* If we didn't find the name *with* the extension, try without. */
2004-08-31 00:19:40 +04:00
if ( data_val . dptr = = NULL | | data_val . dsize = = 0 ) {
2007-09-08 00:57:01 +04:00
char * ext_start = strrchr ( s , ' . ' ) ;
2002-07-15 14:35:28 +04:00
if ( ext_start ) {
2007-09-08 00:57:01 +04:00
if ( ( saved_ext = talloc_strdup ( ctx , ext_start ) ) = = NULL ) {
TALLOC_FREE ( s ) ;
2002-07-15 14:35:28 +04:00
return False ;
2007-09-08 00:57:01 +04:00
}
2002-07-15 14:35:28 +04:00
* ext_start = ' \0 ' ;
2004-08-31 00:19:40 +04:00
data_val = tdb_fetch_bystring ( tdb_mangled_cache , s ) ;
2007-09-08 00:57:01 +04:00
/*
2002-07-15 14:35:28 +04:00
* At this point s is the name without the
* extension . We re - add the extension if saved_ext
* is not null , before freeing saved_ext .
*/
}
}
/* Okay, if we haven't found it we're done. */
2004-08-31 00:19:40 +04:00
if ( data_val . dptr = = NULL | | data_val . dsize = = 0 ) {
2007-09-08 00:57:01 +04:00
TALLOC_FREE ( saved_ext ) ;
TALLOC_FREE ( s ) ;
return False ;
2002-07-15 14:35:28 +04:00
}
2007-09-08 00:57:01 +04:00
/* If we *did* find it, we need to talloc it on the given ctx. */
if ( saved_ext ) {
* out = talloc_asprintf ( ctx , " %s%s " ,
( char * ) data_val . dptr ,
saved_ext ) ;
} else {
* out = talloc_strdup ( ctx , ( char * ) data_val . dptr ) ;
2002-07-15 14:35:28 +04:00
}
2007-09-08 00:57:01 +04:00
TALLOC_FREE ( s ) ;
TALLOC_FREE ( saved_ext ) ;
2004-08-31 00:19:40 +04:00
SAFE_FREE ( data_val . dptr ) ;
2007-09-08 00:57:01 +04:00
return * out ? True : False ;
2002-07-15 14:35:28 +04:00
}
2002-04-11 06:20:56 +04:00
2011-04-14 06:31:18 +04:00
/**
Check if a string is in " normal " case .
* */
static bool strisnormal ( const char * s , int case_default )
{
if ( case_default = = CASE_UPPER )
return ( ! strhaslower ( s ) ) ;
return ( ! strhasupper ( s ) ) ;
}
2002-04-11 06:20:56 +04:00
/*****************************************************************************
2007-09-08 00:57:01 +04:00
Do the actual mangling to 8.3 format .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-01-08 10:50:36 +03:00
static bool to_8_3 ( char magic_char , const char * in , char out [ 13 ] , int default_case )
2002-07-15 14:35:28 +04:00
{
int csum ;
char * p ;
char extension [ 4 ] ;
char base [ 9 ] ;
int baselen = 0 ;
int extlen = 0 ;
2007-09-08 00:57:01 +04:00
char * s = SMB_STRDUP ( in ) ;
2002-07-15 14:35:28 +04:00
extension [ 0 ] = 0 ;
base [ 0 ] = 0 ;
2007-09-08 00:57:01 +04:00
if ( ! s ) {
return False ;
}
p = strrchr ( s , ' . ' ) ;
2002-07-15 14:35:28 +04:00
if ( p & & ( strlen ( p + 1 ) < ( size_t ) 4 ) ) {
2007-10-19 04:40:25 +04:00
bool all_normal = ( strisnormal ( p + 1 , default_case ) ) ; /* XXXXXXXXX */
2002-07-15 14:35:28 +04:00
if ( all_normal & & p [ 1 ] ! = 0 ) {
* p = 0 ;
csum = str_checksum ( s ) ;
* p = ' . ' ;
} else
csum = str_checksum ( s ) ;
} else
csum = str_checksum ( s ) ;
2012-08-09 02:35:28 +04:00
if ( ! strupper_m ( s ) ) {
SAFE_FREE ( s ) ;
return false ;
}
2002-07-15 14:35:28 +04:00
if ( p ) {
if ( p = = s )
2011-05-04 00:52:06 +04:00
strlcpy ( extension , " ___ " , 4 ) ;
2002-07-15 14:35:28 +04:00
else {
* p + + = 0 ;
while ( * p & & extlen < 3 ) {
if ( * p ! = ' . ' ) {
extension [ extlen + + ] = p [ 0 ] ;
}
p + + ;
}
extension [ extlen ] = 0 ;
}
}
2007-09-08 00:57:01 +04:00
2002-07-15 14:35:28 +04:00
p = s ;
while ( * p & & baselen < 5 ) {
2005-05-25 04:51:39 +04:00
if ( isbasechar ( * p ) ) {
2002-07-15 14:35:28 +04:00
base [ baselen + + ] = p [ 0 ] ;
}
p + + ;
}
base [ baselen ] = 0 ;
2007-09-08 00:57:01 +04:00
2002-07-15 14:35:28 +04:00
csum = csum % ( MANGLE_BASE * MANGLE_BASE ) ;
2007-09-08 00:57:01 +04:00
memcpy ( out , base , baselen ) ;
out [ baselen ] = magic_char ;
out [ baselen + 1 ] = mangle ( csum / MANGLE_BASE ) ;
out [ baselen + 2 ] = mangle ( csum ) ;
2002-07-15 14:35:28 +04:00
if ( * extension ) {
2007-09-08 00:57:01 +04:00
out [ baselen + 3 ] = ' . ' ;
2011-05-04 00:52:06 +04:00
strlcpy ( & out [ baselen + 4 ] , extension , 4 ) ;
2007-09-08 00:57:01 +04:00
}
SAFE_FREE ( s ) ;
return True ;
}
2007-10-19 04:40:25 +04:00
static bool must_mangle ( const char * name ,
2007-09-08 00:57:01 +04:00
const struct share_params * p )
{
smb_ucs2_t * name_ucs2 = NULL ;
NTSTATUS status ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2007-09-08 00:57:01 +04:00
2009-03-19 04:20:11 +03:00
if ( ! push_ucs2_talloc ( NULL , & name_ucs2 , name , & converted_size ) ) {
DEBUG ( 0 , ( " push_ucs2_talloc failed! \n " ) ) ;
2007-09-08 00:57:01 +04:00
return False ;
2002-07-15 14:35:28 +04:00
}
2007-09-08 00:57:01 +04:00
status = is_valid_name ( name_ucs2 , False , False ) ;
2009-03-19 04:20:11 +03:00
TALLOC_FREE ( name_ucs2 ) ;
2009-12-18 03:14:30 +03:00
/* We return true if we *must* mangle, so if it's
* a valid name ( status = = OK ) then we must return
* false . Bug # 6939. */
return ! NT_STATUS_IS_OK ( status ) ;
2002-07-15 14:35:28 +04:00
}
2002-04-11 06:20:56 +04:00
/*****************************************************************************
* Convert a filename to DOS format . Return True if successful .
2007-09-08 00:57:01 +04:00
* Input : in Incoming name .
2002-04-11 06:20:56 +04:00
*
2007-09-08 00:57:01 +04:00
* out 8.3 DOS name .
2002-04-11 06:20:56 +04:00
*
* cache83 - If False , the mangled name cache will not be updated .
* This is usually used to prevent that we overwrite
* a conflicting cache entry prematurely , i . e . before
* we know whether the client is really interested in the
* current name . ( See PR # 13758 ) . UKD .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2002-07-15 14:35:28 +04:00
2007-10-19 04:40:25 +04:00
static bool hash_name_to_8_3 ( const char * in ,
2007-09-08 00:57:01 +04:00
char out [ 13 ] ,
2007-10-19 04:40:25 +04:00
bool cache83 ,
2007-09-08 00:57:01 +04:00
int default_case ,
const struct share_params * p )
2002-04-11 06:20:56 +04:00
{
2007-09-08 00:57:01 +04:00
smb_ucs2_t * in_ucs2 = NULL ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2009-01-08 10:50:36 +03:00
char magic_char ;
2008-04-30 01:36:24 +04:00
2014-02-03 06:16:06 +04:00
magic_char = lp_mangling_char ( p ) ;
2005-05-06 12:07:39 +04:00
2007-09-08 00:57:01 +04:00
DEBUG ( 5 , ( " hash_name_to_8_3( %s, cache83 = %s) \n " , in ,
cache83 ? " True " : " False " ) ) ;
2009-03-19 04:20:11 +03:00
if ( ! push_ucs2_talloc ( NULL , & in_ucs2 , in , & converted_size ) ) {
DEBUG ( 0 , ( " push_ucs2_talloc failed! \n " ) ) ;
2007-09-08 00:57:01 +04:00
return False ;
2002-04-11 06:20:56 +04:00
}
2007-09-08 00:57:01 +04:00
/* If it's already 8.3, just copy. */
if ( NT_STATUS_IS_OK ( is_valid_name ( in_ucs2 , False , False ) ) & &
NT_STATUS_IS_OK ( is_8_3_w ( in_ucs2 , False ) ) ) {
2009-03-19 04:20:11 +03:00
TALLOC_FREE ( in_ucs2 ) ;
2011-05-04 00:52:06 +04:00
strlcpy ( out , in , 13 ) ;
2007-09-08 00:57:01 +04:00
return True ;
}
2002-04-11 06:20:56 +04:00
2009-03-19 04:20:11 +03:00
TALLOC_FREE ( in_ucs2 ) ;
2009-01-08 10:50:36 +03:00
if ( ! to_8_3 ( magic_char , in , out , default_case ) ) {
2007-09-08 00:57:01 +04:00
return False ;
2002-04-11 06:20:56 +04:00
}
2007-09-08 00:57:01 +04:00
cache_mangled_name ( out , in ) ;
DEBUG ( 5 , ( " hash_name_to_8_3(%s) ==> [%s] \n " , in , out ) ) ;
return True ;
2002-07-15 14:35:28 +04:00
}
2002-04-11 06:20:56 +04:00
/*
the following provides the abstraction layer to make it easier
to drop in an alternative mangling implementation
*/
2009-01-08 10:36:24 +03:00
static const struct mangle_fns mangle_hash_fns = {
2005-05-06 12:07:39 +04:00
mangle_reset ,
2002-04-11 06:20:56 +04:00
is_mangled ,
2007-09-08 00:57:01 +04:00
must_mangle ,
2002-04-11 06:20:56 +04:00
is_8_3 ,
2007-09-08 00:57:01 +04:00
lookup_name_from_8_3 ,
hash_name_to_8_3
2002-04-11 06:20:56 +04:00
} ;
/* return the methods for this mangling implementation */
2009-01-08 10:36:24 +03:00
const struct mangle_fns * mangle_hash_init ( void )
2002-04-11 06:20:56 +04:00
{
mangle_reset ( ) ;
2014-08-19 18:32:15 +04:00
if ( chartest = = NULL ) {
init_chartest ( ) ;
}
2004-08-31 00:19:40 +04:00
/* Create the in-memory tdb using our custom hash function. */
tdb_mangled_cache = tdb_open_ex ( " mangled_cache " , 1031 , TDB_INTERNAL ,
( O_RDWR | O_CREAT ) , 0644 , NULL , fast_string_hash ) ;
2009-01-08 10:36:24 +03:00
return & mangle_hash_fns ;
2002-04-11 06:20:56 +04:00
}