diff --git a/servers/slapd/back-bdb/add.c b/servers/slapd/back-bdb/add.c
index 0fbb162387..8fbef95a97 100644
--- a/servers/slapd/back-bdb/add.c
+++ b/servers/slapd/back-bdb/add.c
@@ -27,6 +27,7 @@ bdb_add(
const char *text = NULL;
AttributeDescription *children = slap_schema.si_ad_children;
DB_TXN *ltid = NULL;
+ struct bdb_op_info opinfo;
Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0);
@@ -76,7 +77,10 @@ retry: rc = txn_abort( ltid );
goto return_results;
}
- op->o_private = ltid;
+ opinfo.boi_bdb = be;
+ opinfo.boi_txn = ltid;
+ opinfo.boi_err = 0;
+ op->o_private = &opinfo;
/*
* Get the parent dn and see if the corresponding entry exists.
@@ -88,8 +92,8 @@ retry: rc = txn_abort( ltid );
if( pdn != NULL && *pdn != '\0' ) {
Entry *matched = NULL;
- /* get parent with reader lock */
- rc = dn2entry_r( be, ltid, pdn, &p, &matched );
+ /* get parent */
+ rc = bdb_dn2entry( be, ltid, pdn, &p, &matched, 0 );
ch_free( pdn );
switch( rc ) {
@@ -125,7 +129,7 @@ retry: rc = txn_abort( ltid );
0, 0, 0 );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
- matched_dn, NULL, refs, NULL );
+ matched_dn, NULL, refs, NULL );
if( matched != NULL ) {
ber_bvecfree( refs );
@@ -165,7 +169,7 @@ retry: rc = txn_abort( ltid );
0, 0, 0 );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
- matched_dn, NULL, refs, NULL );
+ matched_dn, NULL, refs, NULL );
ber_bvecfree( refs );
free( matched_dn );
diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h
index c9fa58d905..dee9b15684 100644
--- a/servers/slapd/back-bdb/back-bdb.h
+++ b/servers/slapd/back-bdb/back-bdb.h
@@ -74,6 +74,12 @@ struct bdb_info {
#define bi_id2entry bi_databases[BDB_ID2ENTRY]
#define bi_dn2id bi_databases[BDB_DN2ID]
+struct bdb_op_info {
+ BackendDB* boi_bdb;
+ DB_TXN* boi_txn;
+ int boi_err;
+};
+
LDAP_END_DECL
#include "proto-bdb.h"
diff --git a/servers/slapd/back-bdb/backbdb.dsp b/servers/slapd/back-bdb/backbdb.dsp
index 49b043fc9d..e31cc1a786 100644
--- a/servers/slapd/back-bdb/backbdb.dsp
+++ b/servers/slapd/back-bdb/backbdb.dsp
@@ -163,6 +163,10 @@ SOURCE=.\error.c
# End Source File
# Begin Source File
+SOURCE=.\extended.c
+# End Source File
+# Begin Source File
+
SOURCE=.\external.h
# End Source File
# Begin Source File
@@ -179,10 +183,22 @@ SOURCE=.\init.c
# End Source File
# Begin Source File
+SOURCE=.\modify.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\modrdn.c
+# End Source File
+# Begin Source File
+
SOURCE=.\nextid.c
# End Source File
# Begin Source File
+SOURCE=.\passwd.c
+# End Source File
+# Begin Source File
+
SOURCE=".\proto-bdb.h"
# End Source File
# Begin Source File
diff --git a/servers/slapd/back-bdb/bind.c b/servers/slapd/back-bdb/bind.c
index da28294b7d..bd9a8bf58f 100644
--- a/servers/slapd/back-bdb/bind.c
+++ b/servers/slapd/back-bdb/bind.c
@@ -17,13 +17,13 @@
int
bdb_bind(
- Backend *be,
- Connection *conn,
- Operation *op,
- const char *dn,
- const char *ndn,
- int method,
- struct berval *cred,
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ int method,
+ struct berval *cred,
char** edn
)
{
@@ -44,8 +44,8 @@ bdb_bind(
*edn = NULL;
- /* fetch entry */
- rc = dn2entry_r( be, NULL, ndn, &e, &matched );
+ /* get entry */
+ rc = bdb_dn2entry( be, NULL, ndn, &e, &matched, 0 );
switch(rc) {
case DB_NOTFOUND:
@@ -53,7 +53,7 @@ bdb_bind(
break;
default:
send_ldap_result( conn, op, rc=LDAP_OTHER,
- NULL, "internal error", NULL, NULL );
+ NULL, "internal error", NULL, NULL );
return rc;
}
@@ -114,10 +114,10 @@ bdb_bind(
if ( is_entry_alias( e ) ) {
/* entry is an alias, don't allow bind */
Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0,
- 0, 0 );
+ 0, 0 );
send_ldap_result( conn, op, rc = LDAP_ALIAS_PROBLEM,
- NULL, "entry is alias", NULL, NULL );
+ NULL, "entry is alias", NULL, NULL );
goto done;
}
@@ -128,7 +128,7 @@ bdb_bind(
conn, op, e );
Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
- 0, 0 );
+ 0, 0 );
if( refs != NULL ) {
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
@@ -165,7 +165,7 @@ bdb_bind(
if ( (a = attr_find( e->e_attrs, password )) == NULL ) {
send_ldap_result( conn, op, rc = LDAP_INAPPROPRIATE_AUTH,
- NULL, NULL, NULL, NULL );
+ NULL, NULL, NULL, NULL );
goto done;
}
@@ -182,7 +182,7 @@ bdb_bind(
case LDAP_AUTH_KRBV41:
if ( krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) {
send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS,
- NULL, NULL, NULL, NULL );
+ NULL, NULL, NULL, NULL );
goto done;
}
@@ -195,7 +195,7 @@ bdb_bind(
}
sprintf( krbname, "%s%s%s@%s", ad.pname, *ad.pinst ? "."
- : "", ad.pinst, ad.prealm );
+ : "", ad.pinst, ad.prealm );
if ( (a = attr_find( e->e_attrs, krbattr )) == NULL ) {
/*
@@ -206,7 +206,7 @@ bdb_bind(
break;
}
send_ldap_result( conn, op, rc = LDAP_INAPPROPRIATE_AUTH,
- NULL, NULL, NULL, NULL );
+ NULL, NULL, NULL, NULL );
goto done;
} else { /* look for krbname match */
@@ -217,7 +217,7 @@ bdb_bind(
if ( value_find( a->a_desc, a->a_vals, &krbval ) != 0 ) {
send_ldap_result( conn, op,
- rc = LDAP_INVALID_CREDENTIALS,
+ rc = LDAP_INVALID_CREDENTIALS,
NULL, NULL, NULL, NULL );
goto done;
}
@@ -234,7 +234,7 @@ bdb_bind(
default:
send_ldap_result( conn, op, rc = LDAP_STRONG_AUTH_NOT_SUPPORTED,
- NULL, "authentication method not supported", NULL, NULL );
+ NULL, "authentication method not supported", NULL, NULL );
goto done;
}
diff --git a/servers/slapd/back-bdb/compare.c b/servers/slapd/back-bdb/compare.c
index 98d95cdf5e..2764cdf9e8 100644
--- a/servers/slapd/back-bdb/compare.c
+++ b/servers/slapd/back-bdb/compare.c
@@ -15,11 +15,11 @@
int
bdb_compare(
- BackendDB *be,
- Connection *conn,
- Operation *op,
- const char *dn,
- const char *ndn,
+ BackendDB *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
AttributeAssertion *ava
)
{
@@ -32,7 +32,7 @@ bdb_compare(
int manageDSAit = get_manageDSAit( op );
/* get entry */
- rc = dn2entry_r( be, NULL, ndn, &e, &matched );
+ rc = bdb_dn2entry( be, NULL, ndn, &e, &matched, 0 );
switch( rc ) {
case DB_NOTFOUND:
@@ -74,10 +74,10 @@ bdb_compare(
conn, op, e );
Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
- 0, 0 );
+ 0, 0 );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
- e->e_dn, NULL, refs, NULL );
+ e->e_dn, NULL, refs, NULL );
ber_bvecfree( refs );
goto done;
diff --git a/servers/slapd/back-bdb/config.c b/servers/slapd/back-bdb/config.c
index c881bec923..b1bf856a97 100644
--- a/servers/slapd/back-bdb/config.c
+++ b/servers/slapd/back-bdb/config.c
@@ -14,18 +14,18 @@
int
bdb_db_config(
- BackendDB *be,
- const char *fname,
- int lineno,
- int argc,
- char **argv )
+ BackendDB *be,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv )
{
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
if ( bdb == NULL ) {
fprintf( stderr, "%s: line %d: "
"bdb database info is null!\n",
- fname, lineno );
+ fname, lineno );
return 1;
}
@@ -34,7 +34,7 @@ bdb_db_config(
if ( argc < 2 ) {
fprintf( stderr, "%s: line %d: "
"missing dir in \"directory
\" line\n",
- fname, lineno );
+ fname, lineno );
return 1;
}
if ( bdb->bi_dbenv_home ) {
@@ -47,7 +47,7 @@ bdb_db_config(
if ( argc < 2 ) {
fprintf( stderr, "%s: line %d: "
"missing mode in \"mode \" line\n",
- fname, lineno );
+ fname, lineno );
return 1;
}
bdb->bi_dbenv_mode = strtol( argv[1], NULL, 0 );
@@ -59,13 +59,13 @@ bdb_db_config(
if ( argc < 2 ) {
fprintf( stderr, "%s: line %d: "
"missing attr in \"index [pres,eq,approx,sub]\" line\n",
- fname, lineno );
+ fname, lineno );
return 1;
} else if ( argc > 3 ) {
fprintf( stderr, "%s: line %d: "
"extra junk after \"index [pres,eq,approx,sub]\" "
"line (ignored)\n",
- fname, lineno );
+ fname, lineno );
}
rc = attr_index_config( li, fname, lineno, argc - 1, &argv[1] );
@@ -76,7 +76,7 @@ bdb_db_config(
} else {
fprintf( stderr, "%s: line %d: "
"unknown directive \"%s\" in bdb database definition (ignored)\n",
- fname, lineno, argv[0] );
+ fname, lineno, argv[0] );
}
return 0;
diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c
index 0b66029b57..2c9bf2af0c 100644
--- a/servers/slapd/back-bdb/delete.c
+++ b/servers/slapd/back-bdb/delete.c
@@ -15,11 +15,11 @@
int
bdb_delete(
- BackendDB *be,
- Connection *conn,
- Operation *op,
- const char *dn,
- const char *ndn
+ BackendDB *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn
)
{
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
@@ -31,6 +31,7 @@ bdb_delete(
int manageDSAit = get_manageDSAit( op );
AttributeDescription *children = slap_schema.si_ad_children;
DB_TXN *ltid = NULL;
+ struct bdb_op_info opinfo;
Debug(LDAP_DEBUG_ARGS, "==> bdb_delete: %s\n", dn, 0, 0);
@@ -57,13 +58,62 @@ retry: rc = txn_abort( ltid );
goto return_results;
}
- op->o_private = ltid;
+ opinfo.boi_bdb = be;
+ opinfo.boi_txn = ltid;
+ opinfo.boi_err = 0;
+ op->o_private = &opinfo;
- pdn = dn_parent( be, e->e_ndn );
+ /* get entry for read/modify/write */
+ rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, DB_RMW );
+
+ switch( rc ) {
+ case 0:
+ case DB_NOTFOUND:
+ break;
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ default:
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+
+ if ( e == NULL ) {
+ char *matched_dn = NULL;
+ struct berval **refs = NULL;
+
+ Debug( LDAP_DEBUG_ARGS,
+ "<=- bdb_delete: no such object %s\n",
+ dn, 0, 0);
+
+ if ( matched != NULL ) {
+ matched_dn = ch_strdup( matched->e_dn );
+ refs = is_entry_referral( matched )
+ ? get_entry_referrals( be, conn, op, matched )
+ : NULL;
+ bdb_entry_return( be, matched );
+ } else {
+ refs = default_referral;
+ }
+
+ send_ldap_result( conn, op, LDAP_REFERRAL,
+ matched_dn, NULL, refs, NULL );
+
+ if ( matched != NULL ) {
+ ber_bvecfree( refs );
+ free( matched_dn );
+ }
+
+ rc = -1;
+ goto done;
+ }
+
+ pdn = dn_parent( be, ndn );
if( pdn != NULL && *pdn != '\0' ) {
- /* get parent with reader lock */
- rc = dn2entry_r( be, ltid, pdn, &p, NULL );
+ /* get parent */
+ rc = bdb_dn2entry( be, ltid, pdn, &p, NULL, 0 );
ch_free( pdn );
@@ -116,53 +166,7 @@ retry: rc = txn_abort( ltid );
}
}
- /* get entry */
- rc = dn2entry_w( be, ltid, ndn, &e, &matched );
-
- switch( rc ) {
- case 0:
- case DB_NOTFOUND:
- break;
- case DB_LOCK_DEADLOCK:
- case DB_LOCK_NOTGRANTED:
- goto retry;
- default:
- rc = LDAP_OTHER;
- text = "internal error";
- goto return_results;
- }
-
- if ( e == NULL ) {
- char *matched_dn = NULL;
- struct berval **refs = NULL;
-
- Debug( LDAP_DEBUG_ARGS,
- "<=- bdb_delete: no such object %s\n",
- dn, 0, 0);
-
- if ( matched != NULL ) {
- matched_dn = ch_strdup( matched->e_dn );
- refs = is_entry_referral( matched )
- ? get_entry_referrals( be, conn, op, matched )
- : NULL;
- bdb_entry_return( be, matched );
- } else {
- refs = default_referral;
- }
-
- send_ldap_result( conn, op, LDAP_REFERRAL,
- matched_dn, NULL, refs, NULL );
-
- if ( matched != NULL ) {
- ber_bvecfree( refs );
- free( matched_dn );
- }
-
- rc = -1;
- goto done;
- }
-
- if ( !manageDSAit && is_entry_referral( e ) ) {
+ if ( !manageDSAit && is_entry_referral( e ) ) {
/* parent is a referral, don't allow add */
/* parent is an alias, don't allow add */
struct berval **refs = get_entry_referrals( be,
@@ -173,7 +177,7 @@ retry: rc = txn_abort( ltid );
0, 0, 0 );
send_ldap_result( conn, op, LDAP_REFERRAL,
- e->e_dn, NULL, refs, NULL );
+ e->e_dn, NULL, refs, NULL );
ber_bvecfree( refs );
diff --git a/servers/slapd/back-bdb/dn2entry.c b/servers/slapd/back-bdb/dn2entry.c
index c8a34fe55a..f0ba6c7731 100644
--- a/servers/slapd/back-bdb/dn2entry.c
+++ b/servers/slapd/back-bdb/dn2entry.c
@@ -19,11 +19,11 @@
int
bdb_dn2entry(
- BackendDB *be,
+ BackendDB *be,
DB_TXN *tid,
- const char *dn,
+ const char *dn,
Entry **e,
- Entry **matched,
+ Entry **matched,
int flags )
{
int rc;
diff --git a/servers/slapd/back-bdb/dn2id.c b/servers/slapd/back-bdb/dn2id.c
index 2876f438f1..3479310f47 100644
--- a/servers/slapd/back-bdb/dn2id.c
+++ b/servers/slapd/back-bdb/dn2id.c
@@ -14,10 +14,10 @@
int
bdb_dn2id_add(
- BackendDB *be,
+ BackendDB *be,
DB_TXN *txn,
- const char *dn,
- ID id
+ const char *dn,
+ ID id
)
{
int rc;
@@ -102,10 +102,10 @@ done:
int
bdb_dn2id_delete(
- BackendDB *be,
+ BackendDB *be,
DB_TXN *txn,
- const char *dn,
- ID id )
+ const char *dn,
+ ID id )
{
int rc;
DBT key;
@@ -185,9 +185,9 @@ done:
int
bdb_dn2id(
- BackendDB *be,
+ BackendDB *be,
DB_TXN *txn,
- const char *dn,
+ const char *dn,
ID *id )
{
int rc;
@@ -221,9 +221,9 @@ bdb_dn2id(
int
bdb_dn2id_matched(
- BackendDB *be,
+ BackendDB *be,
DB_TXN *txn,
- const char *in,
+ const char *in,
ID *id,
char **matchedDN )
{
@@ -307,9 +307,9 @@ bdb_dn2id_matched(
int
bdb_dn2id_children(
- BackendDB *be,
+ BackendDB *be,
DB_TXN *txn,
- const char *dn )
+ const char *dn )
{
int rc;
DBT key, data;
diff --git a/servers/slapd/back-bdb/extended.c b/servers/slapd/back-bdb/extended.c
new file mode 100644
index 0000000000..04b96f823a
--- /dev/null
+++ b/servers/slapd/back-bdb/extended.c
@@ -0,0 +1,52 @@
+/* extended.c - ldbm backend extended routines */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include
+#include
+
+#include "back-bdb.h"
+#include "external.h"
+
+struct exop {
+ char *oid;
+ SLAP_EXTENDED_FN extended;
+} exop_table[] = {
+ { LDAP_EXOP_X_MODIFY_PASSWD, bdb_exop_passwd },
+ { NULL, NULL }
+};
+
+int
+bdb_extended(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *reqoid,
+ struct berval *reqdata,
+ char **rspoid,
+ struct berval **rspdata,
+ LDAPControl *** rspctrls,
+ const char** text,
+ struct berval *** refs
+)
+{
+ int i;
+
+ for( i=0; exop_table[i].oid != NULL; i++ ) {
+ if( strcmp( exop_table[i].oid, reqoid ) == 0 ) {
+ return (exop_table[i].extended)(
+ be, conn, op,
+ reqoid, reqdata,
+ rspoid, rspdata, rspctrls,
+ text, refs );
+ }
+ }
+
+ *text = "not supported within naming context";
+ return LDAP_OPERATIONS_ERROR;
+}
\ No newline at end of file
diff --git a/servers/slapd/back-bdb/external.h b/servers/slapd/back-bdb/external.h
index db1ccac2c7..0784a7cdd3 100644
--- a/servers/slapd/back-bdb/external.h
+++ b/servers/slapd/back-bdb/external.h
@@ -56,11 +56,11 @@ extern int bdb_unbind LDAP_P(( BackendDB *bd,
Connection *conn, Operation *op ));
extern int bdb_referrals(
- BackendDB *be,
- Connection *conn,
- Operation *op,
- const char *dn,
- const char *ndn,
+ BackendDB *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
const char **text );
LDAP_END_DECL
diff --git a/servers/slapd/back-bdb/id2entry.c b/servers/slapd/back-bdb/id2entry.c
index 8fbff048d4..51751c230c 100644
--- a/servers/slapd/back-bdb/id2entry.c
+++ b/servers/slapd/back-bdb/id2entry.c
@@ -41,6 +41,35 @@ int bdb_id2entry_add(
return rc;
}
+int bdb_id2entry_update(
+ BackendDB *be,
+ DB_TXN *tid,
+ Entry *e )
+{
+ struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+ DB *db = bdb->bi_id2entry->bdi_db;
+ DBT key, data;
+ struct berval *bv;
+ int rc;
+
+ DBTzero( &key );
+ key.data = (char *) &e->e_id;
+ key.size = sizeof(ID);
+
+ rc = entry_encode( e, &bv );
+ if( rc != LDAP_SUCCESS ) {
+ return -1;
+ }
+
+ DBTzero( &data );
+ bv2DBT( bv, &data );
+
+ rc = db->put( db, tid, &key, &data, 0 );
+
+ ber_bvfree( bv );
+ return rc;
+}
+
int bdb_id2entry(
BackendDB *be,
DB_TXN *tid,
diff --git a/servers/slapd/back-bdb/idl.c b/servers/slapd/back-bdb/idl.c
index 16146d12e5..acb67d6c52 100644
--- a/servers/slapd/back-bdb/idl.c
+++ b/servers/slapd/back-bdb/idl.c
@@ -128,11 +128,11 @@ static int idl_delete( ID *ids, ID id )
int
bdb_idl_insert_key(
- BackendDB *be,
- DB *db,
+ BackendDB *be,
+ DB *db,
DB_TXN *tid,
- DBT *key,
- ID id )
+ DBT *key,
+ ID id )
{
int rc;
ID ids[BDB_IDL_DB_SIZE];
@@ -216,11 +216,11 @@ bdb_idl_insert_key(
int
bdb_idl_delete_key(
- BackendDB *be,
- DB *db,
+ BackendDB *be,
+ DB *db,
DB_TXN *tid,
- DBT *key,
- ID id )
+ DBT *key,
+ ID id )
{
int rc;
ID ids[BDB_IDL_DB_SIZE];
diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c
index 632d601aa8..77a4849280 100644
--- a/servers/slapd/back-bdb/init.c
+++ b/servers/slapd/back-bdb/init.c
@@ -242,20 +242,20 @@ bdb_db_destroy( BackendDB *be )
#ifdef SLAPD_BDB_DYNAMIC
int back_bdb_LTX_init_module( int argc, char *argv[] ) {
- BackendInfo bi;
+ BackendInfo bi;
- memset( &bi, '\0', sizeof(bi) );
- bi.bi_type = "bdb";
- bi.bi_init = bdb_initialize;
+ memset( &bi, '\0', sizeof(bi) );
+ bi.bi_type = "bdb";
+ bi.bi_init = bdb_initialize;
- backend_add( &bi );
- return 0;
+ backend_add( &bi );
+ return 0;
}
#endif /* SLAPD_BDB_DYNAMIC */
int
bdb_initialize(
- BackendInfo *bi
+ BackendInfo *bi
)
{
static char *controls[] = {
@@ -305,12 +305,12 @@ bdb_initialize(
bi->bi_op_bind = bdb_bind;
bi->bi_op_compare = bdb_compare;
bi->bi_op_delete = bdb_delete;
+ bi->bi_op_modify = bdb_modify;
+ bi->bi_op_modrdn = bdb_modrdn;
bi->bi_op_search = bdb_search;
#if 0
bi->bi_op_unbind = bdb_unbind;
- bi->bi_op_modify = bdb_modify;
- bi->bi_op_modrdn = bdb_modrdn;
bi->bi_op_abandon = bdb_abandon;
bi->bi_extended = bdb_extended;
@@ -318,8 +318,8 @@ bdb_initialize(
bi->bi_acl_group = bdb_group;
bi->bi_acl_attribute = bdb_attribute;
- bi->bi_chk_referrals = bdb_referrals;
#endif
+ bi->bi_chk_referrals = bdb_referrals;
bi->bi_entry_release_rw = 0;
diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c
new file mode 100644
index 0000000000..46717f07a7
--- /dev/null
+++ b/servers/slapd/back-bdb/modify.c
@@ -0,0 +1,497 @@
+/* modify.c - bdb backend modify routine */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include
+#include
+#include
+
+#include "back-bdb.h"
+#include "external.h"
+
+static int add_values( Entry *e, Modification *mod, char *dn );
+static int delete_values( Entry *e, Modification *mod, char *dn );
+static int replace_values( Entry *e, Modification *mod, char *dn );
+
+int bdb_modify_internal(
+ BackendDB *be,
+ Connection *conn,
+ Operation *op,
+ DB_TXN *tid,
+ const char *dn,
+ Modifications *modlist,
+ Entry *e,
+ const char **text )
+{
+ int rc, err;
+ Modification *mod;
+ Modifications *ml;
+ Attribute *save_attrs;
+
+ Debug(LDAP_DEBUG_TRACE, "bdb_modify_internal: %s\n", dn, 0, 0);
+
+ if ( !acl_check_modlist( be, conn, op, e, modlist )) {
+ return LDAP_INSUFFICIENT_ACCESS;
+ }
+
+ save_attrs = e->e_attrs;
+ e->e_attrs = attrs_dup( e->e_attrs );
+
+ for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
+ mod = &ml->sml_mod;
+
+ switch ( mod->sm_op ) {
+ case LDAP_MOD_ADD:
+ Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: add\n", 0, 0, 0);
+ err = add_values( e, mod, op->o_ndn );
+
+ if( err != LDAP_SUCCESS ) {
+ Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
+ err, *text, 0);
+ *text = "modify: add values failed";
+ }
+ break;
+
+ case LDAP_MOD_DELETE:
+ Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: delete\n", 0, 0, 0);
+ err = delete_values( e, mod, op->o_ndn );
+ assert( err != LDAP_TYPE_OR_VALUE_EXISTS );
+ if( err != LDAP_SUCCESS ) {
+ Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
+ err, *text, 0);
+ *text = "modify: delete values failed";
+ }
+ break;
+
+ case LDAP_MOD_REPLACE:
+ Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: replace\n", 0, 0, 0);
+ err = replace_values( e, mod, op->o_ndn );
+ assert( err != LDAP_TYPE_OR_VALUE_EXISTS );
+ if( err != LDAP_SUCCESS ) {
+ Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
+ err, *text, 0);
+ *text = "modify: replace values failed";
+ }
+ break;
+
+ case SLAP_MOD_SOFTADD:
+ Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: softadd\n", 0, 0, 0);
+ /* Avoid problems in index_add_mods()
+ * We need to add index if necessary.
+ */
+ mod->sm_op = LDAP_MOD_ADD;
+ err = add_values( e, mod, op->o_ndn );
+
+ if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
+ err = LDAP_SUCCESS;
+ }
+
+ if( err != LDAP_SUCCESS ) {
+ Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
+ err, *text, 0);
+ *text = "modify: (soft)add values failed";
+ }
+ break;
+
+ default:
+ Debug(LDAP_DEBUG_ANY, "bdb_modify_internal: invalid op %d\n",
+ mod->sm_op, 0, 0);
+ *text = "Invalid modify operation";
+ err = LDAP_OTHER;
+ Debug(LDAP_DEBUG_ARGS, "bdb_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;
+ }
+ }
+
+ /* check that the entry still obeys the schema */
+ rc = entry_schema_check( e, save_attrs, text );
+ if ( rc != LDAP_SUCCESS ) {
+ attrs_free( e->e_attrs );
+ e->e_attrs = save_attrs;
+ Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n",
+ *text, 0, 0 );
+ return rc;
+ }
+
+#if 0
+ /* delete indices for old attributes */
+ rc = index_entry_del( be, tid, e, save_attrs);
+
+ /* add indices for new attributes */
+ rc = index_entry_add( be, tid, e, e->e_attrs);
+#endif
+
+ attrs_free( save_attrs );
+
+ return rc;
+}
+
+
+int
+bdb_modify(
+ BackendDB *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ Modifications *modlist
+)
+{
+ struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+ int rc;
+ Entry *matched;
+ Entry *e;
+ int manageDSAit = get_manageDSAit( op );
+ const char *text = NULL;
+ DB_TXN *ltid;
+ struct bdb_op_info opinfo;
+
+ Debug(LDAP_DEBUG_ARGS, "bdb_back_modify: %s\n", dn, 0, 0);
+
+ if (0) {
+ /* transaction retry */
+retry: rc = txn_abort( ltid );
+ ltid = NULL;
+ op->o_private = NULL;
+ if( rc != 0 ) {
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+ }
+
+ /* begin transaction */
+ rc = txn_begin( bdb->bi_dbenv, NULL, <id, 0 );
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify: txn_begin failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+
+ opinfo.boi_bdb = be;
+ opinfo.boi_txn = ltid;
+ opinfo.boi_err = 0;
+ op->o_private = &opinfo;
+
+ /* get entry */
+ rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, 0 );
+
+ if ( rc != 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify: dn2entry failed (%d)\n",
+ rc, 0, 0 );
+ switch( rc ) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ case DB_NOTFOUND:
+ break;
+ default:
+ rc = LDAP_OTHER;
+ }
+ text = "internal error";
+ goto return_results;
+ }
+
+ /* acquire and lock entry */
+ if ( e == NULL ) {
+ char* matched_dn = NULL;
+ struct berval **refs = NULL;
+
+ if ( matched != NULL ) {
+ matched_dn = ch_strdup( matched->e_dn );
+ refs = is_entry_referral( matched )
+ ? get_entry_referrals( be, conn, op, matched )
+ : NULL;
+ bdb_entry_return( be, matched );
+
+ } else {
+ refs = default_referral;
+ }
+
+ send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+ matched_dn, NULL, refs, NULL );
+
+ if ( matched != NULL ) {
+ ber_bvecfree( refs );
+ free( matched_dn );
+ }
+
+ return rc;
+ }
+
+ if ( !manageDSAit && is_entry_referral( e ) ) {
+ /* parent is a referral, don't allow add */
+ /* parent is an alias, don't allow add */
+ struct berval **refs = get_entry_referrals( be,
+ conn, op, e );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify: entry is referral\n",
+ 0, 0, 0 );
+
+ send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+ e->e_dn, NULL, refs, NULL );
+
+ ber_bvecfree( refs );
+ goto done;
+ }
+
+ /* Modify the entry */
+ rc = bdb_modify_internal( be, conn, op, ltid, ndn, modlist, e, &text );
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify: modify failed (%d)\n",
+ rc, 0, 0 );
+ switch( rc ) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ }
+ goto return_results;
+ }
+
+ /* change the entry itself */
+ rc = bdb_id2entry_update( be, ltid, e );
+ if ( rc != 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify: id2entry update failed (%d)\n",
+ rc, 0, 0 );
+ switch( rc ) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ }
+ text = "entry update failed";
+ goto return_results;
+ }
+
+ rc = txn_commit( ltid, 0 );
+ ltid = NULL;
+ op->o_private = NULL;
+
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify: txn_commit failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ rc = LDAP_OTHER;
+ text = "commit failed";
+ } else {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify: added id=%08x dn=\"%s\"\n",
+ e->e_id, e->e_dn, 0 );
+ rc = LDAP_SUCCESS;
+ text = NULL;
+ }
+
+return_results:
+ send_ldap_result( conn, op, rc,
+ NULL, text, NULL, NULL );
+
+done:
+ if( ltid != NULL ) {
+ txn_abort( ltid );
+ op->o_private = NULL;
+ }
+
+ bdb_entry_return( be, e );
+ return rc;
+}
+
+static int
+add_values(
+ Entry *e,
+ Modification *mod,
+ char *dn
+)
+{
+ int i;
+ Attribute *a;
+
+ /* char *desc = mod->sm_desc->ad_cname->bv_val; */
+ MatchingRule *mr = mod->sm_desc->ad_type->sat_equality;
+
+ a = attr_find( e->e_attrs, mod->sm_desc );
+
+ /* check if the values we're adding already exist */
+ if ( a != NULL ) {
+ if( mr == NULL || !mr->smr_match ) {
+ /* do not allow add of additional attribute
+ if no equality rule exists */
+ return LDAP_INAPPROPRIATE_MATCHING;
+ }
+
+ for ( i = 0; mod->sm_bvalues[i] != NULL; i++ ) {
+ int rc;
+ int j;
+ const char *text = NULL;
+ struct berval *asserted;
+
+ rc = value_normalize( mod->sm_desc,
+ SLAP_MR_EQUALITY,
+ mod->sm_bvalues[i],
+ &asserted,
+ &text );
+
+ if( rc != LDAP_SUCCESS ) return rc;
+
+ for ( j = 0; a->a_vals[j] != NULL; j++ ) {
+ int match;
+ int rc = value_match( &match, mod->sm_desc, mr,
+ SLAP_MR_MODIFY_MATCHING,
+ a->a_vals[j], asserted, &text );
+
+ if( rc == LDAP_SUCCESS && match == 0 ) {
+ ber_bvfree( asserted );
+ return LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+ }
+
+ ber_bvfree( asserted );
+ }
+ }
+
+ /* no - add them */
+ if( attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 ) {
+ /* this should return result return of attr_merge */
+ return LDAP_OTHER;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+delete_values(
+ Entry *e,
+ Modification *mod,
+ char *dn
+)
+{
+ int i, j, k, found;
+ Attribute *a;
+ char *desc = mod->sm_desc->ad_cname->bv_val;
+ MatchingRule *mr = mod->sm_desc->ad_type->sat_equality;
+
+ /* delete the entire attribute */
+ if ( mod->sm_bvalues == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify_delete: removing entire attribute %s\n",
+ desc, 0, 0 );
+ return attr_delete( &e->e_attrs, mod->sm_desc )
+ ? LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS;
+ }
+
+ if( mr == NULL || !mr->smr_match ) {
+ /* disallow specific attributes from being deleted if
+ no equality rule */
+ return LDAP_INAPPROPRIATE_MATCHING;
+ }
+
+ /* delete specific values - find the attribute first */
+ if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify_delete: could not find attribute %s\n",
+ desc, 0, 0 );
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+
+ /* find each value to delete */
+ for ( i = 0; mod->sm_bvalues[i] != NULL; i++ ) {
+ int rc;
+ const char *text = NULL;
+
+ struct berval *asserted;
+
+ rc = value_normalize( mod->sm_desc,
+ SLAP_MR_EQUALITY,
+ mod->sm_bvalues[i],
+ &asserted,
+ &text );
+
+ if( rc != LDAP_SUCCESS ) return rc;
+
+ found = 0;
+ for ( j = 0; a->a_vals[j] != NULL; j++ ) {
+ int match;
+ int rc = value_match( &match, mod->sm_desc, mr,
+ SLAP_MR_MODIFY_MATCHING,
+ a->a_vals[j], asserted, &text );
+
+ if( rc == LDAP_SUCCESS && match != 0 ) {
+ continue;
+ }
+
+ /* found a matching value */
+ found = 1;
+
+ /* delete it */
+ ber_bvfree( a->a_vals[j] );
+ for ( k = j + 1; a->a_vals[k] != NULL; k++ ) {
+ a->a_vals[k - 1] = a->a_vals[k];
+ }
+ a->a_vals[k - 1] = NULL;
+
+ break;
+ }
+
+ ber_bvfree( asserted );
+
+ /* looked through them all w/o finding it */
+ if ( ! found ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify_delete: could not find value for attr %s\n",
+ desc, 0, 0 );
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+ }
+
+ /* if no values remain, delete the entire attribute */
+ if ( a->a_vals[0] == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modify_delete: removing entire attribute %s\n",
+ desc, 0, 0 );
+ if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
+ return LDAP_NO_SUCH_ATTRIBUTE;
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+replace_values(
+ Entry *e,
+ Modification *mod,
+ char *dn
+)
+{
+ int rc = attr_delete( &e->e_attrs, mod->sm_desc );
+
+ if( rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE ) {
+ return rc;
+ }
+
+ if ( mod->sm_bvalues != NULL &&
+ attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 )
+ {
+ return LDAP_OTHER;
+ }
+
+ return LDAP_SUCCESS;
+}
diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c
new file mode 100644
index 0000000000..456f1b49e2
--- /dev/null
+++ b/servers/slapd/back-bdb/modrdn.c
@@ -0,0 +1,534 @@
+/* modrdn.c - bdb backend modrdn routine */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include
+#include
+
+#include "back-bdb.h"
+#include "external.h"
+
+int
+bdb_modrdn(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
+ const char *newrdn,
+ int deleteoldrdn,
+ const char *newSuperior
+)
+{
+ struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+ AttributeDescription *children = slap_schema.si_ad_children;
+ char *p_dn = NULL, *p_ndn = NULL;
+ char *new_dn = NULL, *new_ndn = NULL;
+ Entry *e, *p = NULL;
+ Entry *matched;
+ int rc;
+ const char *text = NULL;
+ DB_TXN * ltid;
+ struct bdb_op_info opinfo;
+
+ ID id;
+ char *new_rdn_val = NULL; /* Val of new rdn */
+ char *new_rdn_type = NULL; /* Type of new rdn */
+ char *old_rdn = NULL; /* Old rdn's attr type & val */
+ char *old_rdn_type = NULL; /* Type of old rdn attr. */
+ char *old_rdn_val = NULL; /* Old rdn attribute value */
+
+ Entry *np = NULL; /* newSuperior Entry */
+ char *np_dn = NULL; /* newSuperior dn */
+ char *np_ndn = NULL; /* newSuperior ndn */
+ char *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */
+
+ /* Used to interface with bdb_modify_internal() */
+ struct berval add_bv; /* Stores new rdn att */
+ struct berval *add_bvals[2]; /* Stores new rdn att */
+ struct berval del_bv; /* Stores old rdn att */
+ struct berval *del_bvals[2]; /* Stores old rdn att */
+ Modifications mod[2]; /* Used to delete old rdn */
+
+ int manageDSAit = get_manageDSAit( op );
+
+ Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn(%s,%s,%s)\n",
+ dn, newrdn, (newSuperior ? newSuperior : "NULL") );
+
+ if (0) {
+ /* transaction retry */
+retry: rc = txn_abort( ltid );
+ ltid = NULL;
+ op->o_private = NULL;
+ if( rc != 0 ) {
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+ }
+
+ /* begin transaction */
+ rc = txn_begin( bdb->bi_dbenv, NULL, <id, 0 );
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_delete: txn_begin failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+
+ opinfo.boi_bdb = be;
+ opinfo.boi_txn = ltid;
+ opinfo.boi_err = 0;
+ op->o_private = &opinfo;
+
+ /* get entry */
+ rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, 0 );
+
+ switch( rc ) {
+ case 0:
+ case DB_NOTFOUND:
+ break;
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ default:
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+
+ if ( e == NULL ) {
+ char* matched_dn = NULL;
+ struct berval** refs = NULL;
+
+ if( matched != NULL ) {
+ matched_dn = strdup( matched->e_dn );
+ refs = is_entry_referral( matched )
+ ? get_entry_referrals( be, conn, op, matched )
+ : NULL;
+ bdb_entry_return( be, matched );
+ } else {
+ refs = default_referral;
+ }
+
+ send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+ matched_dn, NULL, refs, NULL );
+
+ if ( matched != NULL ) {
+ ber_bvecfree( refs );
+ free( matched_dn );
+ }
+
+ goto done;
+ }
+
+ if (!manageDSAit && is_entry_referral( e ) ) {
+ /* parent is a referral, don't allow add */
+ /* parent is an alias, don't allow add */
+ struct berval **refs = get_entry_referrals( be,
+ conn, op, e );
+
+ Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n",
+ 0, 0, 0 );
+
+ send_ldap_result( conn, op, rc = LDAP_REFERRAL,
+ e->e_dn, NULL, refs, NULL );
+
+ ber_bvecfree( refs );
+ goto done;
+ }
+
+ p_ndn = dn_parent( be, e->e_ndn );
+ if ( p_ndn != NULL ) {
+ /* Make sure parent entry exist and we can write its
+ * children.
+ */
+
+ rc = bdb_dn2entry( be, ltid, p_ndn, &p, NULL, 0 );
+
+ switch( rc ) {
+ case 0:
+ case DB_NOTFOUND:
+ break;
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ default:
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+
+ if( p == NULL) {
+ Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: parent does not exist\n",
+ 0, 0, 0);
+ rc = LDAP_OTHER;
+ goto return_results;
+ }
+
+ /* check parent for "children" acl */
+ if ( ! access_allowed( be, conn, op, p,
+ children, NULL, ACL_WRITE ) )
+ {
+ Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
+ 0, 0 );
+ send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+ NULL, NULL, NULL, NULL );
+ goto return_results;
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: wr to children of entry %s OK\n",
+ p_ndn, 0, 0 );
+
+ p_dn = dn_parent( be, e->e_dn );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: parent dn=%s\n",
+ p_dn, 0, 0 );
+
+ } else {
+ /* no parent, modrdn entry directly under root */
+ if( ! be_isroot( be, op->o_ndn ) ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: no parent & not root\n",
+ 0, 0, 0);
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ goto return_results;
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: no parent, locked root\n",
+ 0, 0, 0 );
+ }
+
+ new_parent_dn = p_dn; /* New Parent unless newSuperior given */
+
+ if ( newSuperior != NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: new parent \"%s\" requested...\n",
+ newSuperior, 0, 0 );
+
+ np_dn = ch_strdup( newSuperior );
+ np_ndn = ch_strdup( np_dn );
+ (void) dn_normalize( np_ndn );
+
+ /* newSuperior == oldParent?, if so ==> ERROR */
+ /* newSuperior == entry being moved?, if so ==> ERROR */
+ /* Get Entry with dn=newSuperior. Does newSuperior exist? */
+
+ rc = bdb_dn2entry( be, ltid, np_ndn, &np, NULL, 0 );
+
+ switch( rc ) {
+ case 0:
+ case DB_NOTFOUND:
+ break;
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ default:
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+
+ if( np == NULL) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: newSup(ndn=%s) not here!\n",
+ np_ndn, 0, 0);
+ rc = LDAP_OTHER;
+ goto return_results;
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: wr to new parent OK np=%p, id=%ld\n",
+ np, np->e_id, 0 );
+
+ /* check newSuperior for "children" acl */
+ if ( !access_allowed( be, conn, op, np, children, NULL, ACL_WRITE ) ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: no wr to newSup children\n",
+ 0, 0, 0 );
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ goto return_results;
+ }
+
+ if ( is_entry_alias( np ) ) {
+ /* entry is an alias, don't allow bind */
+ Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is alias\n",
+ 0, 0, 0 );
+
+ rc = LDAP_ALIAS_PROBLEM;
+ goto return_results;
+ }
+
+ if ( is_entry_referral( np ) ) {
+ /* parent is a referral, don't allow add */
+ /* parent is an alias, don't allow add */
+ Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n",
+ 0, 0, 0 );
+
+ rc = LDAP_OPERATIONS_ERROR;
+ goto return_results;
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_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. */
+ build_new_dn( &new_dn, e->e_dn, new_parent_dn, newrdn );
+
+ new_ndn = ch_strdup(new_dn);
+ (void) dn_normalize( new_ndn );
+
+ Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: new ndn=%s\n",
+ new_ndn, 0, 0 );
+
+ rc = bdb_dn2id ( be, ltid, new_ndn, &id );
+ if( rc != 0 ) {
+ switch( rc ) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ default:
+ rc = LDAP_OTHER;
+ text = "internal error";
+ }
+
+ goto return_results;
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: new ndn=%s does not exist\n",
+ new_ndn, 0, 0 );
+
+ /* Get attribute type and attribute value of our new rdn, we will
+ * need to add that to our new entry
+ */
+
+ new_rdn_type = rdn_attr_type( newrdn );
+ if ( new_rdn_type == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: can't figure out type of newrdn\n",
+ 0, 0, 0 );
+ rc = LDAP_OPERATIONS_ERROR;
+ text = "unknown type used in RDN";
+ goto return_results;
+ }
+
+ new_rdn_val = rdn_attr_value( newrdn );
+ if ( new_rdn_val == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: could not figure out val of newrdn\n",
+ 0, 0, 0 );
+ rc = LDAP_OPERATIONS_ERROR;
+ text = "could not parse RDN value";
+ goto return_results;
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: new_rdn_val=\"%s\", new_rdn_type=\"%s\"\n",
+ new_rdn_val, new_rdn_type, 0 );
+
+ /* Retrieve the old rdn from the entry's dn */
+
+ if ( (old_rdn = dn_rdn( be, dn )) == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: can't figure out old_rdn from dn\n",
+ 0, 0, 0 );
+ rc = LDAP_OTHER;
+ text = "could not parse old DN";
+ goto return_results;
+ }
+
+ if ( (old_rdn_type = rdn_attr_type( old_rdn )) == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_back_modrdn: can't figure out the old_rdn type\n",
+ 0, 0, 0 );
+ rc = LDAP_OTHER;
+ text = "cannot parse RDN from old DN";
+ goto return_results;
+ }
+
+ if ( strcasecmp( old_rdn_type, new_rdn_type ) != 0 ) {
+ /* Not a big deal but we may say something */
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n",
+ old_rdn_type, new_rdn_type, 0 );
+ }
+
+ /* Add new attribute value to the entry */
+ add_bvals[0] = &add_bv; /* Array of bervals */
+ add_bvals[1] = NULL;
+
+ add_bv.bv_val = new_rdn_val;
+ add_bv.bv_len = strlen(new_rdn_val);
+
+ mod[0].sml_desc = NULL;
+ rc = slap_str2ad( new_rdn_type, &mod[0].sml_desc, &text );
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: %s: %s (new)\n",
+ text, new_rdn_type, 0 );
+ goto return_results;
+ }
+ mod[0].sml_bvalues = add_bvals;
+ mod[0].sml_op = SLAP_MOD_SOFTADD;
+ mod[0].sml_next = NULL;
+
+ /* Remove old rdn value if required */
+
+ if (deleteoldrdn) {
+ /* Get value of old rdn */
+ old_rdn_val = rdn_attr_value( old_rdn );
+ if ( old_rdn_val == NULL) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: can't figure out old_rdn_val from old_rdn\n",
+ 0, 0, 0 );
+ rc = LDAP_OTHER;
+ text = "could not parse value from old RDN";
+ goto return_results;
+ }
+
+ del_bvals[0] = &del_bv; /* Array of bervals */
+ del_bvals[1] = NULL;
+
+ /* Remove old value of rdn as an attribute. */
+ del_bv.bv_val = old_rdn_val;
+ del_bv.bv_len = strlen(old_rdn_val);
+
+ mod[1].sml_desc = NULL;
+ rc = slap_str2ad( old_rdn_type, &mod[1].sml_desc, &text );
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: %s: %s (old)\n",
+ text, old_rdn_type, 0 );
+ goto return_results;
+ }
+
+ mod[0].sml_next = &mod[1];
+ mod[1].sml_bvalues = del_bvals;
+ mod[1].sml_op = LDAP_MOD_DELETE;
+ mod[1].sml_next = NULL;
+ }
+
+ /* delete old one */
+ rc = bdb_dn2id_delete( be, ltid, e->e_ndn, e->e_id );
+ if ( rc != 0 ) {
+ rc = LDAP_OTHER;
+ text = "DN index delete fail";
+ goto return_results;
+ }
+
+ free( e->e_dn );
+ free( e->e_ndn );
+ e->e_dn = new_dn;
+ e->e_ndn = new_ndn;
+ new_dn = NULL;
+ new_ndn = NULL;
+
+ /* add new one */
+ rc = bdb_dn2id_add( be, ltid, e->e_ndn, e->e_id );
+ if ( rc != 0 ) {
+ rc = LDAP_OTHER;
+ text = "DN index add failed";
+ goto return_results;
+ }
+
+ /* modify entry */
+ rc = bdb_modify_internal( be, conn, op, ltid, dn, &mod[0], e, &text );
+
+ if( rc != LDAP_SUCCESS ) {
+ goto return_results;
+ }
+
+ /* NOTE: after this you must not free new_dn or new_ndn!
+ * They are used by cache.
+ */
+
+ /* id2entry index */
+ rc = bdb_id2entry_add( be, ltid, e );
+ if ( rc != 0 ) {
+ rc = LDAP_OTHER;
+ text = "entry update failed";
+ goto return_results;
+ }
+
+ rc = LDAP_SUCCESS;
+
+ rc = txn_commit( ltid, 0 );
+ ltid = NULL;
+ op->o_private = NULL;
+
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: txn_commit failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ rc = LDAP_OTHER;
+ text = "commit failed";
+ } else {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_modrdn: added id=%08x dn=\"%s\"\n",
+ e->e_id, e->e_dn, 0 );
+ rc = LDAP_SUCCESS;
+ text = NULL;
+ }
+
+return_results:
+ send_ldap_result( conn, op, rc,
+ NULL, text, NULL, NULL );
+
+done:
+ if( new_dn != NULL ) free( new_dn );
+ if( new_ndn != NULL ) free( new_ndn );
+
+ if( p_dn != NULL ) free( p_dn );
+ if( p_ndn != NULL ) free( p_ndn );
+
+ /* LDAP v2 supporting correct attribute handling. */
+ if( new_rdn_type != NULL ) free(new_rdn_type);
+ if( new_rdn_val != NULL ) free(new_rdn_val);
+ if( old_rdn != NULL ) free(old_rdn);
+ if( old_rdn_type != NULL ) free(old_rdn_type);
+ if( old_rdn_val != NULL ) free(old_rdn_val);
+
+
+ /* LDAP v3 Support */
+ if ( np_dn != NULL ) free( np_dn );
+ if ( np_ndn != NULL ) free( np_ndn );
+
+ if( np != NULL ) {
+ /* free new parent and writer lock */
+ bdb_entry_return( be, np );
+ }
+
+ if( p != NULL ) {
+ /* free parent and writer lock */
+ bdb_entry_return( be, p );
+ }
+
+ /* free entry */
+ if( e != NULL ) {
+ bdb_entry_return( be, e );
+ }
+
+ if( ltid != NULL ) {
+ txn_abort( ltid );
+ op->o_private = NULL;
+ }
+
+ return rc;
+}
diff --git a/servers/slapd/back-bdb/passwd.c b/servers/slapd/back-bdb/passwd.c
index 1639a62979..2731bd5a73 100644
--- a/servers/slapd/back-bdb/passwd.c
+++ b/servers/slapd/back-bdb/passwd.c
@@ -15,23 +15,23 @@
int
bdb_exop_passwd(
- Backend *be,
- Connection *conn,
- Operation *op,
+ Backend *be,
+ Connection *conn,
+ Operation *op,
const char *reqoid,
- struct berval *reqdata,
+ struct berval *reqdata,
char **rspoid,
- struct berval **rspdata,
+ struct berval **rspdata,
LDAPControl *** rspctrls,
const char **text,
- struct berval *** refs
-)
+ struct berval *** refs )
{
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
int rc;
Entry *e = NULL;
struct berval *hash = NULL;
- DB_TXN *ltid;
+ DB_TXN *ltid = NULL;
+ struct bdb_op_info opinfo;
struct berval *id = NULL;
struct berval *new = NULL;
@@ -82,17 +82,48 @@ bdb_exop_passwd(
goto done;
}
- /* fetch entry */
- rc = dn2entry_w( be, NULL, dn, &e, NULL );
+ if (0) {
+ /* transaction retry */
+retry: rc = txn_abort( ltid );
+ ltid = NULL;
+ op->o_private = NULL;
+ if( rc != 0 ) {
+ rc = LDAP_OTHER;
+ *text = "internal error";
+ goto done;
+ }
+ }
+
+ /* begin transaction */
+ rc = txn_begin( bdb->bi_dbenv, NULL, <id, 0 );
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_exop_passwd: txn_begin failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ rc = LDAP_OTHER;
+ *text = "internal error";
+ goto done;
+ }
+
+ opinfo.boi_bdb = be;
+ opinfo.boi_txn = ltid;
+ opinfo.boi_err = 0;
+ op->o_private = &opinfo;
+
+ /* get entry */
+ rc = bdb_dn2entry( be, ltid, dn, &e, NULL, 0 );
switch(rc) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
case DB_NOTFOUND:
case 0:
break;
default:
- send_ldap_result( conn, op, rc=LDAP_OTHER,
- NULL, "internal error", NULL, NULL );
- return rc;
+ rc = LDAP_OTHER;
+ *text = "internal error";
+ goto done;
}
if( e == NULL ) {
@@ -108,11 +139,11 @@ bdb_exop_passwd(
goto done;
}
- rc = LDAP_OPERATIONS_ERROR;
if( is_entry_referral( e ) ) {
/* entry is an referral, don't allow operation */
*text = "authorization entry is referral";
+ rc = LDAP_OPERATIONS_ERROR;
goto done;
}
@@ -128,19 +159,39 @@ bdb_exop_passwd(
ml.sml_op = LDAP_MOD_REPLACE;
ml.sml_next = NULL;
- rc = bdb_modify_internal( be,
- conn, op, op->o_ndn, &ml, e, text );
+ rc = bdb_modify_internal( be, conn, op, ltid,
+ op->o_ndn, &ml, e, text );
- }
-
- if( rc == LDAP_SUCCESS ) {
- /* change the entry itself */
- if( bdb_id2entry_add( be, ltid, e ) != 0 ) {
- *text = "entry update failed";
+ switch(rc) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ bdb_entry_return( be, e );
+ e = NULL;
+ goto retry;
+ case 0:
+ break;
+ default:
rc = LDAP_OTHER;
+ *text = "entry modify failed";
+ goto done;
}
+
}
-
+
+ /* change the entry itself */
+ rc = bdb_id2entry_update( be, ltid, e );
+ if( rc != 0 ) {
+ switch(rc) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ bdb_entry_return( be, e );
+ goto retry;
+ }
+ *text = "entry update failed";
+ rc = LDAP_OTHER;
+ goto done;
+ }
+
done:
if( e != NULL ) {
bdb_entry_return( be, e );
@@ -158,5 +209,10 @@ done:
ber_bvfree( hash );
}
+ if( ltid != NULL ) {
+ txn_abort( ltid );
+ op->o_private = NULL;
+ }
+
return rc;
}
diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h
index 111b51685d..e4cc6e11fd 100644
--- a/servers/slapd/back-bdb/proto-bdb.h
+++ b/servers/slapd/back-bdb/proto-bdb.h
@@ -31,12 +31,6 @@ Entry *bdb_deref_internal_r LDAP_P((
int bdb_dn2entry LDAP_P(( BackendDB *be, DB_TXN *tid,
const char *dn, Entry **e, Entry **matched, int flags ));
-#define dn2entry_r(be, tid, dn, p, m) \
- bdb_dn2entry((be), (tid), (dn), (p), (m), 0 )
-
-#define dn2entry_w(be, tid, dn, p, m) \
- bdb_dn2entry((be), (tid), (dn), (p), (m), DB_RMW )
-
/*
* dn2id.c
*/
@@ -88,6 +82,11 @@ int bdb_id2entry_add(
DB_TXN *tid,
Entry *e );
+int bdb_id2entry_update(
+ BackendDB *be,
+ DB_TXN *tid,
+ Entry *e );
+
int bdb_id2entry_delete(
BackendDB *be,
DB_TXN *tid,
@@ -123,6 +122,35 @@ int bdb_idl_delete_key(
*/
int bdb_next_id( BackendDB *be, DB_TXN *tid, ID *id );
+/*
+ * modify.c
+ */
+int bdb_modify_internal(
+ BackendDB *be,
+ Connection *conn,
+ Operation *op,
+ DB_TXN *tid,
+ const char *dn,
+ Modifications *modlist,
+ Entry *e,
+ const char **text );
+
+/*
+ * passwd.c
+ */
+int
+bdb_exop_passwd(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *reqoid,
+ struct berval *reqdata,
+ char **rspoid,
+ struct berval **rspdata,
+ LDAPControl *** rspctrls,
+ const char **text,
+ struct berval *** refs );
+
/*
* tools.c
*/
diff --git a/servers/slapd/back-bdb/referral.c b/servers/slapd/back-bdb/referral.c
index ef8e5d7ca1..f4e2a08c70 100644
--- a/servers/slapd/back-bdb/referral.c
+++ b/servers/slapd/back-bdb/referral.c
@@ -14,11 +14,11 @@
int
bdb_referrals(
- BackendDB *be,
- Connection *conn,
- Operation *op,
- const char *dn,
- const char *ndn,
+ BackendDB *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn,
const char **text )
{
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
@@ -35,8 +35,8 @@ bdb_referrals(
return rc;
}
- /* fetch entry */
- rc = dn2entry_r( be, NULL, ndn, &e, &matched );
+ /* get entry */
+ rc = bdb_dn2entry( be, NULL, ndn, &e, &matched, 0 );
switch(rc) {
case DB_NOTFOUND:
@@ -44,7 +44,7 @@ bdb_referrals(
break;
default:
send_ldap_result( conn, op, rc=LDAP_OTHER,
- NULL, "internal error", NULL, NULL );
+ NULL, "internal error", NULL, NULL );
return rc;
}
@@ -91,7 +91,7 @@ bdb_referrals(
if( refs != NULL ) {
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
- e->e_dn, NULL, refs, NULL );
+ e->e_dn, NULL, refs, NULL );
}
ber_bvecfree( refs );
diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c
index 78a16e48a8..9ae8746ec9 100644
--- a/servers/slapd/back-bdb/search.c
+++ b/servers/slapd/back-bdb/search.c
@@ -14,14 +14,14 @@
#include "external.h"
static int base_candidate(
- BackendDB *be,
+ BackendDB *be,
Entry *e,
ID *ids );
static int search_candidates(
BackendDB *be,
Entry *e,
Filter *filter,
- int scope,
+ int scope,
int deref,
int manageDSAit,
ID *ids );
@@ -31,19 +31,19 @@ static ID idl_next( ID *ids, ID *cursor );
int
bdb_search(
- BackendDB *be,
- Connection *conn,
- Operation *op,
- const char *base,
- const char *nbase,
- int scope,
- int deref,
- int slimit,
- int tlimit,
- Filter *filter,
- const char *filterstr,
- char **attrs,
- int attrsonly )
+ BackendDB *be,
+ Connection *conn,
+ Operation *op,
+ const char *base,
+ const char *nbase,
+ int scope,
+ int deref,
+ int slimit,
+ int tlimit,
+ Filter *filter,
+ const char *filterstr,
+ char **attrs,
+ int attrsonly )
{
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
int abandon;
@@ -72,8 +72,7 @@ bdb_search(
} else
#endif
{
- /* obtain entry */
- rc = dn2entry_r( be, NULL, nbase, &e, &matched );
+ rc = bdb_dn2entry( be, NULL, nbase, &e, &matched, 0 );
}
switch(rc) {
@@ -82,7 +81,7 @@ bdb_search(
break;
default:
send_ldap_result( conn, op, rc=LDAP_OTHER,
- NULL, "internal error", NULL, NULL );
+ NULL, "internal error", NULL, NULL );
return rc;
}
@@ -125,7 +124,7 @@ bdb_search(
0, 0, 0 );
send_ldap_result( conn, op, LDAP_REFERRAL,
- matched_dn, NULL, refs, NULL );
+ matched_dn, NULL, refs, NULL );
ber_bvecfree( refs );
free( matched_dn );
@@ -137,7 +136,7 @@ bdb_search(
tlimit = -1; /* allow root to set no limit */
} else {
tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
- be->be_timelimit : tlimit;
+ be->be_timelimit : tlimit;
stoptime = op->o_time + tlimit;
}
@@ -145,7 +144,7 @@ bdb_search(
slimit = -1; /* allow root to set no limit */
} else {
slimit = (slimit > be->be_sizelimit || slimit < 1) ?
- be->be_sizelimit : slimit;
+ be->be_sizelimit : slimit;
}
if ( scope == LDAP_SCOPE_BASE ) {
@@ -153,7 +152,7 @@ bdb_search(
} else {
rc = search_candidates( be, e, filter,
- scope, deref, manageDSAit, candidates );
+ scope, deref, manageDSAit, candidates );
}
/* need normalized dn below */
@@ -178,7 +177,7 @@ bdb_search(
for ( id = idl_first( candidates, &cursor );
id != NOID;
- id = idl_next( candidates, &cursor ) )
+ id = idl_next( candidates, &cursor ) )
{
int scopeok = 0;
@@ -357,7 +356,7 @@ done:
static int base_candidate(
- BackendDB *be,
+ BackendDB *be,
Entry *e,
ID *ids )
{
@@ -373,20 +372,72 @@ static int search_candidates(
BackendDB *be,
Entry *e,
Filter *filter,
- int scope,
+ int scope,
int deref,
int manageDSAit,
ID *ids )
{
- Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" (0x%08lx)\n",
- e->e_dn, (long) e->e_id, 0);
+ int rc;
+ Filter f, fand, rf, af, xf;
+ AttributeAssertion aa_ref, aa_alias;
- /* return a RANGE IDL for now */
+ Debug(LDAP_DEBUG_TRACE,
+ "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n",
+ e->e_dn, (long) e->e_id, scope );
+
+ xf.f_or = filter;
+ xf.f_choice = LDAP_FILTER_OR;
+ xf.f_next = NULL;
+
+ if( !manageDSAit ) {
+ /* match referrals */
+ static struct berval bv_ref = { sizeof("REFERRAL")-1, "REFERRAL" };
+ rf.f_choice = LDAP_FILTER_EQUALITY;
+ rf.f_ava = &aa_ref;
+ rf.f_av_desc = slap_schema.si_ad_objectClass;
+ rf.f_av_value = &bv_ref;
+ rf.f_next = xf.f_or;
+ xf.f_or = &rf;
+ }
+
+#ifdef BDB_ALIASES
+ if( deref & LDAP_DEREF_SEARCHING ) {
+ /* match aliases */
+ static struct berval bv_alias = { sizeof("ALIAS")-1, "ALIAS" };
+ af.f_choice = LDAP_FILTER_EQUALITY;
+ af.f_ava = &aa_alias;
+ af.f_av_desc = slap_schema.si_ad_objectClass;
+ af.f_av_value = &bv_alias;
+ af.f_next = xf.f_or;
+ xf.f_or = ⁡
+ }
+#endif
+
+ f.f_next = NULL;
+ f.f_choice = LDAP_FILTER_AND;
+ f.f_and = &fand;
+ fand.f_choice = scope == LDAP_SCOPE_SUBTREE
+ ? SLAPD_FILTER_DN_SUBTREE
+ : SLAPD_FILTER_DN_ONE;
+ fand.f_dn = e->e_ndn;
+ fand.f_next = xf.f_or == filter ? filter : &xf ;
+
+#if 0
+ rc = bdb_filter_candidates( be, &f, ids );
+#else
+ /* a quick hack */
ids[0] = NOID;
ids[1] = e->e_id;
ids[2] = e->e_id+128;
+ rc = 0;
+#endif
- return 0;
+ Debug(LDAP_DEBUG_TRACE,
+ "search_candidates: id=%ld first=%ld last=%ld\n",
+ ids[0], ids[1],
+ BDB_IDL_IS_RANGE( ids ) ? ids[2] : ids[ids[0]] );
+
+ return rc;
}
static ID idl_first( ID *ids, ID *cursor )