Import back-mdb

This commit is contained in:
Howard Chu 2011-09-01 16:52:53 -07:00
parent 02cff39398
commit 0ba4206ed9
28 changed files with 12480 additions and 0 deletions

145
doc/man/man5/slapd-mdb.5 Normal file
View file

@ -0,0 +1,145 @@
.TH SLAPD-MDB 5 "RELEASEDATE" "OpenLDAP LDVERSION"
.\" Copyright 2011 The OpenLDAP Foundation All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.\" $OpenLDAP$
.SH NAME
slapd\-mdb \- Memory-Mapped DB backend to slapd
.SH SYNOPSIS
.B ETCDIR/slapd.conf
.SH DESCRIPTION
The \fBmdb\fP backend to
.BR slapd (8)
uses OpenLDAP's own Memory-Mapped DB (MDB) library to store data.
It relies completely on the underlying operating system for memory
management and does no caching of its own.
.LP
The \fBmdb\fP backend is similar to the \fBhdb\fP backend in that
it uses a hierarchical database layout which
supports subtree renames. It is both more space-efficient and more
execution-efficient than the \fBbdb\fP backend, while being overall
much simpler to manage.
.SH CONFIGURATION
These
.B slapd.conf
options apply to the \fBmdb\fP backend database.
That is, they must follow a "database mdb" line and
come before any subsequent "backend" or "database" lines.
Other database options are described in the
.BR slapd.conf (5)
manual page.
.TP
.BI checkpoint \ <kbyte>\ <min>
Specify the frequency for flushing the database disk buffers.
This setting is only needed if the \fBdbnosync\fP option is used.
The checkpoint will occur if either \fI<kbyte>\fP data has been written or
\fI<min>\fP minutes have passed since the last checkpoint.
Both arguments default to zero, in which case they are ignored. When
the \fI<min>\fP argument is non-zero, an internal task will run every
\fI<min>\fP minutes to perform the checkpoint.
Note: currently the \fI<kbyte>\fP setting is unimplemented.
.TP
.B dbnosync
Specify that on-disk database contents should not be immediately
synchronized with in memory changes.
Enabling this option may improve performance at the expense of data
security. By default, a full data flush/sync is performed when each
transaction is committed.
.TP
.BI directory \ <directory>
Specify the directory where the MDB files containing this database and
associated indexes live.
A separate directory must be specified for each database.
The default is
.BR LOCALSTATEDIR/openldap\-data .
.TP
\fBindex \fR{\fI<attrlist>\fR|\fBdefault\fR} [\fBpres\fR,\fBeq\fR,\fBapprox\fR,\fBsub\fR,\fI<special>\fR]
Specify the indexes to maintain for the given attribute (or
list of attributes).
Some attributes only support a subset of indexes.
If only an \fI<attr>\fP is given, the indices specified for \fBdefault\fR
are maintained.
Note that setting a default does not imply that all attributes will be
indexed. Also, for best performance, an
.B eq
index should always be configured for the
.B objectClass
attribute.
A number of special index parameters may be specified.
The index type
.B sub
can be decomposed into
.BR subinitial ,
.BR subany ,\ and
.B subfinal
indices.
The special type
.B nolang
may be specified to disallow use of this index by language subtypes.
The special type
.B nosubtypes
may be specified to disallow use of this index by named subtypes.
Note: changing \fBindex\fP settings in
.BR slapd.conf (5)
requires rebuilding indices, see
.BR slapindex (8);
changing \fBindex\fP settings
dynamically by LDAPModifying "cn=config" automatically causes rebuilding
of the indices online in a background task.
.TP
.BI maxreaders \ <integer>
Specify the maximum number of threads that may have concurrent read access
to the database. Tools such as slapcat count as a single thread,
in addition to threads in any active slapd processes. The
default is 126.
.TP
.BI maxsize \ <bytes>
Specify the maximum size of the database in bytes. A memory map of this
size is allocated at startup time and the database will not be allowed
to grow beyond this size. The default is 10485760 bytes. This setting
may be changed upward if the configured limit needs to be increased.
Note: It is important to set this to as large a value as possible,
(relative to anticipated growth of the actual data over time) since
growing the size later may not be practical when the system is under
heavy load.
.TP
.BI mode \ <integer>
Specify the file protection mode that newly created database
files should have.
The default is 0600.
.TP
.BI searchstack \ <depth>
Specify the depth of the stack used for search filter evaluation.
Search filters are evaluated on a stack to accommodate nested AND / OR
clauses. An individual stack is assigned to each server thread.
The depth of the stack determines how complex a filter can be
evaluated without requiring any additional memory allocation. Filters that
are nested deeper than the search stack depth will cause a separate
stack to be allocated for that particular search operation. These
allocations can have a major negative impact on server performance,
but specifying too much stack will also consume a great deal of memory.
Each search stack uses 512K bytes per level. The default stack depth
is 16, thus 8MB per thread is used.
.SH ACCESS CONTROL
The
.B mdb
backend honors access control semantics as indicated in
.BR slapd.access (5).
.SH FILES
.TP
.B ETCDIR/slapd.conf
default
.B slapd
configuration file
.SH SEE ALSO
.BR slapd.conf (5),
.BR slapd\-config (5),
.BR slapd (8),
.BR slapadd (8),
.BR slapcat (8),
.BR slapindex (8),
OpenLDAP MDB documentation.
.SH ACKNOWLEDGEMENTS
.so ../Project
Written by Howard Chu.

View file

@ -0,0 +1,61 @@
# Makefile.in for back-mdb
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 2011 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
SRCS = init.c tools.c config.c \
add.c bind.c compare.c delete.c modify.c modrdn.c search.c \
extended.c referral.c operational.c \
attr.c index.c key.c filterindex.c \
dn2entry.c dn2id.c id2entry.c idl.c \
nextid.c monitor.c
OBJS = init.lo tools.lo config.lo \
add.lo bind.lo compare.lo delete.lo modify.lo modrdn.lo search.lo \
extended.lo referral.lo operational.lo \
attr.lo index.lo key.lo filterindex.lo \
dn2entry.lo dn2id.lo id2entry.lo idl.lo \
nextid.lo monitor.lo mdb.lo midl.lo
LDAP_INCDIR= ../../../include
LDAP_LIBDIR= ../../../libraries
BUILD_OPT = "--enable-mdb"
BUILD_MOD = @BUILD_MDB@
mod_DEFS = -DSLAPD_IMPORT
MOD_DEFS = $(@BUILD_MDB@_DEFS)
MOD_LIBS = $(MDB_LIBS)
shared_LDAP_LIBS = $(LDAP_LIBLDAP_R_LA) $(LDAP_LIBLBER_LA)
NT_LINK_LIBS = -L.. -lslapd $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
UNIX_LINK_LIBS = $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
LIBBASE = back_mdb
XINCPATH = -I.. -I$(srcdir)/.. -I$(srcdir)/$(LDAP_LIBDIR)/libmdb
XDEFS = $(MODULES_CPPFLAGS)
all-local-lib: ../.backend
../.backend: lib$(LIBBASE).a
@touch $@
mdb.lo: $(srcdir)/$(LDAP_LIBDIR)/libmdb/mdb.c
$(LTCOMPILE_MOD) $<
midl.lo: $(srcdir)/$(LDAP_LIBDIR)/libmdb/midl.c
$(LTCOMPILE_MOD) $<
veryclean-local-lib: FORCE
$(RM) $(XXHEADERS) $(XXSRCS) .links

View file

@ -0,0 +1,438 @@
/* add.c - ldap mdb back-end add routine */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "back-mdb.h"
int
mdb_add(Operation *op, SlapReply *rs )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
struct berval pdn;
Entry *p = NULL, *oe = op->ora_e;
char textbuf[SLAP_TEXT_BUFLEN];
size_t textlen = sizeof textbuf;
AttributeDescription *children = slap_schema.si_ad_children;
AttributeDescription *entry = slap_schema.si_ad_entry;
MDB_txn *txn = NULL;
ID eid = NOID, pid = 0;
mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
int subentry;
int success;
LDAPControl **postread_ctrl = NULL;
LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
int num_ctrls = 0;
#ifdef LDAP_X_TXN
int settle = 0;
#endif
Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(mdb_add) ": %s\n",
op->ora_e->e_name.bv_val, 0, 0);
#ifdef LDAP_X_TXN
if( op->o_txnSpec ) {
/* acquire connection lock */
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
rs->sr_text = "invalid transaction identifier";
rs->sr_err = LDAP_X_TXN_ID_INVALID;
goto txnReturn;
} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
settle=1;
goto txnReturn;
}
if( op->o_conn->c_txn_backend == NULL ) {
op->o_conn->c_txn_backend = op->o_bd;
} else if( op->o_conn->c_txn_backend != op->o_bd ) {
rs->sr_text = "transaction cannot span multiple database contexts";
rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
goto txnReturn;
}
/* insert operation into transaction */
rs->sr_text = "transaction specified";
rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
txnReturn:
/* release connection lock */
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
if( !settle ) {
send_ldap_result( op, rs );
return rs->sr_err;
}
}
#endif
ctrls[num_ctrls] = 0;
/* check entry's schema */
rs->sr_err = entry_schema_check( op, op->ora_e, NULL,
get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
if ( rs->sr_err != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": entry failed schema check: "
"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
goto return_results;
}
/* add opattrs to shadow as well, only missing attrs will actually
* be added; helps compatibility with older OL versions */
rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
if ( rs->sr_err != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": entry failed op attrs add: "
"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
goto return_results;
}
if ( get_assert( op ) &&
( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
{
rs->sr_err = LDAP_ASSERTION_FAILED;
goto return_results;
}
subentry = is_entry_subentry( op->ora_e );
/* begin transaction */
rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
rs->sr_text = NULL;
if( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": txn_begin failed: %s (%d)\n",
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
txn = moi->moi_txn;
/*
* Get the parent dn and see if the corresponding entry exists.
*/
if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
pdn = slap_empty_bv;
} else {
dnParent( &op->ora_e->e_nname, &pdn );
}
/* get entry or parent */
rs->sr_err = mdb_dn2entry( op, txn, &op->ora_e->e_nname, &p, 1 );
switch( rs->sr_err ) {
case 0:
rs->sr_err = LDAP_ALREADY_EXISTS;
mdb_entry_return( p );
p = NULL;
goto return_results;
case MDB_NOTFOUND:
break;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
if ( !p )
p = (Entry *)&slap_entry_root;
if ( !bvmatch( &pdn, &p->e_nname ) ) {
rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
op->o_tmpmemctx );
if ( p != (Entry *)&slap_entry_root && is_entry_referral( p )) {
BerVarray ref = get_entry_referrals( op, p );
rs->sr_ref = referral_rewrite( ref, &p->e_name,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
ber_bvarray_free( ref );
} else {
rs->sr_ref = NULL;
}
if ( p != (Entry *)&slap_entry_root )
mdb_entry_return( p );
p = NULL;
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": parent "
"does not exist\n", 0, 0, 0 );
rs->sr_err = LDAP_REFERRAL;
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
goto return_results;
}
rs->sr_err = access_allowed( op, p,
children, NULL, ACL_WADD, NULL );
if ( ! rs->sr_err ) {
if ( p != (Entry *)&slap_entry_root )
mdb_entry_return( p );
p = NULL;
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": no write access to parent\n",
0, 0, 0 );
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
rs->sr_text = "no write access to parent";
goto return_results;;
}
if ( p != (Entry *)&slap_entry_root ) {
if ( is_entry_subentry( p ) ) {
mdb_entry_return( p );
p = NULL;
/* parent is a subentry, don't allow add */
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": parent is subentry\n",
0, 0, 0 );
rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
rs->sr_text = "parent is a subentry";
goto return_results;;
}
if ( is_entry_alias( p ) ) {
mdb_entry_return( p );
p = NULL;
/* parent is an alias, don't allow add */
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": parent is alias\n",
0, 0, 0 );
rs->sr_err = LDAP_ALIAS_PROBLEM;
rs->sr_text = "parent is an alias";
goto return_results;;
}
if ( is_entry_referral( p ) ) {
BerVarray ref = get_entry_referrals( op, p );
/* parent is a referral, don't allow add */
rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
op->o_tmpmemctx );
rs->sr_ref = referral_rewrite( ref, &p->e_name,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
ber_bvarray_free( ref );
mdb_entry_return( p );
p = NULL;
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": parent is referral\n",
0, 0, 0 );
rs->sr_err = LDAP_REFERRAL;
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
goto return_results;
}
}
if ( subentry ) {
/* FIXME: */
/* parent must be an administrative point of the required kind */
}
/* free parent */
if ( p != (Entry *)&slap_entry_root ) {
pid = p->e_id;
if ( p->e_nname.bv_len ) {
struct berval ppdn;
/* ITS#5326: use parent's DN if differs from provided one */
dnParent( &op->ora_e->e_name, &ppdn );
if ( !dn_match( &p->e_name, &ppdn ) ) {
struct berval rdn;
struct berval newdn;
dnRdn( &op->ora_e->e_name, &rdn );
build_new_dn( &newdn, &p->e_name, &rdn, NULL );
if ( op->ora_e->e_name.bv_val != op->o_req_dn.bv_val )
ber_memfree( op->ora_e->e_name.bv_val );
op->ora_e->e_name = newdn;
/* FIXME: should check whether
* dnNormalize(newdn) == e->e_nname ... */
}
}
mdb_entry_return( p );
}
p = NULL;
rs->sr_err = access_allowed( op, op->ora_e,
entry, NULL, ACL_WADD, NULL );
if ( ! rs->sr_err ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": no write access to entry\n",
0, 0, 0 );
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
rs->sr_text = "no write access to entry";
goto return_results;;
}
/*
* Check ACL for attribute write access
*/
if (!acl_check_modlist(op, oe, op->ora_modlist)) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": no write access to attribute\n",
0, 0, 0 );
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
rs->sr_text = "no write access to attribute";
goto return_results;;
}
if ( eid == NOID ) {
rs->sr_err = mdb_next_id( op->o_bd, txn, &eid );
if( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": next_id failed (%d)\n",
rs->sr_err, 0, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
op->ora_e->e_id = eid;
}
/* dn2id index */
rs->sr_err = mdb_dn2id_add( op, txn, pid, op->ora_e );
if ( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": dn2id_add failed: %s (%d)\n",
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
switch( rs->sr_err ) {
case MDB_KEYEXIST:
rs->sr_err = LDAP_ALREADY_EXISTS;
break;
default:
rs->sr_err = LDAP_OTHER;
}
goto return_results;
}
/* attribute indexes */
rs->sr_err = mdb_index_entry_add( op, txn, op->ora_e );
if ( rs->sr_err != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": index_entry_add failed\n",
0, 0, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "index generation failed";
goto return_results;
}
/* id2entry index */
rs->sr_err = mdb_id2entry_add( op, txn, op->ora_e );
if ( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": id2entry_add failed\n",
0, 0, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "entry store failed";
goto return_results;
}
/* post-read */
if( op->o_postread ) {
if( postread_ctrl == NULL ) {
postread_ctrl = &ctrls[num_ctrls++];
ctrls[num_ctrls] = NULL;
}
if ( slap_read_controls( op, rs, op->ora_e,
&slap_post_read_bv, postread_ctrl ) )
{
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_add) ": post-read "
"failed!\n", 0, 0, 0 );
if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
/* FIXME: is it correct to abort
* operation if control fails? */
goto return_results;
}
}
}
if ( moi == &opinfo ) {
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
opinfo.moi_oe.oe_key = NULL;
if ( op->o_noop ) {
mdb_txn_abort( txn );
rs->sr_err = LDAP_X_NO_OPERATION;
txn = NULL;
goto return_results;
}
if (( rs->sr_err = mdb_txn_commit( txn )) != 0 ) {
rs->sr_text = "txn_commit failed";
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": %s : %s (%d)\n",
rs->sr_text, mdb_strerror(rs->sr_err), rs->sr_err );
rs->sr_err = LDAP_OTHER;
goto return_results;
}
txn = NULL;
}
Debug(LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_add) ": added%s id=%08lx dn=\"%s\"\n",
op->o_noop ? " (no-op)" : "",
op->ora_e->e_id, op->ora_e->e_dn );
rs->sr_text = NULL;
if( num_ctrls ) rs->sr_ctrls = ctrls;
return_results:
success = rs->sr_err;
send_ldap_result( op, rs );
if( moi == &opinfo ) {
if( txn != NULL ) {
mdb_txn_abort( txn );
}
if ( opinfo.moi_oe.oe_key ) {
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
}
}
if( success == LDAP_SUCCESS ) {
#if 0
if ( mdb->bi_txn_cp_kbyte ) {
TXN_CHECKPOINT( mdb->bi_dbenv,
mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
}
#endif
}
slap_graduate_commit_csn( op );
if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
}
return rs->sr_err;
}

View file

@ -0,0 +1,522 @@
/* attr.c - backend routines for dealing with attributes */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-mdb.h"
#include "config.h"
#include "lutil.h"
/* Find the ad, return -1 if not found,
* set point for insertion if ins is non-NULL
*/
int
mdb_attr_slot( struct mdb_info *mdb, AttributeDescription *ad, int *ins )
{
unsigned base = 0, cursor = 0;
unsigned n = mdb->mi_nattrs;
int val = 0;
while ( 0 < n ) {
unsigned pivot = n >> 1;
cursor = base + pivot;
val = SLAP_PTRCMP( ad, mdb->mi_attrs[cursor]->ai_desc );
if ( val < 0 ) {
n = pivot;
} else if ( val > 0 ) {
base = cursor + 1;
n -= pivot + 1;
} else {
return cursor;
}
}
if ( ins ) {
if ( val > 0 )
++cursor;
*ins = cursor;
}
return -1;
}
static int
ainfo_insert( struct mdb_info *mdb, AttrInfo *a )
{
int x;
int i = mdb_attr_slot( mdb, a->ai_desc, &x );
/* Is it a dup? */
if ( i >= 0 )
return -1;
mdb->mi_attrs = ch_realloc( mdb->mi_attrs, ( mdb->mi_nattrs+1 ) *
sizeof( AttrInfo * ));
if ( x < mdb->mi_nattrs )
AC_MEMCPY( &mdb->mi_attrs[x+1], &mdb->mi_attrs[x],
( mdb->mi_nattrs - x ) * sizeof( AttrInfo *));
mdb->mi_attrs[x] = a;
mdb->mi_nattrs++;
return 0;
}
AttrInfo *
mdb_attr_mask(
struct mdb_info *mdb,
AttributeDescription *desc )
{
int i = mdb_attr_slot( mdb, desc, NULL );
return i < 0 ? NULL : mdb->mi_attrs[i];
}
/* Open all un-opened index DB handles */
int
mdb_attr_dbs_open(
BackendDB *be, MDB_txn *tx0, ConfigReply *cr )
{
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
MDB_txn *txn;
int i, flags;
int rc;
txn = tx0;
if ( txn == NULL ) {
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &txn );
if ( rc ) {
snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
"txn_begin failed: %s (%d).",
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
cr->msg, 0, 0 );
return rc;
}
} else {
rc = 0;
}
flags = MDB_DUPSORT|MDB_DUPFIXED|MDB_INTEGERDUP;
if ( !(slapMode & SLAP_TOOL_READONLY) )
flags |= MDB_CREATE;
for ( i=0; i<mdb->mi_nattrs; i++ ) {
if ( mdb->mi_attrs[i]->ai_dbi ) /* already open */
continue;
rc = mdb_open( txn, mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
flags, &mdb->mi_attrs[i]->ai_dbi );
if ( rc ) {
snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
"mdb_open(%s) failed: %s (%d).",
be->be_suffix[0].bv_val,
mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
cr->msg, 0, 0 );
break;
}
}
/* Only commit if this is our txn */
if ( tx0 == NULL ) {
if ( !rc ) {
rc = mdb_txn_commit( txn );
if ( rc ) {
snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
"txn_commit failed: %s (%d).",
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
cr->msg, 0, 0 );
}
} else {
mdb_txn_abort( txn );
}
}
return rc;
}
void
mdb_attr_dbs_close(
struct mdb_info *mdb,
MDB_txn *txn
)
{
int i;
for ( i=0; i<mdb->mi_nattrs; i++ )
if ( mdb->mi_attrs[i]->ai_dbi )
mdb_close( txn, mdb->mi_attrs[i]->ai_dbi );
}
int
mdb_attr_index_config(
struct mdb_info *mdb,
const char *fname,
int lineno,
int argc,
char **argv,
struct config_reply_s *c_reply)
{
int rc = 0;
int i;
slap_mask_t mask;
char **attrs;
char **indexes = NULL;
attrs = ldap_str2charray( argv[0], "," );
if( attrs == NULL ) {
fprintf( stderr, "%s: line %d: "
"no attributes specified: %s\n",
fname, lineno, argv[0] );
return LDAP_PARAM_ERROR;
}
if ( argc > 1 ) {
indexes = ldap_str2charray( argv[1], "," );
if( indexes == NULL ) {
fprintf( stderr, "%s: line %d: "
"no indexes specified: %s\n",
fname, lineno, argv[1] );
rc = LDAP_PARAM_ERROR;
goto done;
}
}
if( indexes == NULL ) {
mask = mdb->mi_defaultmask;
} else {
mask = 0;
for ( i = 0; indexes[i] != NULL; i++ ) {
slap_mask_t index;
rc = slap_str2index( indexes[i], &index );
if( rc != LDAP_SUCCESS ) {
if ( c_reply )
{
snprintf(c_reply->msg, sizeof(c_reply->msg),
"index type \"%s\" undefined", indexes[i] );
fprintf( stderr, "%s: line %d: %s\n",
fname, lineno, c_reply->msg );
}
rc = LDAP_PARAM_ERROR;
goto done;
}
mask |= index;
}
}
if( !mask ) {
if ( c_reply )
{
snprintf(c_reply->msg, sizeof(c_reply->msg),
"no indexes selected" );
fprintf( stderr, "%s: line %d: %s\n",
fname, lineno, c_reply->msg );
}
rc = LDAP_PARAM_ERROR;
goto done;
}
for ( i = 0; attrs[i] != NULL; i++ ) {
AttrInfo *a;
AttributeDescription *ad;
const char *text;
#ifdef LDAP_COMP_MATCH
ComponentReference* cr = NULL;
AttrInfo *a_cr = NULL;
#endif
if( strcasecmp( attrs[i], "default" ) == 0 ) {
mdb->mi_defaultmask |= mask;
continue;
}
#ifdef LDAP_COMP_MATCH
if ( is_component_reference( attrs[i] ) ) {
rc = extract_component_reference( attrs[i], &cr );
if ( rc != LDAP_SUCCESS ) {
if ( c_reply )
{
snprintf(c_reply->msg, sizeof(c_reply->msg),
"index component reference\"%s\" undefined",
attrs[i] );
fprintf( stderr, "%s: line %d: %s\n",
fname, lineno, c_reply->msg );
}
goto done;
}
cr->cr_indexmask = mask;
/*
* After extracting a component reference
* only the name of a attribute will be remaining
*/
} else {
cr = NULL;
}
#endif
ad = NULL;
rc = slap_str2ad( attrs[i], &ad, &text );
if( rc != LDAP_SUCCESS ) {
if ( c_reply )
{
snprintf(c_reply->msg, sizeof(c_reply->msg),
"index attribute \"%s\" undefined",
attrs[i] );
fprintf( stderr, "%s: line %d: %s\n",
fname, lineno, c_reply->msg );
}
goto done;
}
if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
if (c_reply) {
snprintf(c_reply->msg, sizeof(c_reply->msg),
"index of attribute \"%s\" disallowed", attrs[i] );
fprintf( stderr, "%s: line %d: %s\n",
fname, lineno, c_reply->msg );
}
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
ad->ad_type->sat_approx
&& ad->ad_type->sat_approx->smr_indexer
&& ad->ad_type->sat_approx->smr_filter ) )
{
if (c_reply) {
snprintf(c_reply->msg, sizeof(c_reply->msg),
"approx index of attribute \"%s\" disallowed", attrs[i] );
fprintf( stderr, "%s: line %d: %s\n",
fname, lineno, c_reply->msg );
}
rc = LDAP_INAPPROPRIATE_MATCHING;
goto done;
}
if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
ad->ad_type->sat_equality
&& ad->ad_type->sat_equality->smr_indexer
&& ad->ad_type->sat_equality->smr_filter ) )
{
if (c_reply) {
snprintf(c_reply->msg, sizeof(c_reply->msg),
"equality index of attribute \"%s\" disallowed", attrs[i] );
fprintf( stderr, "%s: line %d: %s\n",
fname, lineno, c_reply->msg );
}
rc = LDAP_INAPPROPRIATE_MATCHING;
goto done;
}
if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
ad->ad_type->sat_substr
&& ad->ad_type->sat_substr->smr_indexer
&& ad->ad_type->sat_substr->smr_filter ) )
{
if (c_reply) {
snprintf(c_reply->msg, sizeof(c_reply->msg),
"substr index of attribute \"%s\" disallowed", attrs[i] );
fprintf( stderr, "%s: line %d: %s\n",
fname, lineno, c_reply->msg );
}
rc = LDAP_INAPPROPRIATE_MATCHING;
goto done;
}
Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
ad->ad_cname.bv_val, mask, 0 );
a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
#ifdef LDAP_COMP_MATCH
a->ai_cr = NULL;
#endif
a->ai_desc = ad;
a->ai_dbi = 0;
if ( mdb->mi_flags & MDB_IS_OPEN ) {
a->ai_indexmask = 0;
a->ai_newmask = mask;
} else {
a->ai_indexmask = mask;
a->ai_newmask = 0;
}
#ifdef LDAP_COMP_MATCH
if ( cr ) {
a_cr = mdb_attr_mask( mdb, ad );
if ( a_cr ) {
/*
* AttrInfo is already in AVL
* just add the extracted component reference
* in the AttrInfo
*/
rc = insert_component_reference( cr, &a_cr->ai_cr );
if ( rc != LDAP_SUCCESS) {
fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
rc = LDAP_PARAM_ERROR;
goto done;
}
continue;
} else {
rc = insert_component_reference( cr, &a->ai_cr );
if ( rc != LDAP_SUCCESS) {
fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
rc = LDAP_PARAM_ERROR;
goto done;
}
}
}
#endif
rc = ainfo_insert( mdb, a );
if( rc ) {
if ( mdb->mi_flags & MDB_IS_OPEN ) {
AttrInfo *b = mdb_attr_mask( mdb, ad );
/* If there is already an index defined for this attribute
* it must be replaced. Otherwise we end up with multiple
* olcIndex values for the same attribute */
if ( b->ai_indexmask & MDB_INDEX_DELETING ) {
/* If we were editing this attr, reset it */
b->ai_indexmask &= ~MDB_INDEX_DELETING;
/* If this is leftover from a previous add, commit it */
if ( b->ai_newmask )
b->ai_indexmask = b->ai_newmask;
b->ai_newmask = a->ai_newmask;
ch_free( a );
rc = 0;
continue;
}
}
if (c_reply) {
snprintf(c_reply->msg, sizeof(c_reply->msg),
"duplicate index definition for attr \"%s\"",
attrs[i] );
fprintf( stderr, "%s: line %d: %s\n",
fname, lineno, c_reply->msg );
}
rc = LDAP_PARAM_ERROR;
goto done;
}
}
done:
ldap_charray_free( attrs );
if ( indexes != NULL ) ldap_charray_free( indexes );
return rc;
}
static int
mdb_attr_index_unparser( void *v1, void *v2 )
{
AttrInfo *ai = v1;
BerVarray *bva = v2;
struct berval bv;
char *ptr;
slap_index2bvlen( ai->ai_indexmask, &bv );
if ( bv.bv_len ) {
bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
ptr = ch_malloc( bv.bv_len+1 );
bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
*bv.bv_val++ = ' ';
slap_index2bv( ai->ai_indexmask, &bv );
bv.bv_val = ptr;
ber_bvarray_add( bva, &bv );
}
return 0;
}
static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
static AttrInfo aidef = { &addef };
void
mdb_attr_index_unparse( struct mdb_info *mdb, BerVarray *bva )
{
int i;
if ( mdb->mi_defaultmask ) {
aidef.ai_indexmask = mdb->mi_defaultmask;
mdb_attr_index_unparser( &aidef, bva );
}
for ( i=0; i<mdb->mi_nattrs; i++ )
mdb_attr_index_unparser( mdb->mi_attrs[i], bva );
}
void
mdb_attr_info_free( AttrInfo *ai )
{
#ifdef LDAP_COMP_MATCH
free( ai->ai_cr );
#endif
free( ai );
}
void
mdb_attr_index_destroy( struct mdb_info *mdb )
{
int i;
for ( i=0; i<mdb->mi_nattrs; i++ )
mdb_attr_info_free( mdb->mi_attrs[i] );
free( mdb->mi_attrs );
}
void mdb_attr_index_free( struct mdb_info *mdb, AttributeDescription *ad )
{
int i;
i = mdb_attr_slot( mdb, ad, NULL );
if ( i >= 0 ) {
mdb_attr_info_free( mdb->mi_attrs[i] );
mdb->mi_nattrs--;
for (; i<mdb->mi_nattrs; i++)
mdb->mi_attrs[i] = mdb->mi_attrs[i+1];
}
}
void mdb_attr_flush( struct mdb_info *mdb )
{
int i;
for ( i=0; i<mdb->mi_nattrs; i++ ) {
if ( mdb->mi_attrs[i]->ai_indexmask & MDB_INDEX_DELETING ) {
int j;
mdb_attr_info_free( mdb->mi_attrs[i] );
mdb->mi_nattrs--;
for (j=i; j<mdb->mi_nattrs; j++)
mdb->mi_attrs[j] = mdb->mi_attrs[j+1];
i--;
}
}
}

