2004-03-31 10:45:39 +04:00
/*
ldb database library
Copyright ( C ) Andrew Tridgell 2004
2004-10-20 23:28:02 +04:00
Copyright ( C ) Stefan Metzmacher 2004
2004-03-31 10:45:39 +04:00
* * 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 tdb backend
*
* Description : core functions for tdb backend
*
* Author : Andrew Tridgell
2004-10-20 23:28:02 +04:00
* Author : Stefan Metzmacher
2004-03-31 10:45:39 +04:00
*/
# include "includes.h"
2004-11-16 12:00:52 +03:00
# include "ldb/include/ldb.h"
# include "ldb/include/ldb_private.h"
2004-04-11 00:18:22 +04:00
# include "ldb/ldb_tdb/ldb_tdb.h"
2004-03-31 10:45:39 +04:00
2004-11-21 18:51:54 +03:00
# define LDBLOCK "INT_LDBLOCK"
2005-02-13 15:27:57 +03:00
/*
2005-06-04 21:13:43 +04:00
callback function used in call to ldb_dn_fold ( ) for determining whether an
attribute type requires case folding .
2005-02-13 15:27:57 +03:00
*/
2005-06-15 06:43:42 +04:00
static int ltdb_case_fold_attr_required ( void * user_data , char * attr )
2005-02-13 15:27:57 +03:00
{
2005-06-15 06:43:42 +04:00
struct ldb_module * module = user_data ;
2005-06-04 21:13:43 +04:00
return ltdb_attribute_flags ( module , attr ) & LTDB_FLAG_CASE_INSENSITIVE ;
2005-02-13 15:27:57 +03:00
}
2004-03-31 10:45:39 +04:00
/*
form a TDB_DATA for a record key
caller frees
2004-05-01 13:45:56 +04:00
note that the key for a record can depend on whether the
dn refers to a case sensitive index record or not
2004-03-31 10:45:39 +04:00
*/
2004-11-15 14:40:27 +03:00
struct TDB_DATA ltdb_key ( struct ldb_module * module , const char * dn )
2004-03-31 10:45:39 +04:00
{
2004-11-15 14:40:27 +03:00
struct ldb_context * ldb = module - > ldb ;
2004-03-31 10:45:39 +04:00
TDB_DATA key ;
char * key_str = NULL ;
2004-05-01 13:45:56 +04:00
char * dn_folded = NULL ;
const char * prefix = LTDB_INDEX " : " ;
const char * s ;
int flags ;
/*
most DNs are case insensitive . The exception is index DNs for
case sensitive attributes
2004-05-04 09:58:22 +04:00
there are 3 cases dealt with in this code :
2005-02-13 15:27:57 +03:00
1 ) if the dn doesn ' t start with @ INDEX : then uppercase the attribute
names and the attributes values of case insensitive attributes
2004-05-04 09:58:22 +04:00
2 ) if the dn starts with @ INDEX : attr and ' attr ' is a case insensitive
attribute then uppercase whole dn
3 ) if the dn starts with @ INDEX : attr and ' attr ' is a case sensitive
attribute then uppercase up to the value of the attribute , but
not the value itself
2004-05-01 13:45:56 +04:00
*/
if ( strncmp ( dn , prefix , strlen ( prefix ) ) = = 0 & &
( s = strchr ( dn + strlen ( prefix ) , ' : ' ) ) ) {
char * attr_name , * attr_name_folded ;
2005-01-02 10:49:29 +03:00
attr_name = talloc_strndup ( ldb , dn + strlen ( prefix ) , ( s - ( dn + strlen ( prefix ) ) ) ) ;
2004-05-01 13:45:56 +04:00
if ( ! attr_name ) {
goto failed ;
}
2004-11-15 14:40:27 +03:00
flags = ltdb_attribute_flags ( module , attr_name ) ;
2004-05-01 13:45:56 +04:00
if ( flags & LTDB_FLAG_CASE_INSENSITIVE ) {
2004-05-06 08:40:15 +04:00
dn_folded = ldb_casefold ( ldb , dn ) ;
2004-05-01 13:45:56 +04:00
} else {
2004-05-06 08:40:15 +04:00
attr_name_folded = ldb_casefold ( ldb , attr_name ) ;
2004-05-01 13:45:56 +04:00
if ( ! attr_name_folded ) {
goto failed ;
}
2005-01-02 10:49:29 +03:00
dn_folded = talloc_asprintf ( ldb , " %s:%s:%s " ,
prefix , attr_name_folded ,
s + 1 ) ;
talloc_free ( attr_name_folded ) ;
2004-05-01 13:45:56 +04:00
}
2005-01-02 10:49:29 +03:00
talloc_free ( attr_name ) ;
2004-05-01 13:45:56 +04:00
} else {
2005-06-15 06:43:42 +04:00
dn_folded = ldb_dn_fold ( module - > ldb , dn ,
module , ltdb_case_fold_attr_required ) ;
2004-05-01 13:45:56 +04:00
}
if ( ! dn_folded ) {
goto failed ;
}
2005-01-02 10:49:29 +03:00
key_str = talloc_asprintf ( ldb , " DN=%s " , dn_folded ) ;
talloc_free ( dn_folded ) ;
2004-03-31 10:45:39 +04:00
if ( ! key_str ) {
2004-05-01 13:45:56 +04:00
goto failed ;
2004-03-31 10:45:39 +04:00
}
key . dptr = key_str ;
key . dsize = strlen ( key_str ) + 1 ;
return key ;
2004-05-01 13:45:56 +04:00
failed :
errno = ENOMEM ;
key . dptr = NULL ;
key . dsize = 0 ;
return key ;
2004-03-31 10:45:39 +04:00
}
2004-04-03 16:29:21 +04:00
/*
lock the database for write - currently a single lock is used
*/
2004-11-21 18:51:54 +03:00
static int ltdb_lock ( struct ldb_module * module , const char * lockname )
2004-04-03 16:29:21 +04:00
{
2004-11-15 14:40:27 +03:00
struct ltdb_private * ltdb = module - > private_data ;
2004-04-03 16:29:21 +04:00
TDB_DATA key ;
int ret ;
2004-11-21 18:51:54 +03:00
if ( lockname = = NULL ) {
return - 1 ;
}
key = ltdb_key ( module , lockname ) ;
2004-04-03 16:29:21 +04:00
if ( ! key . dptr ) {
return - 1 ;
}
ret = tdb_chainlock ( ltdb - > tdb , key ) ;
2005-01-02 10:49:29 +03:00
talloc_free ( key . dptr ) ;
2004-04-03 16:29:21 +04:00
return ret ;
}
/*
unlock the database after a ltdb_lock ( )
*/
2004-11-21 18:51:54 +03:00
static int ltdb_unlock ( struct ldb_module * module , const char * lockname )
2004-04-03 16:29:21 +04:00
{
2004-11-15 14:40:27 +03:00
struct ltdb_private * ltdb = module - > private_data ;
2004-04-03 16:29:21 +04:00
TDB_DATA key ;
2004-11-21 18:51:54 +03:00
if ( lockname = = NULL ) {
return - 1 ;
}
key = ltdb_key ( module , lockname ) ;
2004-04-03 16:29:21 +04:00
if ( ! key . dptr ) {
2004-11-21 18:51:54 +03:00
return - 1 ;
2004-04-03 16:29:21 +04:00
}
tdb_chainunlock ( ltdb - > tdb , key ) ;
2005-01-02 10:49:29 +03:00
talloc_free ( key . dptr ) ;
2004-11-21 18:51:54 +03:00
return 0 ;
2004-04-03 16:29:21 +04:00
}
2004-03-31 10:45:39 +04:00
2004-05-01 13:45:56 +04:00
2005-05-01 16:34:12 +04:00
/*
lock the database for read - use by ltdb_search
*/
int ltdb_lock_read ( struct ldb_module * module )
{
struct ltdb_private * ltdb = module - > private_data ;
TDB_DATA key ;
int ret ;
key = ltdb_key ( module , LDBLOCK ) ;
if ( ! key . dptr ) {
return - 1 ;
}
ret = tdb_chainlock_read ( ltdb - > tdb , key ) ;
talloc_free ( key . dptr ) ;
return ret ;
}
/*
unlock the database after a ltdb_lock_read ( )
*/
int ltdb_unlock_read ( struct ldb_module * module )
{
struct ltdb_private * ltdb = module - > private_data ;
TDB_DATA key ;
key = ltdb_key ( module , LDBLOCK ) ;
if ( ! key . dptr ) {
return - 1 ;
}
tdb_chainunlock_read ( ltdb - > tdb , key ) ;
talloc_free ( key . dptr ) ;
return 0 ;
}
2005-05-18 01:43:47 +04:00
/*
check special dn ' s have valid attributes
currently only @ ATTRIBUTES is checked
*/
int ltdb_check_special_dn ( struct ldb_module * module , const struct ldb_message * msg )
{
struct ltdb_private * ltdb = module - > private_data ;
int i , j ;
if ( strcmp ( msg - > dn , LTDB_ATTRIBUTES ) ! = 0 ) {
return 0 ;
}
/* we have @ATTRIBUTES, let's check attributes are fine */
/* should we check that we deny multivalued attributes ? */
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
for ( j = 0 ; j < msg - > elements [ i ] . num_values ; j + + ) {
if ( ltdb_check_at_attributes_values ( & msg - > elements [ i ] . values [ j ] ) ! = 0 ) {
ltdb - > last_err_string = " Invalid attribute value in an @ATTRIBUTES entry " ;
return - 1 ;
}
}
}
return 0 ;
}
2005-05-01 16:34:12 +04:00
2004-05-01 13:45:56 +04:00
/*
we ' ve made a modification to a dn - possibly reindex and
update sequence number
*/
2004-11-15 14:40:27 +03:00
static int ltdb_modified ( struct ldb_module * module , const char * dn )
2004-05-01 13:45:56 +04:00
{
int ret = 0 ;
if ( strcmp ( dn , LTDB_INDEXLIST ) = = 0 | |
strcmp ( dn , LTDB_ATTRIBUTES ) = = 0 ) {
2004-11-15 14:40:27 +03:00
ret = ltdb_reindex ( module ) ;
2004-05-01 13:45:56 +04:00
}
if ( ret = = 0 & &
strcmp ( dn , LTDB_BASEINFO ) ! = 0 ) {
2004-11-15 14:40:27 +03:00
ret = ltdb_increase_sequence_number ( module ) ;
2004-05-01 13:45:56 +04:00
}
return ret ;
}
2004-03-31 10:45:39 +04:00
/*
store a record into the db
*/
2004-11-15 14:40:27 +03:00
int ltdb_store ( struct ldb_module * module , const struct ldb_message * msg , int flgs )
2004-03-31 10:45:39 +04:00
{
2004-11-15 14:40:27 +03:00
struct ltdb_private * ltdb = module - > private_data ;
2004-03-31 10:45:39 +04:00
TDB_DATA tdb_key , tdb_data ;
int ret ;
2004-11-15 14:40:27 +03:00
tdb_key = ltdb_key ( module , msg - > dn ) ;
2004-03-31 10:45:39 +04:00
if ( ! tdb_key . dptr ) {
return - 1 ;
}
2004-11-16 12:00:52 +03:00
ret = ltdb_pack_data ( module , msg , & tdb_data ) ;
2004-03-31 10:45:39 +04:00
if ( ret = = - 1 ) {
2005-01-02 10:49:29 +03:00
talloc_free ( tdb_key . dptr ) ;
2004-03-31 10:45:39 +04:00
return - 1 ;
}
ret = tdb_store ( ltdb - > tdb , tdb_key , tdb_data , flgs ) ;
if ( ret = = - 1 ) {
goto done ;
}
2004-11-15 14:40:27 +03:00
ret = ltdb_index_add ( module , msg ) ;
2004-03-31 10:45:39 +04:00
if ( ret = = - 1 ) {
tdb_delete ( ltdb - > tdb , tdb_key ) ;
}
done :
2005-01-02 10:49:29 +03:00
talloc_free ( tdb_key . dptr ) ;
talloc_free ( tdb_data . dptr ) ;
2004-03-31 10:45:39 +04:00
return ret ;
}
/*
add a record to the database
*/
2004-11-15 14:40:27 +03:00
static int ltdb_add ( struct ldb_module * module , const struct ldb_message * msg )
2004-03-31 10:45:39 +04:00
{
2004-11-15 14:40:27 +03:00
struct ltdb_private * ltdb = module - > private_data ;
2004-04-03 16:29:21 +04:00
int ret ;
2004-05-06 08:40:15 +04:00
ltdb - > last_err_string = NULL ;
2005-05-18 01:43:47 +04:00
ret = ltdb_check_special_dn ( module , msg ) ;
if ( ret ! = 0 ) {
return ret ;
}
2004-11-21 18:51:54 +03:00
if ( ltdb_lock ( module , LDBLOCK ) ! = 0 ) {
2004-04-03 16:29:21 +04:00
return - 1 ;
}
2004-05-01 13:45:56 +04:00
2004-11-15 14:40:27 +03:00
if ( ltdb_cache_load ( module ) ! = 0 ) {
2004-11-21 18:51:54 +03:00
ltdb_unlock ( module , LDBLOCK ) ;
2004-05-01 13:45:56 +04:00
return - 1 ;
}
2005-05-18 01:43:47 +04:00
2004-11-15 14:40:27 +03:00
ret = ltdb_store ( module , msg , TDB_INSERT ) ;
2004-04-03 16:29:21 +04:00
2004-05-01 13:45:56 +04:00
if ( ret = = 0 ) {
2004-11-15 14:40:27 +03:00
ltdb_modified ( module , msg - > dn ) ;
2004-04-23 17:05:27 +04:00
}
2004-11-21 18:51:54 +03:00
ltdb_unlock ( module , LDBLOCK ) ;
2004-04-03 16:29:21 +04:00
return ret ;
2004-03-31 10:45:39 +04:00
}
/*
delete a record from the database , not updating indexes ( used for deleting
index records )
*/
2004-11-15 14:40:27 +03:00
int ltdb_delete_noindex ( struct ldb_module * module , const char * dn )
2004-03-31 10:45:39 +04:00
{
2004-11-15 14:40:27 +03:00
struct ltdb_private * ltdb = module - > private_data ;
2004-03-31 10:45:39 +04:00
TDB_DATA tdb_key ;
int ret ;
2004-11-15 14:40:27 +03:00
tdb_key = ltdb_key ( module , dn ) ;
2004-03-31 10:45:39 +04:00
if ( ! tdb_key . dptr ) {
return - 1 ;
}
ret = tdb_delete ( ltdb - > tdb , tdb_key ) ;
2005-01-02 10:49:29 +03:00
talloc_free ( tdb_key . dptr ) ;
2004-03-31 10:45:39 +04:00
return ret ;
}
/*
delete a record from the database
*/
2004-11-15 14:40:27 +03:00
static int ltdb_delete ( struct ldb_module * module , const char * dn )
2004-03-31 10:45:39 +04:00
{
2004-11-15 14:40:27 +03:00
struct ltdb_private * ltdb = module - > private_data ;
2004-03-31 10:45:39 +04:00
int ret ;
2005-01-02 10:49:29 +03:00
struct ldb_message * msg = NULL ;
2004-03-31 10:45:39 +04:00
2004-05-06 08:40:15 +04:00
ltdb - > last_err_string = NULL ;
2004-11-21 18:51:54 +03:00
if ( ltdb_lock ( module , LDBLOCK ) ! = 0 ) {
2004-04-03 16:29:21 +04:00
return - 1 ;
}
2004-11-15 14:40:27 +03:00
if ( ltdb_cache_load ( module ) ! = 0 ) {
2005-01-02 10:49:29 +03:00
goto failed ;
}
2005-01-12 19:00:01 +03:00
msg = talloc ( module , struct ldb_message ) ;
2005-01-02 10:49:29 +03:00
if ( msg = = NULL ) {
goto failed ;
2004-05-01 13:45:56 +04:00
}
2004-03-31 10:45:39 +04:00
/* in case any attribute of the message was indexed, we need
to fetch the old record */
2005-01-02 10:49:29 +03:00
ret = ltdb_search_dn1 ( module , dn , msg ) ;
2004-03-31 10:45:39 +04:00
if ( ret ! = 1 ) {
/* not finding the old record is an error */
2004-04-03 16:29:21 +04:00
goto failed ;
2004-03-31 10:45:39 +04:00
}
2004-11-15 14:40:27 +03:00
ret = ltdb_delete_noindex ( module , dn ) ;
2004-03-31 10:45:39 +04:00
if ( ret = = - 1 ) {
2004-04-03 16:29:21 +04:00
goto failed ;
2004-03-31 10:45:39 +04:00
}
/* remove any indexed attributes */
2005-01-02 10:49:29 +03:00
ret = ltdb_index_del ( module , msg ) ;
2004-03-31 10:45:39 +04:00
2004-05-01 13:45:56 +04:00
if ( ret = = 0 ) {
2004-11-15 14:40:27 +03:00
ltdb_modified ( module , dn ) ;
2004-04-23 17:05:27 +04:00
}
2005-01-02 10:49:29 +03:00
talloc_free ( msg ) ;
2004-11-21 18:51:54 +03:00
ltdb_unlock ( module , LDBLOCK ) ;
2004-03-31 10:45:39 +04:00
return ret ;
2004-04-03 16:29:21 +04:00
failed :
2005-01-02 10:49:29 +03:00
talloc_free ( msg ) ;
2004-11-21 18:51:54 +03:00
ltdb_unlock ( module , LDBLOCK ) ;
2004-04-03 16:29:21 +04:00
return - 1 ;
}
/*
find an element by attribute name . At the moment this does a linear search , it should
be re - coded to use a binary search once all places that modify records guarantee
sorted order
return the index of the first matching element if found , otherwise - 1
*/
static int find_element ( const struct ldb_message * msg , const char * name )
{
2004-07-07 05:02:54 +04:00
unsigned int i ;
2004-04-03 16:29:21 +04:00
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
2004-05-01 13:45:56 +04:00
if ( ldb_attr_cmp ( msg - > elements [ i ] . name , name ) = = 0 ) {
2004-04-03 16:29:21 +04:00
return i ;
}
}
return - 1 ;
}
/*
add an element to an existing record . Assumes a elements array that we
can call re - alloc on , and assumed that we can re - use the data pointers from the
passed in additional values . Use with care !
returns 0 on success , - 1 on failure ( and sets errno )
*/
2004-05-06 08:40:15 +04:00
static int msg_add_element ( struct ldb_context * ldb ,
struct ldb_message * msg , struct ldb_message_element * el )
2004-04-03 16:29:21 +04:00
{
struct ldb_message_element * e2 ;
2004-07-07 05:02:54 +04:00
unsigned int i ;
2004-04-03 16:29:21 +04:00
2005-01-12 19:00:01 +03:00
e2 = talloc_realloc ( msg , msg - > elements , struct ldb_message_element ,
2005-01-02 10:49:29 +03:00
msg - > num_elements + 1 ) ;
2004-04-03 16:29:21 +04:00
if ( ! e2 ) {
errno = ENOMEM ;
return - 1 ;
}
msg - > elements = e2 ;
e2 = & msg - > elements [ msg - > num_elements ] ;
e2 - > name = el - > name ;
e2 - > flags = el - > flags ;
e2 - > values = NULL ;
if ( el - > num_values ! = 0 ) {
2005-01-12 19:00:01 +03:00
e2 - > values = talloc_array ( msg - > elements , struct ldb_val , el - > num_values ) ;
2004-04-03 16:29:21 +04:00
if ( ! e2 - > values ) {
errno = ENOMEM ;
return - 1 ;
}
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
e2 - > values [ i ] = el - > values [ i ] ;
}
e2 - > num_values = el - > num_values ;
msg - > num_elements + + ;
return 0 ;
}
/*
delete all elements having a specified attribute name
*/
2004-12-19 13:56:29 +03:00
static int msg_delete_attribute ( struct ldb_module * module ,
struct ldb_context * ldb ,
2004-05-06 08:40:15 +04:00
struct ldb_message * msg , const char * name )
2004-04-03 16:29:21 +04:00
{
2005-01-02 10:49:29 +03:00
unsigned int i , j ;
2004-04-03 16:29:21 +04:00
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
2005-01-02 10:49:29 +03:00
if ( ldb_attr_cmp ( msg - > elements [ i ] . name , name ) = = 0 ) {
2004-12-19 13:56:29 +03:00
for ( j = 0 ; j < msg - > elements [ i ] . num_values ; j + + ) {
ltdb_index_del_value ( module , msg - > dn , & msg - > elements [ i ] , j ) ;
}
2005-01-02 10:49:29 +03:00
talloc_free ( msg - > elements [ i ] . values ) ;
if ( msg - > num_elements > ( i + 1 ) ) {
memmove ( & msg - > elements [ i ] ,
& msg - > elements [ i + 1 ] ,
sizeof ( struct ldb_message_element ) *
( msg - > num_elements - ( i + 1 ) ) ) ;
}
msg - > num_elements - - ;
i - - ;
2005-01-12 19:00:01 +03:00
msg - > elements = talloc_realloc ( msg , msg - > elements ,
2005-01-02 10:49:29 +03:00
struct ldb_message_element ,
msg - > num_elements ) ;
2004-04-03 16:29:21 +04:00
}
}
return 0 ;
2004-03-31 10:45:39 +04:00
}
2004-04-03 16:29:21 +04:00
/*
delete all elements matching an attribute name / value
return 0 on success , - 1 on failure
*/
2004-11-15 14:40:27 +03:00
static int msg_delete_element ( struct ldb_module * module ,
2004-05-01 13:45:56 +04:00
struct ldb_message * msg ,
2004-04-03 16:29:21 +04:00
const char * name ,
const struct ldb_val * val )
{
2004-11-15 14:40:27 +03:00
struct ldb_context * ldb = module - > ldb ;
2004-07-07 05:02:54 +04:00
unsigned int i ;
int found ;
2004-04-03 16:29:21 +04:00
struct ldb_message_element * el ;
2004-07-07 05:02:54 +04:00
found = find_element ( msg , name ) ;
if ( found = = - 1 ) {
2004-04-03 16:29:21 +04:00
return - 1 ;
}
2004-07-07 05:02:54 +04:00
el = & msg - > elements [ found ] ;
2004-04-03 16:29:21 +04:00
for ( i = 0 ; i < el - > num_values ; i + + ) {
2004-11-16 12:00:52 +03:00
if ( ltdb_val_equal ( module , msg - > elements [ i ] . name , & el - > values [ i ] , val ) ) {
2004-04-03 16:29:21 +04:00
if ( i < el - > num_values - 1 ) {
memmove ( & el - > values [ i ] , & el - > values [ i + 1 ] ,
2004-05-06 08:40:15 +04:00
sizeof ( el - > values [ i ] ) * ( el - > num_values - ( i + 1 ) ) ) ;
2004-04-03 16:29:21 +04:00
}
el - > num_values - - ;
2004-05-08 03:54:41 +04:00
if ( el - > num_values = = 0 ) {
2004-12-19 13:56:29 +03:00
return msg_delete_attribute ( module , ldb , msg , name ) ;
2004-05-08 03:54:41 +04:00
}
2004-04-03 16:29:21 +04:00
return 0 ;
}
}
2004-05-08 03:54:41 +04:00
2004-04-03 16:29:21 +04:00
return - 1 ;
}
2004-03-31 10:45:39 +04:00
2004-05-01 13:45:56 +04:00
2004-03-31 10:45:39 +04:00
/*
2004-05-01 13:45:56 +04:00
modify a record - internal interface
2004-04-03 16:29:21 +04:00
yuck - this is O ( n ^ 2 ) . Luckily n is usually small so we probably
get away with it , but if we ever have really large attribute lists
then we ' ll need to look at this again
2004-03-31 10:45:39 +04:00
*/
2004-11-15 14:40:27 +03:00
int ltdb_modify_internal ( struct ldb_module * module , const struct ldb_message * msg )
2004-03-31 10:45:39 +04:00
{
2004-11-15 14:40:27 +03:00
struct ldb_context * ldb = module - > ldb ;
struct ltdb_private * ltdb = module - > private_data ;
2004-03-31 10:45:39 +04:00
TDB_DATA tdb_key , tdb_data ;
2005-01-02 10:49:29 +03:00
struct ldb_message * msg2 ;
2004-07-07 05:02:54 +04:00
unsigned i , j ;
int ret ;
2004-04-03 16:29:21 +04:00
2004-11-15 14:40:27 +03:00
tdb_key = ltdb_key ( module , msg - > dn ) ;
2004-03-31 10:45:39 +04:00
if ( ! tdb_key . dptr ) {
2004-05-01 13:45:56 +04:00
return - 1 ;
2004-03-31 10:45:39 +04:00
}
tdb_data = tdb_fetch ( ltdb - > tdb , tdb_key ) ;
if ( ! tdb_data . dptr ) {
2005-01-02 10:49:29 +03:00
talloc_free ( tdb_key . dptr ) ;
return - 1 ;
}
2005-01-12 19:00:01 +03:00
msg2 = talloc ( tdb_key . dptr , struct ldb_message ) ;
2005-01-02 10:49:29 +03:00
if ( msg2 = = NULL ) {
talloc_free ( tdb_key . dptr ) ;
2004-05-01 13:45:56 +04:00
return - 1 ;
2004-03-31 10:45:39 +04:00
}
2005-01-02 10:49:29 +03:00
ret = ltdb_unpack_data ( module , & tdb_data , msg2 ) ;
2004-03-31 10:45:39 +04:00
if ( ret = = - 1 ) {
2005-01-02 10:49:29 +03:00
talloc_free ( tdb_key . dptr ) ;
2004-03-31 10:45:39 +04:00
free ( tdb_data . dptr ) ;
2004-05-01 13:45:56 +04:00
return - 1 ;
2004-03-31 10:45:39 +04:00
}
2005-01-02 10:49:29 +03:00
if ( ! msg2 - > dn ) {
msg2 - > dn = msg - > dn ;
2004-05-01 13:45:56 +04:00
}
2004-04-03 16:29:21 +04:00
2004-03-31 10:45:39 +04:00
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
2004-12-26 20:30:27 +03:00
struct ldb_message_element * el = & msg - > elements [ i ] ;
struct ldb_message_element * el2 ;
struct ldb_val * vals ;
2004-03-31 10:45:39 +04:00
switch ( msg - > elements [ i ] . flags & LDB_FLAG_MOD_MASK ) {
2004-04-03 16:29:21 +04:00
2004-03-31 10:45:39 +04:00
case LDB_FLAG_MOD_ADD :
2004-04-03 16:29:21 +04:00
/* add this element to the message. fail if it
already exists */
2005-01-02 10:49:29 +03:00
ret = find_element ( msg2 , el - > name ) ;
2004-12-26 20:30:27 +03:00
if ( ret = = - 1 ) {
2005-01-02 10:49:29 +03:00
if ( msg_add_element ( ldb , msg2 , el ) ! = 0 ) {
2004-12-26 20:30:27 +03:00
goto failed ;
}
continue ;
}
2005-01-02 10:49:29 +03:00
el2 = & msg2 - > elements [ ret ] ;
2004-12-26 20:30:27 +03:00
/* An attribute with this name already exists, add all
* values if they don ' t already exist . */
for ( j = 0 ; j < el - > num_values ; j + + ) {
if ( ldb_msg_find_val ( el2 , & el - > values [ j ] ) ) {
ltdb - > last_err_string =
" Type or value exists " ;
goto failed ;
2004-12-06 09:45:51 +03:00
}
2004-03-31 10:45:39 +04:00
}
2004-12-26 20:30:27 +03:00
2005-01-12 19:00:01 +03:00
vals = talloc_realloc ( msg2 - > elements , el2 - > values , struct ldb_val ,
2005-01-02 10:49:29 +03:00
el2 - > num_values + el - > num_values ) ;
2004-12-26 20:30:27 +03:00
if ( vals = = NULL )
2004-04-03 16:29:21 +04:00
goto failed ;
2004-12-26 20:30:27 +03:00
for ( j = 0 ; j < el - > num_values ; j + + ) {
vals [ el2 - > num_values + j ] =
2005-01-02 10:49:29 +03:00
ldb_val_dup ( vals , & el - > values [ j ] ) ;
2004-04-03 16:29:21 +04:00
}
2004-12-26 20:30:27 +03:00
el2 - > values = vals ;
el2 - > num_values + = el - > num_values ;
2004-04-03 16:29:21 +04:00
break ;
case LDB_FLAG_MOD_REPLACE :
/* replace all elements of this attribute name with the elements
2004-05-22 04:52:04 +04:00
listed . The attribute not existing is not an error */
2005-01-02 10:49:29 +03:00
msg_delete_attribute ( module , ldb , msg2 , msg - > elements [ i ] . name ) ;
2004-05-22 04:52:04 +04:00
/* add the replacement element, if not empty */
if ( msg - > elements [ i ] . num_values ! = 0 & &
2005-01-02 10:49:29 +03:00
msg_add_element ( ldb , msg2 , & msg - > elements [ i ] ) ! = 0 ) {
2004-04-03 16:29:21 +04:00
goto failed ;
}
break ;
case LDB_FLAG_MOD_DELETE :
/* we could be being asked to delete all
values or just some values */
if ( msg - > elements [ i ] . num_values = = 0 ) {
2005-01-02 10:49:29 +03:00
if ( msg_delete_attribute ( module , ldb , msg2 ,
2004-05-06 08:40:15 +04:00
msg - > elements [ i ] . name ) ! = 0 ) {
2004-05-08 03:54:41 +04:00
ltdb - > last_err_string = " No such attribute " ;
2004-04-03 16:29:21 +04:00
goto failed ;
}
break ;
}
for ( j = 0 ; j < msg - > elements [ i ] . num_values ; j + + ) {
2004-11-15 14:40:27 +03:00
if ( msg_delete_element ( module ,
2005-01-02 10:49:29 +03:00
msg2 ,
2004-05-01 13:45:56 +04:00
msg - > elements [ i ] . name ,
& msg - > elements [ i ] . values [ j ] ) ! = 0 ) {
2004-05-08 03:54:41 +04:00
ltdb - > last_err_string = " No such attribute " ;
2004-04-03 16:29:21 +04:00
goto failed ;
}
2004-12-19 13:56:29 +03:00
if ( ltdb_index_del_value ( module , msg - > dn , & msg - > elements [ i ] , j ) ! = 0 ) {
goto failed ;
}
2004-04-03 16:29:21 +04:00
}
break ;
2004-03-31 10:45:39 +04:00
}
}
2004-04-03 16:29:21 +04:00
/* we've made all the mods - save the modified record back into the database */
2005-01-02 10:49:29 +03:00
ret = ltdb_store ( module , msg2 , TDB_MODIFY ) ;
2004-04-03 16:29:21 +04:00
2005-01-02 10:49:29 +03:00
talloc_free ( tdb_key . dptr ) ;
2004-04-03 16:29:21 +04:00
free ( tdb_data . dptr ) ;
return ret ;
failed :
2005-01-02 10:49:29 +03:00
talloc_free ( tdb_key . dptr ) ;
2004-03-31 10:45:39 +04:00
free ( tdb_data . dptr ) ;
2004-05-01 13:45:56 +04:00
return - 1 ;
}
/*
modify a record
*/
2004-11-15 14:40:27 +03:00
static int ltdb_modify ( struct ldb_module * module , const struct ldb_message * msg )
2004-05-01 13:45:56 +04:00
{
2004-11-15 14:40:27 +03:00
struct ltdb_private * ltdb = module - > private_data ;
2004-05-01 13:45:56 +04:00
int ret ;
2004-05-06 08:40:15 +04:00
ltdb - > last_err_string = NULL ;
2005-05-18 01:43:47 +04:00
ret = ltdb_check_special_dn ( module , msg ) ;
if ( ret ! = 0 ) {
return ret ;
}
2004-11-21 18:51:54 +03:00
if ( ltdb_lock ( module , LDBLOCK ) ! = 0 ) {
2004-05-01 13:45:56 +04:00
return - 1 ;
}
2004-11-15 14:40:27 +03:00
if ( ltdb_cache_load ( module ) ! = 0 ) {
2004-11-21 18:51:54 +03:00
ltdb_unlock ( module , LDBLOCK ) ;
2004-05-01 13:45:56 +04:00
return - 1 ;
}
2004-11-15 14:40:27 +03:00
ret = ltdb_modify_internal ( module , msg ) ;
2004-05-01 13:45:56 +04:00
if ( ret = = 0 ) {
2004-11-15 14:40:27 +03:00
ltdb_modified ( module , msg - > dn ) ;
2004-05-01 13:45:56 +04:00
}
2004-04-03 16:29:21 +04:00
2004-11-21 18:51:54 +03:00
ltdb_unlock ( module , LDBLOCK ) ;
2004-05-01 13:45:56 +04:00
return ret ;
2004-03-31 10:45:39 +04:00
}
2004-10-20 23:28:02 +04:00
/*
rename a record
*/
2004-11-15 14:40:27 +03:00
static int ltdb_rename ( struct ldb_module * module , const char * olddn , const char * newdn )
2004-10-20 23:28:02 +04:00
{
2004-11-15 14:40:27 +03:00
struct ltdb_private * ltdb = module - > private_data ;
2004-10-20 23:28:02 +04:00
int ret ;
2005-01-02 10:49:29 +03:00
struct ldb_message * msg ;
2004-10-20 23:28:02 +04:00
const char * error_str ;
ltdb - > last_err_string = NULL ;
2004-11-21 18:51:54 +03:00
if ( ltdb_lock ( module , LDBLOCK ) ! = 0 ) {
2004-10-20 23:28:02 +04:00
return - 1 ;
}
2005-01-12 19:00:01 +03:00
msg = talloc ( module , struct ldb_message ) ;
2005-01-02 10:49:29 +03:00
if ( msg = = NULL ) {
goto failed ;
}
2004-10-20 23:28:02 +04:00
/* in case any attribute of the message was indexed, we need
to fetch the old record */
2005-01-02 10:49:29 +03:00
ret = ltdb_search_dn1 ( module , olddn , msg ) ;
2004-10-20 23:28:02 +04:00
if ( ret ! = 1 ) {
/* not finding the old record is an error */
goto failed ;
}
2005-01-02 10:49:29 +03:00
msg - > dn = talloc_strdup ( msg , newdn ) ;
if ( ! msg - > dn ) {
2004-10-20 23:28:02 +04:00
goto failed ;
}
2005-01-02 10:49:29 +03:00
ret = ltdb_add ( module , msg ) ;
2004-10-20 23:28:02 +04:00
if ( ret = = - 1 ) {
goto failed ;
}
2004-11-15 14:40:27 +03:00
ret = ltdb_delete ( module , olddn ) ;
2004-10-20 23:28:02 +04:00
error_str = ltdb - > last_err_string ;
if ( ret = = - 1 ) {
2004-11-15 14:40:27 +03:00
ltdb_delete ( module , newdn ) ;
2004-10-20 23:28:02 +04:00
}
ltdb - > last_err_string = error_str ;
2005-01-02 10:49:29 +03:00
talloc_free ( msg ) ;
2004-11-21 18:51:54 +03:00
ltdb_unlock ( module , LDBLOCK ) ;
2004-10-20 23:28:02 +04:00
return ret ;
2005-01-02 10:49:29 +03:00
2004-10-20 23:28:02 +04:00
failed :
2005-01-02 10:49:29 +03:00
talloc_free ( msg ) ;
2004-11-21 18:51:54 +03:00
ltdb_unlock ( module , LDBLOCK ) ;
2004-10-20 23:28:02 +04:00
return - 1 ;
}
2004-03-31 10:45:39 +04:00
/*
return extended error information
*/
2004-11-15 14:40:27 +03:00
static const char * ltdb_errstring ( struct ldb_module * module )
2004-03-31 10:45:39 +04:00
{
2004-11-15 14:40:27 +03:00
struct ltdb_private * ltdb = module - > private_data ;
2004-05-06 08:40:15 +04:00
if ( ltdb - > last_err_string ) {
return ltdb - > last_err_string ;
}
2004-03-31 10:45:39 +04:00
return tdb_errorstr ( ltdb - > tdb ) ;
}
2004-11-15 14:40:27 +03:00
static const struct ldb_module_ops ltdb_ops = {
2005-06-13 13:10:17 +04:00
. name = " tdb " ,
. search = ltdb_search ,
. search_bytree = ltdb_search_bytree ,
. add_record = ltdb_add ,
. modify_record = ltdb_modify ,
. delete_record = ltdb_delete ,
. rename_record = ltdb_rename ,
. named_lock = ltdb_lock ,
. named_unlock = ltdb_unlock ,
. errstring = ltdb_errstring
2004-03-31 10:45:39 +04:00
} ;
2005-01-02 10:49:29 +03:00
/*
destroy the ltdb context
*/
static int ltdb_destructor ( void * p )
{
struct ltdb_private * ltdb = p ;
tdb_close ( ltdb - > tdb ) ;
return 0 ;
}
2004-03-31 10:45:39 +04:00
/*
connect to the database
*/
struct ldb_context * ltdb_connect ( const char * url ,
unsigned int flags ,
const char * options [ ] )
{
const char * path ;
int tdb_flags , open_flags ;
struct ltdb_private * ltdb ;
TDB_CONTEXT * tdb ;
struct ldb_context * ldb ;
2005-01-12 19:00:01 +03:00
ldb = talloc_zero ( NULL , struct ldb_context ) ;
2004-05-06 08:40:15 +04:00
if ( ! ldb ) {
errno = ENOMEM ;
return NULL ;
}
2004-03-31 10:45:39 +04:00
/* parse the url */
2004-05-03 13:34:18 +04:00
if ( strchr ( url , ' : ' ) ) {
if ( strncmp ( url , " tdb:// " , 6 ) ! = 0 ) {
errno = EINVAL ;
2005-01-02 10:49:29 +03:00
talloc_free ( ldb ) ;
2004-05-03 13:34:18 +04:00
return NULL ;
}
path = url + 6 ;
} else {
path = url ;
2004-03-31 10:45:39 +04:00
}
tdb_flags = TDB_DEFAULT ;
if ( flags & LDB_FLG_RDONLY ) {
open_flags = O_RDONLY ;
} else {
open_flags = O_CREAT | O_RDWR ;
}
2004-04-27 11:10:16 +04:00
/* note that we use quite a large default hash size */
tdb = tdb_open ( path , 10000 , tdb_flags , open_flags , 0666 ) ;
2004-03-31 10:45:39 +04:00
if ( ! tdb ) {
2005-01-02 10:49:29 +03:00
talloc_free ( ldb ) ;
2004-03-31 10:45:39 +04:00
return NULL ;
}
2005-01-12 19:00:01 +03:00
ltdb = talloc_zero ( ldb , struct ltdb_private ) ;
2004-03-31 10:45:39 +04:00
if ( ! ltdb ) {
tdb_close ( tdb ) ;
2005-01-02 10:49:29 +03:00
talloc_free ( ldb ) ;
2004-03-31 10:45:39 +04:00
errno = ENOMEM ;
return NULL ;
}
ltdb - > tdb = tdb ;
2004-05-01 13:45:56 +04:00
ltdb - > sequence_number = 0 ;
2005-01-02 10:49:29 +03:00
talloc_set_destructor ( ltdb , ltdb_destructor ) ;
2004-03-31 10:45:39 +04:00
2005-01-12 19:00:01 +03:00
ldb - > modules = talloc ( ldb , struct ldb_module ) ;
2004-11-15 14:40:27 +03:00
if ( ! ldb - > modules ) {
2005-01-02 10:49:29 +03:00
talloc_free ( ldb ) ;
2004-11-15 14:40:27 +03:00
errno = ENOMEM ;
return NULL ;
}
ldb - > modules - > ldb = ldb ;
ldb - > modules - > prev = ldb - > modules - > next = NULL ;
ldb - > modules - > private_data = ltdb ;
ldb - > modules - > ops = & ltdb_ops ;
2004-03-31 10:45:39 +04:00
return ldb ;
}