Introduction of a new Berkeley DB version 2 (!) specific backend.

BEWARE: the backend will be compiled.
        the backend will NOT be invoked, yet.
        the backend CANNOT be invoked, yet, because it is NOT yet
            integrated into the new initialization/startup environment
            of the slapd server.
This commit is contained in:
Kurt Spanier 1999-02-05 16:23:03 +00:00
parent 8107ec91f0
commit d92b9d3c9e
36 changed files with 7511 additions and 1 deletions

View file

@ -0,0 +1,38 @@
XSRCS = version.c
SRCS = idl.c add.c search.c cache.c dbcache.c dn2id.c id2entry.c \
index.c id2children.c nextid.c abandon.c compare.c group.c \
modify.c modrdn.c delete.c init.c config.c bind.c attr.c \
filterindex.c unbind.c kerberos.c close.c alias.c startup.c \
timing.c porter.c txn.c
OBJS = idl.o add.o search.o cache.o dbcache.o dn2id.o id2entry.o \
index.o id2children.o nextid.o abandon.o compare.o group.o \
modify.o modrdn.o delete.o init.o config.o bind.o attr.o \
filterindex.o unbind.o kerberos.o close.o alias.o startup.o \
timing.o porter.o txn.o
LDAP_INCDIR= ../../../include
LDAP_LIBDIR= ../../../libraries
BUILD_OPT = "--enable-bdb2"
BUILD_SRV = @BUILD_BDB2@
XINCPATH = -I.. -I$(srcdir)/..
PROGRAMS = libback-bdb2.a
all-local-srv: FORCE
$(MAKE) $(MFLAGS) libback-bdb2.a
libback-bdb2.a: version.o
$(AR) ruv $@ $(OBJS) version.o
@$(RANLIB) $@
@touch ../.backend
version.c: $(OBJS) $(LDAP_LIBDEPEND)
$(RM) $@
(u=$${USER-root} v=`$(CAT) $(VERSIONFILE)` d=`$(PWD)` \
h=`$(HOSTNAME)` t=`$(DATE)`; \
$(SED) -e "s|%WHEN%|$${t}|" \
-e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
-e "s|%VERSION%|$${v}|" \
< $(srcdir)/Version.c > $@)

View file

@ -0,0 +1,13 @@
/*
* Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
static char Versionstr[] = " bdb2 backend %VERSION% (%WHEN%)\n\t%WHOANDWHERE%\n";

View file

@ -0,0 +1,55 @@
/* abandon.c - ldbm backend abandon routine */
#include "portable.h"
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <ac/string.h>
#include "slap.h"
#include "back-bdb2.h"
/*ARGSUSED*/
static int
bdb2i_back_abandon_internal(
Backend *be,
Connection *c,
Operation *o,
int msgid )
{
return 0;
}
int
bdb2_back_abandon(
Backend *be,
Connection *c,
Operation *o,
int msgid )
{
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
ret = bdb2i_back_abandon_internal( be, c, o, msgid );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "ABND elapsed=%s\n",
elapsed_time, 0, 0 );
free( elapsed_time );
}
return( ret );
}

View file

@ -0,0 +1,289 @@
/* add.c - ldap bdb2 back-end add routine */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
static int
bdb2i_back_add_internal(
Backend *be,
Connection *conn,
Operation *op,
Entry *e
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *pdn;
Entry *p = NULL;
int rootlock = 0;
int rc = -1;
Debug(LDAP_DEBUG_ARGS, "==> bdb2i_back_add: %s\n", e->e_dn, 0, 0);
/* nobody else can add until we lock our parent */
ldap_pvt_thread_mutex_lock(&li->li_add_mutex);
if ( ( bdb2i_dn2id( be, e->e_ndn ) ) != NOID ) {
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
entry_free( e );
send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
return( -1 );
}
if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n",
0, 0, 0 );
entry_free( e );
send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, "",
"" );
return( -1 );
}
/*
* Get the parent dn and see if the corresponding entry exists.
* If the parent does not exist, only allow the "root" user to
* add the entry.
*/
if ( (pdn = dn_parent( be, e->e_ndn )) != NULL ) {
char *matched = NULL;
/* get parent with writer lock */
if ( (p = bdb2i_dn2entry_w( be, pdn, &matched )) == NULL ) {
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
matched, "" );
if ( matched != NULL ) {
free( matched );
}
entry_free( e );
free( pdn );
return -1;
}
/* don't need the add lock anymore */
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
free(pdn);
if ( matched != NULL ) {
free( matched );
}
if ( ! access_allowed( be, conn, op, p,
"children", NULL, ACL_WRITE ) )
{
Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
"", "" );
/* free parent and writer lock */
bdb2i_cache_return_entry_w( &li->li_cache, p );
entry_free( e );
return -1;
}
} else {
/* no parent, must be adding entry to root */
if ( ! be_isroot( be, op->o_ndn ) ) {
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
Debug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
"", "" );
entry_free( e );
return -1;
}
/*
* no parent, acquire the root write lock
* and release the add lock.
*/
ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
rootlock = 1;
ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
}
/* acquire required reader/writer lock */
if (entry_rdwr_lock(e, 1)) {
if( p != NULL) {
/* free parent and writer lock */
bdb2i_cache_return_entry_w( &li->li_cache, p );
}
if ( rootlock ) {
/* release root lock */
ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
}
Debug( LDAP_DEBUG_ANY, "add: could not lock entry\n",
0, 0, 0 );
entry_free(e);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
return( -1 );
}
e->e_id = bdb2i_next_id( be );
/*
* Try to add the entry to the cache, assign it a new dnid
* This should only fail if the entry already exists.
*/
if ( bdb2i_cache_add_entry_lock( &li->li_cache, e, ENTRY_STATE_CREATING )
!= 0 ) {
if( p != NULL) {
/* free parent and writer lock */
bdb2i_cache_return_entry_w( &li->li_cache, p );
}
if ( rootlock ) {
/* release root lock */
ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
}
Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
0 );
bdb2i_next_id_return( be, e->e_id );
entry_rdwr_unlock(e, 1);
entry_free( e );
send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
return( -1 );
}
/*
* add it to the id2children index for the parent
*/
if ( bdb2i_id2children_add( be, p, e ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "bdb2i_id2children_add failed\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
goto return_results;
}
/*
* Add the entry to the attribute indexes, then add it to
* the id2children index, dn2id index, and the id2entry index.
*/
/* attribute indexes */
if ( bdb2i_index_add_entry( be, e ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "bdb2i_index_add_entry failed\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
goto return_results;
}
/* dn2id index */
if ( bdb2i_dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "bdb2i_dn2id_add failed\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
goto return_results;
}
/* id2entry index */
if ( bdb2i_id2entry_add( be, e ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "bdb2i_id2entry_add failed\n", 0,
0, 0 );
(void) bdb2i_dn2id_delete( be, e->e_ndn );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
goto return_results;
}
send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
rc = 0;
return_results:;
if (p != NULL) {
/* free parent and writer lock */
bdb2i_cache_return_entry_w( &li->li_cache, p );
}
if ( rootlock ) {
/* release root lock */
ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
}
bdb2i_cache_set_state( &li->li_cache, e, 0 );
/* free entry and writer lock */
bdb2i_cache_return_entry_w( &li->li_cache, e );
return( rc );
}
int
bdb2_back_add(
Backend *be,
Connection *conn,
Operation *op,
Entry *e
)
{
DB_LOCK lock;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
if ( bdb2i_enter_backend_w( &li->li_db_env, &lock ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
return( -1 );
}
/* check, if a new default attribute index will be created,
in which case we have to open the index file BEFORE TP */
if ( bdb2i_with_dbenv )
bdb2i_check_default_attr_index_add( li, e );
ret = bdb2i_back_add_internal( be, conn, op, e );
(void) bdb2i_leave_backend( &li->li_db_env, lock );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "conn=%d op=%d ADD elapsed=%s\n",
conn->c_connid, op->o_opid, elapsed_time );
free( elapsed_time );
}
return( ret );
}

View file

@ -0,0 +1,320 @@
/*
* Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to ITSD, Government of BC. The name of ITSD
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <string.h>
#include <ac/socket.h> /* Get struct sockaddr for slap.h */
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
/*
* given an alias object, dereference it to its end point.
* Entry returned has reader lock or is NULL. Starting entry is not released.
*/
Entry *bdb2i_derefAlias_r ( Backend *be,
Connection *conn,
Operation *op,
Entry *e)
{
/* to free cache entries */
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Attribute *a;
int depth;
char **pastAliases;
char *matched;
Entry *origDN = e;
if (!e) return NULL; /* be sure we have a starting entry */
Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 );
/*
* try to deref fully, up to a maximum depth. If the max depth exceeded
* then send an error
*/
for ( depth = 0;
( ( a = attr_find( e->e_attrs, "aliasedobjectname" ) ) != NULL) &&
( depth < be->be_maxDerefDepth );
++depth)
{
/*
* make sure there is a defined aliasedobjectname.
* can only have one value so just use first value (0) in the attr list.
*/
if (a->a_vals[0] && a->a_vals[0]->bv_val) {
char *newDN, *oldDN;
Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n",
e->e_dn, a->a_vals[0]->bv_val, 0 );
newDN = ch_strdup (a->a_vals[0]->bv_val);
oldDN = ch_strdup (e->e_ndn);
/*
* release past lock if not original
*/
if ( (depth > 0) && e ) {
bdb2i_cache_return_entry_r(&li->li_cache, e);
}
/* make sure new and old DN are not same to avoid loops */
dn_normalize_case (newDN);
if ( strcmp (newDN, oldDN) == 0 ) {
Debug( LDAP_DEBUG_TRACE,
"<= %s alias is same as current %s\n",
oldDN, newDN, 0 );
send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
"Circular alias" );
free (newDN);
free (oldDN);
break;
}
/* make sure new and original are not same to avoid deadlocks */
if ( strcmp (newDN, origDN->e_ndn) == 0 ) {
Debug( LDAP_DEBUG_TRACE,
"<= %s alias is same as original %s\n",
oldDN, origDN->e_ndn, 0 );
send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
"Circular alias" );
free (newDN);
free (oldDN);
break;
}
/*
* ok, so what happens if there is an alias in the DN of a dereferenced
* alias object?
*/
if ( (e = bdb2i_dn2entry_r( be, newDN, &matched )) == NULL ) {
/* could not deref return error */
Debug( LDAP_DEBUG_TRACE,
"<= %s is a dangling alias to %s\n",
oldDN, newDN, 0 );
send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "",
"Dangling Alias" );
if(matched != NULL) free(matched);
free (newDN);
free (oldDN);
break;
}
free (newDN);
free (oldDN);
}
else {
/*
* there was an aliasedobjectname defined but no data.
* this can't happen, right?
*/
Debug( LDAP_DEBUG_TRACE,
"<= %s has no data in aliasedobjectname attribute\n",
(e && e->e_dn) ? e->e_dn : "(null)", 0, 0 );
send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
"Alias missing aliasedobjectname" );
break;
}
}
/*
* warn if we pulled out due to exceeding the maximum deref depth
*/
if ( depth >= be->be_maxDerefDepth ) {
Debug( LDAP_DEBUG_TRACE,
"<= deref(\"%s\") exceeded maximum deref depth (%d) at \"%s\"\n",
origDN->e_dn ? origDN->e_dn : "(null)",
be->be_maxDerefDepth,
(e && e->e_ndn) ? e->e_ndn : "(null)");
send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "",
"Maximum alias dereference depth exceeded" );
}
return e;
}
/*
* given a DN fully deref it and return the real DN or original DN if it fails
* This involves finding the last matched part then reconstructing forward
* e.g.
* ou=MyOU,o=MyAliasedOrg,c=MyCountry where o=MyAliasedOrg is an alias for o=MyOrg
* loop starts with newDN = ou=MyOU,o=MyAliasedOrg,c=MyCountry
* dn2entry_r on newDN gives null entry and o=MyAliasedOrg,c=MyCountry matched
* dn2entry_r on matched gives o=MyAliasedOrg,c=MyCountry entry
* remainder is ou=MyOU
* dereferencing o=MyAliasedOrg,c=MyCountry yields entry o=MyOrg,c=MyCountry
* release lock on o=MyAliasedOrg,c=MyCountry entry
* reconstructed dn is ou=MyOU,o=MyOrg,c=MyCountry
* release lock on o=MyOrg,c=MyCountry entry
*/
char *bdb2i_derefDN ( Backend *be,
Connection *conn,
Operation *op,
char *dn
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *matched = 0;
char *newDN = NULL;
int depth, i;
Entry *eMatched;
Entry *eDeref;
Entry *eNew;
if (!dn) return NULL;
Debug( LDAP_DEBUG_TRACE,
"<= dereferencing dn: \"%s\"\n",
dn, 0, 0 );
newDN = ch_strdup ( dn );
/* while we don't have a matched dn, deref the DN */
for ( depth = 0;
( (eMatched = bdb2i_dn2entry_r( be, newDN, &matched )) == NULL) &&
(depth < be->be_maxDerefDepth);
++depth ) {
if ((matched != NULL) && *matched) {
char *submatch;
/*
* make sure there actually is an entry for the matched part
*/
if ( (eMatched = bdb2i_dn2entry_r( be, matched, &submatch )) != NULL) {
char *remainder; /* part before the aliased part */
int rlen = strlen(newDN) - strlen(matched);
Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched, 0, 0 );
remainder = ch_malloc (rlen + 1);
strncpy ( remainder, newDN, rlen );
remainder[rlen] = '\0';
Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 );
if ((eNew = bdb2i_derefAlias_r( be, conn, op, eMatched )) == NULL) {
free (matched);
matched = NULL;
free (newDN);
newDN = NULL;
free (remainder);
remainder = NULL;
bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
eMatched = NULL;
break; /* no associated entry, dont deref */
}
else {
Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 );
i = strcasecmp (matched, eNew->e_dn);
/* free reader lock */
bdb2i_cache_return_entry_r(&li->li_cache, eNew);
free (matched);
matched = NULL;
if (! i) {
/* newDN same as old so not an alias, no need to go further */
free (newDN);
newDN = NULL;
free (remainder);
bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
eMatched = NULL;
break;
}
/*
* we have dereferenced the aliased part so put
* the new dn together
*/
free (newDN);
newDN = ch_malloc (strlen(eMatched->e_dn) + rlen + 1);
strcpy (newDN, remainder);
strcat (newDN, eMatched->e_dn);
Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 );
free (remainder);
}
/* free reader lock */
bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
}
else {
if(submatch != NULL) free(submatch);
break; /* there was no entry for the matched part */
}
}
else {
break; /* there was no matched part */
}
}
/* release lock if a match terminated the loop, there should be no
* outstanding locks at this point
*/
if(eMatched != NULL) {
/* free reader lock */
bdb2i_cache_return_entry_r(&li->li_cache, eMatched);
}
/*
* the final part of the DN might be an alias so try to dereference it.
* e.g. if we had started with dn = o=MyAliasedOrg,c=MyCountry the dn would match
* and the above loop complete but we would still be left with an aliased DN.
*/
if ( (eNew = bdb2i_dn2entry_r( be, newDN, &matched )) != NULL) {
if ((eDeref = bdb2i_derefAlias_r( be, conn, op, eNew )) != NULL) {
free (newDN);
newDN = ch_strdup (eDeref->e_dn);
/* free reader lock */
bdb2i_cache_return_entry_r(&li->li_cache, eDeref);
}
/* free reader lock */
bdb2i_cache_return_entry_r(&li->li_cache, eNew);
}
if (matched != NULL) free(matched);
/*
* warn if we exceeded the max depth as the resulting DN may not be dereferenced
*/
if (depth >= be->be_maxDerefDepth) {
if (newDN) {
Debug( LDAP_DEBUG_TRACE,
"<= max deref depth exceeded in derefDN for \"%s\", result \"%s\"\n",
dn, newDN, 0 );
free (newDN);
newDN = NULL;
} else {
Debug( LDAP_DEBUG_TRACE,
"<= max deref depth exceeded in derefDN for \"%s\", result NULL\n",
dn, 0, 0 );
}
send_ldap_result( conn, op, LDAP_ALIAS_DEREF_PROBLEM, "",
"Maximum alias dereference depth exceeded for base" );
}
if (newDN == NULL) {
newDN = ch_strdup ( dn );
}
Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 );
return newDN;
}

View file

@ -0,0 +1,171 @@
/* attr.c - backend routines for dealing with attributes */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-bdb2.h"
static int
ainfo_type_cmp(
char *type,
struct attrinfo *a
)
{
return( strcasecmp( type, a->ai_type ) );
}
static int
ainfo_cmp(
struct attrinfo *a,
struct attrinfo *b
)
{
return( strcasecmp( a->ai_type, b->ai_type ) );
}
/*
* Called when a duplicate "index" line is encountered.
*
* returns 1 => original from init code, indexmask updated
* 2 => original not from init code, warn the user
*/
static int
ainfo_dup(
struct attrinfo *a,
struct attrinfo *b
)
{
/*
* if the duplicate definition is because we initialized the attr,
* just add what came from the config file. otherwise, complain.
*/
if ( a->ai_indexmask & INDEX_FROMINIT ) {
a->ai_indexmask |= b->ai_indexmask;
return( 1 );
}
return( 2 );
}
void
bdb2i_attr_masks(
struct ldbminfo *li,
char *type,
int *indexmask,
int *syntaxmask
)
{
struct attrinfo *a;
*indexmask = 0;
*syntaxmask = 0;
if ( (a = (struct attrinfo *) avl_find( li->li_attrs, type,
ainfo_type_cmp )) == NULL ) {
if ( (a = (struct attrinfo *) avl_find( li->li_attrs, "default",
ainfo_type_cmp )) == NULL ) {
return;
}
}
*indexmask = a->ai_indexmask;
if ( strcasecmp( a->ai_type, "default" ) == 0 ) {
*syntaxmask = attr_syntax( type );
} else {
*syntaxmask = a->ai_syntaxmask;
}
}
/* BDB2 changed */
void
bdb2i_attr_index_config(
struct ldbminfo *li,
char *fname,
int lineno,
int argc,
char **argv,
int init
)
{
int i, j;
char **attrs, **indexes;
struct attrinfo *a;
attrs = str2charray( argv[0], "," );
if ( argc > 1 ) {
indexes = str2charray( argv[1], "," );
}
for ( i = 0; attrs[i] != NULL; i++ ) {
a = (struct attrinfo *) ch_malloc( sizeof(struct attrinfo) );
a->ai_type = ch_strdup( attrs[i] );
a->ai_syntaxmask = attr_syntax( a->ai_type );
if ( argc == 1 ) {
a->ai_indexmask = (INDEX_PRESENCE | INDEX_EQUALITY |
INDEX_APPROX | INDEX_SUB);
} else {
a->ai_indexmask = 0;
for ( j = 0; indexes[j] != NULL; j++ ) {
if ( strncasecmp( indexes[j], "pres", 4 )
== 0 ) {
a->ai_indexmask |= INDEX_PRESENCE;
} else if ( strncasecmp( indexes[j], "eq", 2 )
== 0 ) {
a->ai_indexmask |= INDEX_EQUALITY;
} else if ( strncasecmp( indexes[j], "approx",
6 ) == 0 ) {
a->ai_indexmask |= INDEX_APPROX;
} else if ( strncasecmp( indexes[j], "sub", 3 )
== 0 ) {
a->ai_indexmask |= INDEX_SUB;
} else if ( strncasecmp( indexes[j], "none", 4 )
== 0 ) {
if ( a->ai_indexmask != 0 ) {
fprintf( stderr,
"%s: line %d: index type \"none\" cannot be combined with other types\n",
fname, lineno );
}
a->ai_indexmask = 0;
} else {
fprintf( stderr,
"%s: line %d: unknown index type \"%s\" (ignored)\n",
fname, lineno, indexes[j] );
fprintf( stderr,
"valid index types are \"pres\", \"eq\", \"approx\", or \"sub\"\n" );
}
}
}
if ( init ) {
a->ai_indexmask |= INDEX_FROMINIT;
} else {
if ( a->ai_indexmask )
bdb2i_txn_attr_config( li, a->ai_type, 0 );
}
switch (avl_insert( &li->li_attrs, (caddr_t) a, ainfo_cmp, ainfo_dup )) {
case 1: /* duplicate - updating init version */
free( a->ai_type );
free( (char *) a );
break;
case 2: /* user duplicate - ignore and warn */
fprintf( stderr,
"%s: line %d: duplicate index definition for attr \"%s\" (ignored)\n",
fname, lineno, a->ai_type );
free( a->ai_type );
free( (char *) a );
break;
default:; /* inserted ok */
/* FALL */
}
}
charray_free( attrs );
if ( argc > 1 )
charray_free( indexes );
}