View file

@ -0,0 +1,162 @@
/* back-mdb.h - mdb back-end header file */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#ifndef _BACK_MDB_H_
#define _BACK_MDB_H_
#include <portable.h>
#include "slap.h"
#include "mdb.h"
LDAP_BEGIN_DECL
#define DN_BASE_PREFIX SLAP_INDEX_EQUALITY_PREFIX
#define DN_ONE_PREFIX '%'
#define DN_SUBTREE_PREFIX '@'
#define MDB_AD2ID 0
#define MDB_DN2ID 1
#define MDB_ID2ENTRY 2
#define MDB_NDB 3
/* The default search IDL stack cache depth */
#define DEFAULT_SEARCH_STACK_DEPTH 16
/* The minimum we can function with */
#define MINIMUM_SEARCH_STACK_DEPTH 8
#define MDB_INDICES 128
/* Default to 10MB max */
#define DEFAULT_MAPSIZE (10*1048576)
#ifdef LDAP_DEVEL
#define MDB_MONITOR_IDX
#endif /* LDAP_DEVEL */
typedef struct mdb_monitor_t {
void *mdm_cb;
struct berval mdm_ndn;
} mdb_monitor_t;
/* From ldap_rq.h */
struct re_s;
struct mdb_info {
MDB_env *mi_dbenv;
/* DB_ENV parameters */
/* The DB_ENV can be tuned via DB_CONFIG */
char *mi_dbenv_home;
u_int32_t mi_dbenv_flags;
int mi_dbenv_mode;
size_t mi_mapsize;
slap_mask_t mi_defaultmask;
int mi_nattrs;
struct mdb_attrinfo **mi_attrs;
void *mi_search_stack;
int mi_search_stack_depth;
int mi_readers;
int mi_txn_cp;
u_int32_t mi_txn_cp_min;
u_int32_t mi_txn_cp_kbyte;
struct re_s *mi_txn_cp_task;
struct re_s *mi_index_task;
mdb_monitor_t mi_monitor;
#ifdef MDB_MONITOR_IDX
ldap_pvt_thread_mutex_t mi_idx_mutex;
Avlnode *mi_idx;
#endif /* MDB_MONITOR_IDX */
int mi_flags;
#define MDB_IS_OPEN 0x01
#define MDB_OPEN_INDEX 0x02
#define MDB_DEL_INDEX 0x08
#define MDB_RE_OPEN 0x10
MDB_dbi mi_dbis[MDB_NDB];
};
#define mi_id2entry mi_dbis[MDB_ID2ENTRY]
#define mi_dn2id mi_dbis[MDB_DN2ID]
#define mi_ad2id mi_dbis[MDB_AD2ID]
typedef struct mdb_op_info {
OpExtra moi_oe;
MDB_txn* moi_txn;
int moi_ref;
char moi_flag;
} mdb_op_info;
#define MOI_READER 0x01
#define MOI_FREEIT 0x02
/* Copy an ID "src" to pointer "dst" in big-endian byte order */
#define MDB_ID2DISK( src, dst ) \
do { int i0; ID tmp; unsigned char *_p; \
tmp = (src); _p = (unsigned char *)(dst); \
for ( i0=sizeof(ID)-1; i0>=0; i0-- ) { \
_p[i0] = tmp & 0xff; tmp >>= 8; \
} \
} while(0)
/* Copy a pointer "src" to a pointer "dst" from big-endian to native order */
#define MDB_DISK2ID( src, dst ) \
do { unsigned i0; ID tmp = 0; unsigned char *_p; \
_p = (unsigned char *)(src); \
for ( i0=0; i0<sizeof(ID); i0++ ) { \
tmp <<= 8; tmp |= *_p++; \
} *(dst) = tmp; \
} while (0)
LDAP_END_DECL
/* for the cache of attribute information (which are indexed, etc.) */
typedef struct mdb_attrinfo {
AttributeDescription *ai_desc; /* attribute description cn;lang-en */
slap_mask_t ai_indexmask; /* how the attr is indexed */
slap_mask_t ai_newmask; /* new settings to replace old mask */
#ifdef LDAP_COMP_MATCH
ComponentReference* ai_cr; /*component indexing*/
#endif
int ai_idx; /* position in AI array */
MDB_dbi ai_dbi;
} AttrInfo;
/* These flags must not clash with SLAP_INDEX flags or ops in slap.h! */
#define MDB_INDEX_DELETING 0x8000U /* index is being modified */
#define MDB_INDEX_UPDATE_OP 0x03 /* performing an index update */
/* For slapindex to record which attrs in an entry belong to which
* index database
*/
typedef struct AttrList {
struct AttrList *next;
Attribute *attr;
} AttrList;
typedef struct IndexRec {
AttrInfo *ai;
AttrList *attrs;
} IndexRec;
#include "proto-mdb.h"
#endif /* _BACK_MDB_H_ */

View file

@ -0,0 +1,156 @@
/* bind.c - mdb backend bind routine */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/unistd.h>
#include "back-mdb.h"
int
mdb_bind( Operation *op, SlapReply *rs )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
Entry *e;
Attribute *a;
AttributeDescription *password = slap_schema.si_ad_userPassword;
MDB_txn *rtxn;
mdb_op_info opinfo = {0}, *moi = &opinfo;
Debug( LDAP_DEBUG_ARGS,
"==> " LDAP_XSTRING(mdb_bind) ": dn: %s\n",
op->o_req_dn.bv_val, 0, 0);
/* allow noauth binds */
switch ( be_rootdn_bind( op, NULL ) ) {
case LDAP_SUCCESS:
/* frontend will send result */
return rs->sr_err = LDAP_SUCCESS;
default:
/* give the database a chance */
/* NOTE: this behavior departs from that of other backends,
* since the others, in case of password checking failure
* do not give the database a chance. If an entry with
* rootdn's name does not exist in the database the result
* will be the same. See ITS#4962 for discussion. */
break;
}
rs->sr_err = mdb_opinfo_get(op, mdb, 1, &moi);
switch(rs->sr_err) {
case 0:
break;
default:
rs->sr_text = "internal error";
send_ldap_result( op, rs );
return rs->sr_err;
}
rtxn = moi->moi_txn;
/* get entry with reader lock */
rs->sr_err = mdb_dn2entry( op, rtxn, &op->o_req_ndn, &e, 0 );
switch(rs->sr_err) {
case MDB_NOTFOUND:
rs->sr_err = LDAP_INVALID_CREDENTIALS;
goto done;
case 0:
break;
case LDAP_BUSY:
rs->sr_text = "ldap_server_busy";
goto done;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto done;
}
ber_dupbv( &op->oq_bind.rb_edn, &e->e_name );
/* check for deleted */
if ( is_entry_subentry( e ) ) {
/* entry is an subentry, don't allow bind */
Debug( LDAP_DEBUG_TRACE, "entry is subentry\n", 0,
0, 0 );
rs->sr_err = LDAP_INVALID_CREDENTIALS;
goto done;
}
if ( is_entry_alias( e ) ) {
/* entry is an alias, don't allow bind */
Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, 0, 0 );
rs->sr_err = LDAP_INVALID_CREDENTIALS;
goto done;
}
if ( is_entry_referral( e ) ) {
Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
0, 0 );
rs->sr_err = LDAP_INVALID_CREDENTIALS;
goto done;
}
switch ( op->oq_bind.rb_method ) {
case LDAP_AUTH_SIMPLE:
a = attr_find( e->e_attrs, password );
if ( a == NULL ) {
rs->sr_err = LDAP_INVALID_CREDENTIALS;
goto done;
}
if ( slap_passwd_check( op, e, a, &op->oq_bind.rb_cred,
&rs->sr_text ) != 0 )
{
/* failure; stop front end from sending result */
rs->sr_err = LDAP_INVALID_CREDENTIALS;
goto done;
}
rs->sr_err = 0;
break;
default:
assert( 0 ); /* should not be reachable */
rs->sr_err = LDAP_STRONG_AUTH_NOT_SUPPORTED;
rs->sr_text = "authentication method not supported";
}
done:
if ( moi == &opinfo ) {
mdb_txn_reset( moi->moi_txn );
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
}
/* free entry and reader lock */
if( e != NULL ) {
mdb_entry_return( e );
}
if ( rs->sr_err ) {
send_ldap_result( op, rs );
if ( rs->sr_ref ) {
ber_bvarray_free( rs->sr_ref );
rs->sr_ref = NULL;
}
}
/* front end will send result on success (rs->sr_err==0) */
return rs->sr_err;
}

View file

@ -0,0 +1,140 @@
/* compare.c - mdb backend compare routine */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "back-mdb.h"
int
mdb_compare( Operation *op, SlapReply *rs )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
Entry *e = NULL;
int manageDSAit = get_manageDSAit( op );
MDB_txn *rtxn;
mdb_op_info opinfo = {0}, *moi = &opinfo;
rs->sr_err = mdb_opinfo_get(op, mdb, 1, &moi);
switch(rs->sr_err) {
case 0:
break;
default:
send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
return rs->sr_err;
}
rtxn = moi->moi_txn;
/* get entry */
rs->sr_err = mdb_dn2entry( op, rtxn, &op->o_req_ndn, &e, 1 );
switch( rs->sr_err ) {
case MDB_NOTFOUND:
case 0:
break;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
if ( rs->sr_err == MDB_NOTFOUND ) {
if ( e != NULL ) {
/* return referral only if "disclose" is granted on the object */
if ( ! access_allowed( op, e, slap_schema.si_ad_entry,
NULL, ACL_DISCLOSE, NULL ) )
{
rs->sr_err = LDAP_NO_SUCH_OBJECT;
} else {
rs->sr_matched = ch_strdup( e->e_dn );
if ( is_entry_referral( e )) {
BerVarray ref = get_entry_referrals( op, e );
rs->sr_ref = referral_rewrite( ref, &e->e_name,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
ber_bvarray_free( ref );
} else {
rs->sr_ref = NULL;
}
rs->sr_err = LDAP_REFERRAL;
}
mdb_entry_return( e );
e = NULL;
} else {
rs->sr_ref = referral_rewrite( default_referral,
NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
rs->sr_err = rs->sr_ref ? LDAP_REFERRAL : LDAP_NO_SUCH_OBJECT;
}
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
send_ldap_result( op, rs );
goto done;
}
if (!manageDSAit && is_entry_referral( e ) ) {
/* return referral only if "disclose" is granted on the object */
if ( !access_allowed( op, e, slap_schema.si_ad_entry,
NULL, ACL_DISCLOSE, NULL ) )
{
rs->sr_err = LDAP_NO_SUCH_OBJECT;
} else {
/* entry is a referral, don't allow compare */
rs->sr_ref = get_entry_referrals( op, e );
rs->sr_err = LDAP_REFERRAL;
rs->sr_matched = e->e_name.bv_val;
}
Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, 0, 0 );
send_ldap_result( op, rs );
ber_bvarray_free( rs->sr_ref );
rs->sr_ref = NULL;
rs->sr_matched = NULL;
goto done;
}
rs->sr_err = slap_compare_entry( op, e, op->orc_ava );
return_results:
send_ldap_result( op, rs );
switch ( rs->sr_err ) {
case LDAP_COMPARE_FALSE:
case LDAP_COMPARE_TRUE:
rs->sr_err = LDAP_SUCCESS;
break;
}
done:
if ( moi == &opinfo ) {
mdb_txn_reset( moi->moi_txn );
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
}
/* free entry */
if ( e != NULL ) {
mdb_entry_return( e );
}
return rs->sr_err;
}

View file

@ -0,0 +1,588 @@
/* config.c - mdb backend configuration file routine */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/ctype.h>
#include <ac/string.h>
#include <ac/errno.h>
#include "back-mdb.h"
#include "config.h"
#include "lutil.h"
#include "ldap_rq.h"
static ConfigDriver mdb_cf_gen;
enum {
MDB_CHKPT = 1,
MDB_DIRECTORY,
MDB_DBNOSYNC,
MDB_INDEX,
MDB_MAXREADERS,
MDB_MAXSIZE,
MDB_MODE,
MDB_SSTACK,
};
static ConfigTable mdbcfg[] = {
{ "directory", "dir", 2, 2, 0, ARG_STRING|ARG_MAGIC|MDB_DIRECTORY,
mdb_cf_gen, "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
"DESC 'Directory for database content' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
{ "checkpoint", "kbyte> <min", 3, 3, 0, ARG_MAGIC|MDB_CHKPT,
mdb_cf_gen, "( OLcfgDbAt:1.2 NAME 'olcDbCheckpoint' "
"DESC 'Database checkpoint interval in kbytes and minutes' "
"SYNTAX OMsDirectoryString SINGLE-VALUE )",NULL, NULL },
{ "dbnosync", NULL, 1, 2, 0, ARG_ON_OFF|ARG_MAGIC|MDB_DBNOSYNC,
mdb_cf_gen, "( OLcfgDbAt:1.4 NAME 'olcDbNoSync' "
"DESC 'Disable synchronous database writes' "
"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
{ "index", "attr> <[pres,eq,approx,sub]", 2, 3, 0, ARG_MAGIC|MDB_INDEX,
mdb_cf_gen, "( OLcfgDbAt:0.2 NAME 'olcDbIndex' "
"DESC 'Attribute index parameters' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ "maxreaders", "num", 2, 2, 0, ARG_INT|ARG_MAGIC|MDB_MAXREADERS,
mdb_cf_gen, "( OLcfgDbAt:12.1 NAME 'olcDbMaxReaders' "
"DESC 'Maximum number of threads that may access the DB concurrently' "
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
{ "maxsize", "size", 2, 2, 0, ARG_ULONG|ARG_MAGIC|MDB_MAXSIZE,
mdb_cf_gen, "( OLcfgDbAt:12.2 NAME 'olcDbMaxSize' "
"DESC 'Maximum size of DB in bytes' "
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
{ "mode", "mode", 2, 2, 0, ARG_MAGIC|MDB_MODE,
mdb_cf_gen, "( OLcfgDbAt:0.3 NAME 'olcDbMode' "
"DESC 'Unix permissions of database files' "
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
{ "searchstack", "depth", 2, 2, 0, ARG_INT|ARG_MAGIC|MDB_SSTACK,
mdb_cf_gen, "( OLcfgDbAt:1.9 NAME 'olcDbSearchStack' "
"DESC 'Depth of search stack in IDLs' "
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
{ NULL, NULL, 0, 0, 0, ARG_IGNORED,
NULL, NULL, NULL, NULL }
};
static ConfigOCs mdbocs[] = {
{
"( OLcfgDbOc:12.1 "
"NAME 'olcMdbConfig' "
"DESC 'MDB backend configuration' "
"SUP olcDatabaseConfig "
"MUST olcDbDirectory "
"MAY ( olcDbCheckpoint $ "
"olcDbNoSync $ olcDbIndex $ olcDbMaxReaders $ olcDbMaxsize $ "
"olcDbMode $ olcDbSearchStack ) )",
Cft_Database, mdbcfg },
{ NULL, 0, NULL }
};
/* perform periodic syncs */
static void *
mdb_checkpoint( void *ctx, void *arg )
{
struct re_s *rtask = arg;
struct mdb_info *mdb = rtask->arg;
mdb_env_sync( mdb->mi_dbenv, 0 );
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
return NULL;
}
/* reindex entries on the fly */
static void *
mdb_online_index( void *ctx, void *arg )
{
struct re_s *rtask = arg;
BackendDB *be = rtask->arg;
struct mdb_info *mdb = be->be_private;
Connection conn = {0};
OperationBuffer opbuf;
Operation *op;
MDB_cursor *curs;
MDB_val key, data;
MDB_txn *txn;
ID id;
Entry *e;
int rc, getnext = 1;
int i;
connection_fake_init( &conn, &opbuf, ctx );
op = &opbuf.ob_op;
op->o_bd = be;
id = 1;
key.mv_data = &id;
key.mv_size = sizeof(ID);
while ( 1 ) {
if ( slapd_shutdown )
break;
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &txn );
if ( rc )
break;
if ( getnext ) {
getnext = 0;
rc = mdb_cursor_open( txn, mdb->mi_id2entry, &curs );
if ( rc ) {
mdb_txn_abort( txn );
break;
}
rc = mdb_cursor_get( curs, &key, &data, MDB_SET_RANGE );
memcpy( &id, key.mv_data, sizeof( id ));
mdb_cursor_close( curs );
if ( rc ) {
mdb_txn_abort( txn );
if ( rc == MDB_NOTFOUND )
rc = 0;
break;
}
}
rc = mdb_id2entry( op, txn, id, &e );
if ( rc ) {
mdb_txn_abort( txn );
if ( rc == MDB_NOTFOUND ) {
id++;
getnext = 1;
continue;
}
break;
}
rc = mdb_index_entry( op, txn, MDB_INDEX_UPDATE_OP, e );
if ( rc == 0 ) {
rc = mdb_txn_commit( txn );
txn = NULL;
}
if ( rc )
break;
id++;
getnext = 1;
}
for ( i = 0; i < mdb->mi_nattrs; i++ ) {
if ( mdb->mi_attrs[ i ]->ai_indexmask & MDB_INDEX_DELETING
|| mdb->mi_attrs[ i ]->ai_newmask == 0 )
{
continue;
}
mdb->mi_attrs[ i ]->ai_indexmask = mdb->mi_attrs[ i ]->ai_newmask;
mdb->mi_attrs[ i ]->ai_newmask = 0;
}
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
mdb->mi_index_task = NULL;
ldap_pvt_runqueue_remove( &slapd_rq, rtask );
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
return NULL;
}
/* Cleanup loose ends after Modify completes */
static int
mdb_cf_cleanup( ConfigArgs *c )
{
struct mdb_info *mdb = c->be->be_private;
int rc = 0;
if ( mdb->mi_flags & MDB_DEL_INDEX ) {
mdb_attr_flush( mdb );
mdb->mi_flags ^= MDB_DEL_INDEX;
}
if ( mdb->mi_flags & MDB_RE_OPEN ) {
mdb->mi_flags ^= MDB_RE_OPEN;
rc = c->be->bd_info->bi_db_close( c->be, &c->reply );
if ( rc == 0 )
rc = c->be->bd_info->bi_db_open( c->be, &c->reply );
/* If this fails, we need to restart */
if ( rc ) {
slapd_shutdown = 2;
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"failed to reopen database, rc=%d", rc );
Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_cf_cleanup)
": %s\n", c->cr_msg, 0, 0 );
rc = LDAP_OTHER;
}
}
if ( mdb->mi_flags & MDB_OPEN_INDEX ) {
rc = mdb_attr_dbs_open( c->be, NULL, &c->reply );
if ( rc )
rc = LDAP_OTHER;
}
return rc;
}
static int
mdb_cf_gen( ConfigArgs *c )
{
struct mdb_info *mdb = c->be->be_private;
int rc;
if ( c->op == SLAP_CONFIG_EMIT ) {
rc = 0;
switch( c->type ) {
case MDB_MODE: {
char buf[64];
struct berval bv;
bv.bv_len = snprintf( buf, sizeof(buf), "0%o", mdb->mi_dbenv_mode );
if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
bv.bv_val = buf;
value_add_one( &c->rvalue_vals, &bv );
} else {
rc = 1;
}
} break;
case MDB_CHKPT:
if ( mdb->mi_txn_cp ) {
char buf[64];
struct berval bv;
bv.bv_len = snprintf( buf, sizeof(buf), "%ld %ld",
(long) mdb->mi_txn_cp_kbyte, (long) mdb->mi_txn_cp_min );
if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
bv.bv_val = buf;
value_add_one( &c->rvalue_vals, &bv );
} else {
rc = 1;
}
} else {
rc = 1;
}
break;
case MDB_DIRECTORY:
if ( mdb->mi_dbenv_home ) {
c->value_string = ch_strdup( mdb->mi_dbenv_home );
} else {
rc = 1;
}
break;
case MDB_DBNOSYNC:
if ( mdb->mi_dbenv_flags & MDB_NOSYNC )
c->value_int = 1;
break;
case MDB_INDEX:
mdb_attr_index_unparse( mdb, &c->rvalue_vals );
if ( !c->rvalue_vals ) rc = 1;
break;
case MDB_SSTACK:
c->value_int = mdb->mi_search_stack_depth;
break;
case MDB_MAXREADERS:
c->value_int = mdb->mi_readers;
break;
case MDB_MAXSIZE:
c->value_ulong = mdb->mi_mapsize;
break;
}
return rc;
} else if ( c->op == LDAP_MOD_DELETE ) {
rc = 0;
switch( c->type ) {
case MDB_MODE:
#if 0
/* FIXME: does it make any sense to change the mode,
* if we don't exec a chmod()? */
mdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
break;
#endif
/* single-valued no-ops */
case MDB_SSTACK:
case MDB_MAXREADERS:
case MDB_MAXSIZE:
break;
case MDB_CHKPT:
if ( mdb->mi_txn_cp_task ) {
struct re_s *re = mdb->mi_txn_cp_task;
mdb->mi_txn_cp_task = NULL;
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
ldap_pvt_runqueue_stoptask( &slapd_rq, re );
ldap_pvt_runqueue_remove( &slapd_rq, re );
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
}
mdb->mi_txn_cp = 0;
break;
case MDB_DIRECTORY:
mdb->mi_flags |= MDB_RE_OPEN;
ch_free( mdb->mi_dbenv_home );
mdb->mi_dbenv_home = NULL;
c->cleanup = mdb_cf_cleanup;
ldap_pvt_thread_pool_purgekey( mdb->mi_dbenv );
break;
case MDB_DBNOSYNC:
mdb_env_set_flags( mdb->mi_dbenv, MDB_NOSYNC, 0 );
break;
case MDB_INDEX:
if ( c->valx == -1 ) {
int i;
/* delete all (FIXME) */
for ( i = 0; i < mdb->mi_nattrs; i++ ) {
mdb->mi_attrs[i]->ai_indexmask |= MDB_INDEX_DELETING;
}
mdb->mi_flags |= MDB_DEL_INDEX;
c->cleanup = mdb_cf_cleanup;
} else {
struct berval bv, def = BER_BVC("default");
char *ptr;
for (ptr = c->line; !isspace( (unsigned char) *ptr ); ptr++);
bv.bv_val = c->line;
bv.bv_len = ptr - bv.bv_val;
if ( bvmatch( &bv, &def )) {
mdb->mi_defaultmask = 0;
} else {
int i;
char **attrs;
char sep;
sep = bv.bv_val[ bv.bv_len ];
bv.bv_val[ bv.bv_len ] = '\0';
attrs = ldap_str2charray( bv.bv_val, "," );
for ( i = 0; attrs[ i ]; i++ ) {
AttributeDescription *ad = NULL;
const char *text;
AttrInfo *ai;
slap_str2ad( attrs[ i ], &ad, &text );
/* if we got here... */
assert( ad != NULL );
ai = mdb_attr_mask( mdb, ad );
/* if we got here... */
assert( ai != NULL );
ai->ai_indexmask |= MDB_INDEX_DELETING;
mdb->mi_flags |= MDB_DEL_INDEX;
c->cleanup = mdb_cf_cleanup;
}
bv.bv_val[ bv.bv_len ] = sep;
ldap_charray_free( attrs );
}
}
break;
}
return rc;
}
switch( c->type ) {
case MDB_MODE:
if ( ASCII_DIGIT( c->argv[1][0] ) ) {
long mode;
char *next;
errno = 0;
mode = strtol( c->argv[1], &next, 0 );
if ( errno != 0 || next == c->argv[1] || next[0] != '\0' ) {
fprintf( stderr, "%s: "
"unable to parse mode=\"%s\".\n",
c->log, c->argv[1] );
return 1;
}
mdb->mi_dbenv_mode = mode;
} else {
char *m = c->argv[1];
int who, what, mode = 0;
if ( strlen( m ) != STRLENOF("-rwxrwxrwx") ) {
return 1;
}
if ( m[0] != '-' ) {
return 1;
}
m++;
for ( who = 0; who < 3; who++ ) {
for ( what = 0; what < 3; what++, m++ ) {
if ( m[0] == '-' ) {
continue;
} else if ( m[0] != "rwx"[what] ) {
return 1;
}
mode += ((1 << (2 - what)) << 3*(2 - who));
}
}
mdb->mi_dbenv_mode = mode;
}
break;
case MDB_CHKPT: {
long l;
mdb->mi_txn_cp = 1;
if ( lutil_atolx( &l, c->argv[1], 0 ) != 0 ) {
fprintf( stderr, "%s: "
"invalid kbyte \"%s\" in \"checkpoint\".\n",
c->log, c->argv[1] );
return 1;
}
mdb->mi_txn_cp_kbyte = l;
if ( lutil_atolx( &l, c->argv[2], 0 ) != 0 ) {
fprintf( stderr, "%s: "
"invalid minutes \"%s\" in \"checkpoint\".\n",
c->log, c->argv[2] );
return 1;
}
mdb->mi_txn_cp_min = l;
/* If we're in server mode and time-based checkpointing is enabled,
* submit a task to perform periodic checkpoints.
*/
if ((slapMode & SLAP_SERVER_MODE) && mdb->mi_txn_cp_min ) {
struct re_s *re = mdb->mi_txn_cp_task;
if ( re ) {
re->interval.tv_sec = mdb->mi_txn_cp_min * 60;
} else {
if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
fprintf( stderr, "%s: "
"\"checkpoint\" must occur after \"suffix\".\n",
c->log );
return 1;
}
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
mdb->mi_txn_cp_task = ldap_pvt_runqueue_insert( &slapd_rq,
mdb->mi_txn_cp_min * 60, mdb_checkpoint, mdb,
LDAP_XSTRING(mdb_checkpoint), c->be->be_suffix[0].bv_val );
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
}
}
} break;
case MDB_DIRECTORY: {
FILE *f;
char *ptr, *testpath;
int len;
len = strlen( c->value_string );
testpath = ch_malloc( len + STRLENOF(LDAP_DIRSEP) + STRLENOF("DUMMY") + 1 );
ptr = lutil_strcopy( testpath, c->value_string );
*ptr++ = LDAP_DIRSEP[0];
strcpy( ptr, "DUMMY" );
f = fopen( testpath, "w" );
if ( f ) {
fclose( f );
unlink( testpath );
}
ch_free( testpath );
if ( !f ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: invalid path: %s",
c->log, strerror( errno ));
Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 );
return -1;
}
if ( mdb->mi_dbenv_home )
ch_free( mdb->mi_dbenv_home );
mdb->mi_dbenv_home = c->value_string;
}
break;
case MDB_DBNOSYNC:
if ( c->value_int )
mdb->mi_dbenv_flags |= MDB_NOSYNC;
else
mdb->mi_dbenv_flags ^= MDB_NOSYNC;
if ( mdb->mi_flags & MDB_IS_OPEN ) {
mdb_env_set_flags( mdb->mi_dbenv, MDB_NOSYNC,
c->value_int );
}
break;
case MDB_INDEX:
rc = mdb_attr_index_config( mdb, c->fname, c->lineno,
c->argc - 1, &c->argv[1], &c->reply);
if( rc != LDAP_SUCCESS ) return 1;
c->cleanup = mdb_cf_cleanup;
mdb->mi_flags |= MDB_OPEN_INDEX;
if (( mdb->mi_flags & MDB_IS_OPEN ) && !mdb->mi_index_task ) {
/* Start the task as soon as we finish here. Set a long
* interval (10 hours) so that it only gets scheduled once.
*/
if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
fprintf( stderr, "%s: "
"\"index\" must occur after \"suffix\".\n",
c->log );
return 1;
}
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
mdb->mi_index_task = ldap_pvt_runqueue_insert( &slapd_rq, 36000,
mdb_online_index, c->be,
LDAP_XSTRING(mdb_online_index), c->be->be_suffix[0].bv_val );
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
}
break;
case MDB_SSTACK:
if ( c->value_int < MINIMUM_SEARCH_STACK_DEPTH ) {
fprintf( stderr,
"%s: depth %d too small, using %d\n",
c->log, c->value_int, MINIMUM_SEARCH_STACK_DEPTH );
c->value_int = MINIMUM_SEARCH_STACK_DEPTH;
}
mdb->mi_search_stack_depth = c->value_int;
break;
case MDB_MAXREADERS:
mdb->mi_readers = c->value_int;
if ( mdb->mi_flags & MDB_IS_OPEN )
mdb->mi_flags |= MDB_RE_OPEN;
break;
case MDB_MAXSIZE:
mdb->mi_mapsize = c->value_ulong;
if ( mdb->mi_flags & MDB_IS_OPEN )
mdb->mi_flags |= MDB_RE_OPEN;
break;
}
return 0;
}
int mdb_back_init_cf( BackendInfo *bi )
{
int rc;
bi->bi_cf_ocs = mdbocs;
rc = config_register_schema( mdbcfg, mdbocs );
if ( rc ) return rc;
return 0;
}

