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-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_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
2004-10-20 23:28:02 +04:00
/*
rename a record
*/
2004-11-15 14:40:27 +03:00
static int lldb_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 lldb_private * lldb = module - > private_data ;
2004-10-20 23:28:02 +04:00
int ret = 0 ;
char * newrdn , * p ;
const char * parentdn = " " ;
2005-01-06 05:32:43 +03:00
TALLOC_CTX * mem_ctx = talloc_new ( lldb ) ;
2004-10-20 23:28:02 +04:00
/* ignore ltdb specials */
if ( olddn [ 0 ] = = ' @ ' | | newdn [ 0 ] = = ' @ ' ) {
return 0 ;
}
2005-01-02 10:49:29 +03:00
newrdn = talloc_strdup ( mem_ctx , newdn ) ;
2004-10-20 23:28:02 +04:00
if ( ! newrdn ) {
return - 1 ;
}
p = strchr ( newrdn , ' , ' ) ;
if ( p ) {
* p + + = ' \0 ' ;
parentdn = p ;
}
lldb - > last_rc = ldap_rename_s ( lldb - > ldap , olddn , newrdn , parentdn , 1 , NULL , NULL ) ;
if ( lldb - > last_rc ! = LDAP_SUCCESS ) {
ret = - 1 ;
}
2005-01-02 10:49:29 +03:00
talloc_free ( mem_ctx ) ;
2004-10-20 23:28:02 +04:00
return ret ;
}
2004-03-31 10:45:39 +04:00
/*
delete a record
*/
2004-11-15 14:40:27 +03:00
static int lldb_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 lldb_private * lldb = module - > private_data ;
2004-03-31 10:45:39 +04:00
int ret = 0 ;
2004-05-01 13:45:56 +04:00
/* ignore ltdb specials */
if ( dn [ 0 ] = = ' @ ' ) {
return 0 ;
}
2004-03-31 10:45:39 +04:00
lldb - > last_rc = ldap_delete_s ( lldb - > ldap , dn ) ;
if ( lldb - > last_rc ! = LDAP_SUCCESS ) {
ret = - 1 ;
}
return ret ;
}
/*
free a search result
*/
2004-11-15 14:40:27 +03:00
static int lldb_search_free ( struct ldb_module * module , struct ldb_message * * res )
2004-03-31 10:45:39 +04:00
{
2005-01-02 10:49:29 +03:00
talloc_free ( res ) ;
2004-03-31 10:45:39 +04:00
return 0 ;
}
/*
add a single set of ldap message values to a ldb_message
*/
2004-05-06 08:40:15 +04:00
static int lldb_add_msg_attr ( struct ldb_context * ldb ,
struct ldb_message * msg ,
2004-03-31 10:45:39 +04:00
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 ;
}
2005-01-12 19:00:01 +03:00
el = talloc_realloc ( msg , msg - > elements , struct ldb_message_element ,
2005-01-02 10:49:29 +03: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 ] ;
2005-01-02 10:49:29 +03:00
el - > name = talloc_strdup ( msg - > elements , attr ) ;
2004-04-03 16:29:21 +04:00
if ( ! el - > name ) {
errno = ENOMEM ;
return - 1 ;
}
el - > flags = 0 ;
el - > num_values = 0 ;
2005-01-12 19:00:01 +03:00
el - > values = talloc_array ( msg - > elements , struct ldb_val , count ) ;
2004-04-03 16:29:21 +04:00
if ( ! el - > values ) {
errno = ENOMEM ;
return - 1 ;
}
2004-03-31 10:45:39 +04:00
for ( i = 0 ; i < count ; i + + ) {
2005-01-02 10:49:29 +03:00
el - > values [ i ] . data = talloc_memdup ( el - > values , bval [ i ] - > bv_val , bval [ i ] - > bv_len ) ;
2004-04-03 16:29:21 +04:00
if ( ! el - > values [ i ] . data ) {
2004-03-31 10:45:39 +04:00
return - 1 ;
}
2004-04-03 16:29:21 +04:00
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
*/
2004-11-15 14:40:27 +03:00
static int lldb_search ( struct ldb_module * module , const char * base ,
2004-03-31 10:45:39 +04:00
enum ldb_scope scope , const char * expression ,
2004-05-08 03:54:41 +04:00
const char * const * attrs , struct ldb_message * * * res )
2004-03-31 10:45:39 +04:00
{
2004-11-15 14:40:27 +03:00
struct ldb_context * ldb = module - > ldb ;
struct lldb_private * lldb = module - > private_data ;
2004-03-31 10:45:39 +04:00
int count , msg_count ;
LDAPMessage * ldapres , * msg ;
2004-11-15 15:30:28 +03:00
if ( base = = NULL ) {
base = " " ;
}
2004-03-31 10:45:39 +04:00
lldb - > last_rc = ldap_search_s ( lldb - > ldap , base , ( int ) scope ,
2004-10-28 17:19:39 +04:00
expression ,
discard_const_p ( char * , attrs ) ,
0 , & ldapres ) ;
2004-03-31 10:45:39 +04:00
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 ;
}
2005-01-12 19:00:01 +03:00
( * res ) = talloc_array ( lldb , struct ldb_message * , count + 1 ) ;
2004-03-31 10:45:39 +04:00
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? */
2004-05-06 13:55:05 +04:00
ldb_debug ( ldb , LDB_DEBUG_FATAL , " Fatal: ldap message count inconsistent \n " ) ;
2004-03-31 10:45:39 +04:00
break ;
}
2005-01-12 19:00:01 +03:00
( * res ) [ msg_count ] = talloc ( * res , struct ldb_message ) ;
2004-03-31 10:45:39 +04:00
if ( ! ( * res ) [ msg_count ] ) {
goto failed ;
}
( * res ) [ msg_count + 1 ] = NULL ;
dn = ldap_get_dn ( lldb - > ldap , msg ) ;
if ( ! dn ) {
goto failed ;
}
2005-01-02 10:49:29 +03:00
( * res ) [ msg_count ] - > dn = talloc_strdup ( ( * res ) [ msg_count ] , dn ) ;
2004-03-31 10:45:39 +04:00
ldap_memfree ( dn ) ;
if ( ! ( * res ) [ msg_count ] - > dn ) {
goto failed ;
}
( * res ) [ msg_count ] - > num_elements = 0 ;
( * res ) [ msg_count ] - > elements = NULL ;
2004-04-28 11:32:37 +04:00
( * res ) [ msg_count ] - > private_data = NULL ;
2004-03-31 10:45:39 +04:00
/* 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 ) {
2004-05-06 08:40:15 +04:00
lldb_add_msg_attr ( ldb , ( * res ) [ msg_count ] , attr , bval ) ;
2004-03-31 10:45:39 +04:00
ldap_value_free_len ( bval ) ;
}
ldap_memfree ( attr ) ;
}
if ( berptr ) ber_free ( berptr , 0 ) ;
msg_count + + ;
}
ldap_msgfree ( ldapres ) ;
return msg_count ;
failed :
2004-11-15 14:40:27 +03:00
if ( * res ) lldb_search_free ( module , * res ) ;
2004-03-31 10:45:39 +04:00
return - 1 ;
}
/*
convert a ldb_message structure to a list of LDAPMod structures
ready for ldap_add ( ) or ldap_modify ( )
*/
2004-05-06 08:40:15 +04:00
static LDAPMod * * lldb_msg_to_mods ( struct ldb_context * ldb ,
const struct ldb_message * msg , int use_flags )
2004-03-31 10:45:39 +04:00
{
LDAPMod * * mods ;
2004-07-07 05:02:54 +04:00
unsigned int i , j ;
int num_mods = 0 ;
2004-03-31 10:45:39 +04:00
/* allocate maximum number of elements needed */
2005-01-12 19:00:01 +03:00
mods = talloc_array ( ldb , LDAPMod * , msg - > num_elements + 1 ) ;
2004-03-31 10:45:39 +04:00
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
2005-01-12 19:00:01 +03:00
mods [ num_mods ] = talloc ( ldb , LDAPMod ) ;
2004-03-31 10:45:39 +04:00
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 ;
2005-01-12 19:00:01 +03:00
mods [ num_mods ] - > mod_vals . modv_bvals = talloc_array ( mods [ num_mods ] ,
2005-01-02 10:49:29 +03:00
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 + + ) {
2005-01-12 19:00:01 +03:00
mods [ num_mods ] - > mod_vals . modv_bvals [ j ] = talloc ( mods [ num_mods ] - > mod_vals . modv_bvals ,
2005-01-02 10:49:29 +03:00
struct berval ) ;
2004-04-03 16:29:21 +04:00
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 :
2005-01-02 10:49:29 +03:00
talloc_free ( mods ) ;
2004-03-31 10:45:39 +04:00
return NULL ;
}
/*
add a record
*/
2004-11-15 14:40:27 +03:00
static int lldb_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 ldb_context * ldb = module - > ldb ;
struct lldb_private * lldb = module - > private_data ;
2004-03-31 10:45:39 +04:00
LDAPMod * * mods ;
int ret = 0 ;
2004-05-01 13:45:56 +04:00
/* ignore ltdb specials */
if ( msg - > dn [ 0 ] = = ' @ ' ) {
return 0 ;
}
2004-05-06 08:40:15 +04:00
mods = lldb_msg_to_mods ( ldb , msg , 0 ) ;
2004-03-31 10:45:39 +04:00
lldb - > last_rc = ldap_add_s ( lldb - > ldap , msg - > dn , mods ) ;
if ( lldb - > last_rc ! = LDAP_SUCCESS ) {
ret = - 1 ;
}
2005-01-02 10:49:29 +03:00
talloc_free ( mods ) ;
2004-03-31 10:45:39 +04:00
return ret ;
}
/*
modify a record
*/
2004-11-15 14:40:27 +03:00
static int lldb_modify ( 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 lldb_private * lldb = module - > private_data ;
2004-03-31 10:45:39 +04:00
LDAPMod * * mods ;
int ret = 0 ;
2004-05-01 13:45:56 +04:00
/* ignore ltdb specials */
if ( msg - > dn [ 0 ] = = ' @ ' ) {
return 0 ;
}
2004-05-06 08:40:15 +04:00
mods = lldb_msg_to_mods ( ldb , msg , 1 ) ;
2004-03-31 10:45:39 +04:00
lldb - > last_rc = ldap_modify_s ( lldb - > ldap , msg - > dn , mods ) ;
if ( lldb - > last_rc ! = LDAP_SUCCESS ) {
ret = - 1 ;
}
2005-01-02 10:49:29 +03:00
talloc_free ( mods ) ;
2004-03-31 10:45:39 +04:00
return ret ;
}
2004-11-21 18:51:54 +03:00
static int lldb_lock ( struct ldb_module * module , const char * lockname )
{
int ret = 0 ;
if ( lockname = = NULL ) {
return - 1 ;
}
/* TODO implement a local locking mechanism here */
return ret ;
}
static int lldb_unlock ( struct ldb_module * module , const char * lockname )
{
int ret = 0 ;
if ( lockname = = NULL ) {
return - 1 ;
}
/* TODO implement a local unlocking mechanism here */
return ret ;
}
2004-03-31 10:45:39 +04:00
/*
return extended error information
*/
2004-11-15 14:40:27 +03:00
static const char * lldb_errstring ( struct ldb_module * module )
2004-03-31 10:45:39 +04:00
{
2004-11-15 14:40:27 +03:00
struct lldb_private * lldb = module - > private_data ;
2004-03-31 10:45:39 +04:00
return ldap_err2string ( lldb - > last_rc ) ;
}
2004-11-15 14:40:27 +03:00
static const struct ldb_module_ops lldb_ops = {
" ldap " ,
2004-03-31 10:45:39 +04:00
lldb_search ,
lldb_search_free ,
lldb_add ,
lldb_modify ,
lldb_delete ,
2004-10-20 23:28:02 +04:00
lldb_rename ,
2004-11-21 18:51:54 +03:00
lldb_lock ,
lldb_unlock ,
2004-03-31 10:45:39 +04:00
lldb_errstring
} ;
2005-01-02 10:49:29 +03:00
static int lldb_destructor ( void * p )
{
struct lldb_private * lldb = p ;
ldap_unbind ( lldb - > ldap ) ;
return 0 ;
}
2004-03-31 10:45:39 +04:00
/*
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 ;
2004-10-20 23:28:02 +04:00
int i , version = 3 ;
2004-03-31 10:45:39 +04:00
2005-01-12 19:00:01 +03:00
ldb = talloc ( NULL , struct ldb_context ) ;
2004-03-31 10:45:39 +04:00
if ( ! ldb ) {
errno = ENOMEM ;
goto failed ;
}
2005-01-12 19:00:01 +03:00
lldb = talloc ( ldb , struct lldb_private ) ;
2004-03-31 10:45:39 +04:00
if ( ! lldb ) {
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 ;
}
2005-01-02 10:49:29 +03:00
talloc_set_destructor ( lldb , lldb_destructor ) ;
2004-10-20 23:28:02 +04:00
lldb - > last_rc = ldap_set_option ( lldb - > ldap , LDAP_OPT_PROTOCOL_VERSION , & version ) ;
if ( lldb - > last_rc ! = LDAP_SUCCESS ) {
goto failed ;
}
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 ) {
errno = ENOMEM ;
goto failed ;
}
ldb - > modules - > ldb = ldb ;
ldb - > modules - > prev = ldb - > modules - > next = NULL ;
ldb - > modules - > private_data = lldb ;
ldb - > modules - > ops = & lldb_ops ;
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 + + ) ;
2005-01-12 19:00:01 +03:00
lldb - > options = talloc_array ( lldb , char * , i + 1 ) ;
2004-03-31 10:45:39 +04:00
if ( ! lldb - > options ) {
goto failed ;
}
for ( i = 0 ; options [ i ] ; i + + ) {
lldb - > options [ i + 1 ] = NULL ;
2005-01-02 10:49:29 +03:00
lldb - > options [ i ] = talloc_strdup ( lldb - > options , options [ i ] ) ;
2004-03-31 10:45:39 +04:00
if ( ! lldb - > options [ i ] ) {
goto failed ;
}
}
}
return ldb ;
failed :
2005-01-02 10:49:29 +03:00
talloc_free ( ldb ) ;
2004-03-31 10:45:39 +04:00
return NULL ;
}
2004-04-11 00:18:22 +04:00