View file

@ -0,0 +1,185 @@
/* back-bdb2.h - ldap bdb2 back-end header file */
#ifndef _BACK_BDB2_H_
#define _BACK_BDB2_H_
#include "ldbm.h"
#include "db.h"
LDAP_BEGIN_DECL
#define DEFAULT_CACHE_SIZE 1000
/* since DEFAULT_DB_PAGE_SIZE is 1K, we have 128K,
which is suggested by Sleepycat */
#define DEFAULT_DBCACHE_SIZE (128 * DEFAULT_DB_PAGE_SIZE)
#define DEFAULT_DB_DIRECTORY "/usr/tmp"
#define DEFAULT_MODE 0600
#define SUBLEN 3
/*
* there is a single index for each attribute. these prefixes insure
* that there is no collision among keys.
*/
#define EQ_PREFIX '=' /* prefix for equality keys */
#define APPROX_PREFIX '~' /* prefix for approx keys */
#define SUB_PREFIX '*' /* prefix for substring keys */
#define CONT_PREFIX '\\' /* prefix for continuation keys */
#define UNKNOWN_PREFIX '?' /* prefix for unknown keys */
#define DEFAULT_BLOCKSIZE 8192
/*
* This structure represents an id block on disk and an id list
* in core.
*
* The fields have the following meanings:
*
* b_nmax maximum number of ids in this block. if this is == ALLIDSBLOCK,
* then this block represents all ids.
* b_nids current number of ids in use in this block. if this
* is == INDBLOCK, then this block is an indirect block
* containing a list of other blocks containing actual ids.
* the list is terminated by an id of NOID.
* b_ids a list of the actual ids themselves
*/
typedef ID ID_BLOCK;
#define ID_BLOCK_NMAX_OFFSET 0
#define ID_BLOCK_NIDS_OFFSET 1
#define ID_BLOCK_IDS_OFFSET 2
/* all ID_BLOCK macros operate on a pointer to a ID_BLOCK */
#define ID_BLOCK_NMAX(b) ((b)[ID_BLOCK_NMAX_OFFSET])
#define ID_BLOCK_NIDS(b) ((b)[ID_BLOCK_NIDS_OFFSET])
#define ID_BLOCK_ID(b, n) ((b)[ID_BLOCK_IDS_OFFSET+(n)])
#define ID_BLOCK_NOID(b, n) (ID_BLOCK_ID((b),(n)) == NOID)
#define ID_BLOCK_ALLIDS_VALUE 0
#define ID_BLOCK_ALLIDS(b) (ID_BLOCK_NMAX(b) == ID_BLOCK_ALLIDS_VALUE)
#define ID_BLOCK_INDIRECT_VALUE 0
#define ID_BLOCK_INDIRECT(b) (ID_BLOCK_NIDS(b) == ID_BLOCK_INDIRECT_VALUE)
/* for the in-core cache of entries */
struct cache {
int c_maxsize;
int c_cursize;
Avlnode *c_dntree;
Avlnode *c_idtree;
Entry *c_lruhead; /* lru - add accessed entries here */
Entry *c_lrutail; /* lru - rem lru entries from here */
ldap_pvt_thread_mutex_t c_mutex;
};
/* for the cache of open index files (re-used for txn) */
struct dbcache {
int dbc_refcnt;
int dbc_maxids;
int dbc_maxindirect;
time_t dbc_lastref;
long dbc_blksize;
char *dbc_name;
LDBM dbc_db;
struct dbcache *next;
};
typedef struct dbcache BDB2_TXN_FILES;
/* for the cache of attribute information (which are indexed, etc.) */
struct attrinfo {
char *ai_type; /* type name (cn, sn, ...) */
int ai_indexmask; /* how the attr is indexed */
#define INDEX_PRESENCE 0x01
#define INDEX_EQUALITY 0x02
#define INDEX_APPROX 0x04
#define INDEX_SUB 0x08
#define INDEX_UNKNOWN 0x10
#define INDEX_FROMINIT 0x20
int ai_syntaxmask; /* what kind of syntax */
/* ...from slap.h...
#define SYNTAX_CIS 0x01
#define SYNTAX_CES 0x02
#define SYNTAX_BIN 0x04
... etc. ...
*/
};
#define MAXDBCACHE 10
/* this could be made an option */
#ifndef SLAPD_NEXTID_CHUNK
#define SLAPD_NEXTID_CHUNK 32
#endif
/* TP stuff */
typedef struct _bdb2_txn_head {
/* counter and timer to control checkpoints */
size_t txn_cnt;
time_t txn_chkp;
/* a list of all DB files in use */
BDB2_TXN_FILES *dbFiles;
/* for performance reasons we have pointers to fixed descriptors */
BDB2_TXN_FILES *dbFileHandle[4];
#define BDB2_DB_DN_FILE 0
#define BDB2_DB_DN2ID_FILE 1
#define BDB2_DB_ID2ENTRY_FILE 2
#define BDB2_DB_ID2CHILDREN_FILE 3
#define BDB2_DB_OC_IDX_FILE 4
/* is the default attribute index set to non-none */
int withDefIDX;
#define BDB2_WITH_DEF_IDX 1
} BDB2_TXN_HEAD;
/* end of TP stuff */
struct ldbminfo {
ID li_nextid;
#if SLAPD_NEXTID_CHUNK > 1
ID li_nextid_wrote;
#endif
char *li_nextid_file;
ldap_pvt_thread_mutex_t li_root_mutex;
ldap_pvt_thread_mutex_t li_add_mutex;
ldap_pvt_thread_mutex_t li_nextid_mutex;
int li_mode;
char *li_directory;
struct cache li_cache;
Avlnode *li_attrs;
int li_dbcachesize;
int li_dbcachewsync;
struct dbcache li_dbcache[MAXDBCACHE];
ldap_pvt_thread_mutex_t li_dbcache_mutex;
ldap_pvt_thread_cond_t li_dbcache_cv;
/* Berkeley DB2 Environment */
DB_ENV li_db_env;
char *li_dbhome;
BDB2_TXN_HEAD li_txn_head;
};
extern int bdb2i_with_dbenv;
#include "proto-back-bdb2.h"
LDAP_END_DECL
#endif /* _back_bdb2_h_ */

View file

@ -0,0 +1,262 @@
/* bind.c - bdb2 backend bind and unbind routines */
#include "portable.h"
#include <stdio.h>
#include <ac/krb.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/unistd.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
#include <lutil.h>
#ifdef HAVE_KERBEROS
extern int bdb2i_krbv4_ldap_auth();
#endif
static int
crypted_value_find(
struct berval **vals,
struct berval *v,
int syntax,
int normalize,
struct berval *cred
)
{
int i;
for ( i = 0; vals[i] != NULL; i++ ) {
if ( syntax != SYNTAX_BIN ) {
int result;
#ifdef SLAPD_CRYPT
ldap_pvt_thread_mutex_lock( &crypt_mutex );
#endif
result = lutil_passwd(
(char*) cred->bv_val,
(char*) vals[i]->bv_val);
#ifdef SLAPD_CRYPT
ldap_pvt_thread_mutex_unlock( &crypt_mutex );
#endif
return result;
} else {
if ( value_cmp( vals[i], v, syntax, normalize ) == 0 ) {
return( 0 );
}
}
}
return( 1 );
}
static int
bdb2i_back_bind_internal(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
int method,
struct berval *cred,
char** edn
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Entry *e;
Attribute *a;
int rc;
char *matched;
#ifdef HAVE_KERBEROS
char krbname[MAX_K_NAME_SZ + 1];
AUTH_DAT ad;
#endif
Debug(LDAP_DEBUG_ARGS, "==> bdb2_back_bind: dn: %s\n", dn, 0, 0);
*edn = NULL;
/* get entry with reader lock */
if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) {
/* allow noauth binds */
if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
/*
* bind successful, but return 1 so we don't
* authorize based on noauth credentials
*/
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
rc = 1;
} else if ( be_isroot_pw( be, dn, cred ) ) {
/* front end will send result */
*edn = ch_strdup( be_root_dn( be ) );
rc = 0;
} else {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, NULL );
rc = 1;
}
if ( matched != NULL ) {
free( matched );
}
return( rc );
}
*edn = ch_strdup( e->e_dn );
/* check for deleted */
switch ( method ) {
case LDAP_AUTH_SIMPLE:
if ( cred->bv_len == 0 ) {
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
/* stop front end from sending result */
rc = 1;
goto return_results;
} else if ( be_isroot_pw( be, dn, cred ) ) {
/* front end will send result */
*edn = ch_strdup( be_root_dn( be ) );
rc = 0;
goto return_results;
}
if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) {
if ( be_isroot_pw( be, dn, cred ) ) {
/* front end will send result */
*edn = ch_strdup( be_root_dn( be ) );
rc = 0;
goto return_results;
}
send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
NULL, NULL );
rc = 1;
goto return_results;
}
if ( crypted_value_find( a->a_vals, cred, a->a_syntax, 0, cred ) != 0 )
{
if ( be_isroot_pw( be, dn, cred ) ) {
/* front end will send result */
*edn = ch_strdup( be_root_dn( be ) );
rc = 0;
goto return_results;
}
send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
NULL, NULL );
rc = 1;
goto return_results;
}
rc = 0;
break;
#ifdef HAVE_KERBEROS
case LDAP_AUTH_KRBV41:
if ( bdb2i_krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) {
send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
NULL, NULL );
rc = 0;
goto return_results;
}
sprintf( krbname, "%s%s%s@%s", ad.pname, *ad.pinst ? "."
: "", ad.pinst, ad.prealm );
if ( (a = attr_find( e->e_attrs, "krbname" )) == NULL ) {
/*
* no krbName values present: check against DN
*/
if ( strcasecmp( dn, krbname ) == 0 ) {
rc = 0; /* XXX wild ass guess */
break;
}
send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
NULL, NULL );
rc = 1;
goto return_results;
} else { /* look for krbName match */
struct berval krbval;
krbval.bv_val = krbname;
krbval.bv_len = strlen( krbname );
if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 ) != 0 ) {
send_ldap_result( conn, op,
LDAP_INVALID_CREDENTIALS, NULL, NULL );
rc = 1;
goto return_results;
}
}
rc = 0;
break;
case LDAP_AUTH_KRBV42:
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
/* stop front end from sending result */
rc = 1;
goto return_results;
#endif
default:
send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED,
NULL, "auth method not supported" );
rc = 1;
goto return_results;
}
return_results:;
/* free entry and reader lock */
bdb2i_cache_return_entry_r( &li->li_cache, e );
/* front end with send result on success (rc==0) */
return( rc );
}
int
bdb2_back_bind(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
int method,
struct berval *cred,
char** edn
)
{
DB_LOCK lock;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
if ( bdb2i_enter_backend_r( &li->li_db_env, &lock ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
return( 1 );
}
ret = bdb2i_back_bind_internal( be, conn, op, dn, method, cred, edn );
(void) bdb2i_leave_backend( &li->li_db_env, lock );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "conn=%d op=%d BIND elapsed=%s\n",
conn->c_connid, op->o_opid, elapsed_time );
free( elapsed_time );
}
return( ret );
}

View file

@ -0,0 +1,462 @@
/* cache.c - routines to maintain an in-core cache of entries */
#include "portable.h"
#include <stdio.h>
#include <ac/errno.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
static int cache_delete_entry_internal(struct cache *cache, Entry *e);
#ifdef LDAP_DEBUG
static void lru_print(struct cache *cache);
#endif
/*
* the cache has three entry points (ways to find things):
*
* by entry e.g., if you already have an entry from the cache
* and want to delete it. (really by entry ptr)
* by dn e.g., when looking for the base object of a search
* by id e.g., for search candidates
*
* these correspond to three different avl trees that are maintained.
*/
static int
cache_entry_cmp( Entry *e1, Entry *e2 )
{
return( e1 < e2 ? -1 : (e1 > e2 ? 1 : 0) );
}
static int
cache_entrydn_cmp( Entry *e1, Entry *e2 )
{
/* compare their normalized UPPERCASED dn's */
return( strcmp( e1->e_ndn, e2->e_ndn ) );
}
static int
cache_entryid_cmp( Entry *e1, Entry *e2 )
{
return( e1->e_id < e2->e_id ? -1 : (e1->e_id > e2->e_id ? 1 : 0) );
}
void
bdb2i_cache_set_state( struct cache *cache, Entry *e, int state )
{
/* set cache mutex */
ldap_pvt_thread_mutex_lock( &cache->c_mutex );
e->e_state = state;
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
}
#ifdef not_used
static void
cache_return_entry( struct cache *cache, Entry *e )
{
/* set cache mutex */
ldap_pvt_thread_mutex_lock( &cache->c_mutex );
if ( --e->e_refcnt == 0 && e->e_state == ENTRY_STATE_DELETED ) {
entry_free( e );
}
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
}
#endif
static void
cache_return_entry_rw( struct cache *cache, Entry *e, int rw )
{
Debug( LDAP_DEBUG_TRACE, "====> cache_return_entry_%s\n",
rw ? "w" : "r", 0, 0);
/* set cache mutex */
ldap_pvt_thread_mutex_lock( &cache->c_mutex );
entry_rdwr_unlock(e, rw);;
if ( --e->e_refcnt == 0 && e->e_state == ENTRY_STATE_DELETED ) {
entry_free( e );
}
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
}
void
bdb2i_cache_return_entry_r( struct cache *cache, Entry *e )
{
cache_return_entry_rw(cache, e, 0);
}
void
bdb2i_cache_return_entry_w( struct cache *cache, Entry *e )
{
cache_return_entry_rw(cache, e, 1);
}
#define LRU_DELETE( cache, e ) { \
if ( e->e_lruprev != NULL ) { \
e->e_lruprev->e_lrunext = e->e_lrunext; \
} else { \
cache->c_lruhead = e->e_lrunext; \
} \
if ( e->e_lrunext != NULL ) { \
e->e_lrunext->e_lruprev = e->e_lruprev; \
} else { \
cache->c_lrutail = e->e_lruprev; \
} \
}
#define LRU_ADD( cache, e ) { \
e->e_lrunext = cache->c_lruhead; \
if ( e->e_lrunext != NULL ) { \
e->e_lrunext->e_lruprev = e; \
} \
cache->c_lruhead = e; \
e->e_lruprev = NULL; \
if ( cache->c_lrutail == NULL ) { \
cache->c_lrutail = e; \
} \
}
/*
* cache_create_entry_lock - create an entry in the cache, and lock it.
* returns: 0 entry has been created and locked
* 1 entry already existed
* -1 something bad happened
*/
int
bdb2i_cache_add_entry_lock(
struct cache *cache,
Entry *e,
int state
)
{
int i, rc;
Entry *ee;
/* set cache mutex */
ldap_pvt_thread_mutex_lock( &cache->c_mutex );
if ( avl_insert( &cache->c_dntree, (caddr_t) e,
cache_entrydn_cmp, avl_dup_error ) != 0 )
{
Debug( LDAP_DEBUG_TRACE,
"====> cache_add_entry lock: entry %20s id %lu already in dn cache\n",
e->e_dn, e->e_id, 0 );
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( 1 );
}
/* id tree */
if ( avl_insert( &cache->c_idtree, (caddr_t) e,
cache_entryid_cmp, avl_dup_error ) != 0 )
{
Debug( LDAP_DEBUG_ANY,
"====> entry %20s id %lu already in id cache\n",
e->e_dn, e->e_id, 0 );
/* delete from dn tree inserted above */
if ( avl_delete( &cache->c_dntree, (caddr_t) e,
cache_entrydn_cmp ) == NULL )
{
Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
0, 0, 0 );
}
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( -1 );
}
e->e_state = state;
e->e_refcnt = 1;
/* lru */
LRU_ADD( cache, e );
if ( ++cache->c_cursize > cache->c_maxsize ) {
/*
* find the lru entry not currently in use and delete it.
* in case a lot of entries are in use, only look at the
* first 10 on the tail of the list.
*/
i = 0;
while ( cache->c_lrutail != NULL && cache->c_lrutail->e_refcnt
!= 0 && i < 10 ) {
/* move this in-use entry to the front of the q */
ee = cache->c_lrutail;
LRU_DELETE( cache, ee );
LRU_ADD( cache, ee );
i++;
}
/*
* found at least one to delete - try to get back under
* the max cache size.
*/
while ( cache->c_lrutail != NULL && cache->c_lrutail->e_refcnt
== 0 && cache->c_cursize > cache->c_maxsize ) {
e = cache->c_lrutail;
/* XXX check for writer lock - should also check no readers pending */
#ifdef LDAP_DEBUG
assert(!ldap_pvt_thread_rdwr_active(&e->e_rdwr));
#endif
/* delete from cache and lru q */
rc = cache_delete_entry_internal( cache, e );
entry_free( e );
}
}
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( 0 );
}
/*
* cache_find_entry_dn2id - find an entry in the cache, given dn
*/
ID
bdb2i_cache_find_entry_dn2id(
Backend *be,
struct cache *cache,
char *dn
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Entry e, *ep;
ID id;
/* set cache mutex */
ldap_pvt_thread_mutex_lock( &cache->c_mutex );
e.e_dn = dn;
e.e_ndn = dn_normalize_case( ch_strdup( dn ) );
if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
cache_entrydn_cmp )) != NULL )
{
/*
* ep now points to an unlocked entry
* we do not need to lock the entry if we only
* check the state, refcnt, LRU, and id.
*/
free(e.e_ndn);
Debug(LDAP_DEBUG_TRACE, "====> cache_find_entry_dn2id: found dn: %s\n",
dn, 0, 0);
/*
* entry is deleted or not fully created yet
*/
if ( ep->e_state == ENTRY_STATE_DELETED ||
ep->e_state == ENTRY_STATE_CREATING )
{
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( NOID );
}
/* lru */
LRU_DELETE( cache, ep );
LRU_ADD( cache, ep );
/* save id */
id = ep->e_id;
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( id );
}
free(e.e_ndn);
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( NOID );
}
/*
* cache_find_entry_id - find an entry in the cache, given id
*/
Entry *
bdb2i_cache_find_entry_id(
struct cache *cache,
ID id,
int rw
)
{
Entry e;
Entry *ep;
e.e_id = id;
try_again:
/* set cache mutex */
ldap_pvt_thread_mutex_lock( &cache->c_mutex );
if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
cache_entryid_cmp )) != NULL )
{
Debug(LDAP_DEBUG_TRACE,
"====> cache_find_entry_dn2id: found id: %ld rw: %d\n",
id, rw, 0);
/*
* entry is deleted or not fully created yet
*/
if ( ep->e_state == ENTRY_STATE_DELETED ||
ep->e_state == ENTRY_STATE_CREATING )
{
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( NULL );
}
/* acquire reader lock */
if ( entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
/* could not acquire entry lock...
* owner cannot free as we have the cache locked.
* so, unlock the cache, yield, and try again.
*/
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
ldap_pvt_thread_yield();
goto try_again;
}
/* lru */
LRU_DELETE( cache, ep );
LRU_ADD( cache, ep );
ep->e_refcnt++;
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( ep );
}
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( NULL );
}
/*
* cache_delete_entry - delete the entry e from the cache. the caller
* should have obtained e (increasing its ref count) via a call to one
* of the cache_find_* routines. the caller should *not* call the
* cache_return_entry() routine prior to calling cache_delete_entry().
* it performs this function.
*
* returns: 0 e was deleted ok
* 1 e was not in the cache
* -1 something bad happened
*/
int
bdb2i_cache_delete_entry(
struct cache *cache,
Entry *e
)
{
int rc;
Debug( LDAP_DEBUG_TRACE, "====> cache_delete_entry:\n", 0, 0, 0 );
/* XXX check for writer lock - should also check no readers pending */
#ifdef LDAP_DEBUG
assert(ldap_pvt_thread_rdwr_writers(&e->e_rdwr));
#endif
/* set cache mutex */
ldap_pvt_thread_mutex_lock( &cache->c_mutex );
rc = cache_delete_entry_internal( cache, e );
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( rc );
}
static int
cache_delete_entry_internal(
struct cache *cache,
Entry *e
)
{
int rc = 0; /* return code */
/* dn tree */
if ( avl_delete( &cache->c_dntree, (caddr_t) e, cache_entrydn_cmp )
== NULL )
{
rc = -1;
}
/* id tree */
if ( avl_delete( &cache->c_idtree, (caddr_t) e, cache_entryid_cmp )
== NULL )
{
rc = -1;
}
if (rc != 0) {
return rc;
}
/* lru */
LRU_DELETE( cache, e );
cache->c_cursize--;
/*
* flag entry to be freed later by a call to cache_return_entry()
*/
e->e_state = ENTRY_STATE_DELETED;
return( 0 );
}
#ifdef LDAP_DEBUG
static void
lru_print( struct cache *cache )
{
Entry *e;
fprintf( stderr, "LRU queue (head to tail):\n" );
for ( e = cache->c_lruhead; e != NULL; e = e->e_lrunext ) {
fprintf( stderr, "\tdn %20s id %lu refcnt %d\n", e->e_dn,
e->e_id, e->e_refcnt );
}
fprintf( stderr, "LRU queue (tail to head):\n" );
for ( e = cache->c_lrutail; e != NULL; e = e->e_lruprev ) {
fprintf( stderr, "\tdn %20s id %lu refcnt %d\n", e->e_dn,
e->e_id, e->e_refcnt );
}
}
#endif