View file

@ -0,0 +1,470 @@
/* delete.c - mdb backend delete routine */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "lutil.h"
#include "back-mdb.h"
int
mdb_delete( Operation *op, SlapReply *rs )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
struct berval pdn = {0, NULL};
Entry *e = NULL;
Entry *p = NULL;
int manageDSAit = get_manageDSAit( op );
AttributeDescription *children = slap_schema.si_ad_children;
AttributeDescription *entry = slap_schema.si_ad_entry;
MDB_txn *txn = NULL;
mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
LDAPControl **preread_ctrl = NULL;
LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
int num_ctrls = 0;
int parent_is_glue = 0;
int parent_is_leaf = 0;
#ifdef LDAP_X_TXN
int settle = 0;
#endif
Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(mdb_delete) ": %s\n",
op->o_req_dn.bv_val, 0, 0 );
#ifdef LDAP_X_TXN
if( op->o_txnSpec ) {
/* acquire connection lock */
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
rs->sr_text = "invalid transaction identifier";
rs->sr_err = LDAP_X_TXN_ID_INVALID;
goto txnReturn;
} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
settle=1;
goto txnReturn;
}
if( op->o_conn->c_txn_backend == NULL ) {
op->o_conn->c_txn_backend = op->o_bd;
} else if( op->o_conn->c_txn_backend != op->o_bd ) {
rs->sr_text = "transaction cannot span multiple database contexts";
rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
goto txnReturn;
}
/* insert operation into transaction */
rs->sr_text = "transaction specified";
rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
txnReturn:
/* release connection lock */
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
if( !settle ) {
send_ldap_result( op, rs );
return rs->sr_err;
}
}
#endif
ctrls[num_ctrls] = 0;
/* allocate CSN */
if ( BER_BVISNULL( &op->o_csn ) ) {
struct berval csn;
char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
csn.bv_val = csnbuf;
csn.bv_len = sizeof(csnbuf);
slap_get_csn( op, &csn, 1 );
}
/* begin transaction */
rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
rs->sr_text = NULL;
if( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_delete) ": txn_begin failed: "
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
txn = moi->moi_txn;
if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
dnParent( &op->o_req_ndn, &pdn );
}
/* get parent */
rs->sr_err = mdb_dn2entry( op, txn, &pdn, &p, 1 );
switch( rs->sr_err ) {
case 0:
case MDB_NOTFOUND:
break;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
if ( rs->sr_err == MDB_NOTFOUND ) {
Debug( LDAP_DEBUG_ARGS,
"<=- " LDAP_XSTRING(mdb_delete) ": no such object %s\n",
op->o_req_dn.bv_val, 0, 0);
if ( p && !BER_BVISEMPTY( &p->e_name )) {
rs->sr_matched = ch_strdup( p->e_name.bv_val );
if ( is_entry_referral( p )) {
BerVarray ref = get_entry_referrals( op, p );
rs->sr_ref = referral_rewrite( ref, &p->e_name,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
ber_bvarray_free( ref );
} else {
rs->sr_ref = NULL;
}
} else {
rs->sr_ref = referral_rewrite( default_referral, NULL,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
}
if ( p ) {
mdb_entry_return( p );
p = NULL;
}
rs->sr_err = LDAP_REFERRAL;
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
goto return_results;
}
/* get entry */
rs->sr_err = mdb_dn2entry( op, txn, &op->o_req_ndn, &e, 0 );
switch( rs->sr_err ) {
case MDB_NOTFOUND:
e = p;
p = NULL;
case 0:
break;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
/* FIXME : dn2entry() should return non-glue entry */
if ( rs->sr_err == MDB_NOTFOUND || ( !manageDSAit && is_entry_glue( e ))) {
Debug( LDAP_DEBUG_ARGS,
"<=- " LDAP_XSTRING(mdb_delete) ": no such object %s\n",
op->o_req_dn.bv_val, 0, 0);
rs->sr_matched = ch_strdup( e->e_dn );
if ( is_entry_referral( e )) {
BerVarray ref = get_entry_referrals( op, e );
rs->sr_ref = referral_rewrite( ref, &e->e_name,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
ber_bvarray_free( ref );
} else {
rs->sr_ref = NULL;
}
mdb_entry_return( e );
e = NULL;
rs->sr_err = LDAP_REFERRAL;
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
goto return_results;
}
if ( pdn.bv_len != 0 ) {
/* check parent for "children" acl */
rs->sr_err = access_allowed( op, p,
children, NULL, ACL_WDEL, NULL );
if ( !rs->sr_err ) {
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_delete) ": no write "
"access to parent\n", 0, 0, 0 );
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
rs->sr_text = "no write access to parent";
goto return_results;
}
} else {
/* no parent, must be root to delete */
if( ! be_isroot( op ) ) {
if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
|| be_shadow_update( op ) ) {
p = (Entry *)&slap_entry_root;
/* check parent for "children" acl */
rs->sr_err = access_allowed( op, p,
children, NULL, ACL_WDEL, NULL );
p = NULL;
if ( !rs->sr_err ) {
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_delete)
": no access to parent\n",
0, 0, 0 );
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
rs->sr_text = "no write access to parent";
goto return_results;
}
} else {
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_delete)
": no parent and not root\n", 0, 0, 0 );
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
goto return_results;
}
}
}
if ( get_assert( op ) &&
( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
{
rs->sr_err = LDAP_ASSERTION_FAILED;
goto return_results;
}
rs->sr_err = access_allowed( op, e,
entry, NULL, ACL_WDEL, NULL );
if ( !rs->sr_err ) {
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_delete) ": no write access "
"to entry\n", 0, 0, 0 );
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
rs->sr_text = "no write access to entry";
goto return_results;
}
if ( !manageDSAit && is_entry_referral( e ) ) {
/* entry is a referral, don't allow delete */
rs->sr_ref = get_entry_referrals( op, e );
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_delete) ": entry is referral\n",
0, 0, 0 );
rs->sr_err = LDAP_REFERRAL;
rs->sr_matched = ch_strdup( e->e_name.bv_val );
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
goto return_results;
}
/* pre-read */
if( op->o_preread ) {
if( preread_ctrl == NULL ) {
preread_ctrl = &ctrls[num_ctrls++];
ctrls[num_ctrls] = NULL;
}
if( slap_read_controls( op, rs, e,
&slap_pre_read_bv, preread_ctrl ) )
{
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_delete) ": pre-read "
"failed!\n", 0, 0, 0 );
if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
/* FIXME: is it correct to abort
* operation if control fails? */
goto return_results;
}
}
}
rs->sr_text = NULL;
/* Can't do it if we have kids */
rs->sr_err = mdb_dn2id_children( op, txn, e );
if( rs->sr_err != MDB_NOTFOUND ) {
switch( rs->sr_err ) {
case 0:
Debug(LDAP_DEBUG_ARGS,
"<=- " LDAP_XSTRING(mdb_delete)
": non-leaf %s\n",
op->o_req_dn.bv_val, 0, 0);
rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
rs->sr_text = "subordinate objects must be deleted first";
break;
default:
Debug(LDAP_DEBUG_ARGS,
"<=- " LDAP_XSTRING(mdb_delete)
": has_children failed: %s (%d)\n",
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
}
goto return_results;
}
/* delete from dn2id */
rs->sr_err = mdb_dn2id_delete( op, txn, p->e_id, e );
if ( rs->sr_err != 0 ) {
Debug(LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_delete) ": dn2id failed: "
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_text = "DN index delete failed";
rs->sr_err = LDAP_OTHER;
goto return_results;
}
/* delete indices for old attributes */
rs->sr_err = mdb_index_entry_del( op, txn, e );
if ( rs->sr_err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_delete) ": index failed: "
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_text = "entry index delete failed";
rs->sr_err = LDAP_OTHER;
goto return_results;
}
/* fixup delete CSN */
if ( !SLAP_SHADOW( op->o_bd )) {
struct berval vals[2];
assert( !BER_BVISNULL( &op->o_csn ) );
vals[0] = op->o_csn;
BER_BVZERO( &vals[1] );
rs->sr_err = mdb_index_values( op, txn, slap_schema.si_ad_entryCSN,
vals, 0, SLAP_INDEX_ADD_OP );
if ( rs->sr_err != LDAP_SUCCESS ) {
rs->sr_text = "entryCSN index update failed";
rs->sr_err = LDAP_OTHER;
goto return_results;
}
}
/* delete from id2entry */
rs->sr_err = mdb_id2entry_delete( op->o_bd, txn, e );
if ( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_delete) ": id2entry failed: "
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_text = "entry delete failed";
rs->sr_err = LDAP_OTHER;
goto return_results;
}
if ( pdn.bv_len != 0 ) {
parent_is_glue = is_entry_glue(p);
rs->sr_err = mdb_dn2id_children( op, txn, p );
if ( rs->sr_err != MDB_NOTFOUND ) {
switch( rs->sr_err ) {
case 0:
break;
default:
Debug(LDAP_DEBUG_ARGS,
"<=- " LDAP_XSTRING(mdb_delete)
": has_children failed: %s (%d)\n",
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
parent_is_leaf = 1;
}
mdb_entry_return( p );
p = NULL;
}
if( moi == &opinfo ) {
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
opinfo.moi_oe.oe_key = NULL;
if( op->o_noop ) {
mdb_txn_abort( txn );
rs->sr_err = LDAP_X_NO_OPERATION;
txn = NULL;
goto return_results;
} else {
rs->sr_err = mdb_txn_commit( txn );
}
txn = NULL;
}
if( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_delete) ": txn_%s failed: %s (%d)\n",
op->o_noop ? "abort (no-op)" : "commit",
mdb_strerror(rs->sr_err), rs->sr_err );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "commit failed";
goto return_results;
}
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_delete) ": deleted%s id=%08lx dn=\"%s\"\n",
op->o_noop ? " (no-op)" : "",
e->e_id, op->o_req_dn.bv_val );
rs->sr_err = LDAP_SUCCESS;
rs->sr_text = NULL;
if( num_ctrls ) rs->sr_ctrls = ctrls;
return_results:
if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
op->o_delete_glue_parent = 1;
}
if ( p != NULL ) {
mdb_entry_return( p );
}
/* free entry */
if( e != NULL ) {
mdb_entry_return( e );
}
if( moi == &opinfo ) {
if( txn != NULL ) {
mdb_txn_abort( txn );
}
if ( opinfo.moi_oe.oe_key ) {
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
}
}
send_ldap_result( op, rs );
slap_graduate_commit_csn( op );
if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
}
#if 0
if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
TXN_CHECKPOINT( mdb->bi_dbenv,
mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
}
#endif
return rs->sr_err;
}

View file

