2007-07-13 05:22:09 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1996-05-04 11:50:46 +04:00
Character set conversion Extensions
2001-07-04 11:15:53 +04:00
Copyright ( C ) Igor Vergeichik < iverg @ mail . ru > 2001
Copyright ( C ) Andrew Tridgell 2001
2001-11-12 03:53:34 +03:00
Copyright ( C ) Simo Sorce 2001
2003-04-22 17:15:24 +04:00
Copyright ( C ) Martin Pool 2003
2007-07-13 05:22:09 +04:00
1996-05-04 11:50:46 +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
1996-05-04 11:50:46 +04:00
( at your option ) any later version .
2007-07-13 05:22:09 +04:00
1996-05-04 11:50:46 +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-07-13 05:22:09 +04:00
1996-05-04 11:50:46 +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/>.
1996-05-04 11:50:46 +04:00
*/
# include "includes.h"
2001-07-04 11:15:53 +04:00
2006-04-08 21:25:31 +04:00
/**
* Destroy global objects allocated by init_iconv ( )
* */
void gfree_charcnv ( void )
{
2011-03-25 00:37:00 +03:00
TALLOC_FREE ( global_iconv_handle ) ;
2006-04-08 21:25:31 +04:00
}
2003-02-24 06:09:08 +03:00
/**
* Copy a string from a char * unix src to a dos codepage string destination .
*
* @ return the number of bytes occupied by the string in the destination .
*
* @ param flags can include
* < dl >
* < dt > STR_TERMINATE < / dt > < dd > means include the null termination < / dd >
* < dt > STR_UPPER < / dt > < dd > means uppercase in the destination < / dd >
* < / dl >
*
* @ param dest_len the maximum length in bytes allowed in the
2007-09-14 02:08:59 +04:00
* destination .
2003-02-24 06:09:08 +03:00
* */
2002-11-12 01:13:05 +03:00
size_t push_ascii ( void * dest , const char * src , size_t dest_len , int flags )
1999-12-13 16:27:58 +03:00
{
2002-11-12 01:13:05 +03:00
size_t src_len = strlen ( src ) ;
2007-09-14 02:08:59 +04:00
char * tmpbuf = NULL ;
2011-03-31 00:08:31 +04:00
size_t size ;
bool ret ;
1997-01-09 21:02:17 +03:00
2007-09-14 02:08:59 +04:00
/* No longer allow a length of -1. */
if ( dest_len = = ( size_t ) - 1 ) {
smb_panic ( " push_ascii - dest_len == -1 " ) ;
}
1996-05-04 11:50:46 +04:00
2001-07-04 11:15:53 +04:00
if ( flags & STR_UPPER ) {
2007-09-14 02:08:59 +04:00
tmpbuf = SMB_STRDUP ( src ) ;
if ( ! tmpbuf ) {
smb_panic ( " malloc fail " ) ;
}
2012-08-09 02:35:28 +04:00
if ( ! strupper_m ( tmpbuf ) ) {
SAFE_FREE ( tmpbuf ) ;
return ( size_t ) - 1 ;
}
2001-07-04 11:15:53 +04:00
src = tmpbuf ;
}
2001-02-15 00:56:57 +03:00
2007-09-14 02:08:59 +04:00
if ( flags & ( STR_TERMINATE | STR_TERMINATE_ASCII ) ) {
2001-07-04 11:15:53 +04:00
src_len + + ;
2007-09-14 02:08:59 +04:00
}
2001-07-04 11:15:53 +04:00
2011-03-31 00:08:31 +04:00
ret = convert_string ( CH_UNIX , CH_DOS , src , src_len , dest , dest_len , & size ) ;
if ( ret = = false & &
2007-09-19 21:52:06 +04:00
( flags & ( STR_TERMINATE | STR_TERMINATE_ASCII ) )
& & dest_len > 0 ) {
( ( char * ) dest ) [ 0 ] = ' \0 ' ;
2007-09-14 02:08:59 +04:00
}
2007-09-19 21:52:06 +04:00
SAFE_FREE ( tmpbuf ) ;
2011-03-31 00:08:31 +04:00
return ret ? size : ( size_t ) - 1 ;
1997-05-09 01:17:59 +04:00
}
2007-09-14 02:08:59 +04:00
/********************************************************************
Push and malloc an ascii string . src and dest null terminated .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-02-24 06:09:08 +03:00
/**
* Copy a string from a dos codepage source to a unix char * destination .
*
* The resulting string in " dest " is always null terminated .
*
* @ param flags can have :
* < dl >
* < dt > STR_TERMINATE < / dt >
* < dd > STR_TERMINATE means the string in @ p src
* is null terminated , and src_len is ignored . < / dd >
* < / dl >
*
* @ param src_len is the length of the source area in bytes .
* @ returns the number of bytes occupied by the string in @ p src .
* */
2002-11-12 01:13:05 +03:00
size_t pull_ascii ( char * dest , const void * src , size_t dest_len , size_t src_len , int flags )
1999-12-13 16:27:58 +03:00
{
2011-03-31 00:08:31 +04:00
bool ret ;
size_t size = 0 ;
2001-07-04 11:15:53 +04:00
2007-09-19 13:40:40 +04:00
if ( dest_len = = ( size_t ) - 1 ) {
/* No longer allow dest_len of -1. */
smb_panic ( " pull_ascii - invalid dest_len of -1 " ) ;
}
2001-07-04 11:15:53 +04:00
2002-07-15 14:35:28 +04:00
if ( flags & STR_TERMINATE ) {
2002-11-12 01:13:05 +03:00
if ( src_len = = ( size_t ) - 1 ) {
2006-07-11 22:01:26 +04:00
src_len = strlen ( ( const char * ) src ) + 1 ;
2002-07-15 14:35:28 +04:00
} else {
2006-07-11 22:01:26 +04:00
size_t len = strnlen ( ( const char * ) src , src_len ) ;
2002-11-12 01:13:05 +03:00
if ( len < src_len )
len + + ;
2002-07-15 14:35:28 +04:00
src_len = len ;
}
}
2001-07-04 11:15:53 +04:00
2011-03-31 00:08:31 +04:00
ret = convert_string ( CH_DOS , CH_UNIX , src , src_len , dest , dest_len , & size ) ;
if ( ret = = false ) {
size = 0 ;
2004-03-12 01:48:24 +03:00
dest_len = 0 ;
}
2001-07-04 11:15:53 +04:00
2011-03-31 00:08:31 +04:00
if ( dest_len & & size ) {
2007-05-07 23:27:46 +04:00
/* Did we already process the terminating zero ? */
2011-03-31 00:08:31 +04:00
if ( dest [ MIN ( size - 1 , dest_len - 1 ) ] ! = 0 ) {
dest [ MIN ( size , dest_len - 1 ) ] = 0 ;
2007-05-07 23:27:46 +04:00
}
} else {
2003-05-08 09:10:44 +04:00
dest [ 0 ] = 0 ;
2007-05-07 23:27:46 +04:00
}
2001-07-04 11:15:53 +04:00
return src_len ;
1998-01-17 10:08:21 +03:00
}
2007-07-13 05:22:09 +04:00
/**
* Copy a string from a dos codepage source to a unix char * destination .
2009-06-10 22:58:00 +04:00
* Talloc version .
2007-07-13 05:22:09 +04:00
*
* The resulting string in " dest " is always null terminated .
*
* @ param flags can have :
* < dl >
* < dt > STR_TERMINATE < / dt >
* < dd > STR_TERMINATE means the string in @ p src
* is null terminated , and src_len is ignored . < / dd >
* < / dl >
*
* @ param src_len is the length of the source area in bytes .
* @ returns the number of bytes occupied by the string in @ p src .
* */
static size_t pull_ascii_base_talloc ( TALLOC_CTX * ctx ,
2009-03-19 04:20:11 +03:00
char * * ppdest ,
const void * src ,
size_t src_len ,
int flags )
2007-07-13 05:22:09 +04:00
{
char * dest = NULL ;
2008-10-17 02:40:57 +04:00
size_t dest_len ;
2007-07-13 05:22:09 +04:00
* ppdest = NULL ;
2008-10-17 02:40:57 +04:00
if ( ! src_len ) {
return 0 ;
}
2011-03-24 05:00:05 +03:00
if ( src_len = = ( size_t ) - 1 ) {
2013-02-26 15:32:32 +04:00
smb_panic ( " src_len == -1 in pull_ascii_base_talloc " ) ;
2011-03-24 05:00:05 +03:00
}
2007-07-13 05:22:09 +04:00
if ( flags & STR_TERMINATE ) {
2011-03-24 05:00:05 +03:00
size_t len = strnlen ( ( const char * ) src , src_len ) ;
if ( len < src_len )
len + + ;
src_len = len ;
2007-07-13 05:22:09 +04:00
/* Ensure we don't use an insane length from the client. */
if ( src_len > = 1024 * 1024 ) {
2007-09-13 01:48:20 +04:00
char * msg = talloc_asprintf ( ctx ,
" Bad src length (%u) in "
" pull_ascii_base_talloc " ,
2007-09-13 04:31:02 +04:00
( unsigned int ) src_len ) ;
2007-09-13 01:48:20 +04:00
smb_panic ( msg ) ;
2007-07-13 05:22:09 +04:00
}
}
2008-10-17 02:40:57 +04:00
/* src_len != -1 here. */
2009-03-19 04:20:11 +03:00
if ( ! convert_string_talloc ( ctx , CH_DOS , CH_UNIX , src , src_len , & dest ,
2011-03-24 02:59:41 +03:00
& dest_len ) ) {
2008-10-17 02:40:57 +04:00
dest_len = 0 ;
2008-04-30 01:36:24 +04:00
}
2007-07-13 05:22:09 +04:00
2008-10-17 02:40:57 +04:00
if ( dest_len & & dest ) {
2007-07-13 05:22:09 +04:00
/* Did we already process the terminating zero ? */
2008-10-17 02:40:57 +04:00
if ( dest [ dest_len - 1 ] ! = 0 ) {
size_t size = talloc_get_size ( dest ) ;
/* Have we got space to append the '\0' ? */
if ( size < = dest_len ) {
/* No, realloc. */
2011-06-07 05:10:15 +04:00
dest = talloc_realloc ( ctx , dest , char ,
2008-10-17 02:40:57 +04:00
dest_len + 1 ) ;
if ( ! dest ) {
/* talloc fail. */
dest_len = ( size_t ) - 1 ;
return 0 ;
}
}
/* Yay - space ! */
dest [ dest_len ] = ' \0 ' ;
dest_len + + ;
2007-07-13 05:22:09 +04:00
}
} else if ( dest ) {
dest [ 0 ] = 0 ;
}
* ppdest = dest ;
return src_len ;
}
2003-02-24 06:09:08 +03:00
/**
* Copy a string from a char * src to a unicode destination .
*
* @ returns the number of bytes occupied by the string in the destination .
*
* @ param flags can have :
*
* < dl >
* < dt > STR_TERMINATE < dd > means include the null termination .
* < dt > STR_UPPER < dd > means uppercase in the destination .
* < dt > STR_NOALIGN < dd > means don ' t do alignment .
* < / dl >
*
* @ param dest_len is the maximum length allowed in the
2007-09-19 13:40:40 +04:00
* destination .
2003-02-24 06:09:08 +03:00
* */
2003-09-05 03:03:58 +04:00
2011-05-03 06:25:29 +04:00
static size_t push_ucs2 ( const void * base_ptr , void * dest , const char * src , size_t dest_len , int flags )
2001-07-04 11:15:53 +04:00
{
2002-11-12 01:13:05 +03:00
size_t len = 0 ;
2003-09-05 03:03:58 +04:00
size_t src_len ;
2011-03-31 00:08:31 +04:00
size_t size = 0 ;
bool ret ;
2001-07-04 11:15:53 +04:00
2007-09-19 13:40:40 +04:00
if ( dest_len = = ( size_t ) - 1 ) {
/* No longer allow dest_len of -1. */
smb_panic ( " push_ucs2 - invalid dest_len of -1 " ) ;
}
2001-07-04 11:15:53 +04:00
2002-11-12 01:13:05 +03:00
if ( flags & STR_TERMINATE )
2003-09-05 03:03:58 +04:00
src_len = ( size_t ) - 1 ;
else
src_len = strlen ( src ) ;
2001-07-04 11:15:53 +04:00
if ( ucs2_align ( base_ptr , dest , flags ) ) {
* ( char * ) dest = 0 ;
dest = ( void * ) ( ( char * ) dest + 1 ) ;
2003-09-05 03:03:58 +04:00
if ( dest_len )
dest_len - - ;
2001-07-04 11:15:53 +04:00
len + + ;
}
2001-07-25 08:00:40 +04:00
/* ucs2 is always a multiple of 2 bytes */
dest_len & = ~ 1 ;
2011-03-31 00:08:31 +04:00
ret = convert_string ( CH_UNIX , CH_UTF16LE , src , src_len , dest , dest_len , & size ) ;
if ( ret = = false ) {
2007-09-19 21:52:06 +04:00
if ( ( flags & STR_TERMINATE ) & &
dest & &
dest_len ) {
* ( char * ) dest = 0 ;
}
return len ;
2004-03-12 01:48:24 +03:00
}
2011-03-31 00:08:31 +04:00
len + = size ;
2003-07-27 06:28:25 +04:00
if ( flags & STR_UPPER ) {
2006-07-11 22:01:26 +04:00
smb_ucs2_t * dest_ucs2 = ( smb_ucs2_t * ) dest ;
2003-07-27 06:28:25 +04:00
size_t i ;
2006-09-25 20:19:30 +04:00
2012-12-17 17:25:31 +04:00
/* We check for i < (size / 2) below as the dest string isn't null
2006-09-25 20:19:30 +04:00
terminated if STR_TERMINATE isn ' t set . */
2012-12-17 17:25:31 +04:00
for ( i = 0 ; i < ( size / 2 ) & & i < ( dest_len / 2 ) & & dest_ucs2 [ i ] ; i + + ) {
2011-07-20 00:35:45 +04:00
smb_ucs2_t v = toupper_w ( dest_ucs2 [ i ] ) ;
2003-07-27 06:28:25 +04:00
if ( v ! = dest_ucs2 [ i ] ) {
dest_ucs2 [ i ] = v ;
}
}
}
2001-07-04 11:15:53 +04:00
return len ;
2001-02-15 00:56:57 +03:00
}
2001-01-08 02:00:49 +03:00
2007-07-13 05:22:09 +04:00
/**
Copy a string from a ucs2 source to a unix char * destination .
Talloc version with a base pointer .
Uses malloc if TALLOC_CTX is NULL ( this is a bad interface and
needs fixing . JRA ) .
Flags can have :
STR_TERMINATE means the string in src is null terminated .
STR_NOALIGN means don ' t try to align .
if STR_TERMINATE is set then src_len is ignored if it is - 1.
src_len is the length of the source area in bytes
Return the number of bytes occupied by the string in src .
The resulting string in " dest " is always null terminated .
* */
2011-03-24 04:09:03 +03:00
static size_t pull_ucs2_base_talloc ( TALLOC_CTX * ctx ,
const void * base_ptr ,
char * * ppdest ,
const void * src ,
size_t src_len ,
int flags )
2007-07-13 05:22:09 +04:00
{
char * dest ;
size_t dest_len ;
2011-03-15 02:12:31 +03:00
size_t ucs2_align_len = 0 ;
2007-07-13 05:22:09 +04:00
* ppdest = NULL ;
# ifdef DEVELOPER
/* Ensure we never use the braindead "malloc" varient. */
if ( ctx = = NULL ) {
smb_panic ( " NULL talloc CTX in pull_ucs2_base_talloc \n " ) ;
}
# endif
2007-09-17 14:50:59 +04:00
if ( ! src_len ) {
return 0 ;
}
2011-03-24 05:00:05 +03:00
if ( src_len = = ( size_t ) - 1 ) {
/* no longer used anywhere, but worth checking */
smb_panic ( " sec_len == -1 in pull_ucs2_base_talloc " ) ;
}
2007-07-13 05:22:09 +04:00
if ( ucs2_align ( base_ptr , src , flags ) ) {
src = ( const void * ) ( ( const char * ) src + 1 ) ;
2011-03-24 05:00:05 +03:00
src_len - - ;
2011-03-15 02:12:31 +03:00
ucs2_align_len = 1 ;
2007-07-13 05:22:09 +04:00
}
if ( flags & STR_TERMINATE ) {
/* src_len -1 is the default for null terminated strings. */
2011-03-24 05:00:05 +03:00
size_t len = strnlen_w ( ( const smb_ucs2_t * ) src ,
src_len / 2 ) ;
if ( len < src_len / 2 )
len + + ;
src_len = len * 2 ;
2007-07-13 05:22:09 +04:00
/* Ensure we don't use an insane length from the client. */
if ( src_len > = 1024 * 1024 ) {
smb_panic ( " Bad src length in pull_ucs2_base_talloc \n " ) ;
}
}
/* ucs2 is always a multiple of 2 bytes */
2008-10-17 02:40:57 +04:00
src_len & = ~ 1 ;
2007-07-13 05:22:09 +04:00
2008-04-30 01:36:24 +04:00
if ( ! convert_string_talloc ( ctx , CH_UTF16LE , CH_UNIX , src , src_len ,
2011-03-24 02:59:41 +03:00
( void * ) & dest , & dest_len ) ) {
2007-09-19 21:52:06 +04:00
dest_len = 0 ;
2007-07-13 05:22:09 +04:00
}
if ( dest_len ) {
/* Did we already process the terminating zero ? */
if ( dest [ dest_len - 1 ] ! = 0 ) {
2007-09-12 03:57:59 +04:00
size_t size = talloc_get_size ( dest ) ;
/* Have we got space to append the '\0' ? */
if ( size < = dest_len ) {
/* No, realloc. */
2011-06-07 05:10:15 +04:00
dest = talloc_realloc ( ctx , dest , char ,
2007-09-12 03:57:59 +04:00
dest_len + 1 ) ;
if ( ! dest ) {
/* talloc fail. */
dest_len = ( size_t ) - 1 ;
return 0 ;
}
}
/* Yay - space ! */
dest [ dest_len ] = ' \0 ' ;
dest_len + + ;
2007-07-13 05:22:09 +04:00
}
} else if ( dest ) {
dest [ 0 ] = 0 ;
}
* ppdest = dest ;
2011-03-15 02:12:31 +03:00
return src_len + ucs2_align_len ;
2007-07-13 05:22:09 +04:00
}
2009-03-17 06:04:43 +03:00
/**
Copy a string from a char * src to a unicode or ascii
dos codepage destination choosing unicode or ascii based on the
flags supplied
Return the number of bytes occupied by the string in the destination .
flags can have :
STR_TERMINATE means include the null termination .
STR_UPPER means uppercase in the destination .
STR_ASCII use ascii even with unicode packet .
STR_NOALIGN means don ' t do alignment .
dest_len is the maximum length allowed in the destination . If dest_len
is - 1 then no maxiumum is used .
* */
2011-03-22 07:30:43 +03:00
size_t push_string_check_fn ( void * dest , const char * src ,
size_t dest_len , int flags )
2009-03-17 06:04:43 +03:00
{
if ( ! ( flags & STR_ASCII ) & & ( flags & STR_UNICODE ) ) {
return push_ucs2 ( NULL , dest , src , dest_len , flags ) ;
}
return push_ascii ( dest , src , dest_len , flags ) ;
}
2009-04-06 16:56:13 +04:00
2003-02-24 06:09:08 +03:00
/**
2002-11-12 01:13:05 +03:00
Copy a string from a char * src to a unicode or ascii
dos codepage destination choosing unicode or ascii based on the
flags in the SMB buffer starting at base_ptr .
Return the number of bytes occupied by the string in the destination .
flags can have :
STR_TERMINATE means include the null termination .
STR_UPPER means uppercase in the destination .
STR_ASCII use ascii even with unicode packet .
STR_NOALIGN means don ' t do alignment .
dest_len is the maximum length allowed in the destination . If dest_len
is - 1 then no maxiumum is used .
2003-02-24 06:09:08 +03:00
* */
2002-11-12 01:13:05 +03:00
2011-03-22 07:30:43 +03:00
size_t push_string_base ( const char * base , uint16 flags2 ,
2009-03-17 06:04:43 +03:00
void * dest , const char * src ,
size_t dest_len , int flags )
1996-05-04 11:50:46 +04:00
{
2003-03-18 04:48:11 +03:00
2001-07-04 11:15:53 +04:00
if ( ! ( flags & STR_ASCII ) & & \
( ( flags & STR_UNICODE | | \
2007-08-02 22:06:45 +04:00
( flags2 & FLAGS2_UNICODE_STRINGS ) ) ) ) {
2009-03-17 06:04:43 +03:00
return push_ucs2 ( base , dest , src , dest_len , flags ) ;
2001-07-04 11:15:53 +04:00
}
return push_ascii ( dest , src , dest_len , flags ) ;
1996-05-04 11:50:46 +04:00
}
2007-07-13 05:22:09 +04:00
/**
Copy a string from a unicode or ascii source ( depending on
the packet flags ) to a char * destination .
Variant that uses talloc .
Flags can have :
STR_TERMINATE means the string in src is null terminated .
STR_UNICODE means to force as unicode .
STR_ASCII use ascii even with unicode packet .
STR_NOALIGN means don ' t do alignment .
if STR_TERMINATE is set then src_len is ignored is it is - 1
src_len is the length of the source area in bytes .
Return the number of bytes occupied by the string in src .
The resulting string in " dest " is always null terminated .
* */
2011-03-22 07:30:43 +03:00
size_t pull_string_talloc ( TALLOC_CTX * ctx ,
const void * base_ptr ,
uint16 smb_flags2 ,
char * * ppdest ,
const void * src ,
size_t src_len ,
int flags )
2007-07-13 05:22:09 +04:00
{
if ( ( base_ptr = = NULL ) & & ( ( flags & ( STR_ASCII | STR_UNICODE ) ) = = 0 ) ) {
smb_panic ( " No base ptr to get flg2 and neither ASCII nor "
" UNICODE defined " ) ;
}
if ( ! ( flags & STR_ASCII ) & & \
( ( flags & STR_UNICODE | | \
( smb_flags2 & FLAGS2_UNICODE_STRINGS ) ) ) ) {
return pull_ucs2_base_talloc ( ctx ,
base_ptr ,
ppdest ,
src ,
src_len ,
flags ) ;
}
return pull_ascii_base_talloc ( ctx ,
ppdest ,
src ,
src_len ,
flags ) ;
1996-05-04 11:50:46 +04:00
}
2004-03-17 00:59:11 +03:00
2011-04-12 10:31:08 +04:00
/*******************************************************************
Write a string in ( little - endian ) unicode format . src is in
the current DOS codepage . len is the length in bytes of the
string pointed to by dst .
if null_terminate is True then null terminate the packet ( adds 2 bytes )
the return value is the length in bytes consumed by the string , including the
null termination if applied
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
size_t dos_PutUniCode ( char * dst , const char * src , size_t len , bool null_terminate )
{
int flags = null_terminate ? STR_UNICODE | STR_NOALIGN | STR_TERMINATE
: STR_UNICODE | STR_NOALIGN ;
return push_ucs2 ( NULL , dst , src , len , flags ) ;
}
/* Converts a string from internal samba format to unicode. Always terminates.
* Actually just a wrapper round push_ucs2_talloc ( ) .
*/
int rpcstr_push_talloc ( TALLOC_CTX * ctx , smb_ucs2_t * * dest , const char * src )
{
size_t size ;
if ( push_ucs2_talloc ( ctx , dest , src , & size ) )
return size ;
else
return - 1 ;
}