View file

@ -0,0 +1,52 @@
/* close.c - close bdb2 backend */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
static int
bdb2i_back_db_close_internal( Backend *be )
{
Debug( LDAP_DEBUG_TRACE, "bdb2 backend saving nextid\n", 0, 0, 0 );
if ( bdb2i_next_id_save( be ) < 0 ) {
Debug( LDAP_DEBUG_ANY, "bdb2 backend nextid save failed!\n", 0, 0, 0 );
}
Debug( LDAP_DEBUG_TRACE, "bdb2 backend syncing\n", 0, 0, 0 );
bdb2i_cache_flush_all( be );
Debug( LDAP_DEBUG_TRACE, "bdb2 backend done syncing\n", 0, 0, 0 );
return 0;
}
int
bdb2_back_db_close( Backend *be )
{
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
ret = bdb2i_back_db_close_internal( be );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "CLOSE elapsed=%s\n",
elapsed_time, 0, 0 );
free( elapsed_time );
}
return( ret );
}

View file

@ -0,0 +1,107 @@
/* compare.c - bdb2 backend compare routine */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
static int
bdb2i_back_compare_internal(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
Ava *ava
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *matched;
Entry *e;
Attribute *a;
int rc;
/* get entry with reader lock */
if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
if(matched == NULL) free(matched);
return( 1 );
}
/* check for deleted */
if ( ! access_allowed( be, conn, op, e,
ava->ava_type, &ava->ava_value, ACL_COMPARE ) )
{
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
rc = 1;
goto return_results;
}
if ( (a = attr_find( e->e_attrs, ava->ava_type )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_ATTRIBUTE, "", "" );
rc = 1;
goto return_results;
}
if ( value_find( a->a_vals, &ava->ava_value, a->a_syntax, 1 ) == 0 )
send_ldap_result( conn, op, LDAP_COMPARE_TRUE, "", "" );
else
send_ldap_result( conn, op, LDAP_COMPARE_FALSE, "", "" );
rc = 0;
return_results:;
bdb2i_cache_return_entry_r( &li->li_cache, e );
return( rc );
}
int
bdb2_back_compare(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
Ava *ava
)
{
DB_LOCK lock;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
if ( bdb2i_enter_backend_r( &li->li_db_env, &lock ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
return( 1 );
}
ret = bdb2i_back_compare_internal( be, conn, op, dn, ava );
(void) bdb2i_leave_backend( &li->li_db_env, lock );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "conn=%d op=%d CMP elapsed=%s\n",
conn->c_connid, op->o_opid, elapsed_time );
free( elapsed_time );
}
return( ret );
}

View file

@ -0,0 +1,138 @@
/* config.c - bdb2 backend configuration file routine */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-bdb2.h"
static int
bdb2i_back_db_config_internal(
Backend *be,
char *fname,
int lineno,
int argc,
char **argv
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
if ( li == NULL ) {
fprintf( stderr, "%s: line %d: ldbm backend info is null!\n",
fname, lineno );
return( 1 );
}
/* directory where database files live */
if ( strcasecmp( argv[0], "directory" ) == 0 ) {
if ( argc < 2 ) {
fprintf( stderr,
"%s: line %d: missing dir in \"directory <dir>\" line\n",
fname, lineno );
return( 1 );
}
li->li_directory = ch_strdup( argv[1] );
li->li_nextid_file =
ch_malloc( strlen(li->li_directory) + sizeof("/NEXTID") );
strcpy(li->li_nextid_file, li->li_directory);
strcat(li->li_nextid_file, "/NEXTID");
/* mode with which to create new database files */
} else if ( strcasecmp( argv[0], "mode" ) == 0 ) {
if ( argc < 2 ) {
fprintf( stderr,
"%s: line %d: missing mode in \"mode <mode>\" line\n",
fname, lineno );
return( 1 );
}
li->li_mode = strtol( argv[1], NULL, 0 );
/* attribute to index */
} else if ( strcasecmp( argv[0], "index" ) == 0 ) {
if ( argc < 2 ) {
fprintf( stderr,
"%s: line %d: missing attr in \"index <attr> [pres,eq,approx,sub]\" line\n",
fname, lineno );
return( 1 );
} else if ( argc > 3 ) {
fprintf( stderr,
"%s: line %d: extra junk after \"index <attr> [pres,eq,approx,sub]\" line (ignored)\n",
fname, lineno );
}
bdb2i_attr_index_config( li, fname, lineno, argc - 1, &argv[1], 0 );
/* size of the cache in entries */
} else if ( strcasecmp( argv[0], "cachesize" ) == 0 ) {
if ( argc < 2 ) {
fprintf( stderr,
"%s: line %d: missing size in \"cachesize <size>\" line\n",
fname, lineno );
return( 1 );
}
li->li_cache.c_maxsize = atoi( argv[1] );
/* size of each dbcache in bytes */
} else if ( strcasecmp( argv[0], "dbcachesize" ) == 0 ) {
if ( argc < 2 ) {
fprintf( stderr,
"%s: line %d: missing size in \"dbcachesize <size>\" line\n",
fname, lineno );
return( 1 );
}
li->li_dbcachesize = atoi( argv[1] );
/* we should at least have the suggested 128k */
if ( li->li_dbcachesize < DEFAULT_DBCACHE_SIZE )
li->li_dbcachesize = DEFAULT_DBCACHE_SIZE;
/* no write sync */
} else if ( strcasecmp( argv[0], "dbcachenowsync" ) == 0 ) {
li->li_dbcachewsync = 0;
/* anything else */
} else {
fprintf( stderr,
"%s: line %d: unknown directive \"%s\" in ldbm database definition (ignored)\n",
fname, lineno, argv[0] );
}
return 0;
}
int
bdb2_back_db_config(
Backend *be,
char *fname,
int lineno,
int argc,
char **argv
)
{
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
ret = bdb2i_back_db_config_internal( be, fname, lineno, argc, argv );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "CONFIG elapsed=%s\n",
elapsed_time, 0, 0 );
free( elapsed_time );
}
return( ret );
}

View file

@ -0,0 +1,252 @@
/* ldbmcache.c - maintain a cache of open bdb2 files */
#include "portable.h"
#include <stdio.h>
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include "ldapconfig.h"
#include "slap.h"
#include "back-bdb2.h"
#define ldbm_open_env( buf, flags, mode, dbcachesize, env ) \
ldbm_open( (buf), (flags), (mode), (dbcachesize) )
struct dbcache *
bdb2i_cache_open(
Backend *be,
char *name,
char *suffix,
int flags
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
int i, lru;
time_t oldtime, curtime;
char buf[MAXPATHLEN];
LDBM db;
struct stat st;
int dbcachesize;
/* sprintf( buf, "%s%s%s%s", li->li_directory, DEFAULT_DIRSEP, name, suffix ); */
sprintf( buf, "%s%s", name, suffix );
/* if in slapd, all files are open, so return handle from file cache */
if ( bdb2i_with_dbenv )
return( bdb2i_get_db_file_cache( li, buf ));
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_cache_open( \"%s\", %d, %o )\n", buf,
flags, li->li_mode );
lru = 0;
ldap_pvt_thread_mutex_lock( &currenttime_mutex );
curtime = currenttime;
ldap_pvt_thread_mutex_unlock( &currenttime_mutex );
oldtime = curtime;
ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
for ( i = 0; i < MAXDBCACHE && li->li_dbcache[i].dbc_name != NULL;
i++ ) {
/* already open - return it */
if ( strcmp( li->li_dbcache[i].dbc_name, buf ) == 0 ) {
li->li_dbcache[i].dbc_refcnt++;
Debug( LDAP_DEBUG_TRACE,
"<= bdb2i_cache_open (cache %d)\n", i, 0, 0 );
ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
return( &li->li_dbcache[i] );
}
/* keep track of lru db */
if ( li->li_dbcache[i].dbc_lastref < oldtime &&
li->li_dbcache[i].dbc_refcnt == 0 ) {
lru = i;
oldtime = li->li_dbcache[i].dbc_lastref;
}
}
/* no empty slots, not already open - close lru and use that slot */
if ( i == MAXDBCACHE ) {
i = lru;
if ( li->li_dbcache[i].dbc_refcnt != 0 ) {
Debug( LDAP_DEBUG_ANY,
"bdb2i_cache_open no unused db to close - waiting\n",
0, 0, 0 );
lru = -1;
while ( lru == -1 ) {
ldap_pvt_thread_cond_wait( &li->li_dbcache_cv,
&li->li_dbcache_mutex );
for ( i = 0; i < MAXDBCACHE; i++ ) {
if ( li->li_dbcache[i].dbc_refcnt
== 0 ) {
lru = i;
break;
}
}
}
i = lru;
}
ldbm_close( li->li_dbcache[i].dbc_db );
free( li->li_dbcache[i].dbc_name );
li->li_dbcache[i].dbc_name = NULL;
}
dbcachesize = li->li_dbcachesize;
if ( bdb2i_with_dbenv ) dbcachesize = 0;
if ( (li->li_dbcache[i].dbc_db = ldbm_open_env( buf, flags, li->li_mode,
dbcachesize, &li->li_db_env )) == NULL ) {
Debug( LDAP_DEBUG_TRACE,
"<= bdb2i_cache_open NULL \"%s\" errno %d reason \"%s\")\n",
buf, errno, errno > -1 && errno < sys_nerr ?
sys_errlist[errno] : "unknown" );
ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
return( NULL );
}
li->li_dbcache[i].dbc_name = ch_strdup( buf );
li->li_dbcache[i].dbc_refcnt = 1;
li->li_dbcache[i].dbc_lastref = curtime;
if ( stat( buf, &st ) == 0 ) {
li->li_dbcache[i].dbc_blksize = st.st_blksize;
} else {
li->li_dbcache[i].dbc_blksize = DEFAULT_BLOCKSIZE;
}
li->li_dbcache[i].dbc_maxids = (li->li_dbcache[i].dbc_blksize /
sizeof(ID)) - ID_BLOCK_IDS_OFFSET;
li->li_dbcache[i].dbc_maxindirect = (SLAPD_LDBM_MIN_MAXIDS /
li->li_dbcache[i].dbc_maxids) + 1;
Debug( LDAP_DEBUG_ARGS,
"bdb2i_cache_open (blksize %ld) (maxids %d) (maxindirect %d)\n",
li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids,
li->li_dbcache[i].dbc_maxindirect );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_cache_open (opened %d)\n", i, 0, 0 );
ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
return( &li->li_dbcache[i] );
}
void
bdb2i_cache_close( Backend *be, struct dbcache *db )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
/* if in slapd, all files stay open and we have only
readers or one writer */
if ( bdb2i_with_dbenv ) return;
ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
if ( --db->dbc_refcnt == 0 ) {
ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
}
ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
}
void
bdb2i_cache_really_close( Backend *be, struct dbcache *db )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
/* if in slapd, all files stay open and we have only
readers or one writer */
if ( bdb2i_with_dbenv ) return;
ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
if ( --db->dbc_refcnt == 0 ) {
ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
ldbm_close( db->dbc_db );
free( db->dbc_name );
db->dbc_name = NULL;
}
ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
}
void
bdb2i_cache_flush_all( Backend *be )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
int i;
/* if in slapd, syncing is done by TP */
if ( bdb2i_with_dbenv ) return;
ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
for ( i = 0; i < MAXDBCACHE; i++ ) {
if ( li->li_dbcache[i].dbc_name != NULL ) {
Debug( LDAP_DEBUG_TRACE, "ldbm flushing db (%s)\n",
li->li_dbcache[i].dbc_name, 0, 0 );
ldbm_sync( li->li_dbcache[i].dbc_db );
}
}
ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
}
Datum
bdb2i_cache_fetch(
struct dbcache *db,
Datum key
)
{
Datum data;
ldbm_datum_init( data );
data = ldbm_fetch( db->dbc_db, key );
return( data );
}
int
bdb2i_cache_store(
struct dbcache *db,
Datum key,
Datum data,
int flags
)
{
int rc;
#ifdef LDBM_DEBUG
Statslog( LDAP_DEBUG_STATS,
"=> bdb2i_cache_store(): key.dptr=%s, key.dsize=%d\n",
key.dptr, key.dsize, 0, 0, 0 );
Statslog( LDAP_DEBUG_STATS,
"=> bdb2i_cache_store(): key.dptr=0x%08x, data.dptr=0x%0 8x\n",
key.dptr, data.dptr, 0, 0, 0 );
Statslog( LDAP_DEBUG_STATS,
"=> bdb2i_cache_store(): data.dptr=%s, data.dsize=%d\n",
data.dptr, data.dsize, 0, 0, 0 );
Statslog( LDAP_DEBUG_STATS,
"=> bdb2i_cache_store(): flags=0x%08x\n",
flags, 0, 0, 0, 0 );
#endif /* LDBM_DEBUG */
rc = ldbm_store( db->dbc_db, key, data, flags );
return( rc );
}
int
bdb2i_cache_delete(
struct dbcache *db,
Datum key
)
{
int rc;
rc = ldbm_delete( db->dbc_db, key );
return( rc );
}

View file

@ -0,0 +1,194 @@
/* delete.c - bdb2 backend delete routine */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
static int
bdb2i_back_delete_internal(
Backend *be,
Connection *conn,
Operation *op,
char *dn
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *matched = NULL;
char *pdn = NULL;
Entry *e, *p = NULL;
int rootlock = 0;
int rc = -1;
Debug(LDAP_DEBUG_ARGS, "==> bdb2i_back_delete: %s\n", dn, 0, 0);
/* get entry with writer lock */
if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: no such object %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
if ( matched != NULL ) {
free( matched );
}
return( -1 );
}
/* check for deleted */
if ( bdb2i_has_children( be, e ) ) {
Debug(LDAP_DEBUG_ARGS, "<=- bdb2i_back_delete: non leaf %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF, "",
"" );
goto return_results;
}
#ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
if ( ! access_allowed( be, conn, op, e,
"entry", NULL, ACL_WRITE ) )
{
Debug(LDAP_DEBUG_ARGS,
"<=- bdb2i_back_delete: insufficient access %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
goto return_results;
}
#endif
/* delete from parent's id2children entry */
if( (pdn = dn_parent( be, dn )) != NULL ) {
if( (p = bdb2i_dn2entry_w( be, pdn, &matched )) == NULL) {
Debug( LDAP_DEBUG_TRACE,
"<=- bdb2i_back_delete: parent does not exist\n", 0, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
"", "");
goto return_results;
}
#ifndef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
/* check parent for "children" acl */
if ( ! access_allowed( be, conn, op, p,
"children", NULL, ACL_WRITE ) )
{
Debug( LDAP_DEBUG_TRACE,
"<=- bdb2i_back_delete: no access to parent\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
"", "" );
goto return_results;
}
#endif
} else {
/* no parent, must be root to delete */
if( ! be_isroot( be, op->o_ndn ) ) {
Debug( LDAP_DEBUG_TRACE,
"<=- bdb2i_back_delete: no parent & not root\n", 0, 0, 0);
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
"", "");
goto return_results;
}
ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
rootlock = 1;
}
if ( bdb2i_id2children_remove( be, p, e ) != 0 ) {
Debug(LDAP_DEBUG_ARGS,
"<=- bdb2i_back_delete: operations error %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "","" );
goto return_results;
}
/* delete from dn2id mapping */
if ( bdb2i_dn2id_delete( be, e->e_dn ) != 0 ) {
Debug(LDAP_DEBUG_ARGS,
"<=- bdb2i_back_delete: operations error %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
goto return_results;
}
/* delete from disk and cache */
if ( bdb2i_id2entry_delete( be, e ) != 0 ) {
Debug(LDAP_DEBUG_ARGS,
"<=- bdb2i_back_delete: operations error %s\n",
dn, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
goto return_results;
}
send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
rc = 0;
return_results:;
if ( pdn != NULL ) free(pdn);
if( p != NULL ) {
/* free parent and writer lock */
bdb2i_cache_return_entry_w( &li->li_cache, p );
}
if ( rootlock ) {
/* release root lock */
ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
}
/* free entry and writer lock */
bdb2i_cache_return_entry_w( &li->li_cache, e );
if ( matched != NULL ) free(matched);
return rc;
}
int
bdb2_back_delete(
Backend *be,
Connection *conn,
Operation *op,
char *dn
)
{
DB_LOCK lock;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
if ( bdb2i_enter_backend_w( &li->li_db_env, &lock ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
return( -1 );
}
ret = bdb2i_back_delete_internal( be, conn, op, dn );
(void) bdb2i_leave_backend( &li->li_db_env, lock );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "conn=%d op=%d DEL elapsed=%s\n",
conn->c_connid, op->o_opid, elapsed_time );
free( elapsed_time );
}
return( ret );
}

View file

@ -0,0 +1,232 @@
/* dn2id.c - routines to deal with the dn2id index */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
int
bdb2i_dn2id_add(
Backend *be,
char *dn,
ID id
)
{
int rc, flags;
struct dbcache *db;
Datum key, data;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
ldbm_datum_init( key );
ldbm_datum_init( data );
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_dn2id_add( \"%s\", %ld )\n", dn, id, 0 );
if ( (db = bdb2i_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_WRCREAT ))
== NULL ) {
Debug( LDAP_DEBUG_ANY, "Could not open/create dn2id%s\n",
LDBM_SUFFIX, 0, 0 );
return( -1 );
}
dn = ch_strdup( dn );
dn_normalize_case( dn );
key.dptr = dn;
key.dsize = strlen( dn ) + 1;
data.dptr = (char *) &id;
data.dsize = sizeof(ID);
flags = LDBM_INSERT;
if ( li->li_dbcachewsync ) flags |= LDBM_SYNC;
rc = bdb2i_cache_store( db, key, data, flags );
free( dn );
bdb2i_cache_close( be, db );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id_add %d\n", rc, 0, 0 );
return( rc );
}
ID
bdb2i_dn2id(
Backend *be,
char *dn
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct dbcache *db;
ID id;
Datum key, data;
ldbm_datum_init( key );
ldbm_datum_init( data );
dn = ch_strdup( dn );
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_dn2id( \"%s\" )\n", dn, 0, 0 );
dn_normalize_case( dn );
/* first check the cache */
if ( (id = bdb2i_cache_find_entry_dn2id( be, &li->li_cache, dn )) != NOID ) {
free( dn );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id %lu (in cache)\n", id,
0, 0 );
return( id );
}
if ( (db = bdb2i_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_WRCREAT ))
== NULL ) {
free( dn );
Debug( LDAP_DEBUG_ANY, "<= bdb2i_dn2id could not open dn2id%s\n",
LDBM_SUFFIX, 0, 0 );
return( NOID );
}
key.dptr = dn;
key.dsize = strlen( dn ) + 1;
data = bdb2i_cache_fetch( db, key );
bdb2i_cache_close( be, db );
free( dn );
if ( data.dptr == NULL ) {
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id NOID\n", 0, 0, 0 );
return( NOID );
}
(void) memcpy( (char *) &id, data.dptr, sizeof(ID) );
ldbm_datum_free( db->dbc_db, data );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id %lu\n", id, 0, 0 );
return( id );
}
int
bdb2i_dn2id_delete(
Backend *be,
char *dn
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct dbcache *db;
Datum key;
int rc;
ldbm_datum_init( key );
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_dn2id_delete( \"%s\" )\n", dn, 0, 0 );
if ( (db = bdb2i_cache_open( be, "dn2id", LDBM_SUFFIX, LDBM_WRCREAT ))
== NULL ) {
Debug( LDAP_DEBUG_ANY,
"<= bdb2i_dn2id_delete could not open dn2id%s\n", LDBM_SUFFIX,
0, 0 );
return( -1 );
}
dn = ch_strdup( dn );
dn_normalize_case( dn );
key.dptr = dn;
key.dsize = strlen( dn ) + 1;
rc = bdb2i_cache_delete( db, key );
free( dn );
bdb2i_cache_close( be, db );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_dn2id_delete %d\n", rc, 0, 0 );
return( rc );
}
/*
* dn2entry - look up dn in the cache/indexes and return the corresponding
* entry.
*/
static Entry *
dn2entry(
Backend *be,
char *dn,
char **matched,
int rw
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
ID id;
Entry *e = NULL;
char *pdn;
Debug(LDAP_DEBUG_TRACE, "dn2entry_%s: dn: \"%s\"\n",
rw ? "w" : "r", dn, 0);
*matched = NULL;
if ( (id = bdb2i_dn2id( be, dn )) != NOID &&
(e = bdb2i_id2entry( be, id, rw )) != NULL )
{
return( e );
}
if ( id != NOID ) {
Debug(LDAP_DEBUG_ANY,
"dn2entry_%s: no entry for valid id (%lu), dn \"%s\"\n",
rw ? "w" : "r", id, dn);
/* must have been deleted from underneath us */
/* treat as if NOID was found */
}
/* stop when we get to the suffix */
if ( be_issuffix( be, dn ) ) {
return( NULL );
}
/* entry does not exist - see how much of the dn does exist */
if ( (pdn = dn_parent( be, dn )) != NULL ) {
/* get entry with reader lock */
if ( (e = bdb2i_dn2entry_r( be, pdn, matched )) != NULL ) {
if(*matched != NULL) {
free(*matched);
}
*matched = pdn;
/* free entry with reader lock */
bdb2i_cache_return_entry_r( &li->li_cache, e );
} else {
free( pdn );
}
}
return( NULL );
}
Entry *
bdb2i_dn2entry_r(
Backend *be,
char *dn,
char **matched
)
{
return( dn2entry( be, dn, matched, 0 ) );
}
Entry *
bdb2i_dn2entry_w(
Backend *be,
char *dn,
char **matched
)
{
return( dn2entry( be, dn, matched, 1 ) );
}