@ -0,0 +1,64 @@
/* dn2entry.c - routines to deal with the dn2id / id2entry glue */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "back-mdb.h"
/*
* dn2entry - look up dn in the cache/indexes and return the corresponding
* entry. If the requested DN is not found and matched is TRUE, return info
* for the closest ancestor of the DN. Otherwise e is NULL.
*/
int
mdb_dn2entry(
Operation *op,
MDB_txn *tid,
struct berval *dn,
Entry **e,
int matched )
{
int rc, rc2;
ID id = NOID;
struct berval mbv, nmbv;
Debug(LDAP_DEBUG_TRACE, "mdb_dn2entry(\"%s\")\n",
dn->bv_val, 0, 0 );
*e = NULL;
rc = mdb_dn2id( op, tid, dn, &id, &mbv, &nmbv );
if ( rc ) {
if ( matched )
rc2 = mdb_id2entry( op, tid, id, e );
} else {
rc = mdb_id2entry( op, tid, id, e );
}
if ( *e ) {
(*e)->e_name = mbv;
if ( rc == MDB_SUCCESS )
ber_dupbv_x( &(*e)->e_nname, dn, op->o_tmpmemctx );
else
ber_dupbv_x( &(*e)->e_nname, &nmbv, op->o_tmpmemctx );
}
return rc;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,54 @@
/* extended.c - mdb backend extended routines */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "back-mdb.h"
#include "lber_pvt.h"
static struct exop {
struct berval *oid;
BI_op_extended *extended;
} exop_table[] = {
{ NULL, NULL }
};
int
mdb_extended( Operation *op, SlapReply *rs )
/* struct berval *reqoid,
struct berval *reqdata,
char **rspoid,
struct berval **rspdata,
LDAPControl *** rspctrls,
const char** text,
BerVarray *refs
) */
{
int i;
for( i=0; exop_table[i].extended != NULL; i++ ) {
if( ber_bvcmp( exop_table[i].oid, &op->oq_extended.rs_reqoid ) == 0 ) {
return (exop_table[i].extended)( op, rs );
}
}
rs->sr_text = "not supported within naming context";
return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,425 @@
/* id2entry.c - routines to deal with the id2entry database */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/errno.h>
#include "back-mdb.h"
static int mdb_id2entry_put(
Operation *op,
MDB_txn *tid,
Entry *e,
int flag )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
MDB_dbi dbi = mdb->mi_id2entry;
MDB_val key, data;
struct berval bv;
int rc;
struct berval odn, ondn;
/* We only store rdns, and they go in the dn2id database. */
odn = e->e_name; ondn = e->e_nname;
e->e_name = slap_empty_bv;
e->e_nname = slap_empty_bv;
key.mv_data = &e->e_id;
key.mv_size = sizeof(ID);
rc = entry_encode( e, &bv );
e->e_name = odn; e->e_nname = ondn;
if( rc != LDAP_SUCCESS ) {
return -1;
}
data.mv_size = bv.bv_len;
data.mv_data = bv.bv_val;
rc = mdb_put( tid, dbi, &key, &data, flag );
op->o_tmpfree( bv.bv_val, op->o_tmpmemctx );
return rc;
}
/*
* This routine adds (or updates) an entry on disk.
* The cache should be already be updated.
*/
int mdb_id2entry_add(
Operation *op,
MDB_txn *tid,
Entry *e )
{
return mdb_id2entry_put(op, tid, e, MDB_NOOVERWRITE);
}
int mdb_id2entry_update(
Operation *op,
MDB_txn *tid,
Entry *e )
{
return mdb_id2entry_put(op, tid, e, 0);
}
int mdb_id2entry(
Operation *op,
MDB_txn *tid,
ID id,
Entry **e )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
MDB_dbi dbi = mdb->mi_id2entry;
MDB_val key, data;
EntryHeader eh;
int rc = 0;
*e = NULL;
key.mv_data = &id;
key.mv_size = sizeof(ID);
/* fetch it */
rc = mdb_get( tid, dbi, &key, &data );
if ( rc == MDB_NOTFOUND ) {
/* Looking for root entry on an empty-dn suffix? */
if ( !id && BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] )) {
struct berval gluebv = BER_BVC("glue");
Entry *r = entry_alloc();
r->e_id = 0;
attr_merge_one( r, slap_schema.si_ad_objectClass, &gluebv, NULL );
attr_merge_one( r, slap_schema.si_ad_structuralObjectClass, &gluebv, NULL );
r->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END;
*e = r;
return MDB_SUCCESS;
}
}
if ( rc ) return rc;
eh.bv.bv_val = data.mv_data;
eh.bv.bv_len = data.mv_size;
rc = entry_header( &eh );
if ( rc ) return rc;
if ( eh.nvals ) {
eh.bv.bv_len = eh.nvals * sizeof( struct berval );
eh.bv.bv_val = ch_malloc( eh.bv.bv_len );
rc = entry_decode(&eh, e);
} else {
*e = entry_alloc();
}
if( rc == 0 ) {
(*e)->e_id = id;
(*e)->e_name.bv_val = NULL;
(*e)->e_nname.bv_val = NULL;
} else {
ch_free( eh.bv.bv_val );
}
return rc;
}
int mdb_id2entry_delete(
BackendDB *be,
MDB_txn *tid,
Entry *e )
{
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
MDB_dbi dbi = mdb->mi_id2entry;
MDB_val key;
int rc;
key.mv_data = &e->e_id;
key.mv_size = sizeof(ID);
/* delete from database */
rc = mdb_del( tid, dbi, &key, NULL );
return rc;
}
int mdb_entry_return(
Entry *e
)
{
entry_free( e );
return 0;
}
int mdb_entry_release(
Operation *op,
Entry *e,
int rw )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
struct mdb_op_info *moi = NULL;
int rc;
/* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
mdb_entry_return ( e );
if ( slapMode == SLAP_SERVER_MODE ) {
OpExtra *oex;
LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
if ( oex->oe_key == mdb ) {
moi = (mdb_op_info *)oex;
/* If it was setup by entry_get we should probably free it */
if ( moi->moi_flag & MOI_FREEIT ) {
moi->moi_ref--;
if ( moi->moi_ref < 1 ) {
mdb_txn_reset( moi->moi_txn );
moi->moi_ref = 0;
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
op->o_tmpfree( moi, op->o_tmpmemctx );
}
}
break;
}
}
}
return 0;
}
/* return LDAP_SUCCESS IFF we can retrieve the specified entry.
*/
int mdb_entry_get(
Operation *op,
struct berval *ndn,
ObjectClass *oc,
AttributeDescription *at,
int rw,
Entry **ent )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
struct mdb_op_info *moi = NULL;
MDB_txn *txn = NULL;
Entry *e = NULL;
int rc;
const char *at_name = at ? at->ad_cname.bv_val : "(null)";
Debug( LDAP_DEBUG_ARGS,
"=> mdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 );
Debug( LDAP_DEBUG_ARGS,
"=> mdb_entry_get: oc: \"%s\", at: \"%s\"\n",
oc ? oc->soc_cname.bv_val : "(null)", at_name, 0);
rc = mdb_opinfo_get( op, mdb, rw == 0, &moi );
if ( rc )
return LDAP_OTHER;
txn = moi->moi_txn;
/* can we find entry */
rc = mdb_dn2entry( op, txn, ndn, &e, 0 );
switch( rc ) {
case MDB_NOTFOUND:
case 0:
break;
default:
return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY;
}
if (e == NULL) {
Debug( LDAP_DEBUG_ACL,
"=> mdb_entry_get: cannot find entry: \"%s\"\n",
ndn->bv_val, 0, 0 );
rc = LDAP_NO_SUCH_OBJECT;
goto return_results;
}
Debug( LDAP_DEBUG_ACL,
"=> mdb_entry_get: found entry: \"%s\"\n",
ndn->bv_val, 0, 0 );
if ( oc && !is_entry_objectclass( e, oc, 0 )) {
Debug( LDAP_DEBUG_ACL,
"<= mdb_entry_get: failed to find objectClass %s\n",
oc->soc_cname.bv_val, 0, 0 );
rc = LDAP_NO_SUCH_ATTRIBUTE;
goto return_results;
}
/* NOTE: attr_find() or attrs_find()? */
if ( at && attr_find( e->e_attrs, at ) == NULL ) {
Debug( LDAP_DEBUG_ACL,
"<= mdb_entry_get: failed to find attribute %s\n",
at->ad_cname.bv_val, 0, 0 );
rc = LDAP_NO_SUCH_ATTRIBUTE;
goto return_results;
}
return_results:
if( rc != LDAP_SUCCESS ) {
/* free entry */
if ( e )
mdb_entry_return( e );
if (moi->moi_ref == 1) {
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
mdb_txn_reset( txn );
op->o_tmpfree( moi, op->o_tmpmemctx );
}
} else {
*ent = e;
}
Debug( LDAP_DEBUG_TRACE,
"mdb_entry_get: rc=%d\n",
rc, 0, 0 );
return(rc);
}
static void
mdb_reader_free( void *key, void *data )
{
MDB_txn *txn = data;
if ( txn ) mdb_txn_abort( txn );
}
/* free up any keys used by the main thread */
void
mdb_reader_flush( MDB_env *env )
{
void *data;
void *ctx = ldap_pvt_thread_pool_context();
if ( !ldap_pvt_thread_pool_getkey( ctx, env, &data, NULL ) ) {
ldap_pvt_thread_pool_setkey( ctx, env, NULL, 0, NULL, NULL );
mdb_reader_free( env, data );
}
}
int
mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moip )
{
int rc, renew = 0;
void *data;
void *ctx;
mdb_op_info *moi = NULL;
OpExtra *oex;
assert( op != NULL );
if ( !mdb || !moip ) return -1;
/* If no op was provided, try to find the ctx anyway... */
if ( op ) {
ctx = op->o_threadctx;
} else {
ctx = ldap_pvt_thread_pool_context();
}
if ( op ) {
LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
if ( oex->oe_key == mdb ) break;
}
moi = (mdb_op_info *)oex;
}
if ( !moi ) {
moi = *moip;
if ( !moi ) {
if ( op ) {
moi = op->o_tmpalloc(sizeof(struct mdb_op_info),op->o_tmpmemctx);
} else {
moi = ch_malloc(sizeof(mdb_op_info));
}
moi->moi_flag = MOI_FREEIT;
*moip = moi;
}
LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
moi->moi_oe.oe_key = mdb;
moi->moi_ref = 0;
moi->moi_txn = NULL;
}
if ( !rdonly ) {
/* This op started as a reader, but now wants to write. */
if ( moi->moi_flag & MOI_READER ) {
moi = *moip;
LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
} else {
/* This op is continuing an existing write txn */
*moip = moi;
}
moi->moi_ref++;
if ( !moi->moi_txn ) {
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &moi->moi_txn );
if (rc) {
Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
mdb_strerror(rc), rc, 0 );
}
return rc;
}
return 0;
}
/* OK, this is a reader */
if ( !moi->moi_txn ) {
if ( !ctx ) {
/* Shouldn't happen unless we're single-threaded */
rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &moi->moi_txn );
if (rc) {
Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
mdb_strerror(rc), rc, 0 );
}
return rc;
}
if ( ldap_pvt_thread_pool_getkey( ctx, mdb->mi_dbenv, &data, NULL ) ) {
rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &moi->moi_txn );
if (rc) {
Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
mdb_strerror(rc), rc, 0 );
return rc;
}
data = moi->moi_txn;
if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, mdb->mi_dbenv,
data, mdb_reader_free, NULL, NULL ) ) ) {
mdb_txn_abort( moi->moi_txn );
moi->moi_txn = NULL;
Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: thread_pool_setkey failed err (%d)\n",
rc, 0, 0 );
return rc;
}
} else {
moi->moi_txn = data;
renew = 1;
}
moi->moi_flag |= MOI_READER;
}
if ( moi->moi_ref < 1 ) {
moi->moi_ref = 0;
}
if ( renew ) {
mdb_txn_renew( moi->moi_txn );
}
moi->moi_ref++;
if ( *moip != moi )
*moip = moi;
return 0;
}

1166
servers/slapd/back-mdb/idl.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,74 @@
/* idl.h - ldap mdb back-end ID list header file */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#ifndef _MDB_IDL_H_
#define _MDB_IDL_H_
/* IDL sizes - likely should be even bigger
* limiting factors: sizeof(ID), thread stack size
*/
#define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
#define MDB_IDL_DB_SIZE (1<<MDB_IDL_LOGN)
#define MDB_IDL_UM_SIZE (1<<(MDB_IDL_LOGN+1))
#define MDB_IDL_UM_SIZEOF (MDB_IDL_UM_SIZE * sizeof(ID))
#define MDB_IDL_DB_MAX (MDB_IDL_DB_SIZE-1)
#define MDB_IDL_UM_MAX (MDB_IDL_UM_SIZE-1)
#define MDB_IDL_IS_RANGE(ids) ((ids)[0] == NOID)
#define MDB_IDL_RANGE_SIZE (3)
#define MDB_IDL_RANGE_SIZEOF (MDB_IDL_RANGE_SIZE * sizeof(ID))
#define MDB_IDL_SIZEOF(ids) ((MDB_IDL_IS_RANGE(ids) \
? MDB_IDL_RANGE_SIZE : ((ids)[0]+1)) * sizeof(ID))
#define MDB_IDL_RANGE_FIRST(ids) ((ids)[1])
#define MDB_IDL_RANGE_LAST(ids) ((ids)[2])
#define MDB_IDL_RANGE( ids, f, l ) \
do { \
(ids)[0] = NOID; \
(ids)[1] = (f); \
(ids)[2] = (l); \
} while(0)
#define MDB_IDL_ZERO(ids) \
do { \
(ids)[0] = 0; \
(ids)[1] = 0; \
(ids)[2] = 0; \
} while(0)
#define MDB_IDL_IS_ZERO(ids) ( (ids)[0] == 0 )
#define MDB_IDL_IS_ALL( range, ids ) ( (ids)[0] == NOID \
&& (ids)[1] <= (range)[1] && (range)[2] <= (ids)[2] )
#define MDB_IDL_CPY( dst, src ) (AC_MEMCPY( dst, src, MDB_IDL_SIZEOF( src ) ))
#define MDB_IDL_ID( mdb, ids, id ) MDB_IDL_RANGE( ids, id, NOID )
#define MDB_IDL_ALL( ids ) MDB_IDL_RANGE( ids, 1, NOID )
#define MDB_IDL_FIRST( ids ) ( ids[1] )
#define MDB_IDL_LAST( ids ) ( MDB_IDL_IS_RANGE(ids) \
? ids[2] : ids[ids[0]] )
#define MDB_IDL_N( ids ) ( MDB_IDL_IS_RANGE(ids) \
? (ids[2]-ids[1])+1 : ids[0] )
LDAP_BEGIN_DECL
LDAP_END_DECL
#endif

View file

@ -0,0 +1,555 @@
/* index.c - routines for dealing with attribute indexes */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-mdb.h"
#include "lutil_hash.h"
static char presence_keyval[] = {0,0};
static struct berval presence_key = BER_BVC(presence_keyval);
AttrInfo *mdb_index_mask(
Backend *be,
AttributeDescription *desc,
struct berval *atname )
{
AttributeType *at;
AttrInfo *ai = mdb_attr_mask( be->be_private, desc );
if( ai ) {
*atname = desc->ad_cname;
return ai;
}
/* If there is a tagging option, did we ever index the base
* type? If so, check for mask, otherwise it's not there.
*/
if( slap_ad_is_tagged( desc ) && desc != desc->ad_type->sat_ad ) {
/* has tagging option */
ai = mdb_attr_mask( be->be_private, desc->ad_type->sat_ad );
if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOTAGS ) ) {
*atname = desc->ad_type->sat_cname;
return ai;
}
}
/* see if supertype defined mask for its subtypes */
for( at = desc->ad_type; at != NULL ; at = at->sat_sup ) {
/* If no AD, we've never indexed this type */
if ( !at->sat_ad ) continue;
ai = mdb_attr_mask( be->be_private, at->sat_ad );
if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOSUBTYPES ) ) {
*atname = at->sat_cname;
return ai;
}
}
return 0;
}
/* This function is only called when evaluating search filters.
*/
int mdb_index_param(
Backend *be,
AttributeDescription *desc,
int ftype,
MDB_dbi *dbip,
slap_mask_t *maskp,
struct berval *prefixp )
{
AttrInfo *ai;
slap_mask_t mask, type = 0;
ai = mdb_index_mask( be, desc, prefixp );
if ( !ai ) {
#ifdef MDB_MONITOR_IDX
switch ( ftype ) {
case LDAP_FILTER_PRESENT:
type = SLAP_INDEX_PRESENT;
break;
case LDAP_FILTER_APPROX:
type = SLAP_INDEX_APPROX;
break;
case LDAP_FILTER_EQUALITY:
type = SLAP_INDEX_EQUALITY;
break;
case LDAP_FILTER_SUBSTRINGS:
type = SLAP_INDEX_SUBSTR;
break;
default:
return LDAP_INAPPROPRIATE_MATCHING;
}
mdb_monitor_idx_add( be->be_private, desc, type );
#endif /* MDB_MONITOR_IDX */
return LDAP_INAPPROPRIATE_MATCHING;
}
mask = ai->ai_indexmask;
switch( ftype ) {
case LDAP_FILTER_PRESENT:
type = SLAP_INDEX_PRESENT;
if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
*prefixp = presence_key;
goto done;
}
break;
case LDAP_FILTER_APPROX:
type = SLAP_INDEX_APPROX;
if ( desc->ad_type->sat_approx ) {
if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
goto done;
}
break;
}
/* Use EQUALITY rule and index for approximate match */
/* fall thru */
case LDAP_FILTER_EQUALITY:
type = SLAP_INDEX_EQUALITY;
if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
goto done;
}
break;
case LDAP_FILTER_SUBSTRINGS:
type = SLAP_INDEX_SUBSTR;
if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
goto done;
}
break;
default:
return LDAP_OTHER;
}
#ifdef MDB_MONITOR_IDX
mdb_monitor_idx_add( be->be_private, desc, type );
#endif /* MDB_MONITOR_IDX */
return LDAP_INAPPROPRIATE_MATCHING;
done:
*dbip = ai->ai_dbi;
*maskp = mask;
return LDAP_SUCCESS;
}
static int indexer(
Operation *op,
MDB_txn *txn,
MDB_dbi dbi,
AttributeDescription *ad,
struct berval *atname,
BerVarray vals,
ID id,
int opid,
slap_mask_t mask )
{
int rc, i;
struct berval *keys;
assert( mask != 0 );
if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
rc = mdb_key_change( op->o_bd, txn, dbi, &presence_key, id, opid );
if( rc ) {
goto done;
}
}
if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
rc = ad->ad_type->sat_equality->smr_indexer(
LDAP_FILTER_EQUALITY,
mask,
ad->ad_type->sat_syntax,
ad->ad_type->sat_equality,
atname, vals, &keys, op->o_tmpmemctx );
if( rc == LDAP_SUCCESS && keys != NULL ) {
for( i=0; keys[i].bv_val != NULL; i++ ) {
rc = mdb_key_change( op->o_bd, txn, dbi, &keys[i], id, opid );
if( rc ) {
ber_bvarray_free_x( keys, op->o_tmpmemctx );
goto done;
}
}
ber_bvarray_free_x( keys, op->o_tmpmemctx );
}
rc = LDAP_SUCCESS;
}
if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
rc = ad->ad_type->sat_approx->smr_indexer(
LDAP_FILTER_APPROX,
mask,
ad->ad_type->sat_syntax,
ad->ad_type->sat_approx,
atname, vals, &keys, op->o_tmpmemctx );
if( rc == LDAP_SUCCESS && keys != NULL ) {
for( i=0; keys[i].bv_val != NULL; i++ ) {
rc = mdb_key_change( op->o_bd, txn, dbi, &keys[i], id, opid );
if( rc ) {
ber_bvarray_free_x( keys, op->o_tmpmemctx );
goto done;
}
}
ber_bvarray_free_x( keys, op->o_tmpmemctx );
}
rc = LDAP_SUCCESS;
}
if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
rc = ad->ad_type->sat_substr->smr_indexer(
LDAP_FILTER_SUBSTRINGS,
mask,
ad->ad_type->sat_syntax,
ad->ad_type->sat_substr,
atname, vals, &keys, op->o_tmpmemctx );
if( rc == LDAP_SUCCESS && keys != NULL ) {
for( i=0; keys[i].bv_val != NULL; i++ ) {
rc = mdb_key_change( op->o_bd, txn, dbi, &keys[i], id, opid );
if( rc ) {
ber_bvarray_free_x( keys, op->o_tmpmemctx );
goto done;
}
}
ber_bvarray_free_x( keys, op->o_tmpmemctx );
}
rc = LDAP_SUCCESS;
}
done:
switch( rc ) {
/* The callers all know how to deal with these results */
case 0:
break;
/* Anything else is bad news */
default:
rc = LDAP_OTHER;
}
return rc;
}
static int index_at_values(
Operation *op,
MDB_txn *txn,
AttributeDescription *ad,
AttributeType *type,
struct berval *tags,
BerVarray vals,
ID id,
int opid )
{
int rc;
slap_mask_t mask = 0;
int ixop = opid;
AttrInfo *ai = NULL;
if ( opid == MDB_INDEX_UPDATE_OP )
ixop = SLAP_INDEX_ADD_OP;
if( type->sat_sup ) {
/* recurse */
rc = index_at_values( op, txn, NULL,
type->sat_sup, tags,
vals, id, opid );
if( rc ) return rc;
}
/* If this type has no AD, we've never used it before */
if( type->sat_ad ) {
ai = mdb_attr_mask( op->o_bd->be_private, type->sat_ad );
if ( ai ) {
#ifdef LDAP_COMP_MATCH
/* component indexing */
if ( ai->ai_cr ) {
ComponentReference *cr;
for( cr = ai->ai_cr ; cr ; cr = cr->cr_next ) {
rc = indexer( op, txn, ai->ai_dbi, cr->cr_ad, &type->sat_cname,
cr->cr_nvals, id, ixop,
cr->cr_indexmask );
}
}
#endif
ad = type->sat_ad;
/* If we're updating the index, just set the new bits that aren't
* already in the old mask.
*/
if ( opid == MDB_INDEX_UPDATE_OP )
mask = ai->ai_newmask & ~ai->ai_indexmask;
else
/* For regular updates, if there is a newmask use it. Otherwise
* just use the old mask.
*/
mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
if( mask ) {
rc = indexer( op, txn, ai->ai_dbi, ad, &type->sat_cname,
vals, id, ixop, mask );
if( rc ) return rc;
}
}
}
if( tags->bv_len ) {
AttributeDescription *desc;
desc = ad_find_tags( type, tags );
if( desc ) {
ai = mdb_attr_mask( op->o_bd->be_private, desc );
if( ai ) {
if ( opid == MDB_INDEX_UPDATE_OP )
mask = ai->ai_newmask & ~ai->ai_indexmask;
else
mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
if ( mask ) {
rc = indexer( op, txn, ai->ai_dbi, desc, &desc->ad_cname,
vals, id, ixop, mask );
if( rc ) {
return rc;
}
}
}
}
}
return LDAP_SUCCESS;
}
int mdb_index_values(
Operation *op,
MDB_txn *txn,
AttributeDescription *desc,
BerVarray vals,
ID id,
int opid )
{
int rc;
/* Never index ID 0 */
if ( id == 0 )
return 0;
rc = index_at_values( op, txn, desc,
desc->ad_type, &desc->ad_tags,
vals, id, opid );
return rc;
}
/* Get the list of which indices apply to this attr */
int
mdb_index_recset(
struct mdb_info *mdb,
Attribute *a,
AttributeType *type,
struct berval *tags,
IndexRec *ir )
{
int rc, slot;
AttrList *al;
if( type->sat_sup ) {
/* recurse */
rc = mdb_index_recset( mdb, a, type->sat_sup, tags, ir );
if( rc ) return rc;
}
/* If this type has no AD, we've never used it before */
if( type->sat_ad ) {
slot = mdb_attr_slot( mdb, type->sat_ad, NULL );
if ( slot >= 0 ) {
ir[slot].ai = mdb->mi_attrs[slot];
al = ch_malloc( sizeof( AttrList ));
al->attr = a;
al->next = ir[slot].attrs;
ir[slot].attrs = al;
}
}
if( tags->bv_len ) {
AttributeDescription *desc;
desc = ad_find_tags( type, tags );
if( desc ) {
slot = mdb_attr_slot( mdb, desc, NULL );
if ( slot >= 0 ) {
ir[slot].ai = mdb->mi_attrs[slot];
al = ch_malloc( sizeof( AttrList ));
al->attr = a;
al->next = ir[slot].attrs;
ir[slot].attrs = al;
}
}
}
return LDAP_SUCCESS;
}
/* Apply the indices for the recset */
int mdb_index_recrun(
Operation *op,
struct mdb_info *mdb,
IndexRec *ir0,
ID id,
int base )
{
IndexRec *ir;
AttrList *al;
int i, rc = 0;
/* Never index ID 0 */
if ( id == 0 )
return 0;
for (i=base; i<mdb->mi_nattrs; i+=slap_tool_thread_max) {
ir = ir0 + i;
if ( !ir->ai ) continue;
while (( al = ir->attrs )) {
ir->attrs = al->next;
rc = indexer( op, NULL, ir->ai->ai_dbi, ir->ai->ai_desc,
&ir->ai->ai_desc->ad_type->sat_cname,
al->attr->a_nvals, id, SLAP_INDEX_ADD_OP,
ir->ai->ai_indexmask );
free( al );
if ( rc ) break;
}
}
return rc;
}
int
mdb_index_entry(
Operation *op,
MDB_txn *txn,
int opid,
Entry *e )
{
int rc;
Attribute *ap = e->e_attrs;
#if 0 /* ifdef LDAP_COMP_MATCH */
ComponentReference *cr_list = NULL;
ComponentReference *cr = NULL, *dupped_cr = NULL;
void* decoded_comp;
ComponentSyntaxInfo* csi_attr;
Syntax* syn;
AttributeType* at;
int i, num_attr;
void* mem_op;
struct berval value = {0};
#endif
/* Never index ID 0 */
if ( e->e_id == 0 )
return 0;
Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n",
opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
(long) e->e_id, e->e_dn );
/* add each attribute to the indexes */
for ( ; ap != NULL; ap = ap->a_next ) {
#if 0 /* ifdef LDAP_COMP_MATCH */
AttrInfo *ai;
/* see if attribute has components to be indexed */
ai = mdb_attr_mask( op->o_bd->be_private, ap->a_desc->ad_type->sat_ad );
if ( !ai ) continue;
cr_list = ai->ai_cr;
if ( attr_converter && cr_list ) {
syn = ap->a_desc->ad_type->sat_syntax;
ap->a_comp_data = op->o_tmpalloc( sizeof( ComponentData ), op->o_tmpmemctx );
/* Memory chunk(nibble) pre-allocation for decoders */
mem_op = nibble_mem_allocator ( 1024*16, 1024*4 );
ap->a_comp_data->cd_mem_op = mem_op;
for( cr = cr_list ; cr ; cr = cr->cr_next ) {
/* count how many values in an attribute */
for( num_attr=0; ap->a_vals[num_attr].bv_val != NULL; num_attr++ );
num_attr++;
cr->cr_nvals = (BerVarray)op->o_tmpalloc( sizeof( struct berval )*num_attr, op->o_tmpmemctx );
for( i=0; ap->a_vals[i].bv_val != NULL; i++ ) {
/* decoding attribute value */
decoded_comp = attr_converter ( ap, syn, &ap->a_vals[i] );
if ( !decoded_comp )
return LDAP_DECODING_ERROR;
/* extracting the referenced component */
dupped_cr = dup_comp_ref( op, cr );
csi_attr = ((ComponentSyntaxInfo*)decoded_comp)->csi_comp_desc->cd_extract_i( mem_op, dupped_cr, decoded_comp );
if ( !csi_attr )
return LDAP_DECODING_ERROR;
cr->cr_asn_type_id = csi_attr->csi_comp_desc->cd_type_id;
cr->cr_ad = (AttributeDescription*)get_component_description ( cr->cr_asn_type_id );
if ( !cr->cr_ad )
return LDAP_INVALID_SYNTAX;
at = cr->cr_ad->ad_type;
/* encoding the value of component in GSER */
rc = component_encoder( mem_op, csi_attr, &value );
if ( rc != LDAP_SUCCESS )
return LDAP_ENCODING_ERROR;
/* Normalize the encoded component values */
if ( at->sat_equality && at->sat_equality->smr_normalize ) {
rc = at->sat_equality->smr_normalize (
SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
at->sat_syntax, at->sat_equality,
&value, &cr->cr_nvals[i], op->o_tmpmemctx );
} else {
cr->cr_nvals[i] = value;
}
}
/* The end of BerVarray */
cr->cr_nvals[num_attr-1].bv_val = NULL;
cr->cr_nvals[num_attr-1].bv_len = 0;
}
op->o_tmpfree( ap->a_comp_data, op->o_tmpmemctx );
nibble_mem_free ( mem_op );
ap->a_comp_data = NULL;
}
#endif
rc = mdb_index_values( op, txn, ap->a_desc,
ap->a_nvals, e->e_id, opid );
if( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE,
"<= index_entry_%s( %ld, \"%s\" ) failure\n",
opid == SLAP_INDEX_ADD_OP ? "add" : "del",
(long) e->e_id, e->e_dn );
return rc;
}
}
Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n",
opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
(long) e->e_id, e->e_dn );
return LDAP_SUCCESS;
}

