2004-04-10 20:18:22 +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 message component utility functions
*
* Description : functions for manipulating ldb_message structures
*
* 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
2005-01-02 07:49:29 +00:00
/*
create a new ldb_message in a given memory context ( NULL for top level )
*/
struct ldb_message * ldb_msg_new ( void * mem_ctx )
{
2005-01-12 16:00:01 +00:00
return talloc_zero ( mem_ctx , struct ldb_message ) ;
2005-01-02 07:49:29 +00:00
}
2004-04-10 20:18:22 +00:00
/*
find an element in a message by attribute name
*/
struct ldb_message_element * ldb_msg_find_element ( const struct ldb_message * msg ,
const char * attr_name )
{
2004-07-07 01:02:54 +00:00
unsigned int i ;
2004-04-10 20:18:22 +00:00
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
2004-05-01 09:45:56 +00:00
if ( ldb_attr_cmp ( msg - > elements [ i ] . name , attr_name ) = = 0 ) {
2004-04-10 20:18:22 +00:00
return & msg - > elements [ i ] ;
}
}
return NULL ;
}
2004-05-01 09:45:56 +00:00
/*
see if two ldb_val structures contain exactly the same data
return 1 for a match , 0 for a mis - match
*/
int ldb_val_equal_exact ( const struct ldb_val * v1 , const struct ldb_val * v2 )
{
if ( v1 - > length ! = v2 - > length ) return 0 ;
if ( v1 - > length = = 0 ) return 1 ;
if ( memcmp ( v1 - > data , v2 - > data , v1 - > length ) = = 0 ) {
return 1 ;
}
return 0 ;
}
2004-04-10 20:18:22 +00:00
/*
find a value in an element
2004-05-01 09:45:56 +00:00
assumes case sensitive comparison
2004-04-10 20:18:22 +00:00
*/
struct ldb_val * ldb_msg_find_val ( const struct ldb_message_element * el ,
struct ldb_val * val )
{
2004-07-07 01:02:54 +00:00
unsigned int i ;
2004-04-10 20:18:22 +00:00
for ( i = 0 ; i < el - > num_values ; i + + ) {
2004-05-01 09:45:56 +00:00
if ( ldb_val_equal_exact ( val , & el - > values [ i ] ) ) {
2004-04-10 20:18:22 +00:00
return & el - > values [ i ] ;
}
}
return NULL ;
}
2004-11-16 09:00:52 +00:00
/*
duplicate a ldb_val structure
*/
2005-06-13 09:10:17 +00:00
struct ldb_val ldb_val_dup ( void * mem_ctx , const struct ldb_val * v )
2004-11-16 09:00:52 +00:00
{
struct ldb_val v2 ;
v2 . length = v - > length ;
2005-08-30 00:43:26 +00:00
if ( v - > data = = NULL ) {
2004-11-16 09:00:52 +00:00
v2 . data = NULL ;
return v2 ;
}
/* the +1 is to cope with buggy C library routines like strndup
that look one byte beyond */
2005-01-12 16:00:01 +00:00
v2 . data = talloc_array ( mem_ctx , char , v - > length + 1 ) ;
2004-11-16 09:00:52 +00:00
if ( ! v2 . data ) {
v2 . length = 0 ;
return v2 ;
}
memcpy ( v2 . data , v - > data , v - > length ) ;
( ( char * ) v2 . data ) [ v - > length ] = 0 ;
return v2 ;
}
2004-04-10 20:18:22 +00:00
/*
add an empty element to a message
*/
2004-05-06 04:40:15 +00:00
int ldb_msg_add_empty ( struct ldb_context * ldb ,
struct ldb_message * msg , const char * attr_name , int flags )
2004-04-10 20:18:22 +00:00
{
struct ldb_message_element * els ;
2005-01-12 16:00:01 +00:00
els = talloc_realloc ( msg , msg - > elements ,
2005-01-02 07:49:29 +00:00
struct ldb_message_element , msg - > num_elements + 1 ) ;
2004-04-10 20:18:22 +00:00
if ( ! els ) {
errno = ENOMEM ;
return - 1 ;
}
els [ msg - > num_elements ] . values = NULL ;
els [ msg - > num_elements ] . num_values = 0 ;
els [ msg - > num_elements ] . flags = flags ;
2005-01-02 07:49:29 +00:00
els [ msg - > num_elements ] . name = talloc_strdup ( els , attr_name ) ;
2004-04-10 20:18:22 +00:00
if ( ! els [ msg - > num_elements ] . name ) {
return - 1 ;
}
msg - > elements = els ;
msg - > num_elements + + ;
return 0 ;
}
/*
add an empty element to a message
*/
2004-05-06 04:40:15 +00:00
int ldb_msg_add ( struct ldb_context * ldb ,
struct ldb_message * msg ,
2004-04-10 20:18:22 +00:00
const struct ldb_message_element * el ,
int flags )
{
2004-05-06 04:40:15 +00:00
if ( ldb_msg_add_empty ( ldb , msg , el - > name , flags ) ! = 0 ) {
2004-04-10 20:18:22 +00:00
return - 1 ;
}
msg - > elements [ msg - > num_elements - 1 ] = * el ;
msg - > elements [ msg - > num_elements - 1 ] . flags = flags ;
return 0 ;
}
2004-05-07 23:54:41 +00:00
/*
add a value to a message
*/
int ldb_msg_add_value ( struct ldb_context * ldb ,
struct ldb_message * msg ,
2004-05-09 09:39:47 +00:00
const char * attr_name ,
2005-01-11 13:52:29 +00:00
const struct ldb_val * val )
2004-05-07 23:54:41 +00:00
{
struct ldb_message_element * el ;
struct ldb_val * vals ;
el = ldb_msg_find_element ( msg , attr_name ) ;
if ( ! el ) {
ldb_msg_add_empty ( ldb , msg , attr_name , 0 ) ;
el = ldb_msg_find_element ( msg , attr_name ) ;
}
if ( ! el ) {
return - 1 ;
}
2005-01-12 16:00:01 +00:00
vals = talloc_realloc ( msg , el - > values , struct ldb_val , el - > num_values + 1 ) ;
2004-05-07 23:54:41 +00:00
if ( ! vals ) {
errno = ENOMEM ;
return - 1 ;
}
el - > values = vals ;
el - > values [ el - > num_values ] = * val ;
el - > num_values + + ;
return 0 ;
}
/*
add a string element to a message
*/
int ldb_msg_add_string ( struct ldb_context * ldb , struct ldb_message * msg ,
2005-01-29 04:04:38 +00:00
const char * attr_name , const char * str )
2004-05-07 23:54:41 +00:00
{
struct ldb_val val ;
2005-01-29 04:04:38 +00:00
val . data = discard_const_p ( char , str ) ;
2004-05-07 23:54:41 +00:00
val . length = strlen ( str ) ;
return ldb_msg_add_value ( ldb , msg , attr_name , & val ) ;
}
2005-02-12 11:30:33 +00:00
/*
add a printf formatted element to a message
*/
int ldb_msg_add_fmt ( struct ldb_context * ldb , struct ldb_message * msg ,
const char * attr_name , const char * fmt , . . . )
{
struct ldb_val val ;
va_list ap ;
char * str ;
va_start ( ap , fmt ) ;
str = talloc_vasprintf ( msg , fmt , ap ) ;
va_end ( ap ) ;
if ( str = = NULL ) return - 1 ;
val . data = str ;
val . length = strlen ( str ) ;
return ldb_msg_add_value ( ldb , msg , attr_name , & val ) ;
}
2004-04-10 20:18:22 +00:00
/*
compare two ldb_message_element structures
2004-05-01 09:45:56 +00:00
assumes case senistive comparison
2004-04-10 20:18:22 +00:00
*/
int ldb_msg_element_compare ( struct ldb_message_element * el1 ,
struct ldb_message_element * el2 )
{
2004-07-07 01:02:54 +00:00
unsigned int i ;
2004-04-10 20:18:22 +00:00
if ( el1 - > num_values ! = el2 - > num_values ) {
return el1 - > num_values - el2 - > num_values ;
}
for ( i = 0 ; i < el1 - > num_values ; i + + ) {
if ( ! ldb_msg_find_val ( el2 , & el1 - > values [ i ] ) ) {
return - 1 ;
}
}
return 0 ;
}
2004-05-01 09:45:56 +00:00
2004-12-31 03:51:42 +00:00
/*
compare two ldb_message_element structures
comparing by element name
*/
int ldb_msg_element_compare_name ( struct ldb_message_element * el1 ,
struct ldb_message_element * el2 )
{
return ldb_attr_cmp ( el1 - > name , el2 - > name ) ;
}
2004-05-01 09:45:56 +00:00
/*
convenience functions to return common types from a message
these return the first value if the attribute is multi - valued
*/
2004-05-09 09:39:47 +00:00
const struct ldb_val * ldb_msg_find_ldb_val ( const struct ldb_message * msg , const char * attr_name )
{
struct ldb_message_element * el = ldb_msg_find_element ( msg , attr_name ) ;
if ( ! el | | el - > num_values = = 0 ) {
return NULL ;
}
return & el - > values [ 0 ] ;
}
2004-05-01 09:45:56 +00:00
int ldb_msg_find_int ( const struct ldb_message * msg ,
const char * attr_name ,
int default_value )
{
2004-05-09 09:39:47 +00:00
const struct ldb_val * v = ldb_msg_find_ldb_val ( msg , attr_name ) ;
if ( ! v | | ! v - > data ) {
2004-05-01 09:45:56 +00:00
return default_value ;
}
2004-05-09 09:39:47 +00:00
return strtol ( v - > data , NULL , 0 ) ;
2004-05-01 09:45:56 +00:00
}
unsigned int ldb_msg_find_uint ( const struct ldb_message * msg ,
const char * attr_name ,
2004-06-05 01:30:27 +00:00
unsigned int default_value )
2004-05-01 09:45:56 +00:00
{
2004-05-09 09:39:47 +00:00
const struct ldb_val * v = ldb_msg_find_ldb_val ( msg , attr_name ) ;
if ( ! v | | ! v - > data ) {
2004-05-01 09:45:56 +00:00
return default_value ;
}
2004-05-09 09:39:47 +00:00
return strtoul ( v - > data , NULL , 0 ) ;
2004-05-01 09:45:56 +00:00
}
2004-05-25 13:57:39 +00:00
int64_t ldb_msg_find_int64 ( const struct ldb_message * msg ,
const char * attr_name ,
int64_t default_value )
{
const struct ldb_val * v = ldb_msg_find_ldb_val ( msg , attr_name ) ;
if ( ! v | | ! v - > data ) {
return default_value ;
}
return strtoll ( v - > data , NULL , 0 ) ;
}
uint64_t ldb_msg_find_uint64 ( const struct ldb_message * msg ,
const char * attr_name ,
uint64_t default_value )
{
const struct ldb_val * v = ldb_msg_find_ldb_val ( msg , attr_name ) ;
if ( ! v | | ! v - > data ) {
return default_value ;
}
return strtoull ( v - > data , NULL , 0 ) ;
}
2004-05-01 09:45:56 +00:00
double ldb_msg_find_double ( const struct ldb_message * msg ,
const char * attr_name ,
double default_value )
{
2004-05-09 09:39:47 +00:00
const struct ldb_val * v = ldb_msg_find_ldb_val ( msg , attr_name ) ;
if ( ! v | | ! v - > data ) {
2004-05-01 09:45:56 +00:00
return default_value ;
}
2004-05-09 09:39:47 +00:00
return strtod ( v - > data , NULL ) ;
2004-05-01 09:45:56 +00:00
}
const char * ldb_msg_find_string ( const struct ldb_message * msg ,
const char * attr_name ,
const char * default_value )
{
2004-05-09 09:39:47 +00:00
const struct ldb_val * v = ldb_msg_find_ldb_val ( msg , attr_name ) ;
if ( ! v | | ! v - > data ) {
2004-05-01 09:45:56 +00:00
return default_value ;
}
2004-05-09 09:39:47 +00:00
return v - > data ;
2004-05-01 09:45:56 +00:00
}
2004-12-31 03:51:42 +00:00
/*
sort the elements of a message by name
*/
void ldb_msg_sort_elements ( struct ldb_message * msg )
{
qsort ( msg - > elements , msg - > num_elements , sizeof ( struct ldb_message_element ) ,
( comparison_fn_t ) ldb_msg_element_compare_name ) ;
}
/*
copy a message , allocating new memory for all parts
*/
2005-08-18 15:02:01 +00:00
struct ldb_message * ldb_msg_copy ( TALLOC_CTX * mem_ctx ,
2004-12-31 03:51:42 +00:00
const struct ldb_message * msg )
{
struct ldb_message * msg2 ;
int i , j ;
2005-08-18 15:02:01 +00:00
msg2 = talloc ( mem_ctx , struct ldb_message ) ;
2004-12-31 03:51:42 +00:00
if ( msg2 = = NULL ) return NULL ;
msg2 - > elements = NULL ;
msg2 - > num_elements = 0 ;
msg2 - > private_data = NULL ;
2005-08-18 15:02:01 +00:00
msg2 - > dn = ldb_dn_copy ( msg2 , msg - > dn ) ;
2004-12-31 03:51:42 +00:00
if ( msg2 - > dn = = NULL ) goto failed ;
2005-01-12 16:00:01 +00:00
msg2 - > elements = talloc_array ( msg2 , struct ldb_message_element , msg - > num_elements ) ;
2004-12-31 03:51:42 +00:00
if ( msg2 - > elements = = NULL ) goto failed ;
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
struct ldb_message_element * el1 = & msg - > elements [ i ] ;
struct ldb_message_element * el2 = & msg2 - > elements [ i ] ;
el2 - > flags = el1 - > flags ;
el2 - > num_values = 0 ;
el2 - > values = NULL ;
2005-01-02 07:49:29 +00:00
el2 - > name = talloc_strdup ( msg2 - > elements , el1 - > name ) ;
2004-12-31 03:51:42 +00:00
if ( el2 - > name = = NULL ) goto failed ;
2005-01-12 16:00:01 +00:00
el2 - > values = talloc_array ( msg2 - > elements , struct ldb_val , el1 - > num_values ) ;
2004-12-31 03:51:42 +00:00
for ( j = 0 ; j < el1 - > num_values ; j + + ) {
2005-08-18 15:02:01 +00:00
el2 - > values [ j ] = ldb_val_dup ( el2 - > values , & el1 - > values [ j ] ) ;
2004-12-31 03:51:42 +00:00
if ( el2 - > values [ j ] . data = = NULL & &
el1 - > values [ j ] . length ! = 0 ) {
goto failed ;
}
el2 - > num_values + + ;
}
msg2 - > num_elements + + ;
}
return msg2 ;
failed :
2005-01-02 07:49:29 +00:00
talloc_free ( msg2 ) ;
2004-12-31 03:51:42 +00:00
return NULL ;
}
/*
canonicalise a message , merging elements of the same name
*/
struct ldb_message * ldb_msg_canonicalize ( struct ldb_context * ldb ,
const struct ldb_message * msg )
{
int i ;
struct ldb_message * msg2 ;
msg2 = ldb_msg_copy ( ldb , msg ) ;
if ( msg2 = = NULL ) return NULL ;
ldb_msg_sort_elements ( msg2 ) ;
for ( i = 1 ; i < msg2 - > num_elements ; i + + ) {
struct ldb_message_element * el1 = & msg2 - > elements [ i - 1 ] ;
struct ldb_message_element * el2 = & msg2 - > elements [ i ] ;
if ( ldb_msg_element_compare_name ( el1 , el2 ) = = 0 ) {
2005-01-12 16:00:01 +00:00
el1 - > values = talloc_realloc ( msg2 - > elements , el1 - > values , struct ldb_val ,
2005-01-02 07:49:29 +00:00
el1 - > num_values + el2 - > num_values ) ;
2004-12-31 03:51:42 +00:00
if ( el1 - > values = = NULL ) {
return NULL ;
}
memcpy ( el1 - > values + el1 - > num_values ,
el2 - > values ,
sizeof ( struct ldb_val ) * el2 - > num_values ) ;
el1 - > num_values + = el2 - > num_values ;
2005-06-15 02:45:11 +00:00
talloc_free ( discard_const_p ( char , el2 - > name ) ) ;
2004-12-31 03:51:42 +00:00
if ( i + 1 < msg2 - > num_elements ) {
memmove ( el2 , el2 + 1 , sizeof ( struct ldb_message_element ) *
( msg2 - > num_elements - ( i + 1 ) ) ) ;
}
msg2 - > num_elements - - ;
i - - ;
}
}
return msg2 ;
}
2005-05-16 22:31:45 +00:00
/*
return a ldb_message representing the differences between msg1 and msg2 . If you
then use this in a ldb_modify ( ) call it can be used to save edits to a message
*/
struct ldb_message * ldb_msg_diff ( struct ldb_context * ldb ,
struct ldb_message * msg1 ,
struct ldb_message * msg2 )
{
struct ldb_message * mod ;
struct ldb_message_element * el ;
unsigned int i ;
mod = ldb_msg_new ( ldb ) ;
mod - > dn = msg1 - > dn ;
mod - > num_elements = 0 ;
mod - > elements = NULL ;
msg2 = ldb_msg_canonicalize ( ldb , msg2 ) ;
if ( msg2 = = NULL ) {
return NULL ;
}
/* look in msg2 to find elements that need to be added
or modified */
for ( i = 0 ; i < msg2 - > num_elements ; i + + ) {
el = ldb_msg_find_element ( msg1 , msg2 - > elements [ i ] . name ) ;
if ( el & & ldb_msg_element_compare ( el , & msg2 - > elements [ i ] ) = = 0 ) {
continue ;
}
if ( ldb_msg_add ( ldb , mod ,
& msg2 - > elements [ i ] ,
el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD ) ! = 0 ) {
return NULL ;
}
}
/* look in msg1 to find elements that need to be deleted */
for ( i = 0 ; i < msg1 - > num_elements ; i + + ) {
el = ldb_msg_find_element ( msg2 , msg1 - > elements [ i ] . name ) ;
if ( ! el ) {
if ( ldb_msg_add_empty ( ldb , mod ,
msg1 - > elements [ i ] . name ,
LDB_FLAG_MOD_DELETE ) ! = 0 ) {
return NULL ;
}
}
}
return mod ;
}