2004-03-31 06:45:39 +00:00
/*
ldb database library
Copyright ( C ) Andrew Tridgell 2004
* * NOTE ! The following LGPL license applies to the ldb
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 2 of the License , or ( at your option ) any later version .
This library 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
/*
* Name : ldb
*
* Component : ldb pack / unpack
*
* Description : pack / unpack routines for ldb messages as key / value blobs
*
* Author : Andrew Tridgell
*/
# include "includes.h"
2004-11-16 09:00:52 +00:00
# include "ldb/include/ldb.h"
# include "ldb/include/ldb_private.h"
2004-04-10 20:18:22 +00:00
# include "ldb/ldb_tdb/ldb_tdb.h"
2004-03-31 06:45:39 +00:00
/* change this if the data format ever changes */
2004-05-01 09:45:56 +00:00
# define LTDB_PACKING_FORMAT 0x26011967
/* old packing formats */
# define LTDB_PACKING_FORMAT_NODN 0x26011966
2004-03-31 06:45:39 +00:00
2004-05-14 00:26:37 +00:00
/* use a portable integer format */
2004-12-02 10:14:40 +00:00
static void put_uint32 ( uint32 * p , int ofs , unsigned int val )
2004-05-14 00:26:37 +00:00
{
p + = ofs ;
p [ 0 ] = val & 0xFF ;
p [ 1 ] = ( val > > 8 ) & 0xFF ;
p [ 2 ] = ( val > > 16 ) & 0xFF ;
p [ 3 ] = ( val > > 24 ) & 0xFF ;
}
2004-12-02 10:14:40 +00:00
static unsigned int pull_uint32 ( uint32 * p , int ofs )
2004-05-14 00:26:37 +00:00
{
p + = ofs ;
return p [ 0 ] | ( p [ 1 ] < < 8 ) | ( p [ 2 ] < < 16 ) | ( p [ 3 ] < < 24 ) ;
}
2004-03-31 06:45:39 +00:00
/*
pack a ldb message into a linear buffer in a TDB_DATA
2004-04-03 12:29:21 +00:00
note that this routine avoids saving elements with zero values ,
as these are equivalent to having no element
2004-03-31 06:45:39 +00:00
caller frees the data buffer after use
*/
2004-11-16 09:00:52 +00:00
int ltdb_pack_data ( struct ldb_module * module ,
2004-03-31 06:45:39 +00:00
const struct ldb_message * message ,
struct TDB_DATA * data )
{
2004-11-16 09:00:52 +00:00
struct ldb_context * ldb = module - > ldb ;
2004-07-07 01:02:54 +00:00
unsigned int i , j , real_elements = 0 ;
2004-03-31 06:45:39 +00:00
size_t size ;
char * p ;
2004-05-01 09:45:56 +00:00
size_t len ;
2004-03-31 06:45:39 +00:00
2004-05-20 13:25:06 +00:00
for ( i = 0 ; i < message - > num_elements ; i + + ) {
if ( message - > elements [ i ] . num_values ! = 0 ) {
real_elements + + ;
}
}
2004-03-31 06:45:39 +00:00
/* work out how big it needs to be */
size = 8 ;
2004-05-01 09:45:56 +00:00
size + = 1 + strlen ( message - > dn ) ;
2004-03-31 06:45:39 +00:00
for ( i = 0 ; i < message - > num_elements ; i + + ) {
2004-04-03 12:29:21 +00:00
if ( message - > elements [ i ] . num_values = = 0 ) {
continue ;
}
size + = 1 + strlen ( message - > elements [ i ] . name ) + 4 ;
for ( j = 0 ; j < message - > elements [ i ] . num_values ; j + + ) {
size + = 4 + message - > elements [ i ] . values [ j ] . length + 1 ;
}
2004-03-31 06:45:39 +00:00
}
/* allocate it */
2004-05-06 04:40:15 +00:00
data - > dptr = ldb_malloc ( ldb , size ) ;
2004-03-31 06:45:39 +00:00
if ( ! data - > dptr ) {
errno = ENOMEM ;
return - 1 ;
}
data - > dsize = size ;
p = data - > dptr ;
2004-05-14 00:26:37 +00:00
put_uint32 ( p , 0 , LTDB_PACKING_FORMAT ) ;
2004-05-20 13:25:06 +00:00
put_uint32 ( p , 4 , real_elements ) ;
2004-03-31 06:45:39 +00:00
p + = 8 ;
2004-05-01 09:45:56 +00:00
/* the dn needs to be packed so we can be case preserving
while hashing on a case folded dn */
len = strlen ( message - > dn ) ;
memcpy ( p , message - > dn , len + 1 ) ;
p + = len + 1 ;
2004-03-31 06:45:39 +00:00
for ( i = 0 ; i < message - > num_elements ; i + + ) {
2004-04-03 12:29:21 +00:00
if ( message - > elements [ i ] . num_values = = 0 ) {
continue ;
}
len = strlen ( message - > elements [ i ] . name ) ;
2004-03-31 06:45:39 +00:00
memcpy ( p , message - > elements [ i ] . name , len + 1 ) ;
p + = len + 1 ;
2004-05-14 00:26:37 +00:00
put_uint32 ( p , 0 , message - > elements [ i ] . num_values ) ;
2004-04-03 12:29:21 +00:00
p + = 4 ;
for ( j = 0 ; j < message - > elements [ i ] . num_values ; j + + ) {
2004-05-14 00:26:37 +00:00
put_uint32 ( p , 0 , message - > elements [ i ] . values [ j ] . length ) ;
2004-04-03 12:29:21 +00:00
memcpy ( p + 4 , message - > elements [ i ] . values [ j ] . data ,
message - > elements [ i ] . values [ j ] . length ) ;
p [ 4 + message - > elements [ i ] . values [ j ] . length ] = 0 ;
p + = 4 + message - > elements [ i ] . values [ j ] . length + 1 ;
}
2004-03-31 06:45:39 +00:00
}
return 0 ;
}
2004-04-03 12:29:21 +00:00
/*
free the memory allocated from a ltdb_unpack_data ( )
*/
2004-11-16 09:00:52 +00:00
void ltdb_unpack_data_free ( struct ldb_module * module ,
2004-05-06 04:40:15 +00:00
struct ldb_message * message )
2004-04-03 12:29:21 +00:00
{
2004-11-16 09:00:52 +00:00
struct ldb_context * ldb = module - > ldb ;
2004-07-07 01:02:54 +00:00
unsigned int i ;
2004-04-03 12:29:21 +00:00
for ( i = 0 ; i < message - > num_elements ; i + + ) {
2004-05-06 04:40:15 +00:00
if ( message - > elements [ i ] . values ) ldb_free ( ldb , message - > elements [ i ] . values ) ;
2004-04-03 12:29:21 +00:00
}
2004-05-06 04:40:15 +00:00
if ( message - > elements ) ldb_free ( ldb , message - > elements ) ;
2004-04-03 12:29:21 +00:00
}
2004-03-31 06:45:39 +00:00
/*
unpack a ldb message from a linear buffer in TDB_DATA
note that this does not fill in the class and key elements
2004-04-03 12:29:21 +00:00
caller frees . Memory for the elements [ ] and values [ ] arrays are
malloced , but the memory for the elements is re - used from the
TDB_DATA data . This means the caller only has to free the elements
and values arrays . This can be done with ltdb_unpack_data_free ( )
2004-03-31 06:45:39 +00:00
*/
2004-11-16 09:00:52 +00:00
int ltdb_unpack_data ( struct ldb_module * module ,
2004-03-31 06:45:39 +00:00
const struct TDB_DATA * data ,
struct ldb_message * message )
{
2004-11-16 09:00:52 +00:00
struct ldb_context * ldb = module - > ldb ;
2004-03-31 06:45:39 +00:00
char * p ;
unsigned int remaining ;
2004-07-07 01:02:54 +00:00
unsigned int i , j ;
2004-05-01 09:45:56 +00:00
unsigned format ;
size_t len ;
2004-03-31 06:45:39 +00:00
message - > elements = NULL ;
p = data - > dptr ;
2004-05-01 09:45:56 +00:00
if ( data - > dsize < 8 ) {
2004-03-31 06:45:39 +00:00
errno = EIO ;
goto failed ;
}
2004-05-14 00:26:37 +00:00
format = pull_uint32 ( p , 0 ) ;
message - > num_elements = pull_uint32 ( p , 4 ) ;
2004-05-01 09:45:56 +00:00
p + = 8 ;
remaining = data - > dsize - 8 ;
switch ( format ) {
case LTDB_PACKING_FORMAT_NODN :
message - > dn = NULL ;
break ;
case LTDB_PACKING_FORMAT :
len = strnlen ( p , remaining ) ;
if ( len = = remaining ) {
errno = EIO ;
goto failed ;
}
message - > dn = p ;
remaining - = len + 1 ;
p + = len + 1 ;
break ;
default :
2004-03-31 06:45:39 +00:00
errno = EIO ;
goto failed ;
}
if ( message - > num_elements = = 0 ) {
message - > elements = NULL ;
return 0 ;
}
if ( message - > num_elements > remaining / 6 ) {
errno = EIO ;
goto failed ;
}
2004-05-06 04:40:15 +00:00
message - > elements = ldb_malloc_array_p ( ldb , struct ldb_message_element ,
message - > num_elements ) ;
2004-03-31 06:45:39 +00:00
if ( ! message - > elements ) {
errno = ENOMEM ;
goto failed ;
}
2004-05-20 13:25:06 +00:00
memset ( message - > elements , 0 ,
message - > num_elements * sizeof ( struct ldb_message_element ) ) ;
2004-03-31 06:45:39 +00:00
for ( i = 0 ; i < message - > num_elements ; i + + ) {
2004-04-03 12:29:21 +00:00
if ( remaining < 10 ) {
2004-03-31 06:45:39 +00:00
errno = EIO ;
goto failed ;
}
len = strnlen ( p , remaining - 6 ) ;
2004-05-01 09:45:56 +00:00
if ( len = = remaining - 6 ) {
errno = EIO ;
goto failed ;
}
2004-04-03 12:29:21 +00:00
message - > elements [ i ] . flags = 0 ;
2004-03-31 06:45:39 +00:00
message - > elements [ i ] . name = p ;
remaining - = len + 1 ;
p + = len + 1 ;
2004-05-14 00:26:37 +00:00
message - > elements [ i ] . num_values = pull_uint32 ( p , 0 ) ;
2004-04-03 12:29:21 +00:00
message - > elements [ i ] . values = NULL ;
if ( message - > elements [ i ] . num_values ! = 0 ) {
2004-05-06 04:40:15 +00:00
message - > elements [ i ] . values = ldb_malloc_array_p ( ldb ,
struct ldb_val ,
message - > elements [ i ] . num_values ) ;
2004-04-03 12:29:21 +00:00
if ( ! message - > elements [ i ] . values ) {
errno = ENOMEM ;
goto failed ;
}
}
p + = 4 ;
2004-05-20 13:25:06 +00:00
remaining - = 4 ;
2004-04-03 12:29:21 +00:00
for ( j = 0 ; j < message - > elements [ i ] . num_values ; j + + ) {
2004-05-14 00:26:37 +00:00
len = pull_uint32 ( p , 0 ) ;
2004-04-03 12:29:21 +00:00
if ( len > remaining - 5 ) {
errno = EIO ;
goto failed ;
}
message - > elements [ i ] . values [ j ] . length = len ;
message - > elements [ i ] . values [ j ] . data = p + 4 ;
remaining - = len + 4 + 1 ;
p + = len + 4 + 1 ;
2004-03-31 06:45:39 +00:00
}
}
2004-05-20 13:25:06 +00:00
if ( remaining ! = 0 ) {
ldb_debug ( ldb , LDB_DEBUG_ERROR ,
" Error: %d bytes unread in ltdb_unpack_data \n " , remaining ) ;
}
2004-03-31 06:45:39 +00:00
return 0 ;
failed :
2004-11-16 09:00:52 +00:00
ltdb_unpack_data_free ( module , message ) ;
2004-04-03 12:29:21 +00:00
2004-03-31 06:45:39 +00:00
return - 1 ;
}