View file

@ -0,0 +1,445 @@
/* init.c - initialize mdb backend */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/unistd.h>
#include <ac/stdlib.h>
#include <ac/errno.h>
#include <sys/stat.h>
#include "back-mdb.h"
#include <lutil.h>
#include <ldap_rq.h>
#include "config.h"
static const struct berval mdmi_databases[] = {
BER_BVC("ad2i"),
BER_BVC("dn2i"),
BER_BVC("id2e"),
BER_BVNULL
};
static int
mdb_db_init( BackendDB *be, ConfigReply *cr )
{
struct mdb_info *mdb;
int rc;
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_db_init) ": Initializing mdb database\n",
0, 0, 0 );
/* allocate backend-database-specific stuff */
mdb = (struct mdb_info *) ch_calloc( 1, sizeof(struct mdb_info) );
/* DBEnv parameters */
mdb->mi_dbenv_home = ch_strdup( SLAPD_DEFAULT_DB_DIR );
mdb->mi_dbenv_flags = 0;
mdb->mi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
mdb->mi_search_stack_depth = DEFAULT_SEARCH_STACK_DEPTH;
mdb->mi_search_stack = NULL;
mdb->mi_mapsize = DEFAULT_MAPSIZE;
be->be_private = mdb;
be->be_cf_ocs = be->bd_info->bi_cf_ocs;
#ifndef MDB_MULTIPLE_SUFFIXES
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX;
#endif
rc = mdb_monitor_db_init( be );
return rc;
}
static int
mdb_db_close( BackendDB *be, ConfigReply *cr );
static int
mdb_db_open( BackendDB *be, ConfigReply *cr )
{
int rc, i;
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
struct stat stat1;
u_int32_t flags;
char *dbhome;
MDB_txn *txn;
if ( be->be_suffix == NULL ) {
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_db_open) ": need suffix.\n",
1, 0, 0 );
return -1;
}
Debug( LDAP_DEBUG_ARGS,
LDAP_XSTRING(mdb_db_open) ": \"%s\"\n",
be->be_suffix[0].bv_val, 0, 0 );
/* Check existence of dbenv_home. Any error means trouble */
rc = stat( mdb->mi_dbenv_home, &stat1 );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
"cannot access database directory \"%s\" (%d).\n",
be->be_suffix[0].bv_val, mdb->mi_dbenv_home, errno );
return -1;
}
/* mdb is always clean */
be->be_flags |= SLAP_DBFLAG_CLEAN;
rc = mdb_env_create( &mdb->mi_dbenv );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
"mdb_env_create failed: %s (%d).\n",
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
goto fail;
}
if ( mdb->mi_readers ) {
rc = mdb_env_set_maxreaders( mdb->mi_dbenv, mdb->mi_readers );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
"mdb_env_set_maxreaders failed: %s (%d).\n",
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
goto fail;
}
}
rc = mdb_env_set_mapsize( mdb->mi_dbenv, mdb->mi_mapsize );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
"mdb_env_set_mapsize failed: %s (%d).\n",
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
goto fail;
}
rc = mdb_env_set_maxdbs( mdb->mi_dbenv, MDB_INDICES );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
"mdb_env_set_maxdbs failed: %s (%d).\n",
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
goto fail;
}
#ifdef HAVE_EBCDIC
strcpy( path, mdb->mi_dbenv_home );
__atoe( path );
dbhome = path;
#else
dbhome = mdb->mi_dbenv_home;
#endif
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
"dbenv_open(%s).\n",
be->be_suffix[0].bv_val, mdb->mi_dbenv_home, 0);
flags = mdb->mi_dbenv_flags;
if ( slapMode & SLAP_TOOL_QUICK )
flags |= MDB_NOSYNC;
if ( slapMode & SLAP_TOOL_READONLY)
flags |= MDB_RDONLY;
rc = mdb_env_open( mdb->mi_dbenv, dbhome,
flags, mdb->mi_dbenv_mode );
if ( rc ) {
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_db_open) ": database \"%s\" cannot be opened, err %d. "
"Restore from backup!\n",
be->be_suffix[0].bv_val, rc, 0 );
goto fail;
}
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &txn );
if ( rc ) {
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_db_open) ": database \"%s\" cannot be opened, err %d. "
"Restore from backup!\n",
be->be_suffix[0].bv_val, rc, 0 );
goto fail;
}
/* open (and create) main databases */
for( i = 0; mdmi_databases[i].bv_val; i++ ) {
flags = MDB_INTEGERKEY;
if( i == MDB_ID2ENTRY ) {
if ( !(slapMode & (SLAP_TOOL_READMAIN|SLAP_TOOL_READONLY) ))
flags |= MDB_CREATE;
} else {
if ( i == MDB_DN2ID )
flags |= MDB_DUPSORT;
if ( !(slapMode & SLAP_TOOL_READONLY) )
flags |= MDB_CREATE;
}
rc = mdb_open( txn,
mdmi_databases[i].bv_val,
flags,
&mdb->mi_dbis[i] );
if ( rc != 0 ) {
snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
"mdb_open(%s/%s) failed: %s (%d).",
be->be_suffix[0].bv_val,
mdb->mi_dbenv_home, mdmi_databases[i].bv_val,
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_db_open) ": %s\n",
cr->msg, 0, 0 );
goto fail;
}
if ( i == MDB_DN2ID )
mdb_set_dupsort( txn, mdb->mi_dbis[i], mdb_dup_compare );
}
rc = mdb_attr_dbs_open( be, txn, cr );
if ( rc ) {
mdb_txn_abort( txn );
goto fail;
}
rc = mdb_txn_commit(txn);
if ( rc != 0 ) {
goto fail;
}
/* monitor setup */
rc = mdb_monitor_db_open( be );
if ( rc != 0 ) {
goto fail;
}
mdb->mi_flags |= MDB_IS_OPEN;
return 0;
fail:
mdb_db_close( be, NULL );
return rc;
}
static int
mdb_db_close( BackendDB *be, ConfigReply *cr )
{
int rc;
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
MDB_txn *txn;
/* monitor handling */
(void)mdb_monitor_db_close( be );
mdb->mi_flags &= ~MDB_IS_OPEN;
if( mdb->mi_dbenv ) {
mdb_reader_flush( mdb->mi_dbenv );
}
if ( mdb->mi_dbenv ) {
if ( mdb->mi_dbis[0] ) {
int i;
rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &txn );
mdb_attr_dbs_close( mdb, txn );
for ( i=0; i<MDB_NDB; i++ )
mdb_close( txn, mdb->mi_dbis[i] );
mdb_txn_abort( txn );
/* force a sync */
rc = mdb_env_sync( mdb->mi_dbenv, 1 );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"mdb_db_close: database \"%s\": "
"mdb_env_sync failed: %s (%d).\n",
be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
}
}
mdb_env_close( mdb->mi_dbenv );
mdb->mi_dbenv = NULL;
}
return 0;
}
static int
mdb_db_destroy( BackendDB *be, ConfigReply *cr )
{
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
/* stop and remove checkpoint task */
if ( mdb->mi_txn_cp_task ) {
struct re_s *re = mdb->mi_txn_cp_task;
mdb->mi_txn_cp_task = NULL;
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
ldap_pvt_runqueue_stoptask( &slapd_rq, re );
ldap_pvt_runqueue_remove( &slapd_rq, re );
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
}
/* monitor handling */
(void)mdb_monitor_db_destroy( be );
if( mdb->mi_dbenv_home ) ch_free( mdb->mi_dbenv_home );
mdb_attr_index_destroy( mdb );
ch_free( mdb );
be->be_private = NULL;
return 0;
}
int
mdb_back_initialize(
BackendInfo *bi )
{
int rc;
static char *controls[] = {
LDAP_CONTROL_ASSERT,
LDAP_CONTROL_MANAGEDSAIT,
LDAP_CONTROL_NOOP,
LDAP_CONTROL_PAGEDRESULTS,
LDAP_CONTROL_PRE_READ,
LDAP_CONTROL_POST_READ,
LDAP_CONTROL_SUBENTRIES,
LDAP_CONTROL_X_PERMISSIVE_MODIFY,
#ifdef LDAP_X_TXN
LDAP_CONTROL_X_TXN_SPEC,
#endif
NULL
};
/* initialize the underlying database system */
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_back_initialize) ": initialize "
MDB_UCTYPE " backend\n", 0, 0, 0 );
bi->bi_flags |=
SLAP_BFLAG_INCREMENT |
SLAP_BFLAG_SUBENTRIES |
SLAP_BFLAG_ALIASES |
SLAP_BFLAG_REFERRALS;
bi->bi_controls = controls;
{ /* version check */
int major, minor, patch, ver;
char *version = mdb_version( &major, &minor, &patch );
#ifdef HAVE_EBCDIC
char v2[1024];
/* All our stdio does an ASCII to EBCDIC conversion on
* the output. Strings from the MDB library are already
* in EBCDIC; we have to go back and forth...
*/
strcpy( v2, version );
__etoa( v2 );
version = v2;
#endif
ver = (major << 24) | (minor << 16) | patch;
if( ver != MDB_VERSION_FULL ) {
/* fail if a versions don't match */
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_back_initialize) ": "
"MDB library version mismatch:"
" expected " MDB_VERSION_STRING ","
" got %s\n", version, 0, 0 );
return -1;
}
Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_back_initialize)
": %s\n", version, 0, 0 );
}
bi->bi_open = 0;
bi->bi_close = 0;
bi->bi_config = 0;
bi->bi_destroy = 0;
bi->bi_db_init = mdb_db_init;
bi->bi_db_config = config_generic_wrapper;
bi->bi_db_open = mdb_db_open;
bi->bi_db_close = mdb_db_close;
bi->bi_db_destroy = mdb_db_destroy;
bi->bi_op_add = mdb_add;
bi->bi_op_bind = mdb_bind;
bi->bi_op_compare = mdb_compare;
bi->bi_op_delete = mdb_delete;
bi->bi_op_modify = mdb_modify;
bi->bi_op_modrdn = mdb_modrdn;
bi->bi_op_search = mdb_search;
bi->bi_op_unbind = 0;
bi->bi_extended = mdb_extended;
#if 0 /* FIXME: Redundant, why does this exist? */
bi->bi_chk_referrals = mdb_referrals;
#endif
bi->bi_operational = mdb_operational;
bi->bi_has_subordinates = mdb_hasSubordinates;
bi->bi_entry_release_rw = mdb_entry_release;
bi->bi_entry_get_rw = mdb_entry_get;
/*
* hooks for slap tools
*/
bi->bi_tool_entry_open = mdb_tool_entry_open;
bi->bi_tool_entry_close = mdb_tool_entry_close;
bi->bi_tool_entry_first = backend_tool_entry_first;
bi->bi_tool_entry_first_x = mdb_tool_entry_first_x;
bi->bi_tool_entry_next = mdb_tool_entry_next;
bi->bi_tool_entry_get = mdb_tool_entry_get;
bi->bi_tool_entry_put = mdb_tool_entry_put;
bi->bi_tool_entry_reindex = mdb_tool_entry_reindex;
bi->bi_tool_sync = 0;
bi->bi_tool_dn2id_get = mdb_tool_dn2id_get;
bi->bi_tool_entry_modify = mdb_tool_entry_modify;
bi->bi_connection_init = 0;
bi->bi_connection_destroy = 0;
rc = mdb_back_init_cf( bi );
return rc;
}
#if (SLAPD_MDB == SLAPD_MOD_DYNAMIC)
SLAP_BACKEND_INIT_MODULE( mdb )
#endif /* SLAPD_MDB == SLAPD_MOD_DYNAMIC */

View file

@ -0,0 +1,94 @@
/* index.c - routines for dealing with attribute indexes */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-mdb.h"
#include "idl.h"
/* read a key */
int
mdb_key_read(
Backend *be,
MDB_txn *txn,
MDB_dbi dbi,
struct berval *k,
ID *ids,
MDB_cursor **saved_cursor,
int get_flag
)
{
int rc;
MDB_val key;
Debug( LDAP_DEBUG_TRACE, "=> key_read\n", 0, 0, 0 );
key.mv_size = k->bv_len;
key.mv_data = k->bv_val;
rc = mdb_idl_fetch_key( be, txn, dbi, &key, ids, saved_cursor, get_flag );
if( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE, "<= mdb_index_read: failed (%d)\n",
rc, 0, 0 );
} else {
Debug( LDAP_DEBUG_TRACE, "<= mdb_index_read %ld candidates\n",
(long) MDB_IDL_N(ids), 0, 0 );
}
return rc;
}
/* Add or remove stuff from index files */
int
mdb_key_change(
Backend *be,
MDB_txn *txn,
MDB_dbi dbi,
struct berval *k,
ID id,
int op
)
{
int rc;
MDB_val key;
Debug( LDAP_DEBUG_TRACE, "=> key_change(%s,%lx)\n",
op == SLAP_INDEX_ADD_OP ? "ADD":"DELETE", (long) id, 0 );
key.mv_size = k->bv_len;
key.mv_data = k->bv_val;
if (op == SLAP_INDEX_ADD_OP) {
/* Add values */
rc = mdb_idl_insert_key( be, txn, dbi, &key, id );
if ( rc == MDB_KEYEXIST ) rc = 0;
} else {
/* Delete values */
rc = mdb_idl_delete_key( be, txn, dbi, &key, id );
if ( rc == MDB_NOTFOUND ) rc = 0;
}
Debug( LDAP_DEBUG_TRACE, "<= key_change %d\n", rc, 0, 0 );
return rc;
}

View file

@ -0,0 +1,693 @@
/* modify.c - mdb backend modify routine */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/time.h>
#include "back-mdb.h"
static struct berval scbva[] = {
BER_BVC("glue"),
BER_BVNULL
};
static void
mdb_modify_idxflags(
Operation *op,
AttributeDescription *desc,
int got_delete,
Attribute *newattrs,
Attribute *oldattrs )
{
struct berval ix_at;
AttrInfo *ai;
/* check if modified attribute was indexed
* but not in case of NOOP... */
ai = mdb_index_mask( op->o_bd, desc, &ix_at );
if ( ai ) {
if ( got_delete ) {
Attribute *ap;
struct berval ix2;
ap = attr_find( oldattrs, desc );
if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL;
/* Find all other attrs that index to same slot */
for ( ap = newattrs; ap; ap = ap->a_next ) {
ai = mdb_index_mask( op->o_bd, ap->a_desc, &ix2 );
if ( ai && ix2.bv_val == ix_at.bv_val )
ap->a_flags |= SLAP_ATTR_IXADD;
}
} else {
Attribute *ap;
ap = attr_find( newattrs, desc );
if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD;
}
}
}
int mdb_modify_internal(
Operation *op,
MDB_txn *tid,
Modifications *modlist,
Entry *e,
const char **text,
char *textbuf,
size_t textlen )
{
int rc, err;
Modification *mod;
Modifications *ml;
Attribute *save_attrs;
Attribute *ap;
int glue_attr_delete = 0;
int got_delete;
Debug( LDAP_DEBUG_TRACE, "mdb_modify_internal: 0x%08lx: %s\n",
e->e_id, e->e_dn, 0);
if ( !acl_check_modlist( op, e, modlist )) {
return LDAP_INSUFFICIENT_ACCESS;
}
/* save_attrs will be disposed of by mdb_cache_modify */
save_attrs = e->e_attrs;
e->e_attrs = attrs_dup( e->e_attrs );
for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
int match;
mod = &ml->sml_mod;
switch( mod->sm_op ) {
case LDAP_MOD_ADD:
case LDAP_MOD_REPLACE:
if ( mod->sm_desc == slap_schema.si_ad_structuralObjectClass ) {
value_match( &match, slap_schema.si_ad_structuralObjectClass,
slap_schema.si_ad_structuralObjectClass->
ad_type->sat_equality,
SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
&mod->sm_values[0], &scbva[0], text );
if ( !match ) glue_attr_delete = 1;
}
}
if ( glue_attr_delete )
break;
}
if ( glue_attr_delete ) {
Attribute **app = &e->e_attrs;
while ( *app != NULL ) {
if ( !is_at_operational( (*app)->a_desc->ad_type )) {
Attribute *save = *app;
*app = (*app)->a_next;
attr_free( save );
continue;
}
app = &(*app)->a_next;
}
}
for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
mod = &ml->sml_mod;
got_delete = 0;
switch ( mod->sm_op ) {
case LDAP_MOD_ADD:
Debug(LDAP_DEBUG_ARGS,
"mdb_modify_internal: add %s\n",
mod->sm_desc->ad_cname.bv_val, 0, 0);
err = modify_add_values( e, mod, get_permissiveModify(op),
text, textbuf, textlen );
if( err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
err, *text, 0);
}
break;
case LDAP_MOD_DELETE:
if ( glue_attr_delete ) {
err = LDAP_SUCCESS;
break;
}
Debug(LDAP_DEBUG_ARGS,
"mdb_modify_internal: delete %s\n",
mod->sm_desc->ad_cname.bv_val, 0, 0);
err = modify_delete_values( e, mod, get_permissiveModify(op),
text, textbuf, textlen );
if( err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
err, *text, 0);
} else {
got_delete = 1;
}
break;
case LDAP_MOD_REPLACE:
Debug(LDAP_DEBUG_ARGS,
"mdb_modify_internal: replace %s\n",
mod->sm_desc->ad_cname.bv_val, 0, 0);
err = modify_replace_values( e, mod, get_permissiveModify(op),
text, textbuf, textlen );
if( err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
err, *text, 0);
} else {
got_delete = 1;
}
break;
case LDAP_MOD_INCREMENT:
Debug(LDAP_DEBUG_ARGS,
"mdb_modify_internal: increment %s\n",
mod->sm_desc->ad_cname.bv_val, 0, 0);
err = modify_increment_values( e, mod, get_permissiveModify(op),
text, textbuf, textlen );
if( err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_ARGS,
"mdb_modify_internal: %d %s\n",
err, *text, 0);
} else {
got_delete = 1;
}
break;
case SLAP_MOD_SOFTADD:
Debug(LDAP_DEBUG_ARGS,
"mdb_modify_internal: softadd %s\n",
mod->sm_desc->ad_cname.bv_val, 0, 0);
/* Avoid problems in index_add_mods()
* We need to add index if necessary.
*/
mod->sm_op = LDAP_MOD_ADD;
err = modify_add_values( e, mod, get_permissiveModify(op),
text, textbuf, textlen );
mod->sm_op = SLAP_MOD_SOFTADD;
if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
err = LDAP_SUCCESS;
}
if( err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
err, *text, 0);
}
break;
case SLAP_MOD_SOFTDEL:
Debug(LDAP_DEBUG_ARGS,
"mdb_modify_internal: softdel %s\n",
mod->sm_desc->ad_cname.bv_val, 0, 0);
/* Avoid problems in index_delete_mods()
* We need to add index if necessary.
*/
mod->sm_op = LDAP_MOD_DELETE;
err = modify_delete_values( e, mod, get_permissiveModify(op),
text, textbuf, textlen );
mod->sm_op = SLAP_MOD_SOFTDEL;
if ( err == LDAP_NO_SUCH_ATTRIBUTE ) {
err = LDAP_SUCCESS;
}
if( err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
err, *text, 0);
}
break;
case SLAP_MOD_ADD_IF_NOT_PRESENT:
if ( attr_find( e->e_attrs, mod->sm_desc ) != NULL ) {
/* skip */
err = LDAP_SUCCESS;
break;
}
Debug(LDAP_DEBUG_ARGS,
"mdb_modify_internal: add_if_not_present %s\n",
mod->sm_desc->ad_cname.bv_val, 0, 0);
/* Avoid problems in index_add_mods()
* We need to add index if necessary.
*/
mod->sm_op = LDAP_MOD_ADD;
err = modify_add_values( e, mod, get_permissiveModify(op),
text, textbuf, textlen );
mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
if( err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
err, *text, 0);
}
break;
default:
Debug(LDAP_DEBUG_ANY, "mdb_modify_internal: invalid op %d\n",
mod->sm_op, 0, 0);
*text = "Invalid modify operation";
err = LDAP_OTHER;
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
err, *text, 0);
}
if ( err != LDAP_SUCCESS ) {
attrs_free( e->e_attrs );
e->e_attrs = save_attrs;
/* unlock entry, delete from cache */
return err;
}
/* If objectClass was modified, reset the flags */
if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
e->e_ocflags = 0;
}
if ( glue_attr_delete ) e->e_ocflags = 0;
/* check if modified attribute was indexed
* but not in case of NOOP... */
if ( !op->o_noop ) {
mdb_modify_idxflags( op, mod->sm_desc, got_delete, e->e_attrs, save_attrs );
}
}
/* check that the entry still obeys the schema */
ap = NULL;
rc = entry_schema_check( op, e, save_attrs, get_relax(op), 0, &ap,
text, textbuf, textlen );
if ( rc != LDAP_SUCCESS || op->o_noop ) {
attrs_free( e->e_attrs );
/* clear the indexing flags */
for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
ap->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL);
}
e->e_attrs = save_attrs;
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY,
"entry failed schema check: %s\n",
*text, 0, 0 );
}
/* if NOOP then silently revert to saved attrs */
return rc;
}
/* structuralObjectClass modified! */
if ( ap ) {
assert( ap->a_desc == slap_schema.si_ad_structuralObjectClass );
if ( !op->o_noop ) {
mdb_modify_idxflags( op, slap_schema.si_ad_structuralObjectClass,
1, e->e_attrs, save_attrs );
}
}
/* update the indices of the modified attributes */
/* start with deleting the old index entries */
for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
if ( ap->a_flags & SLAP_ATTR_IXDEL ) {
struct berval *vals;
Attribute *a2;
ap->a_flags &= ~SLAP_ATTR_IXDEL;
a2 = attr_find( e->e_attrs, ap->a_desc );
if ( a2 ) {
/* need to detect which values were deleted */
int i, j;
vals = op->o_tmpalloc( (ap->a_numvals + 1) *
sizeof(struct berval), op->o_tmpmemctx );
j = 0;
for ( i=0; i < ap->a_numvals; i++ ) {
rc = attr_valfind( a2, SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
&ap->a_nvals[i], NULL, op->o_tmpmemctx );
/* Save deleted values */
if ( rc == LDAP_NO_SUCH_ATTRIBUTE )
vals[j++] = ap->a_nvals[i];
}
BER_BVZERO(vals+j);
} else {
/* attribute was completely deleted */
vals = ap->a_nvals;
}
rc = 0;
if ( !BER_BVISNULL( vals )) {
rc = mdb_index_values( op, tid, ap->a_desc,
vals, e->e_id, SLAP_INDEX_DELETE_OP );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY,
"%s: attribute \"%s\" index delete failure\n",
op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 );
attrs_free( e->e_attrs );
e->e_attrs = save_attrs;
}
}
if ( vals != ap->a_nvals )
op->o_tmpfree( vals, op->o_tmpmemctx );
if ( rc ) return rc;
}
}
/* add the new index entries */
for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
if (ap->a_flags & SLAP_ATTR_IXADD) {
ap->a_flags &= ~SLAP_ATTR_IXADD;
rc = mdb_index_values( op, tid, ap->a_desc,
ap->a_nvals,
e->e_id, SLAP_INDEX_ADD_OP );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY,
"%s: attribute \"%s\" index add failure\n",
op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 );
attrs_free( e->e_attrs );
e->e_attrs = save_attrs;
return rc;
}
}
}
return rc;
}
int
mdb_modify( Operation *op, SlapReply *rs )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
Entry *e = NULL;
int manageDSAit = get_manageDSAit( op );
char textbuf[SLAP_TEXT_BUFLEN];
size_t textlen = sizeof textbuf;
MDB_txn *txn = NULL;
mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
Entry dummy = {0};
LDAPControl **preread_ctrl = NULL;
LDAPControl **postread_ctrl = NULL;
LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
int num_ctrls = 0;
#ifdef LDAP_X_TXN
int settle = 0;
#endif
Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(mdb_modify) ": %s\n",
op->o_req_dn.bv_val, 0, 0 );
#ifdef LDAP_X_TXN
if( op->o_txnSpec ) {
/* acquire connection lock */
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
rs->sr_text = "invalid transaction identifier";
rs->sr_err = LDAP_X_TXN_ID_INVALID;
goto txnReturn;
} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
settle=1;
goto txnReturn;
}
if( op->o_conn->c_txn_backend == NULL ) {
op->o_conn->c_txn_backend = op->o_bd;
} else if( op->o_conn->c_txn_backend != op->o_bd ) {
rs->sr_text = "transaction cannot span multiple database contexts";
rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
goto txnReturn;
}
/* insert operation into transaction */
rs->sr_text = "transaction specified";
rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
txnReturn:
/* release connection lock */
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
if( !settle ) {
send_ldap_result( op, rs );
return rs->sr_err;
}
}
#endif
ctrls[num_ctrls] = NULL;
/* Don't touch the opattrs, if this is a contextCSN update
* initiated from updatedn */
if ( !be_isupdate(op) || !op->orm_modlist || op->orm_modlist->sml_next ||
op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) {
slap_mods_opattrs( op, &op->orm_modlist, 1 );
}
/* begin transaction */
rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
rs->sr_text = NULL;
if( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modify) ": txn_begin failed: "
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
txn = moi->moi_txn;
/* get entry or ancestor */
rs->sr_err = mdb_dn2entry( op, txn, &op->o_req_ndn, &e, 1 );
if ( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modify) ": dn2entry failed (%d)\n",
rs->sr_err, 0, 0 );
switch( rs->sr_err ) {
case MDB_NOTFOUND:
break;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
}
/* acquire and lock entry */
/* FIXME: dn2entry() should return non-glue entry */
if (( rs->sr_err == MDB_NOTFOUND ) ||
( !manageDSAit && e && is_entry_glue( e )))
{
if ( e != NULL ) {
rs->sr_matched = ch_strdup( e->e_dn );
if ( is_entry_referral( e )) {
BerVarray ref = get_entry_referrals( op, e );
rs->sr_ref = referral_rewrite( ref, &e->e_name,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
ber_bvarray_free( ref );
} else {
rs->sr_ref = NULL;
}
mdb_entry_return( e );
e = NULL;
} else {
rs->sr_ref = referral_rewrite( default_referral, NULL,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
}
rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
rs->sr_err = LDAP_REFERRAL;
send_ldap_result( op, rs );
goto done;
}
if ( !manageDSAit && is_entry_referral( e ) ) {
/* entry is a referral, don't allow modify */
rs->sr_ref = get_entry_referrals( op, e );
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modify) ": entry is referral\n",
0, 0, 0 );
rs->sr_err = LDAP_REFERRAL;
rs->sr_matched = e->e_name.bv_val;
rs->sr_flags = REP_REF_MUSTBEFREED;
send_ldap_result( op, rs );
rs->sr_matched = NULL;
goto done;
}
if ( get_assert( op ) &&
( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
{
rs->sr_err = LDAP_ASSERTION_FAILED;
goto return_results;
}
if( op->o_preread ) {
if( preread_ctrl == NULL ) {
preread_ctrl = &ctrls[num_ctrls++];
ctrls[num_ctrls] = NULL;
}
if ( slap_read_controls( op, rs, e,
&slap_pre_read_bv, preread_ctrl ) )
{
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_modify) ": pre-read "
"failed!\n", 0, 0, 0 );
if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
/* FIXME: is it correct to abort
* operation if control fails? */
goto return_results;
}
}
}
/* Modify the entry */
dummy = *e;
rs->sr_err = mdb_modify_internal( op, txn, op->orm_modlist,
&dummy, &rs->sr_text, textbuf, textlen );
if( rs->sr_err != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modify) ": modify failed (%d)\n",
rs->sr_err, 0, 0 );
/* Only free attrs if they were dup'd. */
if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
goto return_results;
}
/* change the entry itself */
rs->sr_err = mdb_id2entry_update( op, txn, &dummy );
if ( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modify) ": id2entry update failed " "(%d)\n",
rs->sr_err, 0, 0 );
rs->sr_text = "entry update failed";
goto return_results;
}
if( op->o_postread ) {
if( postread_ctrl == NULL ) {
postread_ctrl = &ctrls[num_ctrls++];
ctrls[num_ctrls] = NULL;
}
if( slap_read_controls( op, rs, &dummy,
&slap_post_read_bv, postread_ctrl ) )
{
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_modify)
": post-read failed!\n", 0, 0, 0 );
if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
/* FIXME: is it correct to abort
* operation if control fails? */
goto return_results;
}
}
}
/* Only free attrs if they were dup'd. */
if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
if( moi == &opinfo ) {
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
opinfo.moi_oe.oe_key = NULL;
if( op->o_noop ) {
mdb_txn_abort( txn );
rs->sr_err = LDAP_X_NO_OPERATION;
txn = NULL;
goto return_results;
} else {
rs->sr_err = mdb_txn_commit( txn );
txn = NULL;
}
}
if( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modify) ": txn_%s failed: %s (%d)\n",
op->o_noop ? "abort (no-op)" : "commit",
mdb_strerror(rs->sr_err), rs->sr_err );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "commit failed";
goto return_results;
}
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modify) ": updated%s id=%08lx dn=\"%s\"\n",
op->o_noop ? " (no-op)" : "",
dummy.e_id, op->o_req_dn.bv_val );
rs->sr_err = LDAP_SUCCESS;
rs->sr_text = NULL;
if( num_ctrls ) rs->sr_ctrls = ctrls;
return_results:
if( dummy.e_attrs ) {
attrs_free( dummy.e_attrs );
}
send_ldap_result( op, rs );
#if 0
if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
TXN_CHECKPOINT( mdb->bi_dbenv,
mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
}
#endif
done:
slap_graduate_commit_csn( op );
if( moi == &opinfo ) {
if( txn != NULL ) {
mdb_txn_abort( txn );
}
if ( opinfo.moi_oe.oe_key ) {
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
}
}
if( e != NULL ) {
mdb_entry_return( e );
}
if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
}
if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
}
rs->sr_text = NULL;
return rs->sr_err;
}