View file

@ -0,0 +1,59 @@
#ifndef _BDB2_EXTERNAL_H
#define _BDB2_EXTERNAL_H
LDAP_BEGIN_DECL
extern int bdb2_back_initialize LDAP_P(( BackendInfo *bi ));
extern int bdb2_back_open LDAP_P(( BackendInfo *bi ));
extern int bdb2_back_close LDAP_P(( BackendInfo *bi ));
extern int bdb2_back_destroy LDAP_P(( BackendInfo *bi ));
extern int bdb2_back_db_init LDAP_P(( BackendDB *bd ));
extern int bdb2_back_db_open LDAP_P(( BackendDB *bd ));
extern int bdb2_back_db_close LDAP_P(( BackendDB *bd ));
extern int bdb2_back_db_destroy LDAP_P(( BackendDB *bd ));
extern int bdb2_back_db_config LDAP_P(( BackendDB *bd,
char *fname, int lineno, int argc, char **argv ));
extern int bdb2_back_bind LDAP_P(( BackendDB *bd,
Connection *conn, Operation *op,
char *dn, int method, struct berval *cred, char** edn ));
extern int bdb2_back_unbind LDAP_P(( BackendDB *bd,
Connection *conn, Operation *op ));
extern int bdb2_back_search LDAP_P(( BackendDB *bd,
Connection *conn, Operation *op,
char *base, int scope, int deref, int sizelimit, int timelimit,
Filter *filter, char *filterstr, char **attrs, int attrsonly ));
extern int bdb2_back_compare LDAP_P((BackendDB *bd,
Connection *conn, Operation *op,
char *dn, Ava *ava ));
extern int bdb2_back_modify LDAP_P(( BackendDB *bd,
Connection *conn, Operation *op,
char *dn, LDAPModList *ml ));
extern int bdb2_back_modrdn LDAP_P(( BackendDB *bd,
Connection *conn, Operation *op,
char *dn, char*newrdn, int deleteoldrdn ));
extern int bdb2_back_add LDAP_P(( BackendDB *bd,
Connection *conn, Operation *op, Entry *e ));
extern int bdb2_back_delete LDAP_P(( BackendDB *bd,
Connection *conn, Operation *op, char *dn ));
extern int bdb2_back_abandon LDAP_P(( BackendDB *bd,
Connection *conn, Operation *op, int msgid ));
extern int bdb2_back_group LDAP_P(( BackendDB *bd,
Entry *target, char* gr_ndn, char* op_ndn,
char* objectclassValue, char* groupattrName));
LDAP_END_DECL
#endif /* _BDB2_EXTERNAL_H */

View file

@ -0,0 +1,353 @@
/* filterindex.c - generate the list of candidate entries from a filter */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-bdb2.h"
static ID_BLOCK *ava_candidates( Backend *be, Ava *ava, int type );
static ID_BLOCK *presence_candidates( Backend *be, char *type );
static ID_BLOCK *approx_candidates( Backend *be, Ava *ava );
static ID_BLOCK *list_candidates( Backend *be, Filter *flist, int ftype );
static ID_BLOCK *substring_candidates( Backend *be, Filter *f );
static ID_BLOCK *substring_comp_candidates( Backend *be, char *type, char *val, int prepost );
/*
* test_filter - test a filter against a single entry.
* returns 0 filter matched
* -1 filter did not match
* >0 an ldap error code
*/
ID_BLOCK *
bdb2i_filter_candidates(
Backend *be,
Filter *f
)
{
ID_BLOCK *result, *tmp1, *tmp2;
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_filter_candidates\n", 0, 0, 0 );
result = NULL;
switch ( f->f_choice ) {
case LDAP_FILTER_EQUALITY:
Debug( LDAP_DEBUG_FILTER, "\tEQUALITY\n", 0, 0, 0 );
result = ava_candidates( be, &f->f_ava, LDAP_FILTER_EQUALITY );
break;
case LDAP_FILTER_SUBSTRINGS:
Debug( LDAP_DEBUG_FILTER, "\tSUBSTRINGS\n", 0, 0, 0 );
result = substring_candidates( be, f );
break;
case LDAP_FILTER_GE:
Debug( LDAP_DEBUG_FILTER, "\tGE\n", 0, 0, 0 );
result = ava_candidates( be, &f->f_ava, LDAP_FILTER_GE );
break;
case LDAP_FILTER_LE:
Debug( LDAP_DEBUG_FILTER, "\tLE\n", 0, 0, 0 );
result = ava_candidates( be, &f->f_ava, LDAP_FILTER_LE );
break;
case LDAP_FILTER_PRESENT:
Debug( LDAP_DEBUG_FILTER, "\tPRESENT\n", 0, 0, 0 );
result = presence_candidates( be, f->f_type );
break;
case LDAP_FILTER_APPROX:
Debug( LDAP_DEBUG_FILTER, "\tAPPROX\n", 0, 0, 0 );
result = approx_candidates( be, &f->f_ava );
break;
case LDAP_FILTER_AND:
Debug( LDAP_DEBUG_FILTER, "\tAND\n", 0, 0, 0 );
result = list_candidates( be, f->f_and, LDAP_FILTER_AND );
break;
case LDAP_FILTER_OR:
Debug( LDAP_DEBUG_FILTER, "\tOR\n", 0, 0, 0 );
result = list_candidates( be, f->f_or, LDAP_FILTER_OR );
break;
case LDAP_FILTER_NOT:
Debug( LDAP_DEBUG_FILTER, "\tNOT\n", 0, 0, 0 );
tmp1 = bdb2i_idl_allids( be );
tmp2 = bdb2i_filter_candidates( be, f->f_not );
result = bdb2i_idl_notin( be, tmp1, tmp2 );
bdb2i_idl_free( tmp2 );
bdb2i_idl_free( tmp1 );
break;
}
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_filter_candidates %lu\n",
result ? ID_BLOCK_NIDS(result) : 0, 0, 0 );
return( result );
}
static ID_BLOCK *
ava_candidates(
Backend *be,
Ava *ava,
int type
)
{
ID_BLOCK *idl;
Debug( LDAP_DEBUG_TRACE, "=> ava_candidates 0x%x\n", type, 0, 0 );
switch ( type ) {
case LDAP_FILTER_EQUALITY:
idl = bdb2i_index_read( be, ava->ava_type, INDEX_EQUALITY,
ava->ava_value.bv_val );
break;
case LDAP_FILTER_GE:
idl = bdb2i_idl_allids( be );
break;
case LDAP_FILTER_LE:
idl = bdb2i_idl_allids( be );
break;
}
Debug( LDAP_DEBUG_TRACE, "<= ava_candidates %lu\n",
idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
return( idl );
}
static ID_BLOCK *
presence_candidates(
Backend *be,
char *type
)
{
ID_BLOCK *idl;
Debug( LDAP_DEBUG_TRACE, "=> presence_candidates\n", 0, 0, 0 );
idl = bdb2i_index_read( be, type, 0, "*" );
Debug( LDAP_DEBUG_TRACE, "<= presence_candidates %lu\n",
idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
return( idl );
}
static ID_BLOCK *
approx_candidates(
Backend *be,
Ava *ava
)
{
char *w, *c;
ID_BLOCK *idl, *tmp;
Debug( LDAP_DEBUG_TRACE, "=> approx_candidates\n", 0, 0, 0 );
idl = NULL;
for ( w = first_word( ava->ava_value.bv_val ); w != NULL;
w = next_word( w ) ) {
c = phonetic( w );
if ( (tmp = bdb2i_index_read( be, ava->ava_type, INDEX_APPROX, c ))
== NULL ) {
free( c );
bdb2i_idl_free( idl );
Debug( LDAP_DEBUG_TRACE, "<= approx_candidates NULL\n",
0, 0, 0 );
return( NULL );
}
free( c );
if ( idl == NULL ) {
idl = tmp;
} else {
idl = bdb2i_idl_intersection( be, idl, tmp );
}
}
Debug( LDAP_DEBUG_TRACE, "<= approx_candidates %lu\n",
idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
return( idl );
}
static ID_BLOCK *
list_candidates(
Backend *be,
Filter *flist,
int ftype
)
{
ID_BLOCK *idl, *tmp, *tmp2;
Filter *f;
Debug( LDAP_DEBUG_TRACE, "=> list_candidates 0x%x\n", ftype, 0, 0 );
idl = NULL;
for ( f = flist; f != NULL; f = f->f_next ) {
if ( (tmp = bdb2i_filter_candidates( be, f )) == NULL &&
ftype == LDAP_FILTER_AND ) {
Debug( LDAP_DEBUG_TRACE,
"<= list_candidates NULL\n", 0, 0, 0 );
bdb2i_idl_free( idl );
return( NULL );
}
tmp2 = idl;
if ( idl == NULL ) {
idl = tmp;
} else if ( ftype == LDAP_FILTER_AND ) {
idl = bdb2i_idl_intersection( be, idl, tmp );
bdb2i_idl_free( tmp );
bdb2i_idl_free( tmp2 );
} else {
idl = bdb2i_idl_union( be, idl, tmp );
bdb2i_idl_free( tmp );
bdb2i_idl_free( tmp2 );
}
}
Debug( LDAP_DEBUG_TRACE, "<= list_candidates %lu\n",
idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
return( idl );
}
static ID_BLOCK *
substring_candidates(
Backend *be,
Filter *f
)
{
int i;
ID_BLOCK *idl, *tmp, *tmp2;
Debug( LDAP_DEBUG_TRACE, "=> substring_candidates\n", 0, 0, 0 );
idl = NULL;
/* initial */
if ( f->f_sub_initial != NULL ) {
if ( (int) strlen( f->f_sub_initial ) < SUBLEN - 1 ) {
idl = bdb2i_idl_allids( be );
} else if ( (idl = substring_comp_candidates( be, f->f_sub_type,
f->f_sub_initial, '^' )) == NULL ) {
return( NULL );
}
}
/* final */
if ( f->f_sub_final != NULL ) {
if ( (int) strlen( f->f_sub_final ) < SUBLEN - 1 ) {
tmp = bdb2i_idl_allids( be );
} else if ( (tmp = substring_comp_candidates( be, f->f_sub_type,
f->f_sub_final, '$' )) == NULL ) {
bdb2i_idl_free( idl );
return( NULL );
}
if ( idl == NULL ) {
idl = tmp;
} else {
tmp2 = idl;
idl = bdb2i_idl_intersection( be, idl, tmp );
bdb2i_idl_free( tmp );
bdb2i_idl_free( tmp2 );
}
}
for ( i = 0; f->f_sub_any != NULL && f->f_sub_any[i] != NULL; i++ ) {
if ( (int) strlen( f->f_sub_any[i] ) < SUBLEN ) {
tmp = bdb2i_idl_allids( be );
} else if ( (tmp = substring_comp_candidates( be, f->f_sub_type,
f->f_sub_any[i], 0 )) == NULL ) {
bdb2i_idl_free( idl );
return( NULL );
}
if ( idl == NULL ) {
idl = tmp;
} else {
tmp2 = idl;
idl = bdb2i_idl_intersection( be, idl, tmp );
bdb2i_idl_free( tmp );
bdb2i_idl_free( tmp2 );
}
}
Debug( LDAP_DEBUG_TRACE, "<= substring_candidates %lu\n",
idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
return( idl );
}
static ID_BLOCK *
substring_comp_candidates(
Backend *be,
char *type,
char *val,
int prepost
)
{
int i, len;
ID_BLOCK *idl, *tmp, *tmp2;
char *p;
char buf[SUBLEN + 1];
Debug( LDAP_DEBUG_TRACE, "=> substring_comp_candidates\n", 0, 0, 0 );
len = strlen( val );
idl = NULL;
/* prepend ^ for initial substring */
if ( prepost == '^' ) {
buf[0] = '^';
for ( i = 0; i < SUBLEN - 1; i++ ) {
buf[i + 1] = val[i];
}
buf[SUBLEN] = '\0';
if ( (idl = bdb2i_index_read( be, type, INDEX_SUB, buf )) == NULL ) {
return( NULL );
}
} else if ( prepost == '$' ) {
p = val + len - SUBLEN + 1;
for ( i = 0; i < SUBLEN - 1; i++ ) {
buf[i] = p[i];
}
buf[SUBLEN - 1] = '$';
buf[SUBLEN] = '\0';
if ( (idl = bdb2i_index_read( be, type, INDEX_SUB, buf )) == NULL ) {
return( NULL );
}
}
for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
for ( i = 0; i < SUBLEN; i++ ) {
buf[i] = p[i];
}
buf[SUBLEN] = '\0';
if ( (tmp = bdb2i_index_read( be, type, INDEX_SUB, buf )) == NULL ) {
bdb2i_idl_free( idl );
return( NULL );
}
if ( idl == NULL ) {
idl = tmp;
} else {
tmp2 = idl;
idl = bdb2i_idl_intersection( be, idl, tmp );
bdb2i_idl_free( tmp );
bdb2i_idl_free( tmp2 );
}
}
Debug( LDAP_DEBUG_TRACE, "<= substring_comp_candidates %lu\n",
idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
return( idl );
}

View file

@ -0,0 +1,171 @@
/* group.c - bdb2 backend acl group routine */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
#ifdef SLAPD_ACLGROUPS
/* return 0 IFF op_dn is a value in member attribute
* of entry with gr_dn AND that entry has an objectClass
* value of groupOfNames
*/
static int
bdb2i_back_group_internal(
Backend *be,
Entry *target,
char *gr_ndn,
char *op_ndn,
char *objectclassValue,
char *groupattrName
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Entry *e;
char *matched;
Attribute *objectClass;
Attribute *member;
int rc;
Debug( LDAP_DEBUG_TRACE,
"=> bdb2i_back_group: gr dn: \"%s\"\n",
gr_ndn, 0, 0 );
Debug( LDAP_DEBUG_TRACE,
"=> bdb2i_back_group: op dn: \"%s\"\n",
op_ndn, 0, 0 );
Debug( LDAP_DEBUG_TRACE,
"=> bdb2i_back_group: objectClass: \"%s\" attrName: \"%s\"\n",
objectclassValue, groupattrName, 0 );
Debug( LDAP_DEBUG_TRACE,
"=> bdb2i_back_group: tr dn: \"%s\"\n",
target->e_ndn, 0, 0 );
if (strcmp(target->e_ndn, gr_ndn) == 0) {
/* we already have a LOCKED copy of the entry */
e = target;
Debug( LDAP_DEBUG_ARGS,
"=> bdb2i_back_group: target is group: \"%s\"\n",
gr_ndn, 0, 0 );
} else {
/* can we find group entry with reader lock */
if ((e = bdb2i_dn2entry_r(be, gr_ndn, &matched )) == NULL) {
Debug( LDAP_DEBUG_TRACE,
"=> bdb2i_back_group: cannot find group: \"%s\" matched: \"%s\"\n",
gr_ndn, (matched ? matched : ""), 0 );
if (matched != NULL)
free(matched);
return( 1 );
}
Debug( LDAP_DEBUG_ARGS,
"=> bdb2i_back_group: found group: \"%s\"\n",
gr_ndn, 0, 0 );
}
/* check for deleted */
/* find it's objectClass and member attribute values
* make sure this is a group entry
* finally test if we can find op_dn in the member attribute value list *
*/
rc = 1;
if ((objectClass = attr_find(e->e_attrs, "objectclass")) == NULL) {
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_back_group: failed to find objectClass\n", 0, 0, 0 );
}
else if ((member = attr_find(e->e_attrs, groupattrName)) == NULL) {
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_back_group: failed to find %s\n", groupattrName, 0, 0 );
}
else {
struct berval bvObjectClass;
struct berval bvMembers;
Debug( LDAP_DEBUG_ARGS, "<= bdb2i_back_group: found objectClass and %s\n", groupattrName, 0, 0 );
bvObjectClass.bv_val = objectclassValue;
bvObjectClass.bv_len = strlen( bvObjectClass.bv_val );
bvMembers.bv_val = op_ndn;
bvMembers.bv_len = strlen( op_ndn );
if (value_find(objectClass->a_vals, &bvObjectClass, SYNTAX_CIS, 1) != 0) {
Debug( LDAP_DEBUG_TRACE,
"<= bdb2i_back_group: failed to find %s in objectClass\n",
objectclassValue, 0, 0 );
}
else if (value_find(member->a_vals, &bvMembers, SYNTAX_CIS, 1) != 0) {
Debug( LDAP_DEBUG_ACL,
"<= bdb2i_back_group: \"%s\" not in \"%s\": %s\n",
op_ndn, gr_ndn, groupattrName );
}
else {
Debug( LDAP_DEBUG_ACL,
"<= bdb2i_back_group: \"%s\" is in \"%s\": %s\n",
op_ndn, gr_ndn, groupattrName );
rc = 0;
}
}
if( target != e ) {
/* free entry and reader lock */
bdb2i_cache_return_entry_r( &li->li_cache, e );
}
Debug( LDAP_DEBUG_ARGS, "bdb2i_back_group: rc: %d\n", rc, 0, 0 );
return(rc);
}
int
bdb2_back_group(
Backend *be,
Entry *target,
char *gr_ndn,
char *op_ndn,
char *objectclassValue,
char *groupattrName
)
{
DB_LOCK lock;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
if ( bdb2i_enter_backend_r( &li->li_db_env, &lock ) != 0 ) {
return( 1 );
}
ret = bdb2i_back_group_internal( be, target, gr_ndn, op_ndn,
objectclassValue, groupattrName );
(void) bdb2i_leave_backend( &li->li_db_env, lock );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "GRP elapsed=%s\n",
elapsed_time, 0, 0 );
free( elapsed_time );
}
return( ret );
}
#endif /* SLAPD_ACLGROUPS */

View file

@ -0,0 +1,139 @@
/* id2children.c - routines to deal with the id2children index */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
int
bdb2i_id2children_add(
Backend *be,
Entry *p,
Entry *e
)
{
struct dbcache *db;
Datum key;
int len, rc;
ID_BLOCK *idl;
char buf[20];
ldbm_datum_init( key );
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_id2children_add( %lu, %lu )\n",
p ? p->e_id : 0, e->e_id, 0 );
if ( (db = bdb2i_cache_open( be, "id2children", LDBM_SUFFIX,
LDBM_WRCREAT )) == NULL ) {
Debug( LDAP_DEBUG_ANY,
"<= bdb2i_id2children_add -1 could not open \"id2children%s\"\n",
LDBM_SUFFIX, 0, 0 );
return( -1 );
}
sprintf( buf, "%c%ld", EQ_PREFIX, p ? p->e_id : 0 );
key.dptr = buf;
key.dsize = strlen( buf ) + 1;
if ( bdb2i_idl_insert_key( be, db, key, e->e_id ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2children_add -1 (idl_insert)\n",
0, 0, 0 );
bdb2i_cache_close( be, db );
return( -1 );
}
bdb2i_cache_close( be, db );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2children_add 0\n", 0, 0, 0 );
return( 0 );
}
int
bdb2i_id2children_remove(
Backend *be,
Entry *p,
Entry *e
)
{
struct dbcache *db;
Datum key;
int len, rc;
ID_BLOCK *idl;
char buf[20];
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_id2children_remove( %lu, %lu )\n",
p ? p->e_id : 0, e->e_id, 0 );
if ( (db = bdb2i_cache_open( be, "id2children", LDBM_SUFFIX,
LDBM_WRCREAT )) == NULL ) {
Debug( LDAP_DEBUG_ANY,
"<= bdb2i_id2children_remove -1 could not open \"id2children%s\"\n",
LDBM_SUFFIX, 0, 0 );
return( -1 );
}
ldbm_datum_init( key );
sprintf( buf, "%c%ld", EQ_PREFIX, p ? p->e_id : 0 );
key.dptr = buf;
key.dsize = strlen( buf ) + 1;
if ( bdb2i_idl_delete_key( be, db, key, e->e_id ) != 0 ) {
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2children_remove -1 (idl_delete)\n",
0, 0, 0 );
bdb2i_cache_close( be, db );
return( -1 );
}
bdb2i_cache_close( be, db );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2children_remove 0\n", 0, 0, 0 );
return( 0 );
}
int
bdb2i_has_children(
Backend *be,
Entry *p
)
{
struct dbcache *db;
Datum key;
int rc = 0;
ID_BLOCK *idl;
char buf[20];
ldbm_datum_init( key );
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_has_children( %lu )\n", p->e_id , 0, 0 );
if ( (db = bdb2i_cache_open( be, "id2children", LDBM_SUFFIX,
LDBM_WRCREAT )) == NULL ) {
Debug( LDAP_DEBUG_ANY,
"<= bdb2i_has_children -1 could not open \"id2children%s\"\n",
LDBM_SUFFIX, 0, 0 );
return( 0 );
}
sprintf( buf, "%c%ld", EQ_PREFIX, p->e_id );
key.dptr = buf;
key.dsize = strlen( buf ) + 1;
idl = bdb2i_idl_fetch( be, db, key );
bdb2i_cache_close( be, db );
if( idl != NULL ) {
bdb2i_idl_free( idl );
rc = 1;
}
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_has_children( %lu ): %s\n",
p->e_id, rc ? "yes" : "no", 0 );
return( rc );
}

