2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
Easy management of byte - length data
Copyright ( C ) Andrew Tridgell 2001
Copyright ( C ) Andrew Bartlett 2001
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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04:00
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
2014-09-22 13:31:23 +04:00
# include "replace.h"
# include "attr.h"
# include "data_blob.h"
2022-02-17 05:35:42 +03:00
# include "lib/util/samba_util.h"
2024-04-04 01:07:06 +03:00
# include "lib/util/tsort.h"
2003-08-13 05:53:07 +04:00
2008-10-12 03:46:15 +04:00
const DATA_BLOB data_blob_null = { NULL , 0 } ;
2006-02-28 16:12:39 +03:00
/**
* @ file
* @ brief Manipulation of arbitrary data blobs
* */
/**
2003-08-13 05:53:07 +04:00
construct a data blob , must be freed with data_blob_free ( )
you can pass NULL for p and get a blank data blob
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ DATA_BLOB data_blob_named ( const void * p , size_t length , const char * name )
2010-05-18 20:57:29 +04:00
{
return data_blob_talloc_named ( NULL , p , length , name ) ;
}
/**
construct a data blob , using supplied TALLOC_CTX
* */
_PUBLIC_ DATA_BLOB data_blob_talloc_named ( TALLOC_CTX * mem_ctx , const void * p , size_t length , const char * name )
2003-08-13 05:53:07 +04:00
{
DATA_BLOB ret ;
r6528: - in tdb_fetch() we effectively disallowed zero length records by
returning NULL/0, which is the same as we used for a failure. Having
to look at tdb->ecode (which we never do) is too error prone.
Instead, tdb_fetch() should behave like malloc() and talloc(), where
zero length is not special and malloc(0) returns a valid pointer.
- similarly in data_blob(), asking for data_blob(NULL, 0) should
return a zero blob, but asking for data_blob(ptr, 0) should return a
zero length blob with a valid pointer, just like talloc() and malloc()
This change fixes the SummaryInformation stream stored in the tdb
backend when manipulated from w2k. The w2k client was using
SET_EOF_INFORMATION to create a zero-length stream, which we return
STATUS_NOT_FOUND on, as the tdb_fetch() gave us back a NULL/0 blob,
which we returned as not-found
(This used to be commit 162bbe4402b9de6ac06103df904b9fc204fbff29)
2005-04-30 13:04:14 +04:00
if ( p = = NULL & & length = = 0 ) {
2003-08-13 05:53:07 +04:00
ZERO_STRUCT ( ret ) ;
return ret ;
}
if ( p ) {
2010-05-18 20:57:29 +04:00
ret . data = ( uint8_t * ) talloc_memdup ( mem_ctx , p , length ) ;
2003-08-13 05:53:07 +04:00
} else {
2010-05-18 20:57:29 +04:00
ret . data = talloc_array ( mem_ctx , uint8_t , length ) ;
2004-08-25 07:23:39 +04:00
}
if ( ret . data = = NULL ) {
ret . length = 0 ;
return ret ;
2003-08-13 05:53:07 +04:00
}
2004-09-26 10:41:59 +04:00
talloc_set_name_const ( ret . data , name ) ;
2003-08-13 05:53:07 +04:00
ret . length = length ;
return ret ;
}
2006-02-28 16:12:39 +03:00
/**
2003-12-13 05:20:40 +03:00
construct a zero data blob , using supplied TALLOC_CTX .
use this sparingly as it initialises data - better to initialise
yourself if you want specific data in the blob
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ DATA_BLOB data_blob_talloc_zero ( TALLOC_CTX * mem_ctx , size_t length )
2003-12-13 05:20:40 +03:00
{
DATA_BLOB blob = data_blob_talloc ( mem_ctx , NULL , length ) ;
data_blob_clear ( & blob ) ;
return blob ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
free a data blob
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ void data_blob_free ( DATA_BLOB * d )
2003-08-13 05:53:07 +04:00
{
if ( d ) {
2021-08-03 10:09:05 +03:00
TALLOC_FREE ( d - > data ) ;
2003-08-13 05:53:07 +04:00
d - > length = 0 ;
}
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
clear a DATA_BLOB ' s contents
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ void data_blob_clear ( DATA_BLOB * d )
2003-08-13 05:53:07 +04:00
{
if ( d - > data ) {
2018-12-11 16:31:26 +03:00
memset_s ( d - > data , d - > length , 0 , d - > length ) ;
2003-08-13 05:53:07 +04:00
}
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
free a data blob and clear its contents
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ void data_blob_clear_free ( DATA_BLOB * d )
2003-08-13 05:53:07 +04:00
{
data_blob_clear ( d ) ;
data_blob_free ( d ) ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
check if two data blobs are equal
2006-02-28 16:12:39 +03:00
* */
2007-06-20 08:15:39 +04:00
_PUBLIC_ int data_blob_cmp ( const DATA_BLOB * d1 , const DATA_BLOB * d2 )
2003-08-13 05:53:07 +04:00
{
2007-06-20 08:15:39 +04:00
int ret ;
if ( d1 - > data = = NULL & & d2 - > data ! = NULL ) {
return - 1 ;
2003-08-13 05:53:07 +04:00
}
2007-06-20 08:15:39 +04:00
if ( d1 - > data ! = NULL & & d2 - > data = = NULL ) {
return 1 ;
2003-08-13 05:53:07 +04:00
}
2007-06-20 08:15:39 +04:00
if ( d1 - > data = = d2 - > data ) {
2024-04-04 01:07:06 +03:00
return NUMERIC_CMP ( d1 - > length , d2 - > length ) ;
2003-08-13 05:53:07 +04:00
}
2007-06-20 08:15:39 +04:00
ret = memcmp ( d1 - > data , d2 - > data , MIN ( d1 - > length , d2 - > length ) ) ;
if ( ret = = 0 ) {
2023-09-21 03:55:53 +03:00
/* Note this ordering is used in conditional aces */
2024-04-04 01:07:06 +03:00
return NUMERIC_CMP ( d1 - > length , d2 - > length ) ;
2022-02-17 05:35:42 +03:00
}
return ret ;
}
/**
check if two data blobs are equal , where the time taken should not depend on the
contents of either blob .
* */
2022-05-11 02:39:14 +03:00
_PUBLIC_ bool data_blob_equal_const_time ( const DATA_BLOB * d1 , const DATA_BLOB * d2 )
2022-02-17 05:35:42 +03:00
{
2022-05-11 03:07:43 +03:00
bool ret ;
2022-02-17 05:35:42 +03:00
if ( d1 - > data = = NULL & & d2 - > data ! = NULL ) {
2022-05-11 02:39:14 +03:00
return false ;
2022-02-17 05:35:42 +03:00
}
if ( d1 - > data ! = NULL & & d2 - > data = = NULL ) {
2022-05-11 02:39:14 +03:00
return false ;
2022-02-17 05:35:42 +03:00
}
2022-05-11 02:39:14 +03:00
if ( d1 - > length ! = d2 - > length ) {
return false ;
2022-02-17 05:35:42 +03:00
}
2022-05-11 02:39:14 +03:00
if ( d1 - > data = = d2 - > data ) {
return true ;
2003-08-13 05:53:07 +04:00
}
2022-05-11 03:07:43 +03:00
ret = mem_equal_const_time ( d1 - > data , d2 - > data , d1 - > length ) ;
return ret ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2004-12-01 19:51:37 +03:00
print the data_blob as hex string
2006-02-28 16:12:39 +03:00
* */
2009-11-04 09:42:53 +03:00
_PUBLIC_ char * data_blob_hex_string_lower ( TALLOC_CTX * mem_ctx , const DATA_BLOB * blob )
2004-12-01 19:51:37 +03:00
{
2014-12-03 17:54:19 +03:00
size_t i ;
2004-12-01 19:51:37 +03:00
char * hex_string ;
2005-01-27 10:08:20 +03:00
hex_string = talloc_array ( mem_ctx , char , ( blob - > length * 2 ) + 1 ) ;
2004-12-01 19:51:37 +03:00
if ( ! hex_string ) {
return NULL ;
}
2009-09-23 01:20:36 +04:00
/* this must be lowercase or w2k8 cannot join a samba domain,
as this routine is used to encode extended DNs and windows
only accepts lowercase hexadecimal numbers */
2004-12-01 19:51:37 +03:00
for ( i = 0 ; i < blob - > length ; i + + )
2009-09-23 01:20:36 +04:00
slprintf ( & hex_string [ i * 2 ] , 3 , " %02x " , blob - > data [ i ] ) ;
2004-12-01 19:51:37 +03:00
2007-01-13 18:39:49 +03:00
hex_string [ ( blob - > length * 2 ) ] = ' \0 ' ;
2004-12-01 19:51:37 +03:00
return hex_string ;
}
2004-12-18 07:38:43 +03:00
2009-11-04 09:42:53 +03:00
_PUBLIC_ char * data_blob_hex_string_upper ( TALLOC_CTX * mem_ctx , const DATA_BLOB * blob )
{
2014-12-03 17:54:19 +03:00
size_t i ;
2009-11-04 09:42:53 +03:00
char * hex_string ;
hex_string = talloc_array ( mem_ctx , char , ( blob - > length * 2 ) + 1 ) ;
if ( ! hex_string ) {
return NULL ;
}
for ( i = 0 ; i < blob - > length ; i + + )
slprintf ( & hex_string [ i * 2 ] , 3 , " %02X " , blob - > data [ i ] ) ;
hex_string [ ( blob - > length * 2 ) ] = ' \0 ' ;
return hex_string ;
}
2006-02-28 16:12:39 +03:00
/**
2004-12-18 07:38:43 +03:00
useful for constructing data blobs in test suites , while
avoiding const warnings
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ DATA_BLOB data_blob_string_const ( const char * str )
2004-12-18 07:38:43 +03:00
{
DATA_BLOB blob ;
2007-09-08 17:27:14 +04:00
blob . data = discard_const_p ( uint8_t , str ) ;
2008-08-21 13:24:58 +04:00
blob . length = str ? strlen ( str ) : 0 ;
2004-12-18 07:38:43 +03:00
return blob ;
}
2008-10-13 07:20:26 +04:00
/**
useful for constructing data blobs in test suites , while
avoiding const warnings
* */
_PUBLIC_ DATA_BLOB data_blob_string_const_null ( const char * str )
{
DATA_BLOB blob ;
blob . data = discard_const_p ( uint8_t , str ) ;
blob . length = str ? strlen ( str ) + 1 : 0 ;
return blob ;
}
2006-03-06 03:24:51 +03:00
/**
* Create a new data blob from const data
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ DATA_BLOB data_blob_const ( const void * p , size_t length )
2004-12-21 18:15:49 +03:00
{
DATA_BLOB blob ;
2007-09-08 17:27:14 +04:00
blob . data = discard_const_p ( uint8_t , p ) ;
2004-12-21 18:15:49 +03:00
blob . length = length ;
return blob ;
}
2005-05-26 05:00:58 +04:00
2006-02-28 16:12:39 +03:00
/**
2005-11-09 11:06:56 +03:00
realloc a data_blob
2006-02-28 16:12:39 +03:00
* */
2007-08-29 17:07:03 +04:00
_PUBLIC_ bool data_blob_realloc ( TALLOC_CTX * mem_ctx , DATA_BLOB * blob , size_t length )
2005-11-09 11:06:56 +03:00
{
2021-07-23 09:27:37 +03:00
uint8_t * tmp = talloc_realloc ( mem_ctx , blob - > data , uint8_t , length ) ;
if ( tmp = = NULL ) {
2007-08-29 17:07:03 +04:00
return false ;
2021-07-23 09:27:37 +03:00
}
blob - > data = tmp ;
2005-11-09 11:06:56 +03:00
blob - > length = length ;
2007-08-29 17:07:03 +04:00
return true ;
2005-11-09 11:06:56 +03:00
}
2006-07-25 04:53:03 +04:00
2006-02-28 16:12:39 +03:00
/**
2005-05-26 05:00:58 +04:00
append some data to a data blob
2006-02-28 16:12:39 +03:00
* */
2007-08-29 17:07:03 +04:00
_PUBLIC_ bool data_blob_append ( TALLOC_CTX * mem_ctx , DATA_BLOB * blob ,
2006-07-21 04:56:48 +04:00
const void * p , size_t length )
2005-05-26 05:00:58 +04:00
{
2006-07-25 04:53:03 +04:00
size_t old_len = blob - > length ;
size_t new_len = old_len + length ;
2022-04-28 17:08:42 +03:00
if ( length = = 0 ) {
return true ;
}
2006-07-25 04:53:03 +04:00
if ( new_len < length | | new_len < old_len ) {
2007-08-29 17:07:03 +04:00
return false ;
2006-07-25 04:53:03 +04:00
}
if ( ( const uint8_t * ) p + length < ( const uint8_t * ) p ) {
2007-08-29 17:07:03 +04:00
return false ;
2006-07-25 04:53:03 +04:00
}
2007-08-29 17:07:03 +04:00
if ( ! data_blob_realloc ( mem_ctx , blob , new_len ) ) {
return false ;
2006-07-25 04:53:03 +04:00
}
memcpy ( blob - > data + old_len , p , length ) ;
2007-08-29 17:07:03 +04:00
return true ;
2005-05-26 05:00:58 +04:00
}
2005-11-09 11:06:56 +03:00
2021-12-10 04:59:22 +03:00
/**
pad the length of a data blob to a multiple of
' pad ' . ' pad ' must be a power of two .
* */
_PUBLIC_ bool data_blob_pad ( TALLOC_CTX * mem_ctx , DATA_BLOB * blob ,
size_t pad )
{
size_t old_len = blob - > length ;
size_t new_len = ( old_len + pad - 1 ) & ~ ( pad - 1 ) ;
if ( new_len < old_len ) {
return false ;
}
if ( ! data_blob_realloc ( mem_ctx , blob , new_len ) ) {
return false ;
}
memset ( blob - > data + old_len , 0 , new_len - old_len ) ;
return true ;
}