View file

@ -0,0 +1,655 @@
/* modrdn.c - mdb backend modrdn routine */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "back-mdb.h"
int
mdb_modrdn( Operation *op, SlapReply *rs )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
AttributeDescription *children = slap_schema.si_ad_children;
AttributeDescription *entry = slap_schema.si_ad_entry;
struct berval p_dn, p_ndn;
struct berval new_dn = {0, NULL}, new_ndn = {0, NULL};
Entry *e = NULL;
Entry *p = NULL;
/* LDAP v2 supporting correct attribute handling. */
char textbuf[SLAP_TEXT_BUFLEN];
size_t textlen = sizeof textbuf;
MDB_txn *txn = NULL;
struct mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
Entry dummy = {0};
Entry *np = NULL; /* newSuperior Entry */
struct berval *np_dn = NULL; /* newSuperior dn */
struct berval *np_ndn = NULL; /* newSuperior ndn */
struct berval *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */
int manageDSAit = get_manageDSAit( op );
ID nid;
LDAPControl **preread_ctrl = NULL;
LDAPControl **postread_ctrl = NULL;
LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
int num_ctrls = 0;
int parent_is_glue = 0;
int parent_is_leaf = 0;
#ifdef LDAP_X_TXN
int settle = 0;
#endif
Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(mdb_modrdn) "(%s,%s,%s)\n",
op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
#ifdef LDAP_X_TXN
if( op->o_txnSpec ) {
/* acquire connection lock */
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
rs->sr_text = "invalid transaction identifier";
rs->sr_err = LDAP_X_TXN_ID_INVALID;
goto txnReturn;
} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
settle=1;
goto txnReturn;
}
if( op->o_conn->c_txn_backend == NULL ) {
op->o_conn->c_txn_backend = op->o_bd;
} else if( op->o_conn->c_txn_backend != op->o_bd ) {
rs->sr_text = "transaction cannot span multiple database contexts";
rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
goto txnReturn;
}
/* insert operation into transaction */
rs->sr_text = "transaction specified";
rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
txnReturn:
/* release connection lock */
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
if( !settle ) {
send_ldap_result( op, rs );
return rs->sr_err;
}
}
#endif
ctrls[num_ctrls] = NULL;
slap_mods_opattrs( op, &op->orr_modlist, 1 );
/* begin transaction */
rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
rs->sr_text = NULL;
if( rs->sr_err != 0 ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn) ": txn_begin failed: "
"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
txn = moi->moi_txn;
if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
#ifdef MDB_MULTIPLE_SUFFIXES
/* Allow renaming one suffix entry to another */
p_ndn = slap_empty_bv;
#else
/* There can only be one suffix entry */
rs->sr_err = LDAP_NAMING_VIOLATION;
rs->sr_text = "cannot rename suffix entry";
goto return_results;
#endif
} else {
dnParent( &op->o_req_ndn, &p_ndn );
}
np_ndn = &p_ndn;
/* Make sure parent entry exist and we can write its
* children.
*/
rs->sr_err = mdb_dn2entry( op, txn, &p_ndn, &p, 0 );
switch( rs->sr_err ) {
case MDB_NOTFOUND:
Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn)
": parent does not exist\n", 0, 0, 0);
rs->sr_ref = referral_rewrite( default_referral, NULL,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
rs->sr_err = LDAP_REFERRAL;
send_ldap_result( op, rs );
ber_bvarray_free( rs->sr_ref );
goto done;
case 0:
break;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
/* check parent for "children" acl */
rs->sr_err = access_allowed( op, p,
children, NULL,
op->oq_modrdn.rs_newSup == NULL ?
ACL_WRITE : ACL_WDEL,
NULL );
if ( ! rs->sr_err ) {
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
0, 0 );
rs->sr_text = "no write access to parent's children";
goto return_results;
}
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn) ": wr to children "
"of entry %s OK\n", p_ndn.bv_val, 0, 0 );
if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
p_dn = slap_empty_bv;
} else {
dnParent( &op->o_req_dn, &p_dn );
}
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn) ": parent dn=%s\n",
p_dn.bv_val, 0, 0 );
/* get entry */
rs->sr_err = mdb_dn2entry( op, txn, &op->o_req_ndn, &e, 0 );
switch( rs->sr_err ) {
case MDB_NOTFOUND:
e = p;
p = NULL;
case 0:
break;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
/* FIXME: dn2entry() should return non-glue entry */
if (( rs->sr_err == MDB_NOTFOUND ) ||
( !manageDSAit && e && is_entry_glue( e )))
{
if( e != NULL ) {
rs->sr_matched = ch_strdup( e->e_dn );
if ( is_entry_referral( e )) {
BerVarray ref = get_entry_referrals( op, e );
rs->sr_ref = referral_rewrite( ref, &e->e_name,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
ber_bvarray_free( ref );
} else {
rs->sr_ref = NULL;
}
mdb_entry_return( e );
e = NULL;
} else {
rs->sr_ref = referral_rewrite( default_referral, NULL,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
}
rs->sr_err = LDAP_REFERRAL;
send_ldap_result( op, rs );
ber_bvarray_free( rs->sr_ref );
free( (char *)rs->sr_matched );
rs->sr_ref = NULL;
rs->sr_matched = NULL;
goto done;
}
if ( get_assert( op ) &&
( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
{
rs->sr_err = LDAP_ASSERTION_FAILED;
goto return_results;
}
/* check write on old entry */
rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL );
if ( ! rs->sr_err ) {
Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
0, 0 );
rs->sr_text = "no write access to old entry";
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
goto return_results;
}
if (!manageDSAit && is_entry_referral( e ) ) {
/* entry is a referral, don't allow rename */
rs->sr_ref = get_entry_referrals( op, e );
Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn)
": entry %s is referral\n", e->e_dn, 0, 0 );
rs->sr_err = LDAP_REFERRAL,
rs->sr_matched = e->e_name.bv_val;
send_ldap_result( op, rs );
ber_bvarray_free( rs->sr_ref );
rs->sr_ref = NULL;
rs->sr_matched = NULL;
goto done;
}
new_parent_dn = &p_dn; /* New Parent unless newSuperior given */
if ( op->oq_modrdn.rs_newSup != NULL ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn)
": new parent \"%s\" requested...\n",
op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
/* newSuperior == oldParent? */
if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) {
Debug( LDAP_DEBUG_TRACE, "mdb_back_modrdn: "
"new parent \"%s\" same as the old parent \"%s\"\n",
op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */
}
}
/* There's a MDB_MULTIPLE_SUFFIXES case here that this code doesn't
* support. E.g., two suffixes dc=foo,dc=com and dc=bar,dc=net.
* We do not allow modDN
* dc=foo,dc=com
* newrdn dc=bar
* newsup dc=net
* and we probably should. But since MULTIPLE_SUFFIXES is deprecated
* I'm ignoring this problem for now.
*/
if ( op->oq_modrdn.rs_newSup != NULL ) {
if ( op->oq_modrdn.rs_newSup->bv_len ) {
np_dn = op->oq_modrdn.rs_newSup;
np_ndn = op->oq_modrdn.rs_nnewSup;
/* newSuperior == oldParent? - checked above */
/* newSuperior == entry being moved?, if so ==> ERROR */
if ( dnIsSuffix( np_ndn, &e->e_nname )) {
rs->sr_err = LDAP_NO_SUCH_OBJECT;
rs->sr_text = "new superior not found";
goto return_results;
}
/* Get Entry with dn=newSuperior. Does newSuperior exist? */
rs->sr_err = mdb_dn2entry( op, txn, np_ndn, &np, 0 );
switch( rs->sr_err ) {
case 0:
break;
case MDB_NOTFOUND:
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn)
": newSup(ndn=%s) not here!\n",
np_ndn->bv_val, 0, 0);
rs->sr_text = "new superior not found";
rs->sr_err = LDAP_NO_SUCH_OBJECT;
goto return_results;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
/* check newSuperior for "children" acl */
rs->sr_err = access_allowed( op, np, children,
NULL, ACL_WADD, NULL );
if( ! rs->sr_err ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn)
": no wr to newSup children\n",
0, 0, 0 );
rs->sr_text = "no write access to new superior's children";
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
goto return_results;
}
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn)
": wr to new parent OK np=%p, id=%ld\n",
(void *) np, (long) np->e_id, 0 );
if ( is_entry_alias( np ) ) {
/* parent is an alias, don't allow add */
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn)
": entry is alias\n",
0, 0, 0 );
rs->sr_text = "new superior is an alias";
rs->sr_err = LDAP_ALIAS_PROBLEM;
goto return_results;
}
if ( is_entry_referral( np ) ) {
/* parent is a referral, don't allow add */
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn)
": entry is referral\n",
0, 0, 0 );
rs->sr_text = "new superior is a referral";
rs->sr_err = LDAP_OTHER;
goto return_results;
}
new_parent_dn = &np->e_name;
} else {
np_dn = NULL;
/* no parent, modrdn entry directly under root */
if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
|| be_isupdate( op ) ) {
np = (Entry *)&slap_entry_root;
/* check parent for "children" acl */
rs->sr_err = access_allowed( op, np,
children, NULL, ACL_WADD, NULL );
np = NULL;
if ( ! rs->sr_err ) {
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
Debug( LDAP_DEBUG_TRACE,
"no access to new superior\n",
0, 0, 0 );
rs->sr_text =
"no write access to new superior's children";
goto return_results;
}
}
}
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn)
": wr to new parent's children OK\n",
0, 0, 0 );
new_parent_dn = np_dn;
}
/* Build target dn and make sure target entry doesn't exist already. */
if (!new_dn.bv_val) {
build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, op->o_tmpmemctx );
}
if (!new_ndn.bv_val) {
dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, op->o_tmpmemctx );
}
Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn) ": new ndn=%s\n",
new_ndn.bv_val, 0, 0 );
/* Shortcut the search */
rs->sr_err = mdb_dn2id ( op, txn, &new_ndn, &nid, NULL, NULL );
switch( rs->sr_err ) {
case MDB_NOTFOUND:
break;
case 0:
/* Allow rename to same DN */
if ( nid == e->e_id )
break;
rs->sr_err = LDAP_ALREADY_EXISTS;
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
assert( op->orr_modlist != NULL );
if( op->o_preread ) {
if( preread_ctrl == NULL ) {
preread_ctrl = &ctrls[num_ctrls++];
ctrls[num_ctrls] = NULL;
}
if( slap_read_controls( op, rs, e,
&slap_pre_read_bv, preread_ctrl ) )
{
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_modrdn)
": pre-read failed!\n", 0, 0, 0 );
if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
/* FIXME: is it correct to abort
* operation if control fails? */
goto return_results;
}
}
}
/* delete old DN */
rs->sr_err = mdb_dn2id_delete( op, txn, p->e_id, e );
if ( rs->sr_err != 0 ) {
Debug(LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_modrdn)
": dn2id del failed: %s (%d)\n",
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "DN index delete fail";
goto return_results;
}
/* copy the entry, then override some fields */
dummy = *e;
dummy.e_name = new_dn;
dummy.e_nname = new_ndn;
dummy.e_attrs = NULL;
/* add new DN */
rs->sr_err = mdb_dn2id_add( op, txn, np ? np->e_id : p->e_id, &dummy );
if ( rs->sr_err != 0 ) {
Debug(LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_modrdn)
": dn2id add failed: %s (%d)\n",
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "DN index add failed";
goto return_results;
}
dummy.e_attrs = e->e_attrs;
/* modify entry */
rs->sr_err = mdb_modify_internal( op, txn, op->orr_modlist, &dummy,
&rs->sr_text, textbuf, textlen );
if( rs->sr_err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_modrdn)
": modify failed: %s (%d)\n",
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
goto return_results;
}
/* id2entry index */
rs->sr_err = mdb_id2entry_update( op, txn, &dummy );
if ( rs->sr_err != 0 ) {
Debug(LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_modrdn)
": id2entry failed: %s (%d)\n",
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "entry update failed";
goto return_results;
}
if ( p_ndn.bv_len != 0 ) {
parent_is_glue = is_entry_glue(p);
rs->sr_err = mdb_dn2id_children( op, txn, p );
if ( rs->sr_err != MDB_NOTFOUND ) {
switch( rs->sr_err ) {
case 0:
break;
default:
Debug(LDAP_DEBUG_ARGS,
"<=- " LDAP_XSTRING(mdb_modrdn)
": has_children failed: %s (%d)\n",
mdb_strerror(rs->sr_err), rs->sr_err, 0 );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
parent_is_leaf = 1;
}
mdb_entry_return( p );
p = NULL;
}
if( op->o_postread ) {
if( postread_ctrl == NULL ) {
postread_ctrl = &ctrls[num_ctrls++];
ctrls[num_ctrls] = NULL;
}
if( slap_read_controls( op, rs, &dummy,
&slap_post_read_bv, postread_ctrl ) )
{
Debug( LDAP_DEBUG_TRACE,
"<=- " LDAP_XSTRING(mdb_modrdn)
": post-read failed!\n", 0, 0, 0 );
if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
/* FIXME: is it correct to abort
* operation if control fails? */
goto return_results;
}
}
}
if( moi == &opinfo ) {
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
opinfo.moi_oe.oe_key = NULL;
if( op->o_noop ) {
mdb_txn_abort( txn );
rs->sr_err = LDAP_X_NO_OPERATION;
txn = NULL;
/* Only free attrs if they were dup'd. */
if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
goto return_results;
} else {
if(( rs->sr_err=mdb_txn_commit( txn )) != 0 ) {
rs->sr_text = "txn_commit failed";
} else {
rs->sr_err = LDAP_SUCCESS;
}
txn = NULL;
}
}
if( rs->sr_err != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn) ": %s : %s (%d)\n",
rs->sr_text, mdb_strerror(rs->sr_err), rs->sr_err );
rs->sr_err = LDAP_OTHER;
goto return_results;
}
Debug(LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_modrdn)
": rdn modified%s id=%08lx dn=\"%s\"\n",
op->o_noop ? " (no-op)" : "",
dummy.e_id, op->o_req_dn.bv_val );
rs->sr_text = NULL;
if( num_ctrls ) rs->sr_ctrls = ctrls;
return_results:
if ( dummy.e_attrs ) {
attrs_free( dummy.e_attrs );
}
send_ldap_result( op, rs );
#if 0
if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
TXN_CHECKPOINT( mdb->bi_dbenv,
mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
}
#endif
if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
op->o_delete_glue_parent = 1;
}
done:
slap_graduate_commit_csn( op );
if( new_ndn.bv_val != NULL ) op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
if( new_dn.bv_val != NULL ) op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
/* LDAP v3 Support */
if( np != NULL ) {
/* free new parent */
mdb_entry_return( np );
}
if( p != NULL ) {
/* free parent */
mdb_entry_return( p );
}
/* free entry */
if( e != NULL ) {
mdb_entry_return( e );
}
if( moi == &opinfo ) {
if( txn != NULL ) {
mdb_txn_abort( txn );
}
if ( opinfo.moi_oe.oe_key ) {
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
}
}
if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
}
if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
}
return rs->sr_err;
}

View file