View file

@ -0,0 +1,174 @@
/* id2entry.c - routines to deal with the id2entry index */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
int
bdb2i_id2entry_add( Backend *be, Entry *e )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct dbcache *db;
Datum key, data;
int len, rc, flags;
ldbm_datum_init( key );
ldbm_datum_init( data );
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_id2entry_add( %lu, \"%s\" )\n", e->e_id,
e->e_dn, 0 );
if ( (db = bdb2i_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT ))
== NULL ) {
Debug( LDAP_DEBUG_ANY, "Could not open/create id2entry%s\n",
LDBM_SUFFIX, 0, 0 );
return( -1 );
}
key.dptr = (char *) &e->e_id;
key.dsize = sizeof(ID);
ldap_pvt_thread_mutex_lock( &entry2str_mutex );
data.dptr = entry2str( e, &len, 1 );
data.dsize = len + 1;
/* store it */
flags = LDBM_REPLACE;
if ( li->li_dbcachewsync ) flags |= LDBM_SYNC;
rc = bdb2i_cache_store( db, key, data, flags );
ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
bdb2i_cache_close( be, db );
(void) bdb2i_cache_add_entry_lock( &li->li_cache, e, 0 );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_add %d\n", rc, 0, 0 );
/* XXX should entries be born locked, i.e. apply writer lock here? */
return( rc );
}
int
bdb2i_id2entry_delete( Backend *be, Entry *e )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct dbcache *db;
Datum key;
int rc;
Debug(LDAP_DEBUG_TRACE, "=> bdb2i_id2entry_delete( %lu, \"%s\" )\n", e->e_id,
e->e_dn, 0 );
#ifdef LDAP_DEBUG
/* check for writer lock */
assert(ldap_pvt_thread_rdwr_writers(&e->e_rdwr));
#endif
ldbm_datum_init( key );
if ( (db = bdb2i_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT ))
== NULL ) {
Debug( LDAP_DEBUG_ANY, "Could not open/create id2entry%s\n",
LDBM_SUFFIX, 0, 0 );
return( -1 );
}
if ( bdb2i_cache_delete_entry( &li->li_cache, e ) != 0 ) {
Debug(LDAP_DEBUG_ANY, "could not delete %lu (%s) from cache\n",
e->e_id, e->e_dn, 0 );
}
key.dptr = (char *) &e->e_id;
key.dsize = sizeof(ID);
rc = bdb2i_cache_delete( db, key );
bdb2i_cache_close( be, db );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_delete %d\n", rc, 0, 0 );
return( rc );
}
/* XXX returns entry with reader/writer lock */
Entry *
bdb2i_id2entry( Backend *be, ID id, int rw )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct dbcache *db;
Datum key, data;
Entry *e;
ldbm_datum_init( key );
ldbm_datum_init( data );
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_id2entry_%s( %ld )\n",
rw ? "w" : "r", id, 0 );
if ( (e = bdb2i_cache_find_entry_id( &li->li_cache, id, rw )) != NULL ) {
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_%s 0x%lx (cache)\n",
rw ? "w" : "r", (unsigned long)e, 0 );
return( e );
}
if ( (db = bdb2i_cache_open( be, "id2entry", LDBM_SUFFIX, LDBM_WRCREAT ))
== NULL ) {
Debug( LDAP_DEBUG_ANY, "Could not open id2entry%s\n",
LDBM_SUFFIX, 0, 0 );
return( NULL );
}
key.dptr = (char *) &id;
key.dsize = sizeof(ID);
data = bdb2i_cache_fetch( db, key );
if ( data.dptr == NULL ) {
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_%s( %ld ) not found\n",
rw ? "w" : "r", id, 0 );
bdb2i_cache_close( be, db );
return( NULL );
}
e = str2entry( data.dptr );
ldbm_datum_free( db->dbc_db, data );
bdb2i_cache_close( be, db );
if ( e == NULL ) {
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_%s( %ld ) (failed)\n",
rw ? "w" : "r", id, 0 );
return( NULL );
}
/* acquire required reader/writer lock */
if (entry_rdwr_lock(e, rw)) {
/* XXX set DELETE flag?? */
entry_free(e);
return(NULL);
}
e->e_id = id;
(void) bdb2i_cache_add_entry_lock( &li->li_cache, e, 0 );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_id2entry_%s( %ld ) (disk)\n",
rw ? "w" : "r", id, 0 );
return( e );
}
Entry *
bdb2i_id2entry_r( Backend *be, ID id )
{
return( bdb2i_id2entry( be, id, 0 ) );
}
Entry *
bdb2i_id2entry_w( Backend *be, ID id )
{
return( bdb2i_id2entry( be, id, 1 ) );
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,362 @@
/* index.c - routines for dealing with attribute indexes */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
static int add_value(Backend *be, struct dbcache *db, char *type, int indextype, char *val, ID id);
static int index2prefix(int indextype);
int
bdb2i_index_add_entry(
Backend *be,
Entry *e
)
{
Attribute *ap;
char *dnval;
struct berval bv;
struct berval *bvals[2];
Debug( LDAP_DEBUG_TRACE, "=> index_add( %ld, \"%s\" )\n", e->e_id,
e->e_dn, 0 );
/*
* dn index entry - make it look like an attribute so it works
* with bdb2i_index_add_values() call
*/
bv.bv_val = ch_strdup( e->e_dn );
bv.bv_len = strlen( bv.bv_val );
(void) dn_normalize_case( bv.bv_val );
bvals[0] = &bv;
bvals[1] = NULL;
/* add the dn to the indexes */
bdb2i_index_add_values( be, "dn", bvals, e->e_id );
free( bv.bv_val );
/* add each attribute to the indexes */
for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
bdb2i_index_add_values( be, ap->a_type, ap->a_vals, e->e_id );
}
Debug( LDAP_DEBUG_TRACE, "<= index_add( %ld, \"%s\" ) 0\n", e->e_id,
e->e_dn, 0 );
return( 0 );
}
int
bdb2i_index_add_mods(
Backend *be,
LDAPModList *ml,
ID id
)
{
int rc;
for ( ; ml != NULL; ml = ml->ml_next ) {
LDAPMod *mod = &ml->ml_mod;
switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
case LDAP_MOD_ADD:
case LDAP_MOD_REPLACE:
rc = bdb2i_index_add_values( be, mod->mod_type,
mod->mod_bvalues, id );
break;
case LDAP_MOD_DELETE:
rc = 0;
break;
}
if ( rc != 0 ) {
return( rc );
}
}
return( 0 );
}
ID_BLOCK *
bdb2i_index_read(
Backend *be,
char *type,
int indextype,
char *val
)
{
struct dbcache *db;
Datum key;
ID_BLOCK *idl;
int indexmask, syntax;
char prefix;
char *realval, *tmpval;
char buf[BUFSIZ];
ldbm_datum_init( key );
prefix = index2prefix( indextype );
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_index_read( \"%s\" \"%c\" \"%s\" )\n",
type, prefix, val );
bdb2i_attr_masks( be->be_private, type, &indexmask, &syntax );
if ( ! (indextype & indexmask) ) {
idl = bdb2i_idl_allids( be );
Debug( LDAP_DEBUG_TRACE,
"<= bdb2i_index_read %lu candidates (allids - not indexed)\n",
idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
return( idl );
}
attr_normalize( type );
if ( (db = bdb2i_cache_open( be, type, LDBM_SUFFIX, LDBM_WRCREAT ))
== NULL ) {
Debug( LDAP_DEBUG_ANY,
"<= bdb2i_index_read NULL (could not open %s%s)\n", type,
LDBM_SUFFIX, 0 );
return( NULL );
}
realval = val;
tmpval = NULL;
if ( prefix != UNKNOWN_PREFIX ) {
unsigned int len = strlen( val );
if ( (len + 2) < sizeof(buf) ) {
realval = buf;
} else {
/* value + prefix + null */
tmpval = (char *) ch_malloc( len + 2 );
realval = tmpval;
}
realval[0] = prefix;
strcpy( &realval[1], val );
}
key.dptr = realval;
key.dsize = strlen( realval ) + 1;
idl = bdb2i_idl_fetch( be, db, key );
if ( tmpval != NULL ) {
free( tmpval );
}
bdb2i_cache_close( be, db );
Debug( LDAP_DEBUG_TRACE, "<= bdb2i_index_read %lu candidates\n",
idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
return( idl );
}
static int
add_value(
Backend *be,
struct dbcache *db,
char *type,
int indextype,
char *val,
ID id
)
{
int rc;
Datum key;
ID_BLOCK *idl;
char prefix;
char *realval, *tmpval, *s;
char buf[BUFSIZ];
ldbm_datum_init( key );
prefix = index2prefix( indextype );
Debug( LDAP_DEBUG_TRACE, "=> add_value( \"%c%s\" )\n", prefix, val, 0 );
realval = val;
tmpval = NULL;
idl = NULL;
if ( prefix != UNKNOWN_PREFIX ) {
unsigned int len = strlen( val );
if ( (len + 2) < sizeof(buf) ) {
realval = buf;
} else {
/* value + prefix + null */
tmpval = (char *) ch_malloc( len + 2 );
realval = tmpval;
}
realval[0] = prefix;
strcpy( &realval[1], val );
}
key.dptr = realval;
key.dsize = strlen( realval ) + 1;
rc = bdb2i_idl_insert_key( be, db, key, id );
if ( tmpval != NULL ) {
free( tmpval );
}
bdb2i_idl_free( idl );
ldap_pvt_thread_yield();
/* Debug( LDAP_DEBUG_TRACE, "<= add_value %d\n", rc, 0, 0 ); */
return( rc );
}
int
bdb2i_index_add_values(
Backend *be,
char *type,
struct berval **vals,
ID id
)
{
char *val, *p, *code, *w;
unsigned i, j, len;
int indexmask, syntax;
char buf[SUBLEN + 1];
char vbuf[BUFSIZ];
char *bigbuf;
struct dbcache *db;
Debug( LDAP_DEBUG_TRACE, "=> bdb2i_index_add_values( \"%s\", %ld )\n", type,
id, 0 );
bdb2i_attr_masks( be->be_private, type, &indexmask, &syntax );
if ( indexmask == 0 ) {
return( 0 );
}
if ( (db = bdb2i_cache_open( be, type, LDBM_SUFFIX, LDBM_WRCREAT ))
== NULL ) {
Debug( LDAP_DEBUG_ANY,
"<= bdb2i_index_add_values -1 (could not open/create %s%s)\n",
type, LDBM_SUFFIX, 0 );
return( -1 );
}
for ( i = 0; vals[i] != NULL; i++ ) {
/*
* presence index entry
*/
if ( indexmask & INDEX_PRESENCE ) {
add_value( be, db, type, INDEX_PRESENCE, "*", id );
}
Debug( LDAP_DEBUG_TRACE, "*** bdb2i_index_add_values syntax 0x%x syntax bin 0x%x\n",
syntax, SYNTAX_BIN, 0 );
if ( syntax & SYNTAX_BIN ) {
bdb2i_cache_close( be, db );
return( 0 );
}
bigbuf = NULL;
len = vals[i]->bv_len;
/* value + null */
if ( len + 2 > sizeof(vbuf) ) {
bigbuf = (char *) ch_malloc( len + 1 );
val = bigbuf;
} else {
val = vbuf;
}
(void) memcpy( val, vals[i]->bv_val, len );
val[len] = '\0';
value_normalize( val, syntax );
/*
* equality index entry
*/
if ( indexmask & INDEX_EQUALITY ) {
add_value( be, db, type, INDEX_EQUALITY, val, id );
}
/*
* approximate index entry
*/
if ( indexmask & INDEX_APPROX ) {
for ( w = first_word( val ); w != NULL;
w = next_word( w ) ) {
if ( (code = phonetic( w )) != NULL ) {
add_value( be, db, type, INDEX_APPROX,
code, id );
free( code );
}
}
}
/*
* substrings index entry
*/
if ( indexmask & INDEX_SUB ) {
/* leading and trailing */
if ( len > SUBLEN - 2 ) {
buf[0] = '^';
for ( j = 0; j < SUBLEN - 1; j++ ) {
buf[j + 1] = val[j];
}
buf[SUBLEN] = '\0';
add_value( be, db, type, INDEX_SUB, buf, id );
p = val + len - SUBLEN + 1;
for ( j = 0; j < SUBLEN - 1; j++ ) {
buf[j] = p[j];
}
buf[SUBLEN - 1] = '$';
buf[SUBLEN] = '\0';
add_value( be, db, type, INDEX_SUB, buf, id );
}
/* any */
for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
for ( j = 0; j < SUBLEN; j++ ) {
buf[j] = p[j];
}
buf[SUBLEN] = '\0';
add_value( be, db, type, INDEX_SUB, buf, id );
}
}
if ( bigbuf != NULL ) {
free( bigbuf );
}
}
bdb2i_cache_close( be, db );
return( 0 );
}
static int
index2prefix( int indextype )
{
int prefix;
switch ( indextype ) {
case INDEX_EQUALITY:
prefix = EQ_PREFIX;
break;
case INDEX_APPROX:
prefix = APPROX_PREFIX;
break;
case INDEX_SUB:
prefix = SUB_PREFIX;
break;
default:
prefix = UNKNOWN_PREFIX;
break;
}
return( prefix );
}

View file

@ -0,0 +1,196 @@
/* init.c - initialize bdb2 backend */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
int
bdb2_back_initialize(
BackendInfo *bi
)
{
bi->bi_open = bdb2_back_open;
bi->bi_config = NULL;
bi->bi_close = bdb2_back_close;
bi->bi_destroy = bdb2_back_destroy;
bi->bi_db_init = bdb2_back_db_init;
bi->bi_db_config = bdb2_back_db_config;
bi->bi_db_open = bdb2_back_db_open;
bi->bi_db_close = bdb2_back_db_close;
bi->bi_db_destroy = bdb2_back_db_destroy;
bi->bi_op_bind = bdb2_back_bind;
bi->bi_op_unbind = bdb2_back_unbind;
bi->bi_op_search = bdb2_back_search;
bi->bi_op_compare = bdb2_back_compare;
bi->bi_op_modify = bdb2_back_modify;
bi->bi_op_modrdn = bdb2_back_modrdn;
bi->bi_op_add = bdb2_back_add;
bi->bi_op_delete = bdb2_back_delete;
bi->bi_op_abandon = bdb2_back_abandon;
bi->bi_acl_group = bdb2_back_group;
return 0;
}
int
bdb2_back_destroy(
BackendInfo *bi
)
{
return 0;
}
int
bdb2_back_open(
BackendInfo *bi
)
{
int rc;
/* initialize the underlying database system */
rc = bdb2_initialize();
return rc;
}
int
bdb2_back_close(
BackendInfo *bi
)
{
/* close the underlying database system */
bdb2_shutdown();
return 0;
}
/* BDB2 changed */
static int
bdb2i_back_db_init_internal(
Backend *be
)
{
struct ldbminfo *li;
char *argv[ 4 ];
int i;
/* allocate backend-specific stuff */
li = (struct ldbminfo *) ch_calloc( 1, sizeof(struct ldbminfo) );
/* arrange to read nextid later (on first request for it) */
li->li_nextid = NOID;
#if SLAPD_NEXTID_CHUNCK > 1
li->li_nextid_wrote = NOID
#endif
/* default cache size */
li->li_cache.c_maxsize = DEFAULT_CACHE_SIZE;
/* default database cache size */
li->li_dbcachesize = DEFAULT_DBCACHE_SIZE;
/* default cache mode is sync on write */
li->li_dbcachewsync = 1;
/* default file creation mode */
li->li_mode = DEFAULT_MODE;
/* default database directory */
li->li_directory = DEFAULT_DB_DIRECTORY;
/* always index dn, id2children, objectclass (used in some searches) */
argv[ 0 ] = "dn";
argv[ 1 ] = "dn";
argv[ 2 ] = NULL;
attr_syntax_config( "ldbm dn initialization", 0, 2, argv );
argv[ 0 ] = "dn";
argv[ 1 ] = "sub";
argv[ 2 ] = "eq";
argv[ 3 ] = NULL;
bdb2i_attr_index_config( li, "ldbm dn initialization", 0, 3, argv, 1 );
argv[ 0 ] = "id2children";
argv[ 1 ] = "eq";
argv[ 2 ] = NULL;
bdb2i_attr_index_config( li, "ldbm id2children initialization", 0, 2, argv,
1 );
argv[ 0 ] = "objectclass";
argv[ 1 ] = ch_strdup( "pres,eq" );
argv[ 2 ] = NULL;
bdb2i_attr_index_config( li, "ldbm objectclass initialization", 0, 2, argv,
1 );
free( argv[ 1 ] );
/* initialize various mutex locks & condition variables */
ldap_pvt_thread_mutex_init( &li->li_root_mutex );
ldap_pvt_thread_mutex_init( &li->li_add_mutex );
ldap_pvt_thread_mutex_init( &li->li_cache.c_mutex );
ldap_pvt_thread_mutex_init( &li->li_nextid_mutex );
ldap_pvt_thread_mutex_init( &li->li_dbcache_mutex );
ldap_pvt_thread_cond_init( &li->li_dbcache_cv );
/* initialize the TP file head */
bdb2i_txn_head_init( &li->li_txn_head );
be->be_private = li;
return 0;
}
int
bdb2_back_db_init(
Backend *be
)
{
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
ret = bdb2i_back_db_init_internal( be );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "INIT elapsed=%s\n",
elapsed_time, 0, 0 );
free( elapsed_time );
}
return( ret );
}
int
bdb2_back_db_open(
BackendDB *be
)
{
return 0;
}
int
bdb2_back_db_destroy(
BackendDB *be
)
{
/* should free/destroy every in be_private */
free( be->be_private );
be->be_private = NULL;
return 0;
}

