2004-03-31 10:45:39 +04: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 ldap backend
*
* Description : core files for LDAP backend
*
* Author : Andrew Tridgell
*/
# include "includes.h"
2004-04-11 00:18:22 +04:00
# include "ldb/ldb_ldap/ldb_ldap.h"
2004-03-31 10:45:39 +04:00
#if 0
/*
2004-04-03 16:29:21 +04:00
we don ' t need this right now , but will once we add some backend
2004-03-31 10:45:39 +04:00
options
*/
/*
find an option in an option list ( a null terminated list of strings )
this assumes the list is short . If it ever gets long then we really
should do this in some smarter way
*/
static const char * lldb_option_find ( const struct lldb_private * lldb , const char * name )
{
int i ;
size_t len = strlen ( name ) ;
if ( ! lldb - > options ) return NULL ;
for ( i = 0 ; lldb - > options [ i ] ; i + + ) {
if ( strncmp ( lldb - > options [ i ] , name , len ) = = 0 & &
lldb - > options [ i ] [ len ] = = ' = ' ) {
return & lldb - > options [ i ] [ len + 1 ] ;
}
}
return NULL ;
}
# endif
/*
close / free the connection
*/
static int lldb_close ( struct ldb_context * ldb )
{
int i , ret = 0 ;
2004-04-28 11:05:28 +04:00
struct lldb_private * lldb = ldb - > private_data ;
2004-03-31 10:45:39 +04:00
if ( ldap_unbind ( lldb - > ldap ) ! = LDAP_SUCCESS ) {
ret = - 1 ;
}
if ( lldb - > options ) {
for ( i = 0 ; lldb - > options [ i ] ; i + + ) {
free ( lldb - > options [ i ] ) ;
}
free ( lldb - > options ) ;
}
free ( lldb ) ;
free ( ldb ) ;
return ret ;
}
/*
delete a record
*/
static int lldb_delete ( struct ldb_context * ldb , const char * dn )
{
2004-04-28 11:05:28 +04:00
struct lldb_private * lldb = ldb - > private_data ;
2004-03-31 10:45:39 +04:00
int ret = 0 ;
lldb - > last_rc = ldap_delete_s ( lldb - > ldap , dn ) ;
if ( lldb - > last_rc ! = LDAP_SUCCESS ) {
ret = - 1 ;
}
return ret ;
}
/*
free a search message
*/
static int lldb_msg_free ( struct ldb_context * ldb , struct ldb_message * msg )
{
2004-04-03 16:29:21 +04:00
int i , j ;
2004-03-31 10:45:39 +04:00
free ( msg - > dn ) ;
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
free ( msg - > elements [ i ] . name ) ;
2004-04-03 16:29:21 +04:00
for ( j = 0 ; j < msg - > elements [ i ] . num_values ; j + + ) {
if ( msg - > elements [ i ] . values [ j ] . data ) {
free ( msg - > elements [ i ] . values [ j ] . data ) ;
}
2004-03-31 10:45:39 +04:00
}
2004-04-03 16:29:21 +04:00
free ( msg - > elements [ i ] . values ) ;
2004-03-31 10:45:39 +04:00
}
if ( msg - > elements ) free ( msg - > elements ) ;
free ( msg ) ;
return 0 ;
}
/*
free a search result
*/
static int lldb_search_free ( struct ldb_context * ldb , struct ldb_message * * res )
{
int i ;
for ( i = 0 ; res [ i ] ; i + + ) {
if ( lldb_msg_free ( ldb , res [ i ] ) ! = 0 ) {
return - 1 ;
}
}
free ( res ) ;
return 0 ;
}
/*
add a single set of ldap message values to a ldb_message
*/
static int lldb_add_msg_attr ( struct ldb_message * msg ,
const char * attr , struct berval * * bval )
{
int count , i ;
struct ldb_message_element * el ;
count = ldap_count_values_len ( bval ) ;
if ( count < = 0 ) {
return - 1 ;
}
el = realloc_p ( msg - > elements , struct ldb_message_element ,
2004-04-03 16:29:21 +04:00
msg - > num_elements + 1 ) ;
2004-03-31 10:45:39 +04:00
if ( ! el ) {
errno = ENOMEM ;
return - 1 ;
}
msg - > elements = el ;
2004-04-03 16:29:21 +04:00
el = & msg - > elements [ msg - > num_elements ] ;
el - > name = strdup ( attr ) ;
if ( ! el - > name ) {
errno = ENOMEM ;
return - 1 ;
}
el - > flags = 0 ;
el - > num_values = 0 ;
el - > values = malloc_array_p ( struct ldb_val , count ) ;
if ( ! el - > values ) {
errno = ENOMEM ;
return - 1 ;
}
2004-03-31 10:45:39 +04:00
for ( i = 0 ; i < count ; i + + ) {
2004-04-03 16:29:21 +04:00
el - > values [ i ] . data = malloc ( bval [ i ] - > bv_len ) ;
if ( ! el - > values [ i ] . data ) {
2004-03-31 10:45:39 +04:00
return - 1 ;
}
2004-04-03 16:29:21 +04:00
memcpy ( el - > values [ i ] . data , bval [ i ] - > bv_val , bval [ i ] - > bv_len ) ;
el - > values [ i ] . length = bval [ i ] - > bv_len ;
el - > num_values + + ;
2004-03-31 10:45:39 +04:00
}
2004-04-03 16:29:21 +04:00
msg - > num_elements + + ;
2004-03-31 10:45:39 +04:00
return 0 ;
}
/*
search for matching records
*/
static int lldb_search ( struct ldb_context * ldb , const char * base ,
enum ldb_scope scope , const char * expression ,
const char * * attrs , struct ldb_message * * * res )
{
2004-04-28 11:05:28 +04:00
struct lldb_private * lldb = ldb - > private_data ;
2004-03-31 10:45:39 +04:00
int count , msg_count ;
LDAPMessage * ldapres , * msg ;
lldb - > last_rc = ldap_search_s ( lldb - > ldap , base , ( int ) scope ,
expression , attrs , 0 , & ldapres ) ;
if ( lldb - > last_rc ! = LDAP_SUCCESS ) {
return - 1 ;
}
count = ldap_count_entries ( lldb - > ldap , ldapres ) ;
if ( count = = - 1 | | count = = 0 ) {
ldap_msgfree ( ldapres ) ;
return count ;
}
( * res ) = malloc_array_p ( struct ldb_message * , count + 1 ) ;
if ( ! * res ) {
ldap_msgfree ( ldapres ) ;
errno = ENOMEM ;
return - 1 ;
}
( * res ) [ 0 ] = NULL ;
msg_count = 0 ;
/* loop over all messages */
for ( msg = ldap_first_entry ( lldb - > ldap , ldapres ) ;
msg ;
msg = ldap_next_entry ( lldb - > ldap , msg ) ) {
BerElement * berptr = NULL ;
char * attr , * dn ;
if ( msg_count = = count ) {
/* hmm, got too many? */
fprintf ( stderr , " Too many messages?! \n " ) ;
break ;
}
( * res ) [ msg_count ] = malloc_p ( struct ldb_message ) ;
if ( ! ( * res ) [ msg_count ] ) {
goto failed ;
}
( * res ) [ msg_count + 1 ] = NULL ;
dn = ldap_get_dn ( lldb - > ldap , msg ) ;
if ( ! dn ) {
goto failed ;
}
( * res ) [ msg_count ] - > dn = strdup ( dn ) ;
ldap_memfree ( dn ) ;
if ( ! ( * res ) [ msg_count ] - > dn ) {
goto failed ;
}
( * res ) [ msg_count ] - > num_elements = 0 ;
( * res ) [ msg_count ] - > elements = NULL ;
( * res ) [ msg_count ] - > private = NULL ;
/* loop over all attributes */
for ( attr = ldap_first_attribute ( lldb - > ldap , msg , & berptr ) ;
attr ;
attr = ldap_next_attribute ( lldb - > ldap , msg , berptr ) ) {
struct berval * * bval ;
bval = ldap_get_values_len ( lldb - > ldap , msg , attr ) ;
if ( bval ) {
lldb_add_msg_attr ( ( * res ) [ msg_count ] , attr , bval ) ;
ldap_value_free_len ( bval ) ;
}
ldap_memfree ( attr ) ;
}
if ( berptr ) ber_free ( berptr , 0 ) ;
msg_count + + ;
}
ldap_msgfree ( ldapres ) ;
return msg_count ;
failed :
if ( * res ) lldb_search_free ( ldb , * res ) ;
return - 1 ;
}
/*
free a set of mods from lldb_msg_to_mods ( )
*/
static void lldb_mods_free ( LDAPMod * * mods )
{
int i , j ;
if ( ! mods ) return ;
for ( i = 0 ; mods [ i ] ; i + + ) {
if ( mods [ i ] - > mod_vals . modv_bvals ) {
for ( j = 0 ; mods [ i ] - > mod_vals . modv_bvals [ j ] ; j + + ) {
free ( mods [ i ] - > mod_vals . modv_bvals [ j ] ) ;
}
free ( mods [ i ] - > mod_vals . modv_bvals ) ;
}
free ( mods [ i ] ) ;
}
free ( mods ) ;
}
/*
convert a ldb_message structure to a list of LDAPMod structures
ready for ldap_add ( ) or ldap_modify ( )
*/
static LDAPMod * * lldb_msg_to_mods ( const struct ldb_message * msg , int use_flags )
{
LDAPMod * * mods ;
2004-04-03 16:29:21 +04:00
int i , j , num_mods = 0 ;
2004-03-31 10:45:39 +04:00
/* allocate maximum number of elements needed */
mods = malloc_array_p ( LDAPMod * , msg - > num_elements + 1 ) ;
if ( ! mods ) {
errno = ENOMEM ;
return NULL ;
}
mods [ 0 ] = NULL ;
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
2004-04-03 16:29:21 +04:00
const struct ldb_message_element * el = & msg - > elements [ i ] ;
2004-03-31 10:45:39 +04:00
mods [ num_mods ] = malloc_p ( LDAPMod ) ;
if ( ! mods [ num_mods ] ) {
goto failed ;
}
mods [ num_mods + 1 ] = NULL ;
mods [ num_mods ] - > mod_op = LDAP_MOD_BVALUES ;
if ( use_flags ) {
2004-04-03 16:29:21 +04:00
switch ( el - > flags & LDB_FLAG_MOD_MASK ) {
2004-03-31 10:45:39 +04:00
case LDB_FLAG_MOD_ADD :
mods [ num_mods ] - > mod_op | = LDAP_MOD_ADD ;
break ;
case LDB_FLAG_MOD_DELETE :
mods [ num_mods ] - > mod_op | = LDAP_MOD_DELETE ;
break ;
case LDB_FLAG_MOD_REPLACE :
mods [ num_mods ] - > mod_op | = LDAP_MOD_REPLACE ;
break ;
}
}
2004-04-03 16:29:21 +04:00
mods [ num_mods ] - > mod_type = el - > name ;
mods [ num_mods ] - > mod_vals . modv_bvals = malloc_array_p ( struct berval * ,
1 + el - > num_values ) ;
2004-03-31 10:45:39 +04:00
if ( ! mods [ num_mods ] - > mod_vals . modv_bvals ) {
goto failed ;
}
2004-04-03 16:29:21 +04:00
for ( j = 0 ; j < el - > num_values ; j + + ) {
mods [ num_mods ] - > mod_vals . modv_bvals [ j ] = malloc_p ( struct berval ) ;
if ( ! mods [ num_mods ] - > mod_vals . modv_bvals [ j ] ) {
goto failed ;
}
mods [ num_mods ] - > mod_vals . modv_bvals [ j ] - > bv_val = el - > values [ j ] . data ;
mods [ num_mods ] - > mod_vals . modv_bvals [ j ] - > bv_len = el - > values [ j ] . length ;
2004-03-31 10:45:39 +04:00
}
2004-04-03 16:29:21 +04:00
mods [ num_mods ] - > mod_vals . modv_bvals [ j ] = NULL ;
2004-03-31 10:45:39 +04:00
num_mods + + ;
}
return mods ;
failed :
lldb_mods_free ( mods ) ;
return NULL ;
}
/*
add a record
*/
static int lldb_add ( struct ldb_context * ldb , const struct ldb_message * msg )
{
2004-04-28 11:05:28 +04:00
struct lldb_private * lldb = ldb - > private_data ;
2004-03-31 10:45:39 +04:00
LDAPMod * * mods ;
int ret = 0 ;
mods = lldb_msg_to_mods ( msg , 0 ) ;
lldb - > last_rc = ldap_add_s ( lldb - > ldap , msg - > dn , mods ) ;
if ( lldb - > last_rc ! = LDAP_SUCCESS ) {
ret = - 1 ;
}
lldb_mods_free ( mods ) ;
return ret ;
}
/*
modify a record
*/
static int lldb_modify ( struct ldb_context * ldb , const struct ldb_message * msg )
{
2004-04-28 11:05:28 +04:00
struct lldb_private * lldb = ldb - > private_data ;
2004-03-31 10:45:39 +04:00
LDAPMod * * mods ;
int ret = 0 ;
mods = lldb_msg_to_mods ( msg , 1 ) ;
lldb - > last_rc = ldap_modify_s ( lldb - > ldap , msg - > dn , mods ) ;
if ( lldb - > last_rc ! = LDAP_SUCCESS ) {
ret = - 1 ;
}
lldb_mods_free ( mods ) ;
return ret ;
}
/*
return extended error information
*/
static const char * lldb_errstring ( struct ldb_context * ldb )
{
2004-04-28 11:05:28 +04:00
struct lldb_private * lldb = ldb - > private_data ;
2004-03-31 10:45:39 +04:00
return ldap_err2string ( lldb - > last_rc ) ;
}
static const struct ldb_backend_ops lldb_ops = {
lldb_close ,
lldb_search ,
lldb_search_free ,
lldb_add ,
lldb_modify ,
lldb_delete ,
lldb_errstring
} ;
/*
connect to the database
*/
struct ldb_context * lldb_connect ( const char * url ,
unsigned int flags ,
const char * options [ ] )
{
struct ldb_context * ldb = NULL ;
struct lldb_private * lldb = NULL ;
int i ;
ldb = malloc_p ( struct ldb_context ) ;
if ( ! ldb ) {
errno = ENOMEM ;
goto failed ;
}
lldb = malloc_p ( struct lldb_private ) ;
if ( ! lldb ) {
free ( ldb ) ;
errno = ENOMEM ;
goto failed ;
}
lldb - > ldap = NULL ;
lldb - > options = NULL ;
lldb - > last_rc = ldap_initialize ( & lldb - > ldap , url ) ;
if ( lldb - > last_rc ! = LDAP_SUCCESS ) {
goto failed ;
}
ldb - > ops = & lldb_ops ;
2004-04-28 11:05:28 +04:00
ldb - > private_data = lldb ;
2004-03-31 10:45:39 +04:00
if ( options ) {
/* take a copy of the options array, so we don't have to rely
on the caller keeping it around ( it might be dynamic ) */
for ( i = 0 ; options [ i ] ; i + + ) ;
lldb - > options = malloc_array_p ( char * , i + 1 ) ;
if ( ! lldb - > options ) {
goto failed ;
}
for ( i = 0 ; options [ i ] ; i + + ) {
lldb - > options [ i + 1 ] = NULL ;
lldb - > options [ i ] = strdup ( options [ i ] ) ;
if ( ! lldb - > options [ i ] ) {
goto failed ;
}
}
}
return ldb ;
failed :
if ( lldb & & lldb - > options ) {
for ( i = 0 ; lldb - > options [ i ] ; i + + ) {
free ( lldb - > options [ i ] ) ;
}
free ( lldb - > options ) ;
}
if ( lldb & & lldb - > ldap ) {
ldap_unbind ( lldb - > ldap ) ;
}
if ( lldb ) free ( lldb ) ;
if ( ldb ) free ( ldb ) ;
return NULL ;
}
2004-04-11 00:18:22 +04:00