@ -0,0 +1,656 @@
/* monitor.c - monitor mdb backend */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/unistd.h>
#include <ac/stdlib.h>
#include <ac/errno.h>
#include <sys/stat.h>
#include "lutil.h"
#include "back-mdb.h"
#include "../back-monitor/back-monitor.h"
#include "config.h"
static ObjectClass *oc_olmMDBDatabase;
static AttributeDescription *ad_olmDbDirectory;
#ifdef MDB_MONITOR_IDX
static int
mdb_monitor_idx_entry_add(
struct mdb_info *mdb,
Entry *e );
static AttributeDescription *ad_olmMDBNotIndexed;
#endif /* MDB_MONITOR_IDX */
/*
* NOTE: there's some confusion in monitor OID arc;
* by now, let's consider:
*
* Subsystems monitor attributes 1.3.6.1.4.1.4203.666.1.55.0
* Databases monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1
* MDB database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.1
*
* Subsystems monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0
* Databases monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1
* MDB database monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1.1
*/
static struct {
char *name;
char *oid;
} s_oid[] = {
{ "olmMDBAttributes", "olmDatabaseAttributes:1" },
{ "olmMDBObjectClasses", "olmDatabaseObjectClasses:1" },
{ NULL }
};
static struct {
char *desc;
AttributeDescription **ad;
} s_at[] = {
{ "( olmMDBAttributes:4 "
"NAME ( 'olmDbDirectory' ) "
"DESC 'Path name of the directory "
"where the database environment resides' "
"SUP monitoredInfo "
"NO-USER-MODIFICATION "
"USAGE dSAOperation )",
&ad_olmDbDirectory },
#ifdef MDB_MONITOR_IDX
{ "( olmMDBAttributes:5 "
"NAME ( 'olmMDBNotIndexed' ) "
"DESC 'Missing indexes resulting from candidate selection' "
"SUP monitoredInfo "
"NO-USER-MODIFICATION "
"USAGE dSAOperation )",
&ad_olmMDBNotIndexed },
#endif /* MDB_MONITOR_IDX */
{ NULL }
};
static struct {
char *desc;
ObjectClass **oc;
} s_oc[] = {
/* augments an existing object, so it must be AUXILIARY
* FIXME: derive from some ABSTRACT "monitoredEntity"? */
{ "( olmMDBObjectClasses:2 "
"NAME ( 'olmMDBDatabase' ) "
"SUP top AUXILIARY "
"MAY ( "
"olmDbDirectory "
#ifdef MDB_MONITOR_IDX
"$ olmMDBNotIndexed "
#endif /* MDB_MONITOR_IDX */
") )",
&oc_olmMDBDatabase },
{ NULL }
};
static int
mdb_monitor_update(
Operation *op,
SlapReply *rs,
Entry *e,
void *priv )
{
struct mdb_info *mdb = (struct mdb_info *) priv;
#ifdef MDB_MONITOR_IDX
mdb_monitor_idx_entry_add( mdb, e );
#endif /* MDB_MONITOR_IDX */
return SLAP_CB_CONTINUE;
}
#if 0 /* uncomment if required */
static int
mdb_monitor_modify(
Operation *op,
SlapReply *rs,
Entry *e,
void *priv )
{
return SLAP_CB_CONTINUE;
}
#endif
static int
mdb_monitor_free(
Entry *e,
void **priv )
{
struct berval values[ 2 ];
Modification mod = { 0 };
const char *text;
char textbuf[ SLAP_TEXT_BUFLEN ];
int i, rc;
/* NOTE: if slap_shutdown != 0, priv might have already been freed */
*priv = NULL;
/* Remove objectClass */
mod.sm_op = LDAP_MOD_DELETE;
mod.sm_desc = slap_schema.si_ad_objectClass;
mod.sm_values = values;
mod.sm_numvals = 1;
values[ 0 ] = oc_olmMDBDatabase->soc_cname;
BER_BVZERO( &values[ 1 ] );
rc = modify_delete_values( e, &mod, 1, &text,
textbuf, sizeof( textbuf ) );
/* don't care too much about return code... */
/* remove attrs */
mod.sm_values = NULL;
mod.sm_numvals = 0;
for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
mod.sm_desc = *s_at[ i ].ad;
rc = modify_delete_values( e, &mod, 1, &text,
textbuf, sizeof( textbuf ) );
/* don't care too much about return code... */
}
return SLAP_CB_CONTINUE;
}
/*
* call from within mdb_initialize()
*/
static int
mdb_monitor_initialize( void )
{
int i, code;
ConfigArgs c;
char *argv[ 3 ];
static int mdb_monitor_initialized = 0;
/* set to 0 when successfully initialized; otherwise, remember failure */
static int mdb_monitor_initialized_failure = 1;
if ( mdb_monitor_initialized++ ) {
return mdb_monitor_initialized_failure;
}
if ( backend_info( "monitor" ) == NULL ) {
return -1;
}
/* register schema here */
argv[ 0 ] = "back-mdb monitor";
c.argv = argv;
c.argc = 3;
c.fname = argv[0];
for ( i = 0; s_oid[ i ].name; i++ ) {
c.lineno = i;
argv[ 1 ] = s_oid[ i ].name;
argv[ 2 ] = s_oid[ i ].oid;
if ( parse_oidm( &c, 0, NULL ) != 0 ) {
Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
": unable to add "
"objectIdentifier \"%s=%s\"\n",
s_oid[ i ].name, s_oid[ i ].oid, 0 );
return 2;
}
}
for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
if ( code != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
": register_at failed for attributeType (%s)\n",
s_at[ i ].desc, 0, 0 );
return 3;
} else {
(*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
}
}
for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
if ( code != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
": register_oc failed for objectClass (%s)\n",
s_oc[ i ].desc, 0, 0 );
return 4;
} else {
(*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
}
}
return ( mdb_monitor_initialized_failure = LDAP_SUCCESS );
}
/*
* call from within mdb_db_init()
*/
int
mdb_monitor_db_init( BackendDB *be )
{
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
if ( mdb_monitor_initialize() == LDAP_SUCCESS ) {
/* monitoring in back-mdb is on by default */
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
}
#ifdef MDB_MONITOR_IDX
mdb->mi_idx = NULL;
ldap_pvt_thread_mutex_init( &mdb->mi_idx_mutex );
#endif /* MDB_MONITOR_IDX */
return 0;
}
/*
* call from within mdb_db_open()
*/
int
mdb_monitor_db_open( BackendDB *be )
{
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
Attribute *a, *next;
monitor_callback_t *cb = NULL;
int rc = 0;
BackendInfo *mi;
monitor_extra_t *mbe;
struct berval dummy = BER_BVC("");
if ( !SLAP_DBMONITORING( be ) ) {
return 0;
}
mi = backend_info( "monitor" );
if ( !mi || !mi->bi_extra ) {
SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
return 0;
}
mbe = mi->bi_extra;
/* don't bother if monitor is not configured */
if ( !mbe->is_configured() ) {
static int warning = 0;
if ( warning++ == 0 ) {
Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_db_open)
": monitoring disabled; "
"configure monitor database to enable\n",
0, 0, 0 );
}
return 0;
}
/* alloc as many as required (plus 1 for objectClass) */
a = attrs_alloc( 1 + 1 );
if ( a == NULL ) {
rc = 1;
goto cleanup;
}
a->a_desc = slap_schema.si_ad_objectClass;
attr_valadd( a, &oc_olmMDBDatabase->soc_cname, NULL, 1 );
next = a->a_next;
{
struct berval bv, nbv;
ber_len_t pathlen = 0, len = 0;
char path[ MAXPATHLEN ] = { '\0' };
char *fname = mdb->mi_dbenv_home,
*ptr;
len = strlen( fname );
if ( fname[ 0 ] != '/' ) {
/* get full path name */
getcwd( path, sizeof( path ) );
pathlen = strlen( path );
if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
fname += 2;
len -= 2;
}
}
bv.bv_len = pathlen + STRLENOF( "/" ) + len;
ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
if ( pathlen ) {
ptr = lutil_strncopy( ptr, path, pathlen );
ptr[ 0 ] = '/';
ptr++;
}
ptr = lutil_strncopy( ptr, fname, len );
if ( ptr[ -1 ] != '/' ) {
ptr[ 0 ] = '/';
ptr++;
}
ptr[ 0 ] = '\0';
attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );
next->a_desc = ad_olmDbDirectory;
next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
next->a_vals[ 0 ] = bv;
next->a_numvals = 1;
if ( BER_BVISNULL( &nbv ) ) {
next->a_nvals = next->a_vals;
} else {
next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
next->a_nvals[ 0 ] = nbv;
}
next = next->a_next;
}
cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
cb->mc_update = mdb_monitor_update;
#if 0 /* uncomment if required */
cb->mc_modify = mdb_monitor_modify;
#endif
cb->mc_free = mdb_monitor_free;
cb->mc_private = (void *)mdb;
/* make sure the database is registered; then add monitor attributes */
rc = mbe->register_database( be, &mdb->mi_monitor.mdm_ndn );
if ( rc == 0 ) {
rc = mbe->register_entry_attrs( &mdb->mi_monitor.mdm_ndn, a, cb,
&dummy, 0, &dummy );
}
cleanup:;
if ( rc != 0 ) {
if ( cb != NULL ) {
ch_free( cb );
cb = NULL;
}
if ( a != NULL ) {
attrs_free( a );
a = NULL;
}
}
/* store for cleanup */
mdb->mi_monitor.mdm_cb = (void *)cb;
/* we don't need to keep track of the attributes, because
* mdb_monitor_free() takes care of everything */
if ( a != NULL ) {
attrs_free( a );
}
return rc;
}
/*
* call from within mdb_db_close()
*/
int
mdb_monitor_db_close( BackendDB *be )
{
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
if ( !BER_BVISNULL( &mdb->mi_monitor.mdm_ndn ) ) {
BackendInfo *mi = backend_info( "monitor" );
monitor_extra_t *mbe;
if ( mi && &mi->bi_extra ) {
mbe = mi->bi_extra;
mbe->unregister_entry_callback( &mdb->mi_monitor.mdm_ndn,
(monitor_callback_t *)mdb->mi_monitor.mdm_cb,
NULL, 0, NULL );
}
memset( &mdb->mi_monitor, 0, sizeof( mdb->mi_monitor ) );
}
return 0;
}
/*
* call from within mdb_db_destroy()
*/
int
mdb_monitor_db_destroy( BackendDB *be )
{
#ifdef MDB_MONITOR_IDX
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
/* TODO: free tree */
ldap_pvt_thread_mutex_destroy( &mdb->mi_idx_mutex );
avl_free( mdb->mi_idx, ch_free );
#endif /* MDB_MONITOR_IDX */
return 0;
}
#ifdef MDB_MONITOR_IDX
#define MDB_MONITOR_IDX_TYPES (4)
typedef struct monitor_idx_t monitor_idx_t;
struct monitor_idx_t {
AttributeDescription *idx_ad;
unsigned long idx_count[MDB_MONITOR_IDX_TYPES];
};
static int
mdb_monitor_bitmask2key( slap_mask_t bitmask )
{
int key;
for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U );
key++ )
bitmask >>= 1;
return key;
}
static struct berval idxbv[] = {
BER_BVC( "present=" ),
BER_BVC( "equality=" ),
BER_BVC( "approx=" ),
BER_BVC( "substr=" ),
BER_BVNULL
};
static ber_len_t
mdb_monitor_idx2len( monitor_idx_t *idx )
{
int i;
ber_len_t len = 0;
for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
if ( idx->idx_count[ i ] != 0 ) {
len += idxbv[i].bv_len;
}
}
return len;
}
static int
monitor_idx_cmp( const void *p1, const void *p2 )
{
const monitor_idx_t *idx1 = (const monitor_idx_t *)p1;
const monitor_idx_t *idx2 = (const monitor_idx_t *)p2;
return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad );
}
static int
monitor_idx_dup( void *p1, void *p2 )
{
monitor_idx_t *idx1 = (monitor_idx_t *)p1;
monitor_idx_t *idx2 = (monitor_idx_t *)p2;
return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0;
}
int
mdb_monitor_idx_add(
struct mdb_info *mdb,
AttributeDescription *desc,
slap_mask_t type )
{
monitor_idx_t idx_dummy = { 0 },
*idx;
int rc = 0, key;
idx_dummy.idx_ad = desc;
key = mdb_monitor_bitmask2key( type ) - 1;
if ( key >= MDB_MONITOR_IDX_TYPES ) {
/* invalid index type */
return -1;
}
ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
idx = (monitor_idx_t *)avl_find( mdb->mi_idx,
(caddr_t)&idx_dummy, monitor_idx_cmp );
if ( idx == NULL ) {
idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 );
idx->idx_ad = desc;
idx->idx_count[ key ] = 1;
switch ( avl_insert( &mdb->mi_idx, (caddr_t)idx,
monitor_idx_cmp, monitor_idx_dup ) )
{
case 0:
break;
default:
ch_free( idx );
rc = -1;
}
} else {
idx->idx_count[ key ]++;
}
ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
return rc;
}
static int
mdb_monitor_idx_apply( void *v_idx, void *v_valp )
{
monitor_idx_t *idx = (monitor_idx_t *)v_idx;
BerVarray *valp = (BerVarray *)v_valp;
struct berval bv;
char *ptr;
char count_buf[ MDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ];
ber_len_t count_len[ MDB_MONITOR_IDX_TYPES ],
idx_len;
int i, num = 0;
idx_len = mdb_monitor_idx2len( idx );
bv.bv_len = 0;
for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
if ( idx->idx_count[ i ] == 0 ) {
continue;
}
count_len[ i ] = snprintf( count_buf[ i ],
sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] );
bv.bv_len += count_len[ i ];
num++;
}
bv.bv_len += idx->idx_ad->ad_cname.bv_len
+ num
+ idx_len;
ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 );
ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val );
for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
if ( idx->idx_count[ i ] == 0 ) {
continue;
}
ptr[ 0 ] = '#';
++ptr;
ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val );
ptr = lutil_strcopy( ptr, count_buf[ i ] );
}
ber_bvarray_add( valp, &bv );
return 0;
}
static int
mdb_monitor_idx_entry_add(
struct mdb_info *mdb,
Entry *e )
{
BerVarray vals = NULL;
Attribute *a;
a = attr_find( e->e_attrs, ad_olmMDBNotIndexed );
ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
avl_apply( mdb->mi_idx, mdb_monitor_idx_apply,
&vals, -1, AVL_INORDER );
ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
if ( vals != NULL ) {
if ( a != NULL ) {
assert( a->a_nvals == a->a_vals );
ber_bvarray_free( a->a_vals );
} else {
Attribute **ap;
for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next )
;
*ap = attr_alloc( ad_olmMDBNotIndexed );
a = *ap;
}
a->a_vals = vals;
a->a_nvals = a->a_vals;
}
return 0;
}
#endif /* MDB_MONITOR_IDX */

View file

@ -0,0 +1,59 @@
/* init.c - initialize mdb backend */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "back-mdb.h"
int mdb_next_id( BackendDB *be, MDB_txn *tid, ID *out )
{
struct mdb_info *mdb = (struct mdb_info *) be->be_private;
int rc;
ID id = 0;
MDB_val key;
MDB_cursor *cursor;
/* Get a read cursor */
rc = mdb_cursor_open( tid, mdb->mi_id2entry, &cursor );
if (rc == 0) {
rc = mdb_cursor_get(cursor, &key, NULL, MDB_LAST);
mdb_cursor_close(cursor);
}
switch(rc) {
case MDB_NOTFOUND:
rc = 0;
*out = 1;
break;
case 0:
memcpy( &id, key.mv_data, sizeof( id ));
*out = ++id;
break;
default:
Debug( LDAP_DEBUG_ANY,
"=> mdb_next_id: get failed: %s (%d)\n",
mdb_strerror(rc), rc, 0 );
goto done;
}
done:
return rc;
}

View file

@ -0,0 +1,119 @@
/* operational.c - mdb backend operational attributes function */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "slap.h"
#include "back-mdb.h"
/*
* sets *hasSubordinates to LDAP_COMPARE_TRUE/LDAP_COMPARE_FALSE
* if the entry has children or not.
*/
int
mdb_hasSubordinates(
Operation *op,
Entry *e,
int *hasSubordinates )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
MDB_txn *rtxn;
mdb_op_info opinfo = {0}, *moi = &opinfo;
int rc;
assert( e != NULL );
rc = mdb_opinfo_get(op, mdb, 1, &moi);
switch(rc) {
case 0:
break;
default:
rc = LDAP_OTHER;
goto done;
}
rtxn = moi->moi_txn;
rc = mdb_dn2id_children( op, rtxn, e );
switch( rc ) {
case 0:
*hasSubordinates = LDAP_COMPARE_TRUE;
break;
case MDB_NOTFOUND:
*hasSubordinates = LDAP_COMPARE_FALSE;
rc = LDAP_SUCCESS;
break;
default:
Debug(LDAP_DEBUG_ARGS,
"<=- " LDAP_XSTRING(mdb_hasSubordinates)
": has_children failed: %s (%d)\n",
mdb_strerror(rc), rc, 0 );
rc = LDAP_OTHER;
}
done:;
if ( moi == &opinfo ) {
mdb_txn_reset( moi->moi_txn );
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
}
return rc;
}
/*
* sets the supported operational attributes (if required)
*/
int
mdb_operational(
Operation *op,
SlapReply *rs )
{
Attribute **ap;
assert( rs->sr_entry != NULL );
for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) {
if ( (*ap)->a_desc == slap_schema.si_ad_hasSubordinates ) {
break;
}
}
if ( *ap == NULL &&
attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL &&
( SLAP_OPATTRS( rs->sr_attr_flags ) ||
ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) )
{
int hasSubordinates, rc;
rc = mdb_hasSubordinates( op, rs->sr_entry, &hasSubordinates );
if ( rc == LDAP_SUCCESS ) {
*ap = slap_operational_hasSubordinate( hasSubordinates == LDAP_COMPARE_TRUE );
assert( *ap != NULL );
ap = &(*ap)->a_next;
}
}
return LDAP_SUCCESS;
}

View file

@ -0,0 +1,376 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#ifndef _PROTO_MDB_H
#define _PROTO_MDB_H
LDAP_BEGIN_DECL
#define MDB_UCTYPE "MDB"
/*
* attr.c
*/
AttrInfo *mdb_attr_mask( struct mdb_info *mdb,
AttributeDescription *desc );
void mdb_attr_flush( struct mdb_info *mdb );
int mdb_attr_slot( struct mdb_info *mdb,
AttributeDescription *desc, int *insert );
int mdb_attr_dbs_open( BackendDB *be, MDB_txn *txn, struct config_reply_s *cr );
void mdb_attr_dbs_close( struct mdb_info *mdb, MDB_txn *txn );
int mdb_attr_index_config LDAP_P(( struct mdb_info *mdb,
const char *fname, int lineno,
int argc, char **argv, struct config_reply_s *cr ));
void mdb_attr_index_unparse LDAP_P(( struct mdb_info *mdb, BerVarray *bva ));
void mdb_attr_index_destroy LDAP_P(( struct mdb_info *mdb ));
void mdb_attr_index_free LDAP_P(( struct mdb_info *mdb,
AttributeDescription *ad ));
void mdb_attr_info_free( AttrInfo *ai );
/*
* config.c
*/
int mdb_back_init_cf( BackendInfo *bi );
/*
* dn2entry.c
*/
int mdb_dn2entry LDAP_P(( Operation *op, MDB_txn *tid,
struct berval *dn, Entry **e, int matched ));
/*
* dn2id.c
*/
int mdb_dn2id(
Operation *op,
MDB_txn *txn,
struct berval *ndn,
ID *id,
struct berval *matched,
struct berval *nmatched );
int mdb_dn2id_add(
Operation *op,
MDB_txn *tid,
ID pid,
Entry *e );
int mdb_dn2id_delete(
Operation *op,
MDB_txn *tid,
ID pid,
Entry *e );
int mdb_dn2id_children(
Operation *op,
MDB_txn *tid,
Entry *e );
int mdb_dn2sups (
Operation *op,
MDB_txn *tid,
struct berval *dn,
ID *sups
);
int mdb_dn2idl(
Operation *op,
MDB_txn *txn,
struct berval *ndn,
ID eid,
ID *ids,
ID *stack );
int mdb_dn2id_parent(
Operation *op,
MDB_txn *txn,
ID eid,
ID *idp );
int mdb_id2name(
Operation *op,
MDB_txn *txn,
MDB_cursor **cursp,
ID eid,
struct berval *name,
struct berval *nname);
int mdb_idscope(
Operation *op,
MDB_txn *txn,
ID base,
ID *ids,
ID *res );
int mdb_idscopes(
Operation *op,
MDB_txn *txn,
MDB_cursor **cursp,
ID base,
ID *scopes );
MDB_cmp_func mdb_dup_compare;
/*
* filterentry.c
*/
int mdb_filter_candidates(
Operation *op,
MDB_txn *txn,
Filter *f,
ID *ids,
ID *tmp,
ID *stack );
/*
* id2entry.c
*/
int mdb_id2entry_add(
Operation *op,
MDB_txn *tid,
Entry *e );
int mdb_id2entry_update(
Operation *op,
MDB_txn *tid,
Entry *e );
int mdb_id2entry_delete(
BackendDB *be,
MDB_txn *tid,
Entry *e);
int mdb_id2entry(
Operation *op,
MDB_txn *tid,
ID id,
Entry **e);
void mdb_entry_free ( Entry *e );
int mdb_entry_return( Entry *e );
BI_entry_release_rw mdb_entry_release;
BI_entry_get_rw mdb_entry_get;
void mdb_reader_flush( MDB_env *env );
int mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moi );
/*
* idl.c
*/
unsigned mdb_idl_search( ID *ids, ID id );
int mdb_idl_fetch_key(
BackendDB *be,
MDB_txn *txn,
MDB_dbi dbi,
MDB_val *key,
ID *ids,
MDB_cursor **saved_cursor,
int get_flag );
int mdb_idl_insert( ID *ids, ID id );
int mdb_idl_insert_key(
BackendDB *be,
MDB_txn *txn,
MDB_dbi dbi,
MDB_val *key,
ID id );
int mdb_idl_delete_key(
BackendDB *be,
MDB_txn *txn,
MDB_dbi dbi,
MDB_val *key,
ID id );
int
mdb_idl_intersection(
ID *a,
ID *b );
int
mdb_idl_union(
ID *a,
ID *b );
ID mdb_idl_first( ID *ids, ID *cursor );
ID mdb_idl_next( ID *ids, ID *cursor );
void mdb_idl_sort( ID *ids, ID *tmp );
int mdb_idl_append( ID *a, ID *b );
int mdb_idl_append_one( ID *ids, ID id );
/*
* index.c
*/
extern AttrInfo *
mdb_index_mask LDAP_P((
Backend *be,
AttributeDescription *desc,
struct berval *name ));
extern int
mdb_index_param LDAP_P((
Backend *be,
AttributeDescription *desc,
int ftype,
MDB_dbi *dbi,
slap_mask_t *mask,
struct berval *prefix ));
extern int
mdb_index_values LDAP_P((
Operation *op,
MDB_txn *txn,
AttributeDescription *desc,
BerVarray vals,
ID id,
int opid ));
extern int
mdb_index_recset LDAP_P((
struct mdb_info *mdb,
Attribute *a,
AttributeType *type,
struct berval *tags,
IndexRec *ir ));
extern int
mdb_index_recrun LDAP_P((
Operation *op,
struct mdb_info *mdb,
IndexRec *ir,
ID id,
int base ));
int mdb_index_entry LDAP_P(( Operation *op, MDB_txn *t, int r, Entry *e ));
#define mdb_index_entry_add(op,t,e) \
mdb_index_entry((op),(t),SLAP_INDEX_ADD_OP,(e))
#define mdb_index_entry_del(op,t,e) \
mdb_index_entry((op),(t),SLAP_INDEX_DELETE_OP,(e))
/*
* key.c
*/
extern int
mdb_key_read(
Backend *be,
MDB_txn *txn,
MDB_dbi dbi,
struct berval *k,
ID *ids,
MDB_cursor **saved_cursor,
int get_flags );
extern int
mdb_key_change(
Backend *be,
MDB_txn *txn,
MDB_dbi dbi,
struct berval *k,
ID id,
int op );
/*
* nextid.c
*/
int mdb_next_id( BackendDB *be, MDB_txn *tid, ID *id );
/*
* modify.c
*/
int mdb_modify_internal(
Operation *op,
MDB_txn *tid,
Modifications *modlist,
Entry *e,
const char **text,
char *textbuf,
size_t textlen );
/*
* monitor.c
*/
int mdb_monitor_db_init( BackendDB *be );
int mdb_monitor_db_open( BackendDB *be );
int mdb_monitor_db_close( BackendDB *be );
int mdb_monitor_db_destroy( BackendDB *be );
#ifdef MDB_MONITOR_IDX
int
mdb_monitor_idx_add(
struct mdb_info *mdb,
AttributeDescription *desc,
slap_mask_t type );
#endif /* MDB_MONITOR_IDX */
/*
* former external.h
*/
extern BI_init mdb_back_initialize;
extern BI_db_config mdb_db_config;
extern BI_op_add mdb_add;
extern BI_op_bind mdb_bind;
extern BI_op_compare mdb_compare;
extern BI_op_delete mdb_delete;
extern BI_op_modify mdb_modify;
extern BI_op_modrdn mdb_modrdn;
extern BI_op_search mdb_search;
extern BI_op_extended mdb_extended;
extern BI_chk_referrals mdb_referrals;
extern BI_operational mdb_operational;
extern BI_has_subordinates mdb_hasSubordinates;
/* tools.c */
extern BI_tool_entry_open mdb_tool_entry_open;
extern BI_tool_entry_close mdb_tool_entry_close;
extern BI_tool_entry_first_x mdb_tool_entry_first_x;
extern BI_tool_entry_next mdb_tool_entry_next;
extern BI_tool_entry_get mdb_tool_entry_get;
extern BI_tool_entry_put mdb_tool_entry_put;
extern BI_tool_entry_reindex mdb_tool_entry_reindex;
extern BI_tool_dn2id_get mdb_tool_dn2id_get;
extern BI_tool_entry_modify mdb_tool_entry_modify;
LDAP_END_DECL
#endif /* _PROTO_MDB_H */

View file