View file

@ -0,0 +1,48 @@
/* kerberos.c - bdb2 backend kerberos bind routines */
#include "portable.h"
#ifdef HAVE_KERBEROS
#include <stdio.h>
#include <ac/krb.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-bdb2.h"
#define LDAP_KRB_PRINCIPAL "ldapserver"
extern char *ldap_srvtab;
extern Attribute *attr_find();
bdb2i_krbv4_ldap_auth(
Backend *be,
struct berval *cred,
AUTH_DAT *ad
)
{
KTEXT_ST k;
KTEXT ktxt = &k;
char instance[INST_SZ];
int err;
Debug( LDAP_DEBUG_TRACE, "=> kerberosv4_ldap_auth\n", 0, 0, 0 );
SAFEMEMCPY( ktxt->dat, cred->bv_val, cred->bv_len );
ktxt->length = cred->bv_len;
strcpy( instance, "*" );
if ( (err = krb_rd_req( ktxt, LDAP_KRB_PRINCIPAL, instance, 0L, ad,
ldap_srvtab )) != KSUCCESS ) {
Debug( LDAP_DEBUG_ANY, "krb_rd_req failed (%s)\n",
krb_err_txt[err], 0, 0 );
return( LDAP_INVALID_CREDENTIALS );
}
return( LDAP_SUCCESS );
}
#endif /* kerberos */

View file

@ -0,0 +1,264 @@
/* modify.c - bdb2 backend modify routine */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
static int add_values(Entry *e, LDAPMod *mod, char *dn);
static int delete_values(Entry *e, LDAPMod *mod, char *dn);
static int replace_values(Entry *e, LDAPMod *mod, char *dn);
static int
bdb2i_back_modify_internal(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
LDAPModList *modlist
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *matched;
LDAPModList *ml;
Entry *e;
int i, err;
Debug(LDAP_DEBUG_ARGS, "bdb2i_back_modify:\n", 0, 0, 0);
if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched,
NULL );
if ( matched != NULL ) {
free( matched );
}
return( -1 );
}
if ( (err = acl_check_modlist( be, conn, op, e, modlist )) != LDAP_SUCCESS ) {
send_ldap_result( conn, op, err, NULL, NULL );
goto error_return;
}
for ( ml = modlist; ml != NULL; ml = ml->ml_next ) {
LDAPMod *mod = &ml->ml_mod;
switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
case LDAP_MOD_ADD:
err = add_values( e, mod, op->o_ndn );
break;
case LDAP_MOD_DELETE:
err = delete_values( e, mod, op->o_ndn );
break;
case LDAP_MOD_REPLACE:
err = replace_values( e, mod, op->o_ndn );
break;
}
if ( err != LDAP_SUCCESS ) {
/* unlock entry, delete from cache */
send_ldap_result( conn, op, err, NULL, NULL );
goto error_return;
}
}
/* check that the entry still obeys the schema */
if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL );
goto error_return;
}
/* check for abandon */
ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
goto error_return;
}
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
/* modify indexes */
if ( bdb2i_index_add_mods( be, modlist, e->e_id ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
goto error_return;
}
/* check for abandon */
ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
goto error_return;
}
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
/* change the entry itself */
if ( bdb2i_id2entry_add( be, e ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
goto error_return;
}
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
bdb2i_cache_return_entry_w( &li->li_cache, e );
return( 0 );
error_return:;
bdb2i_cache_return_entry_w( &li->li_cache, e );
return( -1 );
}
int
bdb2_back_modify(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
LDAPModList *modlist
)
{
DB_LOCK lock;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
if ( bdb2i_enter_backend_w( &li->li_db_env, &lock ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
return( -1 );
}
/* check, if a new default attribute index will be created,
in which case we have to open the index file BEFORE TP */
if ( bdb2i_with_dbenv )
bdb2i_check_default_attr_index_mod( li, modlist );
ret = bdb2i_back_modify_internal( be, conn, op, dn, modlist );
(void) bdb2i_leave_backend( &li->li_db_env, lock );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "conn=%d op=%d MOD elapsed=%s\n",
conn->c_connid, op->o_opid, elapsed_time );
free( elapsed_time );
}
return( ret );
}
static int
add_values(
Entry *e,
LDAPMod *mod,
char *dn
)
{
int i;
Attribute *a;
/* check if the values we're adding already exist */
if ( (a = attr_find( e->e_attrs, mod->mod_type )) != NULL ) {
for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
if ( value_find( a->a_vals, mod->mod_bvalues[i],
a->a_syntax, 3 ) == 0 ) {
return( LDAP_TYPE_OR_VALUE_EXISTS );
}
}
}
/* no - add them */
if( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
return( LDAP_CONSTRAINT_VIOLATION );
}
return( LDAP_SUCCESS );
}
static int
delete_values(
Entry *e,
LDAPMod *mod,
char *dn
)
{
int i, j, k, found;
Attribute *a;
/* delete the entire attribute */
if ( mod->mod_bvalues == NULL ) {
Debug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n",
mod->mod_type, 0, 0 );
return( attr_delete( &e->e_attrs, mod->mod_type ) ?
LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS );
}
/* delete specific values - find the attribute first */
if ( (a = attr_find( e->e_attrs, mod->mod_type )) == NULL ) {
Debug( LDAP_DEBUG_ARGS, "could not find attribute %s\n",
mod->mod_type, 0, 0 );
return( LDAP_NO_SUCH_ATTRIBUTE );
}
/* find each value to delete */
for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
found = 0;
for ( j = 0; a->a_vals[j] != NULL; j++ ) {
if ( value_cmp( mod->mod_bvalues[i], a->a_vals[j],
a->a_syntax, 3 ) != 0 ) {
continue;
}
found = 1;
/* found a matching value - delete it */
ber_bvfree( a->a_vals[j] );
for ( k = j + 1; a->a_vals[k] != NULL; k++ ) {
a->a_vals[k - 1] = a->a_vals[k];
}
a->a_vals[k - 1] = NULL;
break;
}
/* looked through them all w/o finding it */
if ( ! found ) {
Debug( LDAP_DEBUG_ARGS,
"could not find value for attr %s\n",
mod->mod_type, 0, 0 );
return( LDAP_NO_SUCH_ATTRIBUTE );
}
}
return( LDAP_SUCCESS );
}
static int
replace_values(
Entry *e,
LDAPMod *mod,
char *dn
)
{
(void) attr_delete( &e->e_attrs, mod->mod_type );
if ( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
return( LDAP_CONSTRAINT_VIOLATION );
}
return( LDAP_SUCCESS );
}

View file

@ -0,0 +1,237 @@
/* modrdn.c - bdb2 backend modrdn routine */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
static int
bdb2i_back_modrdn_internal(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
char *newrdn,
int deleteoldrdn
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char *matched = NULL;
char *p_dn = NULL, *p_ndn = NULL;
char *new_dn = NULL, *new_ndn = NULL;
char sep[2];
Entry *e, *p = NULL;
int rootlock = 0;
int rc = -1;
/* get entry with writer lock */
if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
if ( matched != NULL ) {
free( matched );
}
return( -1 );
}
#ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
/* check parent for "children" acl */
if ( ! access_allowed( be, conn, op, e,
"entry", NULL, ACL_WRITE ) )
{
Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
"", "" );
goto return_results;
}
#endif
if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) {
/* parent + rdn + separator(s) + null */
if( (p = bdb2i_dn2entry_w( be, p_ndn, &matched )) == NULL) {
Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
0, 0, 0);
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
"", "");
goto return_results;
}
#ifndef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
/* check parent for "children" acl */
if ( ! access_allowed( be, conn, op, p,
"children", NULL, ACL_WRITE ) )
{
Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
"", "" );
goto return_results;
}
#endif
p_dn = dn_parent( be, e->e_dn );
new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn )
+ 3 );
if ( dn_type( e->e_dn ) == DN_X500 ) {
strcpy( new_dn, newrdn );
strcat( new_dn, ", " );
strcat( new_dn, p_dn );
} else {
char *s;
strcpy( new_dn, newrdn );
s = strchr( newrdn, '\0' );
s--;
if ( *s != '.' && *s != '@' ) {
if ( (s = strpbrk( dn, ".@" )) != NULL ) {
sep[0] = *s;
sep[1] = '\0';
strcat( new_dn, sep );
}
}
strcat( new_dn, p_dn );
}
} else {
/* no parent, modrdn entry directly under root */
if( ! be_isroot( be, op->o_ndn ) ) {
Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
0, 0, 0);
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
"", "");
goto return_results;
}
ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
rootlock = 1;
new_dn = ch_strdup( newrdn );
}
new_ndn = dn_normalize_case( ch_strdup( new_dn ) );
if ( (bdb2i_dn2id ( be, new_ndn ) ) != NOID ) {
send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
goto return_results;
}
/* check for abandon */
ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
goto return_results;
}
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
/* add new one */
if ( bdb2i_dn2id_add( be, new_ndn, e->e_id ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
goto return_results;
}
/* delete old one */
if ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
goto return_results;
}
(void) bdb2i_cache_delete_entry( &li->li_cache, e );
free( e->e_dn );
free( e->e_ndn );
e->e_dn = new_dn;
e->e_ndn = new_ndn;
/* XXX
* At some point here we need to update the attribute values in
* the entry itself that were effected by this RDN change
* (respecting the value of the deleteoldrdn parameter).
*
* Since the code to do this has not yet been written, treat this
* omission as a (documented) bug.
*/
/* id2entry index */
if ( bdb2i_id2entry_add( be, e ) != 0 ) {
entry_free( e );
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
goto return_results;
}
send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
rc = 0;
return_results:
if( new_dn != NULL ) free( new_dn );
if( new_ndn != NULL ) free( new_ndn );
if( p_dn != NULL ) free( p_dn );
if( p_ndn != NULL ) free( p_ndn );
if( matched != NULL ) free( matched );
if( p != NULL ) {
/* free parent and writer lock */
bdb2i_cache_return_entry_w( &li->li_cache, p );
}
if ( rootlock ) {
/* release root writer lock */
ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
}
/* free entry and writer lock */
bdb2i_cache_return_entry_w( &li->li_cache, e );
return( rc );
}
int
bdb2_back_modrdn(
Backend *be,
Connection *conn,
Operation *op,
char *dn,
char *newrdn,
int deleteoldrdn
)
{
DB_LOCK lock;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
if ( bdb2i_enter_backend_w( &li->li_db_env, &lock ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
return( -1 );
}
ret = bdb2i_back_modrdn_internal( be, conn, op, dn,
newrdn, deleteoldrdn );
(void) bdb2i_leave_backend( &li->li_db_env, lock );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "conn=%d op=%d MODRDN elapsed=%s\n",
conn->c_connid, op->o_opid, elapsed_time );
free( elapsed_time );
}
return( ret );
}

View file

@ -0,0 +1,184 @@
/* id.c - keep track of the next id to be given out */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include "slap.h"
#include "back-bdb2.h"
static ID
next_id_read( Backend *be )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
ID id;
char buf[20];
char* file = li->li_nextid_file;
FILE* fp;
if ( (fp = fopen( file, "r" )) == NULL ) {
Debug( LDAP_DEBUG_ANY,
"next_id_read: could not open \"%s\"\n",
file, 0, 0 );
return NOID;
}
if ( fgets( buf, sizeof(buf), fp ) == NULL ) {
Debug( LDAP_DEBUG_ANY,
"next_id_read: could not fgets nextid from \"%s\"\n",
file, 0, 0 );
fclose( fp );
return NOID;
}
id = atol( buf );
fclose( fp );
if(id < 1) {
Debug( LDAP_DEBUG_ANY,
"next_id_read %lu: atol(%s) return non-positive integer\n",
id, buf, 0 );
return NOID;
}
return id;
}
static int
next_id_write( Backend *be, ID id )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
char buf[20];
char* file = li->li_nextid_file;
FILE* fp;
int rc;
if ( (fp = fopen( file, "w" )) == NULL ) {
Debug( LDAP_DEBUG_ANY, "next_id_write(%lu): could not open \"%s\"\n",
id, file, 0 );
return -1;
}
rc = 0;
if ( fprintf( fp, "%ld\n", id ) == EOF ) {
Debug( LDAP_DEBUG_ANY, "next_id_write(%lu): cannot fprintf\n",
id, 0, 0 );
rc = -1;
}
if( fclose( fp ) != 0 ) {
Debug( LDAP_DEBUG_ANY, "next_id_write %lu: cannot fclose\n",
id, 0, 0 );
rc = -1;
}
return rc;
}
int
bdb2i_next_id_save( Backend *be )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
ID id = next_id_get( be );
int rc = next_id_write( be, id );
if (rc == 0) {
li->li_nextid_wrote = id;
}
return rc;
}
ID
bdb2i_next_id( Backend *be )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
ID id;
ldap_pvt_thread_mutex_lock( &li->li_nextid_mutex );
/* first time in here since startup - try to read the nexid */
if ( li->li_nextid == NOID ) {
li->li_nextid = next_id_read( be );
if ( li->li_nextid == NOID ) {
li->li_nextid = 1;
}
#if SLAPD_NEXTID_CHUNK > 1
li->li_nextid_wrote = li->li_nextid;
#endif
}
id = li->li_nextid++;
#if SLAPD_NEXTID_CHUNK > 1
if ( li->li_nextid > li->li_nextid_wrote ) {
li->li_nextid_wrote += SLAPD_NEXTID_CHUNK;
(void) next_id_write( be, li->li_nextid_wrote );
}
#else
(void) next_id_write( be, li->li_nextid );
#endif
ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
return( id );
}
void
bdb2i_next_id_return( Backend *be, ID id )
{
#ifdef SLAPD_NEXTID_RETURN
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
ldap_pvt_thread_mutex_lock( &li->li_nextid_mutex );
if ( id != li->li_nextid - 1 ) {
ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
return;
}
li->li_nextid--;
#if !( SLAPD_NEXTID_CHUCK > 1 )
(void) next_id_write( be, li->li_nextid );
#endif
ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
#endif
}
ID
bdb2i_next_id_get( Backend *be )
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
ID id;
ldap_pvt_thread_mutex_lock( &li->li_nextid_mutex );
/* first time in here since startup - try to read the nexid */
if ( li->li_nextid == NOID ) {
li->li_nextid = next_id_read( be );
if ( li->li_nextid == NOID ) {
li->li_nextid = 1;
}
#if SLAPD_NEXTID_CHUNK > 1
li->li_nextid_wrote = li->li_nextid;
#endif
}
id = li->li_nextid;
ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
return( id );
}

View file

@ -0,0 +1,127 @@
/* porter.c - port functions of the bdb2 backend */
#include "portable.h"
#include <stdio.h>
#include <errno.h>
#include <ac/string.h>
#include "slap.h"
#include "back-bdb2.h"
#define PORTER_OBJ "bdb2_backend"
int bdb2i_with_dbenv = 0;
static int
bdb2i_enter_backend( DB_ENV *dbEnv, DB_LOCK *lock, int writer )
{
u_int32_t locker;
db_lockmode_t lock_type;
DBT lock_dbt;
int ret;
if ( !bdb2i_with_dbenv ) return( 0 );
if ( ( ret = lock_id( dbEnv->lk_info, &locker )) != 0 ) {
Debug( LDAP_DEBUG_ANY,
"bdb2i_enter_backend(): unable to get locker id -- %s\n",
strerror( ret ), 0, 0 );
return( ret );
}
lock_type = writer ? DB_LOCK_WRITE : DB_LOCK_READ;
lock_dbt.data = PORTER_OBJ;
lock_dbt.size = strlen( PORTER_OBJ );
switch ( ( ret = lock_get( dbEnv->lk_info, locker, 0, &lock_dbt,
lock_type, lock ))) {
case 0:
Debug( LDAP_DEBUG_ANY, "bdb2i_enter_backend() -- %s lock granted\n",
writer ? "write" : "read", 0, 0 );
break;
case DB_LOCK_NOTGRANTED:
Debug( LDAP_DEBUG_ANY,
"bdb2i_enter_backend() -- %s lock NOT granted\n",
writer ? "write" : "read", 0, 0 );
break;
case DB_LOCK_DEADLOCK:
Debug( LDAP_DEBUG_ANY,
"bdb2i_enter_backend() -- %s lock returned DEADLOCK\n",
writer ? "write" : "read", 0, 0 );
break;
default:
Debug( LDAP_DEBUG_ANY,
"bdb2i_enter_backend() -- %s lock returned ERROR: %s\n",
writer ? "write" : "read", strerror( errno ), 0 );
ret = errno;
break;
}
return( ret );
}
int
bdb2i_enter_backend_r( DB_ENV *dbEnv, DB_LOCK *lock )
{
return( bdb2i_enter_backend( dbEnv, lock, 0 ));
}
int
bdb2i_enter_backend_w( DB_ENV *dbEnv, DB_LOCK *lock )
{
return( bdb2i_enter_backend( dbEnv, lock, 1 ));
}
int
bdb2i_leave_backend( DB_ENV *dbEnv, DB_LOCK lock )
{
int ret;
if ( !bdb2i_with_dbenv ) return( 0 );
switch( ( ret = lock_put( dbEnv->lk_info, lock ))) {
case 0:
Debug( LDAP_DEBUG_ANY, "bdb2i_leave_backend() -- lock released\n",
0, 0, 0 );
break;
case DB_LOCK_NOTHELD:
Debug( LDAP_DEBUG_ANY,
"bdb2i_leave_backend() -- lock NOT held\n",
0, 0, 0 );
break;
case DB_LOCK_DEADLOCK:
Debug( LDAP_DEBUG_ANY,
"bdb2i_leave_backend() -- lock returned DEADLOCK\n",
0, 0, 0 );
break;
default:
Debug( LDAP_DEBUG_ANY,
"bdb2i_leave_backend() -- lock returned ERROR: %s\n",
strerror( errno ), 0, 0 );
ret = errno;
break;
}
return( ret );
}

View file

@ -0,0 +1,177 @@
#ifndef _PROTO_BACK_BDB2
#define _PROTO_BACK_BDB2
#include <ldap_cdefs.h>
#include "external.h"
LDAP_BEGIN_DECL
/*
* alias.c
*/
Entry *bdb2i_derefAlias_r LDAP_P((
Backend *be,
Connection *conn,
Operation *op,
Entry *e ));
char *bdb2i_derefDN LDAP_P((
Backend *be,
Connection *conn,
Operation *op,
char *dn ));
/*
* attr.c
*/
void bdb2i_attr_masks LDAP_P(( struct ldbminfo *li, char *type, int *indexmask,
int *syntaxmask ));
void bdb2i_attr_index_config LDAP_P(( struct ldbminfo *li, char *fname,
int lineno, int argc, char **argv, int init ));
/*
* cache.c
*/
void bdb2i_cache_set_state LDAP_P(( struct cache *cache, Entry *e, int state ));
void bdb2i_cache_return_entry_r LDAP_P(( struct cache *cache, Entry *e ));
void bdb2i_cache_return_entry_w LDAP_P(( struct cache *cache, Entry *e ));
int bdb2i_cache_add_entry_lock LDAP_P(( struct cache *cache, Entry *e,
int state ));
ID bdb2i_cache_find_entry_dn2id LDAP_P(( Backend *be, struct cache *cache,
char *dn ));
Entry * bdb2i_cache_find_entry_id LDAP_P(( struct cache *cache, ID id, int rw ));
int bdb2i_cache_delete_entry LDAP_P(( struct cache *cache, Entry *e ));
/*
* dbcache.c
*/
struct dbcache * bdb2i_cache_open LDAP_P(( Backend *be, char *name, char *suffix,
int flags ));
void bdb2i_cache_close LDAP_P(( Backend *be, struct dbcache *db ));
void bdb2i_cache_really_close LDAP_P(( Backend *be, struct dbcache *db ));
void bdb2i_cache_flush_all LDAP_P(( Backend *be ));
Datum bdb2i_cache_fetch LDAP_P(( struct dbcache *db, Datum key ));
int bdb2i_cache_store LDAP_P(( struct dbcache *db, Datum key, Datum data, int flags ));
int bdb2i_cache_delete LDAP_P(( struct dbcache *db, Datum key ));
/*
* dn2id.c
*/
int bdb2i_dn2id_add LDAP_P(( Backend *be, char *dn, ID id ));
ID bdb2i_dn2id LDAP_P(( Backend *be, char *dn ));
int bdb2i_dn2id_delete LDAP_P(( Backend *be, char *dn ));
Entry * bdb2i_dn2entry_r LDAP_P(( Backend *be, char *dn, char **matched ));
Entry * bdb2i_dn2entry_w LDAP_P(( Backend *be, char *dn, char **matched ));
/*
* filterindex.c
*/
ID_BLOCK * bdb2i_filter_candidates LDAP_P(( Backend *be, Filter *f ));
/*
* id2children.c
*/
int bdb2i_id2children_add LDAP_P(( Backend *be, Entry *p, Entry *e ));
int bdb2i_id2children_remove LDAP_P(( Backend *be, Entry *p, Entry *e ));
int bdb2i_has_children LDAP_P(( Backend *be, Entry *p ));
/*
* id2entry.c
*/
int bdb2i_id2entry_add LDAP_P(( Backend *be, Entry *e ));
int bdb2i_id2entry_delete LDAP_P(( Backend *be, Entry *e ));
Entry * bdb2i_id2entry LDAP_P(( Backend *be, ID id, int rw ));
Entry * bdb2i_id2entry_r LDAP_P(( Backend *be, ID id ));
Entry * bdb2i_id2entry_w LDAP_P(( Backend *be, ID id ));
/*
* idl.c
*/
ID_BLOCK * bdb2i_idl_alloc LDAP_P(( int nids ));
ID_BLOCK * bdb2i_idl_allids LDAP_P(( Backend *be ));
void bdb2i_idl_free LDAP_P(( ID_BLOCK *idl ));
ID_BLOCK * bdb2i_idl_fetch LDAP_P(( Backend *be, struct dbcache *db, Datum key ));
int bdb2i_idl_insert_key LDAP_P(( Backend *be, struct dbcache *db, Datum key, ID id ));
int bdb2i_idl_insert LDAP_P(( ID_BLOCK **idl, ID id, int maxids ));
int bdb2i_idl_delete_key LDAP_P(( Backend *be, struct dbcache *db, Datum key, ID id ));
ID_BLOCK * bdb2i_idl_intersection LDAP_P(( Backend *be, ID_BLOCK *a, ID_BLOCK *b ));
ID_BLOCK * bdb2i_idl_union LDAP_P(( Backend *be, ID_BLOCK *a, ID_BLOCK *b ));
ID_BLOCK * bdb2i_idl_notin LDAP_P(( Backend *be, ID_BLOCK *a, ID_BLOCK *b ));
ID bdb2i_idl_firstid LDAP_P(( ID_BLOCK *idl ));
ID bdb2i_idl_nextid LDAP_P(( ID_BLOCK *idl, ID id ));
/*
* index.c
*/
int bdb2i_index_add_entry LDAP_P(( Backend *be, Entry *e ));
int bdb2i_index_add_mods LDAP_P(( Backend *be, LDAPModList *ml, ID id ));
ID_BLOCK * bdb2i_index_read LDAP_P(( Backend *be, char *type, int indextype, char *val ));
int bdb2i_index_add_values LDAP_P(( Backend *be, char *type, struct berval **vals, ID id ));
/*
* kerberos.c
*/
#ifdef HAVE_KERBEROS
/* bdb2i_krbv4_ldap_auth LDAP_P(( Backend *be, struct berval *cred, AUTH_DAT *ad )); */
#endif
/*
* nextid.c
*/
ID bdb2i_next_id LDAP_P(( Backend *be ));
void bdb2i_next_id_return LDAP_P(( Backend *be, ID id ));
ID bdb2i_next_id_get LDAP_P(( Backend *be ));
int bdb2i_next_id_save LDAP_P(( Backend *be ));
/*
* timing.c
*/
char *bdb2i_elapsed LDAP_P(( struct timeval firsttime,
struct timeval secondtime ));
/*
* porter.c
*/
int bdb2i_enter_backend_r LDAP_P(( DB_ENV *dbEnv, DB_LOCK *lock ));
int bdb2i_enter_backend_w LDAP_P(( DB_ENV *dbEnv, DB_LOCK *lock ));
int bdb2i_leave_backend LDAP_P(( DB_ENV *dbEnv, DB_LOCK lock ));
/*
* txn.c
*/
void bdb2i_txn_head_init LDAP_P(( BDB2_TXN_HEAD *head ));
void bdb2i_txn_attr_config LDAP_P((
struct ldbminfo *li,
char *attr,
int open ));
void bdb2i_txn_open_files LDAP_P(( struct ldbminfo *li ));
void bdb2i_txn_close_files LDAP_P(( BDB2_TXN_HEAD *head ));
BDB2_TXN_FILES *bdb2i_get_db_file_cache LDAP_P((
struct ldbminfo *li,
char *name ));
void bdb2i_check_additional_attr_index LDAP_P(( struct ldbminfo *li ));
void bdb2i_check_default_attr_index_add LDAP_P((
struct ldbminfo *li,
Entry *e ));
void bdb2i_check_default_attr_index_mod LDAP_P((
struct ldbminfo *li,
LDAPModList *modlist ));
LDAP_END_DECL
#endif

View file

@ -0,0 +1,559 @@
/* search.c - bdb2 backend search function */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
static ID_BLOCK *base_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
static ID_BLOCK *onelevel_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
static ID_BLOCK *subtree_candidates(Backend *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, Entry *e, int *err, int lookupbase);
#define GRABSIZE BUFSIZ
#define MAKE_SPACE( n ) { \
if ( rcur + n > rbuf + rmaxsize ) { \
int offset = rcur - rbuf; \
rbuf = ch_realloc( rbuf, rmaxsize + GRABSIZE ); \
rmaxsize += GRABSIZE; \
rcur = rbuf + offset; \
} \
}
static int
bdb2i_back_search_internal(
Backend *be,
Connection *conn,
Operation *op,
char *base,
int scope,
int deref,
int slimit,
int tlimit,
Filter *filter,
char *filterstr,
char **attrs,
int attrsonly
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
int err;
time_t stoptime;
ID_BLOCK *candidates;
ID id;
Entry *e;
Attribute *ref;
char *matched = NULL;
int rmaxsize, nrefs;
char *rbuf, *rcur, *r;
int nentries = 0;
char *realBase;
Debug(LDAP_DEBUG_ARGS, "=> bdb2i_back_search\n", 0, 0, 0);
if ( tlimit == 0 && be_isroot( be, op->o_ndn ) ) {
tlimit = -1; /* allow root to set no limit */
} else {
tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
be->be_timelimit : tlimit;
stoptime = op->o_time + tlimit;
}
if ( slimit == 0 && be_isroot( be, op->o_ndn ) ) {
slimit = -1; /* allow root to set no limit */
} else {
slimit = (slimit > be->be_sizelimit || slimit < 1) ?
be->be_sizelimit : slimit;
}
/*
* check and apply aliasing where the dereferencing applies to
* the subordinates of the base
*/
switch ( deref ) {
case LDAP_DEREF_FINDING:
case LDAP_DEREF_ALWAYS:
realBase = bdb2i_derefDN ( be, conn, op, base );
break;
default:
realBase = ch_strdup(base);
}
(void) dn_normalize_case( realBase );
Debug( LDAP_DEBUG_TRACE, "using base \"%s\"\n",
realBase, 0, 0 );
switch ( scope ) {
case LDAP_SCOPE_BASE:
candidates = base_candidates( be, conn, op, realBase, filter,
attrs, attrsonly, &matched, &err );
break;
case LDAP_SCOPE_ONELEVEL:
candidates = onelevel_candidates( be, conn, op, realBase, filter,
attrs, attrsonly, &matched, &err );
break;
case LDAP_SCOPE_SUBTREE:
candidates = subtree_candidates( be, conn, op, realBase, filter,
attrs, attrsonly, &matched, NULL, &err, 1 );
break;
default:
send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "",
"Bad scope" );
if( realBase != NULL) {
free( realBase );
}
return( -1 );
}
/* null candidates means we could not find the base object */
if ( candidates == NULL ) {
send_ldap_result( conn, op, err, matched, "" );
if ( matched != NULL ) {
free( matched );
}
if( realBase != NULL) {
free( realBase );
}
return( -1 );
}
if ( matched != NULL ) {
free( matched );
}
rmaxsize = 0;
nrefs = 0;
rbuf = rcur = NULL;
MAKE_SPACE( sizeof("Referral:") + 1 );
strcpy( rbuf, "Referral:" );
rcur = strchr( rbuf, '\0' );
for ( id = bdb2i_idl_firstid( candidates ); id != NOID;
id = bdb2i_idl_nextid( candidates, id ) ) {
/* check for abandon */
ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
if ( op->o_abandon ) {
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
bdb2i_idl_free( candidates );
free( rbuf );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
/* check time limit */
ldap_pvt_thread_mutex_lock( &currenttime_mutex );
time( &currenttime );
if ( tlimit != -1 && currenttime > stoptime ) {
ldap_pvt_thread_mutex_unlock( &currenttime_mutex );
send_ldap_search_result( conn, op,
LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf :
NULL, nentries );
bdb2i_idl_free( candidates );
free( rbuf );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
ldap_pvt_thread_mutex_unlock( &currenttime_mutex );
/* get the entry with reader lock */
if ( (e = bdb2i_id2entry_r( be, id )) == NULL ) {
Debug( LDAP_DEBUG_ARGS, "candidate %lu not found\n",
id, 0, 0 );
continue;
}
/*
* if it's a referral, add it to the list of referrals. only do
* this for subtree searches, and don't check the filter explicitly
* here since it's only a candidate anyway.
*/
if ( scope == LDAP_SCOPE_SUBTREE &&
e->e_ndn != NULL &&
strncmp( e->e_ndn, "REF=", 4 ) == 0 &&
(ref = attr_find( e->e_attrs, "ref" )) != NULL )
{
int i, len;
if ( ref->a_vals == NULL ) {
Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n",
e->e_dn, 0, 0 );
} else {
for ( i = 0; ref->a_vals[i] != NULL; i++ ) {
/* referral + newline + null */
MAKE_SPACE( ref->a_vals[i]->bv_len + 2 );
*rcur++ = '\n';
strncpy( rcur, ref->a_vals[i]->bv_val,
ref->a_vals[i]->bv_len );
rcur = rcur + ref->a_vals[i]->bv_len;
*rcur = '\0';
nrefs++;
}
}
/* otherwise it's an entry - see if it matches the filter */
} else {
/* if it matches the filter and scope, send it */
if ( test_filter( be, conn, op, e, filter ) == 0 ) {
int scopeok;
char *dn;
/* check scope */
scopeok = 1;
if ( scope == LDAP_SCOPE_ONELEVEL ) {
if ( (dn = dn_parent( be, e->e_dn )) != NULL ) {
(void) dn_normalize_case( dn );
scopeok = (dn == realBase)
? 1
: (strcmp( dn, realBase ) ? 0 : 1 );
free( dn );
} else {
scopeok = (realBase == NULL || *realBase == '\0');
}
} else if ( scope == LDAP_SCOPE_SUBTREE ) {
dn = ch_strdup( e->e_ndn );
scopeok = dn_issuffix( dn, realBase );
free( dn );
}
if ( scopeok ) {
/* check size limit */
if ( --slimit == -1 ) {
bdb2i_cache_return_entry_r( &li->li_cache, e );
send_ldap_search_result( conn, op,
LDAP_SIZELIMIT_EXCEEDED, NULL,
nrefs > 0 ? rbuf : NULL, nentries );
bdb2i_idl_free( candidates );
free( rbuf );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
/*
* check and apply aliasing where the dereferencing applies to
* the subordinates of the base
*/
switch ( deref ) {
case LDAP_DEREF_SEARCHING:
case LDAP_DEREF_ALWAYS:
{
Entry *newe = bdb2i_derefAlias_r( be, conn, op, e );
if ( newe == NULL ) { /* problem with the alias */
bdb2i_cache_return_entry_r( &li->li_cache, e );
e = NULL;
}
else if ( newe != e ) { /* reassign e */
bdb2i_cache_return_entry_r( &li->li_cache, e );
e = newe;
}
}
break;
}
if (e) {
switch ( send_search_entry( be, conn, op, e,
attrs, attrsonly ) ) {
case 0: /* entry sent ok */
nentries++;
break;
case 1: /* entry not sent */
break;
case -1: /* connection closed */
bdb2i_cache_return_entry_r( &li->li_cache, e );
bdb2i_idl_free( candidates );
free( rbuf );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
}
}
}
}
if( e != NULL ) {
/* free reader lock */
bdb2i_cache_return_entry_r( &li->li_cache, e );
}
ldap_pvt_thread_yield();
}
bdb2i_idl_free( candidates );
if ( nrefs > 0 ) {
send_ldap_search_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
rbuf, nentries );
} else {
send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL,
nentries );
}
free( rbuf );
if( realBase != NULL) {
free( realBase );
}
return( 0 );
}
int
bdb2_back_search(
Backend *be,
Connection *conn,
Operation *op,
char *base,
int scope,
int deref,
int slimit,
int tlimit,
Filter *filter,
char *filterstr,
char **attrs,
int attrsonly
)
{
DB_LOCK lock;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
if ( bdb2i_enter_backend_r( &li->li_db_env, &lock ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
return( -1 );
}
ret = bdb2i_back_search_internal( be, conn, op, base, scope, deref,
slimit, tlimit, filter, filterstr, attrs, attrsonly );
(void) bdb2i_leave_backend( &li->li_db_env, lock );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "conn=%d op=%d SRCH elapsed=%s\n",
conn->c_connid, op->o_opid, elapsed_time );
free( elapsed_time );
}
return( ret );
}
static ID_BLOCK *
base_candidates(
Backend *be,
Connection *conn,
Operation *op,
char *base,
Filter *filter,
char **attrs,
int attrsonly,
char **matched,
int *err
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
int rc;
ID id;
ID_BLOCK *idl;
Entry *e;
Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", base, 0, 0);
*err = LDAP_SUCCESS;
/* get entry with reader lock */
if ( (e = bdb2i_dn2entry_r( be, base, matched )) == NULL ) {
*err = LDAP_NO_SUCH_OBJECT;
return( NULL );
}
/* check for deleted */
idl = bdb2i_idl_alloc( 1 );
bdb2i_idl_insert( &idl, e->e_id, 1 );
/* free reader lock */
bdb2i_cache_return_entry_r( &li->li_cache, e );
return( idl );
}
static ID_BLOCK *
onelevel_candidates(
Backend *be,
Connection *conn,
Operation *op,
char *base,
Filter *filter,
char **attrs,
int attrsonly,
char **matched,
int *err
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Entry *e = NULL;
Filter *f;
char buf[20];
ID_BLOCK *candidates;
Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0);
*err = LDAP_SUCCESS;
/* get the base object with reader lock */
if ( base != NULL && *base != '\0' &&
(e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
{
*err = LDAP_NO_SUCH_OBJECT;
return( NULL );
}
/*
* modify the filter to be something like this:
*
* parent=baseobject & originalfilter
*/
f = (Filter *) ch_malloc( sizeof(Filter) );
f->f_next = NULL;
f->f_choice = LDAP_FILTER_AND;
f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
f->f_and->f_choice = LDAP_FILTER_EQUALITY;
f->f_and->f_ava.ava_type = ch_strdup( "id2children" );
sprintf( buf, "%ld", e != NULL ? e->e_id : 0 );
f->f_and->f_ava.ava_value.bv_val = ch_strdup( buf );
f->f_and->f_ava.ava_value.bv_len = strlen( buf );
f->f_and->f_next = filter;
/* from here, it's just like subtree_candidates */
candidates = subtree_candidates( be, conn, op, base, f, attrs,
attrsonly, matched, e, err, 0 );
/* free up just the filter stuff we allocated above */
f->f_and->f_next = NULL;
filter_free( f );
/* free entry and reader lock */
if( e != NULL ) {
bdb2i_cache_return_entry_r( &li->li_cache, e );
}
return( candidates );
}
static ID_BLOCK *
subtree_candidates(
Backend *be,
Connection *conn,
Operation *op,
char *base,
Filter *filter,
char **attrs,
int attrsonly,
char **matched,
Entry *e,
int *err,
int lookupbase
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Filter *f, **filterarg_ptr;
ID_BLOCK *candidates;
Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n",
base ? base : "NULL", lookupbase ? "lookupbase" : "", 0);
/*
* get the base object - unless we already have it (from one-level).
* also, unless this is a one-level search or a subtree search
* starting at the very top of our subtree, we need to modify the
* filter to be something like this:
*
* dn=*baseobjectdn & (originalfilter | ref=*)
*
* the "objectclass=referral" part is used to select referrals to return
*/
*err = LDAP_SUCCESS;
f = NULL;
if ( lookupbase ) {
e = NULL;
if ( base != NULL && *base != '\0' &&
(e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
{
*err = LDAP_NO_SUCH_OBJECT;
return( NULL );
}
if (e) {
bdb2i_cache_return_entry_r( &li->li_cache, e );
}
f = (Filter *) ch_malloc( sizeof(Filter) );
f->f_next = NULL;
f->f_choice = LDAP_FILTER_OR;
f->f_or = (Filter *) ch_malloc( sizeof(Filter) );
f->f_or->f_choice = LDAP_FILTER_EQUALITY;
f->f_or->f_avtype = ch_strdup( "objectclass" );
/* Patch to use normalized uppercase */
f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" );
f->f_or->f_avvalue.bv_len = strlen( "REFERRAL" );
filterarg_ptr = &f->f_or->f_next;
*filterarg_ptr = filter;
filter = f;
if ( ! be_issuffix( be, base ) ) {
f = (Filter *) ch_malloc( sizeof(Filter) );
f->f_next = NULL;
f->f_choice = LDAP_FILTER_AND;
f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
f->f_and->f_sub_type = ch_strdup( "dn" );
f->f_and->f_sub_initial = NULL;
f->f_and->f_sub_any = NULL;
f->f_and->f_sub_final = ch_strdup( base );
value_normalize( f->f_and->f_sub_final, SYNTAX_CIS );
f->f_and->f_next = filter;
filter = f;
}
}
candidates = bdb2i_filter_candidates( be, filter );
/* free up just the parts we allocated above */
if ( f != NULL ) {
*filterarg_ptr = NULL;
filter_free( f );
}
return( candidates );
}

View file

@ -0,0 +1,217 @@
/* startup.c - startup bdb2 backend */
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "ldapconfig.h"
#include "slap.h"
#include "back-bdb2.h"
#include "db.h"
static void remove_old_locks( char *home );
static void
bdb2i_db_errcall( char *prefix, char *message )
{
Debug( LDAP_DEBUG_ANY, "dbd2_db_errcall(): %s %s", prefix, message, 0 );
}
void
bdb2i_back_startup_internal(
Backend *be
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
DB_ENV *dbEnv = &li->li_db_env;
int envFlags = DB_CREATE | DB_THREAD | DB_INIT_LOCK | DB_INIT_MPOOL;
int err = 0;
char *home;
char datadir[MAXPATHLEN];
char *config[2] = { datadir, NULL };
/* if the data directory is not an absolute path, have it relative
to the current working directory (which should not be configured !) */
if ( *li->li_directory != *DEFAULT_DIRSEP ) {
char cwd[MAXPATHLEN];
(void) getcwd( cwd, MAXPATHLEN );
sprintf( cwd, "%s%s%s", cwd, DEFAULT_DIRSEP, li->li_directory );
free( li->li_directory );
li->li_directory = strdup( cwd );
}
/* set the DB home directory to the configured one, or the data dir */
if ( li->li_dbhome ) {
if ( *li->li_dbhome != *DEFAULT_DIRSEP ) {
char cwd[MAXPATHLEN];
(void) getcwd( cwd, MAXPATHLEN );
sprintf( cwd, "%s%s%s", cwd, DEFAULT_DIRSEP, li->li_dbhome );
free( li->li_dbhome );
li->li_dbhome = strdup( cwd );
}
home = li->li_dbhome;
} else {
home = li->li_directory;
}
/* set the DATA_DIR */
sprintf( datadir, "DB_DATA_DIR %s", li->li_directory );
/* general initialization of the environment */
memset( dbEnv, 0, sizeof( DB_ENV ));
dbEnv->db_errcall = bdb2i_db_errcall;
dbEnv->db_errpfx = "==>";
/* initialize the lock subsystem */
dbEnv->lk_max = 0;
/* remove old locking tables */
remove_old_locks( home );
/* initialize the mpool subsystem */
dbEnv->mp_size = (size_t) li->li_dbcachesize;
/* now do the db_appinit */
if ( ( err = db_appinit( home, config, dbEnv, envFlags )) ) {
char error[BUFSIZ];
if ( err < 0 ) sprintf( error, "%ld\n", (long) err );
else sprintf( error, "%s\n", strerror( err ));
fprintf( stderr,
"bdb2i_back_startup(): FATAL error in db_appinit() : %s\n",
error );
exit( 1 );
}
bdb2i_with_dbenv = 1;
/* if there are more index files, add them to the DB file list */
bdb2i_check_additional_attr_index( li );
/* now open all DB files */
bdb2i_txn_open_files( li );
}
static void
bdb2i_back_shutdown_internal(
Backend *be
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
DB_ENV *dbEnv = &li->li_db_env;
int err;
/* close all DB files */
bdb2i_txn_close_files( &li->li_txn_head );
/* remove old locking tables */
dbEnv->db_errpfx = "bdb2i_back_shutdown(): lock_unlink:";
if ( ( err = lock_unlink( NULL, 1, dbEnv )) != 0 )
Debug( LDAP_DEBUG_ANY, "bdb2i_back_shutdown(): lock_unlink: %s\n",
strerror( err ), 0, 0);
/* remove old memory pool */
dbEnv->db_errpfx = "bdb2i_back_shutdown(): memp_unlink:";
if ( ( err = memp_unlink( NULL, 1, dbEnv )) != 0 )
Debug( LDAP_DEBUG_ANY, "bdb2i_back_shutdown(): memp_unlink: %s\n",
strerror( err ), 0, 0);
(void) db_appexit( &li->li_db_env );
}
void
bdb2_back_startup(
Backend *be
)
{
struct timeval time1, time2;
char *elapsed_time;
gettimeofday( &time1, NULL );
bdb2i_back_startup_internal( be );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "START elapsed=%s\n",
elapsed_time, 0, 0 );
free( elapsed_time );
}
}
void
bdb2_back_shutdown(
Backend *be
)
{
struct timeval time1, time2;
char *elapsed_time;
gettimeofday( &time1, NULL );
bdb2i_back_shutdown_internal( be );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "SHUTDOWN elapsed=%s\n",
elapsed_time, 0, 0 );
free( elapsed_time );
}
}
static void
remove_old_locks( char *home )
{
DB_ENV dbEnv;
int err;
memset( &dbEnv, 0, sizeof( DB_ENV ));
dbEnv.db_errcall = stderr;
dbEnv.db_errpfx = "remove_old_locks(): db_appinit:";
dbEnv.lk_max = 0;
if ( ( err = db_appinit( home, NULL, &dbEnv, 0 )) != 0 )
Debug( LDAP_DEBUG_ANY, "remove_old_locks(): db_appinit: %s\n",
strerror( err ), 0, 0);
dbEnv.db_errpfx = "remove_old_locks(): lock_unlink:";
if ( ( err = lock_unlink( NULL, 1, &dbEnv )) != 0 )
Debug( LDAP_DEBUG_ANY, "remove_old_locks(): lock_unlink: %s\n",
strerror( err ), 0, 0);
dbEnv.db_errpfx = "remove_old_locks(): db_appexit:";
if ( ( err = db_appexit( &dbEnv )) != 0 )
Debug( LDAP_DEBUG_ANY, "remove_old_locks(): db_appexit: %s\n",
strerror( err ), 0, 0);
}