@ -0,0 +1,149 @@
/* referral.c - MDB backend referral handler */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "back-mdb.h"
int
mdb_referrals( Operation *op, SlapReply *rs )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
Entry *e = NULL;
int rc = LDAP_SUCCESS;
MDB_txn *rtxn;
mdb_op_info opinfo = {0}, *moi = &opinfo;
if( op->o_tag == LDAP_REQ_SEARCH ) {
/* let search take care of itself */
return rc;
}
if( get_manageDSAit( op ) ) {
/* let op take care of DSA management */
return rc;
}
rc = mdb_opinfo_get(op, mdb, 1, &moi);
switch(rc) {
case 0:
break;
default:
return LDAP_OTHER;
}
rtxn = moi->moi_txn;
/* get entry */
rc = mdb_dn2entry( op, rtxn, &op->o_req_ndn, &e, 1 );
switch(rc) {
case MDB_NOTFOUND:
case 0:
break;
case LDAP_BUSY:
rs->sr_text = "ldap server busy";
goto done;
default:
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_referrals)
": dn2entry failed: %s (%d)\n",
mdb_strerror(rc), rc, 0 );
rs->sr_text = "internal error";
rc = LDAP_OTHER;
goto done;
}
if ( rc == MDB_NOTFOUND ) {
rc = LDAP_SUCCESS;
rs->sr_matched = NULL;
if ( e != NULL ) {
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_referrals)
": tag=%lu target=\"%s\" matched=\"%s\"\n",
(unsigned long)op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val );
if( is_entry_referral( e ) ) {
BerVarray ref = get_entry_referrals( op, e );
rc = LDAP_OTHER;
rs->sr_ref = referral_rewrite( ref, &e->e_name,
&op->o_req_dn, LDAP_SCOPE_DEFAULT );
ber_bvarray_free( ref );
if ( rs->sr_ref ) {
rs->sr_matched = ber_strdup_x(
e->e_name.bv_val, op->o_tmpmemctx );
}
}
mdb_entry_return( e );
e = NULL;
}
if( rs->sr_ref != NULL ) {
/* send referrals */
rc = rs->sr_err = LDAP_REFERRAL;
send_ldap_result( op, rs );
ber_bvarray_free( rs->sr_ref );
rs->sr_ref = NULL;
} else if ( rc != LDAP_SUCCESS ) {
rs->sr_text = rs->sr_matched ? "bad referral object" : NULL;
}
if (rs->sr_matched) {
op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
rs->sr_matched = NULL;
}
goto done;
}
if ( is_entry_referral( e ) ) {
/* entry is a referral */
BerVarray refs = get_entry_referrals( op, e );
rs->sr_ref = referral_rewrite(
refs, &e->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
Debug( LDAP_DEBUG_TRACE,
LDAP_XSTRING(mdb_referrals)
": tag=%lu target=\"%s\" matched=\"%s\"\n",
(unsigned long)op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val );
rs->sr_matched = e->e_name.bv_val;
if( rs->sr_ref != NULL ) {
rc = rs->sr_err = LDAP_REFERRAL;
send_ldap_result( op, rs );
ber_bvarray_free( rs->sr_ref );
rs->sr_ref = NULL;
} else {
rc = LDAP_OTHER;
rs->sr_text = "bad referral object";
}
rs->sr_matched = NULL;
ber_bvarray_free( refs );
}
done:
if ( moi == &opinfo ) {
mdb_txn_reset( moi->moi_txn );
LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
}
if ( e )
mdb_entry_return( e );
return rc;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,875 @@
/* tools.c - tools for slap tools */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2011 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include <ac/errno.h>
#define AVL_INTERNAL
#include "back-mdb.h"
#include "idl.h"
static MDB_txn *txn = NULL, *txi = NULL;
static MDB_cursor *cursor = NULL, *idcursor = NULL;
static MDB_val key, data;
static EntryHeader eh;
static ID previd = NOID;
typedef struct dn_id {
ID id;
struct berval dn;
} dn_id;
#define HOLE_SIZE 4096
static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
static unsigned nhmax = HOLE_SIZE;
static unsigned nholes;
static struct berval *tool_base;
static int tool_scope;
static Filter *tool_filter;
static Entry *tool_next_entry;
#if 0
static ID mdb_tool_ix_id;
static Operation *mdb_tool_ix_op;
static int *mdb_tool_index_threads, mdb_tool_index_tcount;
static void *mdb_tool_index_rec;
static struct mdb_info *mdb_tool_info;
static ldap_pvt_thread_mutex_t mdb_tool_index_mutex;
static ldap_pvt_thread_cond_t mdb_tool_index_cond_main;
static ldap_pvt_thread_cond_t mdb_tool_index_cond_work;
static void * mdb_tool_index_task( void *ctx, void *ptr );
#endif
static int mdb_writes, mdb_writes_per_commit;
static int
mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep );
int mdb_tool_entry_open(
BackendDB *be, int mode )
{
/* In Quick mode, commit once per 1000 entries */
mdb_writes = 0;
if ( slapMode & SLAP_TOOL_QUICK )
mdb_writes_per_commit = 1000;
else
mdb_writes_per_commit = 1;
#if 0
/* Set up for threaded slapindex */
if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) {
if ( !mdb_tool_info ) {
ldap_pvt_thread_mutex_init( &mdb_tool_index_mutex );
ldap_pvt_thread_cond_init( &mdb_tool_index_cond_main );
ldap_pvt_thread_cond_init( &mdb_tool_index_cond_work );
if ( mdb->bi_nattrs ) {
int i;
mdb_tool_index_threads = ch_malloc( slap_tool_thread_max * sizeof( int ));
mdb_tool_index_rec = ch_malloc( mdb->bi_nattrs * sizeof( IndexRec ));
mdb_tool_index_tcount = slap_tool_thread_max - 1;
for (i=1; i<slap_tool_thread_max; i++) {
int *ptr = ch_malloc( sizeof( int ));
*ptr = i;
ldap_pvt_thread_pool_submit( &connection_pool,
mdb_tool_index_task, ptr );
}
}
mdb_tool_info = mdb;
}
}
#endif
return 0;
}
int mdb_tool_entry_close(
BackendDB *be )
{
#if 0
if ( mdb_tool_info ) {
slapd_shutdown = 1;
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
/* There might still be some threads starting */
while ( mdb_tool_index_tcount ) {
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
&mdb_tool_index_mutex );
}
mdb_tool_index_tcount = slap_tool_thread_max - 1;
ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
/* Make sure all threads are stopped */
while ( mdb_tool_index_tcount ) {
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
&mdb_tool_index_mutex );
}
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
mdb_tool_info = NULL;
slapd_shutdown = 0;
ch_free( mdb_tool_index_threads );
ch_free( mdb_tool_index_rec );
mdb_tool_index_tcount = slap_tool_thread_max - 1;
}
#endif
if( idcursor ) {
mdb_cursor_close( idcursor );
idcursor = NULL;
}
if( cursor ) {
mdb_cursor_close( cursor );
cursor = NULL;
}
if( txn ) {
if ( mdb_txn_commit( txn ))
return -1;
txn = NULL;
}
if( nholes ) {
unsigned i;
fprintf( stderr, "Error, entries missing!\n");
for (i=0; i<nholes; i++) {
fprintf(stderr, " entry %ld: %s\n",
holes[i].id, holes[i].dn.bv_val);
}
nholes = 0;
return -1;
}
return 0;
}
ID
mdb_tool_entry_first_x(
BackendDB *be,
struct berval *base,
int scope,
Filter *f )
{
tool_base = base;
tool_scope = scope;
tool_filter = f;
return mdb_tool_entry_next( be );
}
ID mdb_tool_entry_next(
BackendDB *be )
{
int rc;
ID id;
struct mdb_info *mdb;
assert( be != NULL );
assert( slapMode & SLAP_TOOL_MODE );
mdb = (struct mdb_info *) be->be_private;
assert( mdb != NULL );
if ( !txn ) {
rc = mdb_txn_begin( mdb->mi_dbenv, MDB_RDONLY, &txn );
if ( rc )
return NOID;
rc = mdb_cursor_open( txn, mdb->mi_id2entry, &cursor );
if ( rc ) {
mdb_txn_abort( txn );
return NOID;
}
}
next:;
rc = mdb_cursor_get( cursor, &key, &data, MDB_NEXT );
if( rc ) {
return NOID;
}
previd = *(ID *)key.mv_data;
id = previd;
if ( tool_filter || tool_base ) {
static Operation op = {0};
static Opheader ohdr = {0};
op.o_hdr = &ohdr;
op.o_bd = be;
op.o_tmpmemctx = NULL;
op.o_tmpmfuncs = &ch_mfuncs;
if ( tool_next_entry ) {
mdb_entry_release( &op, tool_next_entry, 0 );
tool_next_entry = NULL;
}
rc = mdb_tool_entry_get_int( be, id, &tool_next_entry );
if ( rc == LDAP_NO_SUCH_OBJECT ) {
goto next;
}
assert( tool_next_entry != NULL );
if ( tool_filter && test_filter( NULL, tool_next_entry, tool_filter ) != LDAP_COMPARE_TRUE )
{
mdb_entry_release( &op, tool_next_entry, 0 );
tool_next_entry = NULL;
goto next;
}
}
return id;
}
ID mdb_tool_dn2id_get(
Backend *be,
struct berval *dn
)
{
struct mdb_info *mdb;
Operation op = {0};
Opheader ohdr = {0};
ID id;
int rc;
if ( BER_BVISEMPTY(dn) )
return 0;
mdb = (struct mdb_info *) be->be_private;
if ( !txn ) {
rc = mdb_txn_begin( mdb->mi_dbenv, (slapMode & SLAP_TOOL_READONLY) != 0 ?
MDB_RDONLY : 0, &txn );
if ( rc )
return NOID;
}
op.o_hdr = &ohdr;
op.o_bd = be;
op.o_tmpmemctx = NULL;
op.o_tmpmfuncs = &ch_mfuncs;
rc = mdb_dn2id( &op, txn, dn, &id, NULL, NULL );
if ( rc == MDB_NOTFOUND )
return NOID;
return id;
}
static int
mdb_tool_entry_get_int( BackendDB *be, ID id, Entry **ep )
{
Entry *e = NULL;
struct berval dn = BER_BVNULL, ndn = BER_BVNULL;
int rc;
assert( be != NULL );
assert( slapMode & SLAP_TOOL_MODE );
if ( ( tool_filter || tool_base ) && id == previd && tool_next_entry != NULL ) {
*ep = tool_next_entry;
tool_next_entry = NULL;
return LDAP_SUCCESS;
}
if ( id != previd ) {
key.mv_size = sizeof(ID);
key.mv_data = &id;
rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
if ( rc ) {
rc = LDAP_OTHER;
goto done;
}
}
if ( slapMode & SLAP_TOOL_READONLY ) {
Operation op = {0};
Opheader ohdr = {0};
op.o_hdr = &ohdr;
op.o_bd = be;
op.o_tmpmemctx = NULL;
op.o_tmpmfuncs = &ch_mfuncs;
rc = mdb_id2name( &op, txn, &idcursor, id, &dn, &ndn );
if ( rc ) {
rc = LDAP_OTHER;
mdb_entry_return( e );
e = NULL;
goto done;
}
if ( tool_base != NULL ) {
if ( !dnIsSuffixScope( &ndn, tool_base, tool_scope ) ) {
ch_free( dn.bv_val );
ch_free( ndn.bv_val );
rc = LDAP_NO_SUCH_OBJECT;
}
}
}
/* Get the header */
eh.bv.bv_val = data.mv_data;
eh.bv.bv_len = data.mv_size;
rc = entry_header( &eh );
if ( rc ) {
rc = LDAP_OTHER;
goto done;
}
eh.bv.bv_len = eh.nvals * sizeof( struct berval );
eh.bv.bv_val = ch_malloc( eh.bv.bv_len );
rc = entry_decode( &eh, &e );
e->e_id = id;
if ( !BER_BVISNULL( &dn )) {
e->e_name = dn;
e->e_nname = ndn;
} else {
e->e_name.bv_val = NULL;
e->e_nname.bv_val = NULL;
}
e->e_bv = eh.bv;
done:
if ( e != NULL ) {
*ep = e;
}
return rc;
}
Entry*
mdb_tool_entry_get( BackendDB *be, ID id )
{
Entry *e = NULL;
(void)mdb_tool_entry_get_int( be, id, &e );
return e;
}
static int mdb_tool_next_id(
Operation *op,
MDB_txn *tid,
Entry *e,
struct berval *text,
int hole )
{
struct berval dn = e->e_name;
struct berval ndn = e->e_nname;
struct berval pdn, npdn, nmatched;
ID id, pid = 0;
int rc;
if (ndn.bv_len == 0) {
e->e_id = 0;
return 0;
}
rc = mdb_dn2id( op, tid, &ndn, &id, NULL, &nmatched );
if ( rc == MDB_NOTFOUND ) {
if ( !be_issuffix( op->o_bd, &ndn ) ) {
ID eid = e->e_id;
dnParent( &ndn, &npdn );
if ( nmatched.bv_len != npdn.bv_len ) {
dnParent( &dn, &pdn );
e->e_name = pdn;
e->e_nname = npdn;
rc = mdb_tool_next_id( op, tid, e, text, 1 );
e->e_name = dn;
e->e_nname = ndn;
if ( rc ) {
return rc;
}
/* If parent didn't exist, it was created just now
* and its ID is now in e->e_id. Make sure the current
* entry gets added under the new parent ID.
*/
if ( eid != e->e_id ) {
pid = e->e_id;
}
} else {
pid = id;
}
}
rc = mdb_next_id( op->o_bd, tid, &e->e_id );
if ( rc ) {
snprintf( text->bv_val, text->bv_len,
"next_id failed: %s (%d)",
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
return rc;
}
rc = mdb_dn2id_add( op, tid, pid, e );
if ( rc ) {
snprintf( text->bv_val, text->bv_len,
"dn2id_add failed: %s (%d)",
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> mdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
} else if ( hole ) {
if ( nholes == nhmax - 1 ) {
if ( holes == hbuf ) {
holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
} else {
holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
}
nhmax *= 2;
}
ber_dupbv( &holes[nholes].dn, &ndn );
holes[nholes++].id = e->e_id;
}
} else if ( !hole ) {
unsigned i, j;
e->e_id = id;
for ( i=0; i<nholes; i++) {
if ( holes[i].id == e->e_id ) {
free(holes[i].dn.bv_val);
for (j=i;j<nholes;j++) holes[j] = holes[j+1];
holes[j].id = 0;
nholes--;
break;
} else if ( holes[i].id > e->e_id ) {
break;
}
}
}
return rc;
}
static int
mdb_tool_index_add(
Operation *op,
MDB_txn *txn,
Entry *e )
{
struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
if ( !mdb->mi_nattrs )
return 0;
#if 0
if ( slapMode & SLAP_TOOL_QUICK ) {
IndexRec *ir;
int i, rc;
Attribute *a;
ir = mdb_tool_index_rec;
memset(ir, 0, mdb->bi_nattrs * sizeof( IndexRec ));
for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
rc = mdb_index_recset( mdb, a, a->a_desc->ad_type,
&a->a_desc->ad_tags, ir );
if ( rc )
return rc;
}
mdb_tool_ix_id = e->e_id;
mdb_tool_ix_op = op;
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
/* Wait for all threads to be ready */
while ( mdb_tool_index_tcount ) {
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
&mdb_tool_index_mutex );
}
for ( i=1; i<slap_tool_thread_max; i++ )
mdb_tool_index_threads[i] = LDAP_BUSY;
mdb_tool_index_tcount = slap_tool_thread_max - 1;
ldap_pvt_thread_cond_broadcast( &mdb_tool_index_cond_work );
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
rc = mdb_index_recrun( op, mdb, ir, e->e_id, 0 );
if ( rc )
return rc;
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
for ( i=1; i<slap_tool_thread_max; i++ ) {
if ( mdb_tool_index_threads[i] == LDAP_BUSY ) {
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_main,
&mdb_tool_index_mutex );
i--;
continue;
}
if ( mdb_tool_index_threads[i] ) {
rc = mdb_tool_index_threads[i];
break;
}
}
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
return rc;
} else
#endif
{
return mdb_index_entry_add( op, txn, e );
}
}
ID mdb_tool_entry_put(
BackendDB *be,
Entry *e,
struct berval *text )
{
int rc;
struct mdb_info *mdb;
Operation op = {0};
Opheader ohdr = {0};
assert( be != NULL );
assert( slapMode & SLAP_TOOL_MODE );
assert( text != NULL );
assert( text->bv_val != NULL );
assert( text->bv_val[0] == '\0' ); /* overconservative? */
Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(mdb_tool_entry_put)
"( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
mdb = (struct mdb_info *) be->be_private;
if ( !txn ) {
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &txn );
if( rc != 0 ) {
snprintf( text->bv_val, text->bv_len,
"txn_begin failed: %s (%d)",
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
text->bv_val, 0, 0 );
return NOID;
}
}
op.o_hdr = &ohdr;
op.o_bd = be;
op.o_tmpmemctx = NULL;
op.o_tmpmfuncs = &ch_mfuncs;
/* add dn2id indices */
rc = mdb_tool_next_id( &op, txn, e, text, 0 );
if( rc != 0 ) {
goto done;
}
rc = mdb_tool_index_add( &op, txn, e );
if( rc != 0 ) {
snprintf( text->bv_val, text->bv_len,
"index_entry_add failed: %s (%d)",
rc == LDAP_OTHER ? "Internal error" :
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
text->bv_val, 0, 0 );
goto done;
}
/* id2entry index */
rc = mdb_id2entry_add( &op, txn, e );
if( rc != 0 ) {
snprintf( text->bv_val, text->bv_len,
"id2entry_add failed: %s (%d)",
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
text->bv_val, 0, 0 );
goto done;
}
done:
if( rc == 0 ) {
mdb_writes++;
if ( mdb_writes >= mdb_writes_per_commit ) {
rc = mdb_txn_commit( txn );
mdb_writes = 0;
txn = NULL;
if( rc != 0 ) {
snprintf( text->bv_val, text->bv_len,
"txn_commit failed: %s (%d)",
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
text->bv_val, 0, 0 );
e->e_id = NOID;
}
}
} else {
mdb_txn_abort( txn );
txn = NULL;
snprintf( text->bv_val, text->bv_len,
"txn_aborted! %s (%d)",
rc == LDAP_OTHER ? "Internal error" :
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_put) ": %s\n",
text->bv_val, 0, 0 );
e->e_id = NOID;
}
return e->e_id;
}
int mdb_tool_entry_reindex(
BackendDB *be,
ID id,
AttributeDescription **adv )
{
struct mdb_info *mi = (struct mdb_info *) be->be_private;
int rc;
Entry *e;
Operation op = {0};
Opheader ohdr = {0};
Debug( LDAP_DEBUG_ARGS,
"=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld )\n",
(long) id, 0, 0 );
assert( tool_base == NULL );
assert( tool_filter == NULL );
/* No indexes configured, nothing to do. Could return an
* error here to shortcut things.
*/
if (!mi->mi_attrs) {
return 0;
}
/* Check for explicit list of attrs to index */
if ( adv ) {
int i, j, n;
if ( mi->mi_attrs[0]->ai_desc != adv[0] ) {
/* count */
for ( n = 0; adv[n]; n++ ) ;
/* insertion sort */
for ( i = 0; i < n; i++ ) {
AttributeDescription *ad = adv[i];
for ( j = i-1; j>=0; j--) {
if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
adv[j+1] = adv[j];
}
adv[j+1] = ad;
}
}
for ( i = 0; adv[i]; i++ ) {
if ( mi->mi_attrs[i]->ai_desc != adv[i] ) {
for ( j = i+1; j < mi->mi_nattrs; j++ ) {
if ( mi->mi_attrs[j]->ai_desc == adv[i] ) {
AttrInfo *ai = mi->mi_attrs[i];
mi->mi_attrs[i] = mi->mi_attrs[j];
mi->mi_attrs[j] = ai;
break;
}
}
if ( j == mi->mi_nattrs ) {
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_tool_entry_reindex)
": no index configured for %s\n",
adv[i]->ad_cname.bv_val, 0, 0 );
return -1;
}
}
}
mi->mi_nattrs = i;
}
e = mdb_tool_entry_get( be, id );
if( e == NULL ) {
Debug( LDAP_DEBUG_ANY,
LDAP_XSTRING(mdb_tool_entry_reindex)
": could not locate id=%ld\n",
(long) id, 0, 0 );
return -1;
}
if ( !txi ) {
rc = mdb_txn_begin( mi->mi_dbenv, 0, &txi );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_reindex) ": "
"txn_begin failed: %s (%d)\n",
mdb_strerror(rc), rc, 0 );
goto done;
}
}
/*
* just (re)add them for now
* assume that some other routine (not yet implemented)
* will zap index databases
*
*/
Debug( LDAP_DEBUG_TRACE,
"=> " LDAP_XSTRING(mdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
(long) id, e->e_dn, 0 );
op.o_hdr = &ohdr;
op.o_bd = be;
op.o_tmpmemctx = NULL;
op.o_tmpmfuncs = &ch_mfuncs;
rc = mdb_tool_index_add( &op, txi, e );
done:
if( rc == 0 ) {
mdb_writes++;
if ( mdb_writes >= mdb_writes_per_commit ) {
rc = mdb_txn_commit( txi );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_reindex)
": txn_commit failed: %s (%d)\n",
mdb_strerror(rc), rc, 0 );
e->e_id = NOID;
}
txi = NULL;
}
} else {
mdb_txn_abort( txi );
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_reindex)
": txn_aborted! %s (%d)\n",
mdb_strerror(rc), rc, 0 );
e->e_id = NOID;
txi = NULL;
}
mdb_entry_release( &op, e, 0 );
return rc;
}
ID mdb_tool_entry_modify(
BackendDB *be,
Entry *e,
struct berval *text )
{
int rc;
struct mdb_info *mdb;
MDB_txn *tid;
Operation op = {0};
Opheader ohdr = {0};
assert( be != NULL );
assert( slapMode & SLAP_TOOL_MODE );
assert( text != NULL );
assert( text->bv_val != NULL );
assert( text->bv_val[0] == '\0' ); /* overconservative? */
assert ( e->e_id != NOID );
Debug( LDAP_DEBUG_TRACE,
"=> " LDAP_XSTRING(mdb_tool_entry_modify) "( %ld, \"%s\" )\n",
(long) e->e_id, e->e_dn, 0 );
mdb = (struct mdb_info *) be->be_private;
if( cursor ) {
mdb_cursor_close( cursor );
cursor = NULL;
}
rc = mdb_txn_begin( mdb->mi_dbenv, 0, &tid );
if( rc != 0 ) {
snprintf( text->bv_val, text->bv_len,
"txn_begin failed: %s (%d)",
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
text->bv_val, 0, 0 );
return NOID;
}
op.o_hdr = &ohdr;
op.o_bd = be;
op.o_tmpmemctx = NULL;
op.o_tmpmfuncs = &ch_mfuncs;
/* id2entry index */
rc = mdb_id2entry_update( &op, tid, e );
if( rc != 0 ) {
snprintf( text->bv_val, text->bv_len,
"id2entry_add failed: %s (%d)",
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
text->bv_val, 0, 0 );
goto done;
}
done:
if( rc == 0 ) {
rc = mdb_txn_commit( tid );
if( rc != 0 ) {
snprintf( text->bv_val, text->bv_len,
"txn_commit failed: %s (%d)",
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": "
"%s\n", text->bv_val, 0, 0 );
e->e_id = NOID;
}
} else {
mdb_txn_abort( tid );
snprintf( text->bv_val, text->bv_len,
"txn_aborted! %s (%d)",
mdb_strerror(rc), rc );
Debug( LDAP_DEBUG_ANY,
"=> " LDAP_XSTRING(mdb_tool_entry_modify) ": %s\n",
text->bv_val, 0, 0 );
e->e_id = NOID;
}
return e->e_id;
}
#if 0
static void *
mdb_tool_index_task( void *ctx, void *ptr )
{
int base = *(int *)ptr;
free( ptr );
while ( 1 ) {
ldap_pvt_thread_mutex_lock( &mdb_tool_index_mutex );
mdb_tool_index_tcount--;
if ( !mdb_tool_index_tcount )
ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
ldap_pvt_thread_cond_wait( &mdb_tool_index_cond_work,
&mdb_tool_index_mutex );
if ( slapd_shutdown ) {
mdb_tool_index_tcount--;
if ( !mdb_tool_index_tcount )
ldap_pvt_thread_cond_signal( &mdb_tool_index_cond_main );
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
break;
}
ldap_pvt_thread_mutex_unlock( &mdb_tool_index_mutex );
mdb_tool_index_threads[base] = mdb_index_recrun( mdb_tool_ix_op,
mdb_tool_info, mdb_tool_index_rec, mdb_tool_ix_id, base );
}
return NULL;
}
#endif