View file

@ -0,0 +1,35 @@
/* timing.c - timing bdb2 backend */
#include "portable.h"
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <ac/string.h>
#include "slap.h"
#include "back-bdb2.h"
int bdb2i_do_timing = 0;
char *
bdb2i_elapsed( struct timeval firsttime, struct timeval secondtime )
{
long int elapsedmicrosec, elapsedsec;
char elapsed_string[BUFSIZ];
elapsedsec = secondtime.tv_sec - firsttime.tv_sec;
elapsedmicrosec = secondtime.tv_usec - firsttime.tv_usec;
if(elapsedmicrosec < 0) {
elapsedmicrosec += 1000000;
elapsedsec -= 1;
}
sprintf( elapsed_string, "%ld.%.6ld", elapsedsec, elapsedmicrosec );
return( strdup( elapsed_string ));
}

View file

@ -0,0 +1,321 @@
/* txn.c - TP support functions of the bdb2 backend */
#include "txn.h"
void
bdb2i_txn_head_init( BDB2_TXN_HEAD *head )
{
int dbFile;
BDB2_TXN_FILES **fileNodeH;
/* for each fixed DB file allocate a file descriptor node and
initialize the file's name */
fileNodeH = &head->dbFiles;
for ( dbFile = BDB2_DB_DN_FILE; dbFile <= BDB2_DB_OC_IDX_FILE; dbFile++ ) {
char fileName[MAXPATHLEN];
*fileNodeH = head->dbFileHandle[dbFile] =
(BDB2_TXN_FILES *) ch_calloc( 1, sizeof( BDB2_TXN_FILES ));
if ( *fileNodeH == NULL ) {
Debug( LDAP_DEBUG_ANY, "bdb2i_txn_head_init(): out of memory!\n",
0, 0, 0 );
exit( 1 );
}
sprintf( fileName, "%s%s", bdb2i_fixed_filenames[dbFile], LDBM_SUFFIX );
(*fileNodeH)->dbc_name = strdup( fileName );
fileNodeH = &(*fileNodeH)->next;
}
}
static void
bdb2i_init_db_file_cache( struct ldbminfo *li, BDB2_TXN_FILES *fileinfo )
{
time_t curtime;
struct stat st;
char buf[MAXPATHLEN];
pthread_mutex_lock( &currenttime_mutex );
curtime = currenttime;
pthread_mutex_unlock( &currenttime_mutex );
fileinfo->dbc_refcnt = 1;
fileinfo->dbc_lastref = curtime;
sprintf( buf, "%s%s%s", li->li_directory, DEFAULT_DIRSEP,
fileinfo->dbc_name );
if ( stat( buf, &st ) == 0 ) {
fileinfo->dbc_blksize = st.st_blksize;
} else {
fileinfo->dbc_blksize = DEFAULT_BLOCKSIZE;
}
fileinfo->dbc_maxids = ( fileinfo->dbc_blksize / sizeof( ID )) - 2;
fileinfo->dbc_maxindirect = ( SLAPD_LDBM_MIN_MAXIDS /
fileinfo->dbc_maxids ) + 1;
}
void
bdb2i_txn_attr_config(
struct ldbminfo *li,
char *attr,
int open )
{
BDB2_TXN_HEAD *head = &li->li_txn_head;
/* the "attribute" 'default' is special */
if ( strcasecmp( attr, "default" )) {
/* create a new index file node, if the index is not known already */
BDB2_TXN_FILES **fileNodeH;
char fileName[MAXPATHLEN];
sprintf( fileName, "%s%s", attr, LDBM_SUFFIX );
/* search for the end of the list or a node describing
the current attribute */
for ( fileNodeH = &head->dbFiles;
( *fileNodeH && strcasecmp( (*fileNodeH)->dbc_name, fileName ));
fileNodeH = &(*fileNodeH)->next ) {
}
/* unless we have that attribute already... */
if ( *fileNodeH == NULL ) {
BDB2_TXN_FILES *p;
Debug( LDAP_DEBUG_TRACE,
"bdb2i_txn_attr_config(): adding node for \"%s\"\n",
fileName, 0, 0 );
/* if we're out of memory, we have to see, how to exit... */
if ( ( *fileNodeH = p = (BDB2_TXN_FILES *)
ch_calloc( 1, sizeof( BDB2_TXN_FILES )) ) == NULL ) {
Debug( LDAP_DEBUG_ANY,
"bdb2i_txn_attr_config(): out of memory -- FATAL.\n",
0, 0, 0 );
/* during configuration (no files are opened)
we can just exit, otherwise we kill ourself and
hope to shutdown cleanly... */
if ( open ) {
pthread_kill( pthread_self(), LDAP_SIGUSR1 );
} else {
exit( 1 );
}
}
p->dbc_name = strdup( fileName );
/* if requested for, we have to open the DB file */
/* BUT NOT "objectclass", 'cause that's a default index ! */
if ( open && strcasecmp( fileName, "objectclass" )) {
/* since we have an mpool, we should not define a cache size */
p->dbc_db = ldbm_open_env( p->dbc_name, LDBM_WRCREAT,
li->li_mode, 0, &li->li_db_env );
/* if the files could not be opened, something is wrong;
complain */
if ( p->dbc_db == NULL ) {
Debug( LDAP_DEBUG_ANY,
"bdb2i_txn_open_files(): couldn't open file \"%s\" -- FATAL.\n",
p->dbc_name, 0, 0 );
pthread_kill( pthread_self(), LDAP_SIGUSR1 );
}
bdb2i_init_db_file_cache( li, p );
Debug( LDAP_DEBUG_TRACE,
"bdb2i_txn_attr_config(): NEW INDEX FILE \"%s\"\n",
p->dbc_name, 0, 0 );
}
}
} else { /* it is "attribute" 'default' */
head->withDefIDX = BDB2_WITH_DEF_IDX;
}
}
void
bdb2i_txn_open_files( struct ldbminfo *li )
{
BDB2_TXN_HEAD *head = &li->li_txn_head;
BDB2_TXN_FILES *dbFile;
for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
/* since we have an mpool, we should not define a cache size */
dbFile->dbc_db = ldbm_open_env( dbFile->dbc_name, LDBM_WRCREAT,
li->li_mode, 0, &li->li_db_env );
/* if the files could not be opened, something is wrong; complain */
if ( dbFile->dbc_db == NULL ) {
Debug( LDAP_DEBUG_ANY,
"bdb2i_txn_open_files(): couldn't open file \"%s\" -- FATAL.\n",
dbFile->dbc_name, 0, 0 );
exit( 1 );
}
/* initialize the file info */
bdb2i_init_db_file_cache( li, dbFile );
Debug( LDAP_DEBUG_TRACE, "bdb2i_txn_open_files(): OPEN INDEX \"%s\"\n",
dbFile->dbc_name, 0, 0 );
}
}
void
bdb2i_txn_close_files( BDB2_TXN_HEAD *head)
{
BDB2_TXN_FILES *dbFile;
for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
ldbm_close( dbFile->dbc_db );
}
}
BDB2_TXN_FILES *
bdb2i_get_db_file_cache( struct ldbminfo *li, char *name )
{
BDB2_TXN_HEAD *head = &li->li_txn_head;
BDB2_TXN_FILES *dbFile;
int dbFileNum;
for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) {
if ( !strcasecmp( dbFile->dbc_name, name )) return( dbFile );
}
Debug( LDAP_DEBUG_ANY,
"bdb2i_get_db_file_cache(): UPS, could't find \"%s\" \n", name, 0, 0 );
/* ups, we couldn't find the file */
return( NULL );
}
/* check for new attribute indexes, that might have been created
during former runs of slapd */
/* this is called during startup of the slapd server */
void
bdb2i_check_additional_attr_index( struct ldbminfo *li )
{
DIR *datadir;
struct dirent *file;
if ( ( datadir = opendir( li->li_directory ) ) == NULL ) {
/* if ( ( datadir = opendir( "/tmp" ) ) == NULL ) { */
Debug( LDAP_DEBUG_ANY,
"bdb2i_check_additional_attr_index(): ERROR while opening datadir: %s\n",
strerror( errno ), 0, 0 );
exit( 1 );
}
for ( file = readdir( datadir ); file; file = readdir( datadir )) {
char filename[MAXPATHLEN];
int namelen;
strcpy( filename, file->d_name );
namelen = strlen( filename );
if ( namelen > strlen( LDBM_SUFFIX )) {
if ( !strcasecmp( filename + namelen - strlen( LDBM_SUFFIX ),
LDBM_SUFFIX )) {
*(filename + namelen - strlen( LDBM_SUFFIX )) = '\0';
bdb2i_txn_attr_config( li, filename, 0 );
Debug( LDAP_DEBUG_TRACE, "INDEX FILE: %s\n", filename, 0, 0 );
}
}
}
closedir( datadir );
}
/* check for the addition of new attribute indexes during add */
/* this is called after startup of the slapd server */
/* DON'T WORRY ABOUT ACCESS RIGHTS, THAT MIGHT PREVENT US
FROM ADDING ATTRIBUTES LATER ON */
void
bdb2i_check_default_attr_index_add( struct ldbminfo *li, Entry *e )
{
BDB2_TXN_HEAD *head = &li->li_txn_head;
if ( head->withDefIDX == BDB2_WITH_DEF_IDX ) {
Attribute *ap;
for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
if ( strcasecmp( ap->a_type, "objectclass" ))
bdb2i_txn_attr_config( li, ap->a_type, 1 );
}
}
}
/* check for the addition of new attribute indexes during modify */
/* this is called after startup of the slapd server */
/* DON'T WORRY ABOUT ACCESS RIGHTS, THAT MIGHT PREVENT US
FROM ADDING ATTRIBUTES LATER ON */
void
bdb2i_check_default_attr_index_mod( struct ldbminfo *li, LDAPModList *modlist )
{
BDB2_TXN_HEAD *head = &li->li_txn_head;
if ( head->withDefIDX == BDB2_WITH_DEF_IDX ) {
LDAPModList *ml;
char *default_attrs[] = { "modifytimestamp", "modifiersname", NULL };
int attr;
for ( ml = modlist; ml != NULL; ml = ml->ml_next ) {
LDAPMod *mod = &ml->ml_mod;
if (( mod->mod_op & ~LDAP_MOD_BVALUES ) == LDAP_MOD_ADD )
if ( strcasecmp( mod->mod_type, "objectclass" ))
bdb2i_txn_attr_config( li, mod->mod_type, 1 );
}
/* these attributes are default when modifying */
for ( attr = 0; default_attrs[attr]; attr++ ) {
bdb2i_txn_attr_config( li, default_attrs[attr], 1 );
}
}
}

View file

@ -0,0 +1,38 @@
/* txn.h - Header for TP support functions of the bdb2 backend */
#ifndef _BDB2_TXN_H_
#define _BDB2_TXN_H_
#include "portable.h"
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <ac/string.h>
#include <ac/socket.h>
#include <ac/signal.h>
#include "ldapconfig.h"
#include "slap.h"
#include "back-bdb2.h"
#define BDB2_TXN_CHKP_MAX_CNT 20 /* checkpoint every
20 transactions */
#define BDB2_TXN_CHKP_MAX_TIME 600 /* checkpoint after
600 seconds */
char *bdb2i_fixed_filenames[] = {
"dn", "dn2id", "id2entry", "id2children", "objectclass"
};
#endif /* _BDB2_TXN_H_ */

View file

@ -0,0 +1,48 @@
/* unbind.c - handle an ldap unbind operation */
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-bdb2.h"
static int
bdb2i_back_unbind_internal(
Backend *be,
Connection *conn,
Operation *op
)
{
return( 0 );
}
int
bdb2_back_unbind(
Backend *be,
Connection *conn,
Operation *op
)
{
struct timeval time1, time2;
char *elapsed_time;
int ret;
gettimeofday( &time1, NULL );
ret = bdb2i_back_unbind_internal( be, conn, op );
if ( bdb2i_do_timing ) {
gettimeofday( &time2, NULL);
elapsed_time = bdb2i_elapsed( time1, time2 );
Debug( LDAP_DEBUG_ANY, "conn=%d op=%d UNBIND elapsed=%s\n",
conn->c_connid, op->o_opid, elapsed_time );
free( elapsed_time );
}
return( ret );
}

View file

@ -315,7 +315,6 @@ char *derefDN ( Backend *be,
}
Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 );
if (matched != NULL) free(matched);
return newDN;
}