/* lcup.c - lcup operations */
+/* $OpenLDAP$ */
/*
* Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
#ifdef LDAP_CLIENT_UPDATE
+static int psearch_base_candidate(
+ BackendDB *be,
+ Entry *e,
+ ID *ids );
+static int psearch_candidates(
+ BackendDB *be,
+ Operation *op,
+ Entry *e,
+ Filter *filter,
+ int scope,
+ int deref,
+ ID *ids );
+
int
bdb_abandon(
BackendDB *be,
int deref,
int slimit,
int tlimit,
- Filter *filter,
- struct berval *fstr,
+ Filter *filter,
+ struct berval *fstr,
AttributeName *attrs,
int attrsonly )
{
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
LDAP_LIST_FIRST(&op->psearch_spec) = (struct lcup_search_spec *)
- calloc ( 1, sizeof ( struct lcup_search_spec ) );
+ calloc ( 1, sizeof ( struct lcup_search_spec ) );
LDAP_LIST_FIRST(&op->psearch_spec)->op = op;
int slimit = LDAP_LIST_FIRST(&ps_op->psearch_spec)->slimit;
int tlimit = LDAP_LIST_FIRST(&ps_op->psearch_spec)->tlimit;
Filter *filter = LDAP_LIST_FIRST(&ps_op->psearch_spec)->filter;
- struct berval *filterstr = LDAP_LIST_FIRST(&ps_op->psearch_spec)->filterstr;
+ struct berval *filterstr = LDAP_LIST_FIRST(&ps_op->psearch_spec)->filterstr;
int attrsonly = LDAP_LIST_FIRST(&ps_op->psearch_spec)->attrsonly;
- AttributeName *attrs;
+ AttributeName uuid_attr[2];
+ AttributeName *attrs = uuid_attr;
if ( psearch_type != LCUP_PSEARCH_BY_DELETE &&
- psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) {
- attrs = LDAP_LIST_FIRST(&ps_op->psearch_spec)->attrs;
+ psearch_type != LCUP_PSEARCH_BY_SCOPEOUT )
+ {
+ attrs = LDAP_LIST_FIRST(&ps_op->psearch_spec)->attrs;
} else {
- attrs = uuid_attr;
+ attrs[0].an_desc = slap_schema.si_ad_entryUUID;
+ attrs[0].an_oc = NULL;
+ ber_dupbv( &attrs[0].an_name, &attrs[0].an_desc->ad_cname );
+ attrs[1].an_desc = NULL;
+ attrs[1].an_oc = NULL;
+ attrs[1].an_name.bv_len = 0;
+ attrs[1].an_name.bv_val = NULL;
}
#ifdef NEW_LOGGING
default:
send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER,
NULL, "internal error", NULL, NULL );
+ if ( psearch_type == LCUP_PSEARCH_BY_DELETE ||
+ psearch_type == LCUP_PSEARCH_BY_SCOPEOUT )
+ ch_free( attrs[0].an_name.bv_val );
return rc;
}
break;
case LDAP_BUSY:
if (e != NULL) {
- bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
+ bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache,
+ e, &lock);
}
if (matched != NULL) {
- bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
+ bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache,
+ matched, &lock);
}
send_ldap_result( ps_conn, ps_op, LDAP_BUSY,
NULL, "ldap server busy", NULL, NULL );
- LOCK_ID_FREE (bdb->bi_dbenv, locker );
+ LOCK_ID_FREE( bdb->bi_dbenv, locker );
+ if ( psearch_type == LCUP_PSEARCH_BY_DELETE ||
+ psearch_type == LCUP_PSEARCH_BY_SCOPEOUT )
+ ch_free( attrs[0].an_name.bv_val );
return LDAP_BUSY;
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto dn2entry_retry;
default:
if (e != NULL) {
- bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
+ bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache,
+ e, &lock);
}
if (matched != NULL) {
- bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
+ bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache,
+ matched, &lock);
}
send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER,
NULL, "internal error", NULL, NULL );
- LOCK_ID_FREE (bdb->bi_dbenv, locker );
+ LOCK_ID_FREE( bdb->bi_dbenv, locker );
+ if ( psearch_type == LCUP_PSEARCH_BY_DELETE ||
+ psearch_type == LCUP_PSEARCH_BY_SCOPEOUT )
+ ch_free( attrs[0].an_name.bv_val );
return rc;
}
? get_entry_referrals( be, ps_conn, ps_op, matched )
: NULL;
- bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
+ bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache,
+ matched, &lock);
matched = NULL;
if( erefs ) {
send_ldap_result( ps_conn, ps_op, rc=LDAP_REFERRAL ,
matched_dn.bv_val, text, refs, NULL );
- LOCK_ID_FREE (bdb->bi_dbenv, locker );
+ LOCK_ID_FREE( bdb->bi_dbenv, locker );
if ( refs ) ber_bvarray_free( refs );
if ( matched_dn.bv_val ) ber_memfree( matched_dn.bv_val );
+ if ( psearch_type == LCUP_PSEARCH_BY_DELETE ||
+ psearch_type == LCUP_PSEARCH_BY_SCOPEOUT )
+ ch_free( attrs[0].an_name.bv_val );
return rc;
}
}
#ifdef NEW_LOGGING
- LDAP_LOG ( OPERATION, RESULTS,
+ LDAP_LOG( OPERATION, RESULTS,
"bdb_search: entry is referral\n", 0, 0, 0 );
#else
Debug( LDAP_DEBUG_TRACE, "bdb_search: entry is referral\n",
refs ? NULL : "bad referral object",
refs, NULL );
- LOCK_ID_FREE (bdb->bi_dbenv, locker );
+ LOCK_ID_FREE( bdb->bi_dbenv, locker );
ber_bvarray_free( refs );
ber_memfree( matched_dn.bv_val );
+ if ( psearch_type == LCUP_PSEARCH_BY_DELETE ||
+ psearch_type == LCUP_PSEARCH_BY_SCOPEOUT )
+ ch_free( attrs[0].an_name.bv_val );
return 1;
}
/* compute it anyway; root does not use it */
stoptime = ps_op->o_time + tlimit;
+ /* select candidates */
+ if ( scope == LDAP_SCOPE_BASE ) {
+ rc = psearch_base_candidate( be, e, candidates );
+ } else {
+ BDB_IDL_ALL( bdb, candidates );
+ rc = psearch_candidates( be, op, e, filter,
+ scope, deref, candidates );
+ }
+
+ if ( !BDB_IDL_IS_RANGE( candidates ) ) {
+ cursor = bdb_idl_search( candidates, entry->e_id );
+ if ( candidates[cursor] != entry->e_id ) {
+ goto test_done;
+ }
+ } else {
+ if ( entry->e_id < BDB_IDL_RANGE_FIRST(candidates) &&
+ entry->e_id > BDB_IDL_RANGE_LAST(candidates) )
+ {
+ goto test_done;
+ }
+ }
+
/* candidates = { e } */
candidates[0] = 1;
candidates[1] = entry->e_id;
/* if not root and candidates exceed to-be-checked entries, abort */
if ( !isroot && limit->lms_s_unchecked != -1 ) {
if ( BDB_IDL_N(candidates) > (unsigned) limit->lms_s_unchecked ) {
- send_search_result( ps_conn, ps_op,
- LDAP_ADMINLIMIT_EXCEEDED,
- NULL, NULL, NULL, NULL, 0 );
+ send_search_result( ps_conn, ps_op, LDAP_ADMINLIMIT_EXCEEDED,
+ NULL, NULL, NULL, NULL, 0 );
rc = 1;
goto done;
}
ber_dupbv( &csnfge.f_av_value, &ps_op->o_clientupdate_state );
csnfge.f_next = filter;
- if ( !BDB_IDL_IS_RANGE( candidates ) ) {
- cursor = bdb_idl_search( candidates, entry->e_id );
- if ( candidates[cursor] != entry->e_id ) {
- rc = LDAP_SUCCESS;
- goto done;
- }
- } else {
- if ( entry->e_id < BDB_IDL_RANGE_FIRST(candidates) &&
- entry->e_id > BDB_IDL_RANGE_LAST(candidates) ) {
- rc = LDAP_SUCCESS;
- goto done;
- }
- }
-
id = entry->e_id;
/* check for abandon */
if ( psearch_type == LCUP_PSEARCH_BY_ADD ||
psearch_type == LCUP_PSEARCH_BY_DELETE ||
psearch_type == LCUP_PSEARCH_BY_MODIFY ||
- psearch_type == LCUP_PSEARCH_BY_SCOPEOUT ) {
+ psearch_type == LCUP_PSEARCH_BY_SCOPEOUT )
+ {
Attribute* a;
int ret;
int res;
const char *text = NULL;
LDAPControl *ctrls[2];
struct berval *bv;
-
- BerElement *ber = ber_alloc_t( LBER_USE_DER );
-
- if ( ber == NULL ) {
-#ifdef NEW_LOGGING
- LDAP_LOG ( OPERATION, RESULTS,
- "bdb_search: ber_alloc_t failed\n",
- 0, 0, 0 );
-#else
- Debug( LDAP_DEBUG_TRACE,
- "bdb_search: ber_alloc_t failed\n",
- 0, 0, 0 );
-#endif
- send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER,
- NULL, "internal error", NULL, NULL );
- goto done;
- }
+ char berbuf[LBER_ELEMENT_SIZEOF];
+ BerElement *ber = (BerElement *)berbuf;
+
+ ber_init2( ber, NULL, LBER_USE_DER );
LDAP_LIST_FIRST(&ps_op->psearch_spec)->entry_count++;
ctrls[0] = ch_malloc ( sizeof ( LDAPControl ) );
ctrls[1] = NULL;
- if ( LDAP_LIST_FIRST(&ps_op->psearch_spec)->entry_count % ps_op->o_clientupdate_interval == 0 ) {
+ if ( LDAP_LIST_FIRST(
+ &ps_op->psearch_spec)->entry_count %
+ ps_op->o_clientupdate_interval == 0 )
+ {
/* Send cookie */
for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
AttributeDescription *desc = a->a_desc;
if ( desc == slap_schema.si_ad_entryCSN ) {
ber_dupbv( &entrycsn_bv, &a->a_vals[0] );
if ( latest_entrycsn_bv.bv_val == NULL ) {
- ber_dupbv( &latest_entrycsn_bv, &entrycsn_bv );
+ ber_dupbv( &latest_entrycsn_bv,
+ &entrycsn_bv );
} else {
res = value_match( &ret, desc,
desc->ad_type->sat_ordering,
SLAP_MR_ASSERTION_SYNTAX_MATCH,
- &entrycsn_bv, &latest_entrycsn_bv, &text );
+ &entrycsn_bv, &latest_entrycsn_bv,
+ &text );
if ( res != LDAP_SUCCESS ) {
ret = 0;
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, RESULTS,
- "bdb_search: value_match failed\n",
+ "bdb_search: "
+ "value_match failed\n",
0, 0, 0 );
#else
Debug( LDAP_DEBUG_TRACE,
- "bdb_search: value_match failed\n",
+ "bdb_search: "
+ "value_match failed\n",
0, 0, 0 );
#endif
}
if ( ret > 0 ) {
- ch_free( latest_entrycsn_bv.bv_val );
+ ch_free(latest_entrycsn_bv.bv_val);
latest_entrycsn_bv.bv_val = NULL;
ber_dupbv( &latest_entrycsn_bv,
&entrycsn_bv );
}
}
- if ( psearch_type != LCUP_PSEARCH_BY_DELETE || psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) {
- ber_printf( ber,
- "{bb{sON}N}",
+ if ( psearch_type != LCUP_PSEARCH_BY_DELETE ||
+ psearch_type != LCUP_PSEARCH_BY_SCOPEOUT )
+ {
+ ber_printf( ber, "{bb{sON}N}",
SLAP_LCUP_STATE_UPDATE_FALSE,
SLAP_LCUP_ENTRY_DELETED_FALSE,
LCUP_COOKIE_OID, &entrycsn_bv );
} else {
- ber_printf( ber,
- "{bb{sON}N}",
+ ber_printf( ber, "{bb{sON}N}",
SLAP_LCUP_STATE_UPDATE_FALSE,
SLAP_LCUP_ENTRY_DELETED_TRUE,
LCUP_COOKIE_OID, &entrycsn_bv );
} else {
/* Do not send cookie */
- if ( psearch_type != LCUP_PSEARCH_BY_DELETE || psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) {
- ber_printf( ber,
- "{bbN}",
+ if ( psearch_type != LCUP_PSEARCH_BY_DELETE ||
+ psearch_type != LCUP_PSEARCH_BY_SCOPEOUT )
+ {
+ ber_printf( ber, "{bbN}",
SLAP_LCUP_STATE_UPDATE_FALSE,
SLAP_LCUP_ENTRY_DELETED_FALSE );
} else {
- ber_printf( ber,
- "{bbN}",
+ ber_printf( ber, "{bbN}",
SLAP_LCUP_STATE_UPDATE_FALSE,
SLAP_LCUP_ENTRY_DELETED_TRUE );
}
ctrls[0]->ldctl_oid = LDAP_CONTROL_ENTRY_UPDATE;
ctrls[0]->ldctl_iscritical = ps_op->o_clientupdate;
- ret = ber_flatten( ber, &bv );
+ ret = ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 );
if ( ret < 0 ) {
+ ber_free_buf( ber );
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, RESULTS,
- "bdb_search: ber_flatten failed\n",
+ "bdb_search: ber_flatten2 failed\n",
0, 0, 0 );
#else
Debug( LDAP_DEBUG_TRACE,
- "bdb_search: ber_flatten failed\n",
+ "bdb_search: ber_flatten2 failed\n",
0, 0, 0 );
#endif
send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER,
goto done;
}
- ber_dupbv( &ctrls[0]->ldctl_value, bv );
-
result = send_search_entry( be, ps_conn, ps_op,
e, attrs, attrsonly, ctrls);
- ch_free( ctrls[0]->ldctl_value.bv_val );
+ ber_free_buf( ber );
ch_free( ctrls[0] );
- ber_free( ber, 1 );
- ber_bvfree( bv );
if ( psearch_type == LCUP_PSEARCH_BY_MODIFY ) {
struct psid_entry* psid_e;
- LDAP_LIST_FOREACH( psid_e, &op->premodify_list, link) {
- if (psid_e->ps == LDAP_LIST_FIRST(&ps_op->psearch_spec)) {
+ LDAP_LIST_FOREACH( psid_e, &op->premodify_list,
+ link)
+ {
+ if( psid_e->ps ==
+ LDAP_LIST_FIRST(&ps_op->psearch_spec))
+ {
LDAP_LIST_REMOVE(psid_e, link);
break;
}
}
- if (psid_e != NULL)
- free (psid_e);
+ if (psid_e != NULL) free (psid_e);
}
+
} else if ( psearch_type == LCUP_PSEARCH_BY_PREMODIFY ) {
struct psid_entry* psid_e;
- psid_e = (struct psid_entry *) calloc (1, sizeof (struct psid_entry));
+ psid_e = (struct psid_entry *) calloc (1,
+ sizeof(struct psid_entry));
psid_e->ps = LDAP_LIST_FIRST(&ps_op->psearch_spec);
- LDAP_LIST_INSERT_HEAD( &op->premodify_list, psid_e, link );
- }
- else
- {
+ LDAP_LIST_INSERT_HEAD( &op->premodify_list,
+ psid_e, link );
+
+ } else {
printf("Error !\n");
}
}
"bdb_search: %ld scope not okay\n", (long) id, 0, 0);
#else
Debug( LDAP_DEBUG_TRACE,
- "bdb_search: %ld scope not okay\n",
- (long) id, 0, 0 );
+ "bdb_search: %ld scope not okay\n", (long) id, 0, 0 );
#endif
}
} else {
if ( csnfeq.f_ava != NULL && csnfeq.f_av_value.bv_val != NULL ) {
ch_free( csnfeq.f_av_value.bv_val );
}
-
+
if ( csnfge.f_ava != NULL && csnfge.f_av_value.bv_val != NULL ) {
ch_free( csnfge.f_av_value.bv_val );
}
- LOCK_ID_FREE (bdb->bi_dbenv, locker );
+ LOCK_ID_FREE( bdb->bi_dbenv, locker );
if( v2refs ) ber_bvarray_free( v2refs );
if( realbase.bv_val ) ch_free( realbase.bv_val );
+ if ( psearch_type == LCUP_PSEARCH_BY_DELETE ||
+ psearch_type == LCUP_PSEARCH_BY_SCOPEOUT )
+ ch_free( attrs[0].an_name.bv_val );
return rc;
}
+static int psearch_base_candidate(
+ BackendDB *be,
+ Entry *e,
+ ID *ids )
+{
+#ifdef NEW_LOGGING
+ LDAP_LOG ( OPERATION, ENTRY,
+ "psearch_base_candidate: base: \"%s\" (0x%08lx)\n", e->e_dn, (long) e->e_id, 0);
+#else
+ Debug(LDAP_DEBUG_ARGS, "psearch_base_candidates: base: \"%s\" (0x%08lx)\n",
+ e->e_dn, (long) e->e_id, 0);
+#endif
+
+ ids[0] = 1;
+ ids[1] = e->e_id;
+ return 0;
+}
+
+/* Look for "objectClass Present" in this filter.
+ * Also count depth of filter tree while we're at it.
+ */
+static int psearch_oc_filter(
+ Filter *f,
+ int cur,
+ int *max
+)
+{
+ int rc = 0;
+
+ if( cur > *max ) *max = cur;
+
+ switch(f->f_choice) {
+ case LDAP_FILTER_PRESENT:
+ if (f->f_desc == slap_schema.si_ad_objectClass) {
+ rc = 1;
+ }
+ break;
+
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ cur++;
+ for (f=f->f_and; f; f=f->f_next) {
+ (void) psearch_oc_filter(f, cur, max);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return rc;
+}
+
+static int psearch_candidates(
+ BackendDB *be,
+ Operation *op,
+ Entry *e,
+ Filter *filter,
+ int scope,
+ int deref,
+ ID *ids )
+{
+ int rc, depth = 1;
+ Filter f, scopef, rf, xf;
+ ID *stack;
+ AttributeAssertion aa_ref;
+#ifdef BDB_SUBENTRIES
+ Filter sf;
+ AttributeAssertion aa_subentry;
+#endif
+#ifdef BDB_ALIASES
+ Filter af;
+ AttributeAssertion aa_alias;
+#endif
+
+ /*
+ * This routine takes as input a filter (user-filter)
+ * and rewrites it as follows:
+ * (&(scope=DN)[(objectClass=subentry)]
+ * (|[(objectClass=referral)(objectClass=alias)](user-filter))
+ */
+
+#ifdef NEW_LOGGING
+ LDAP_LOG ( OPERATION, ENTRY,
+ "psearch_candidates: base=\"%s\" (0x%08lx) scope=%d\n",
+ e->e_dn, (long) e->e_id, scope);
+#else
+ Debug(LDAP_DEBUG_TRACE,
+ "psearch_candidates: base=\"%s\" (0x%08lx) scope=%d\n",
+ e->e_dn, (long) e->e_id, scope );
+#endif
+
+ xf.f_or = filter;
+ xf.f_choice = LDAP_FILTER_OR;
+ xf.f_next = NULL;
+
+ /* If the user's filter uses objectClass=*,
+ * these clauses are redundant.
+ */
+ if (!psearch_oc_filter(filter, 1, &depth) && !get_subentries_visibility(op) ) {
+ if( !get_manageDSAit(op) ) { /* match referrals */
+ 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 */
+ 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
+ /* We added one of these clauses, filter depth increased */
+ if( xf.f_or != filter ) depth++;
+ }
+
+ f.f_next = NULL;
+ f.f_choice = LDAP_FILTER_AND;
+ f.f_and = &scopef;
+ scopef.f_choice = scope == LDAP_SCOPE_SUBTREE
+ ? SLAPD_FILTER_DN_SUBTREE
+ : SLAPD_FILTER_DN_ONE;
+ scopef.f_dn = &e->e_nname;
+ scopef.f_next = xf.f_or == filter ? filter : &xf ;
+ /* Filter depth increased again, adding scope clause */
+ depth++;
+
+#ifdef BDB_SUBENTRIES
+ if( get_subentries_visibility( op ) ) {
+ struct berval bv_subentry = { sizeof("SUBENTRY")-1, "SUBENTRY" };
+ sf.f_choice = LDAP_FILTER_EQUALITY;
+ sf.f_ava = &aa_subentry;
+ sf.f_av_desc = slap_schema.si_ad_objectClass;
+ sf.f_av_value = bv_subentry;
+ sf.f_next = scopef.f_next;
+ scopef.f_next = &sf;
+ }
+#endif
+
+ /* Allocate IDL stack, plus 1 more for former tmp */
+ stack = ch_malloc( (depth + 1) * BDB_IDL_UM_SIZE * sizeof( ID ) );
+
+ rc = bdb_filter_candidates( be, &f, ids, stack, stack+BDB_IDL_UM_SIZE );
+
+ ch_free( stack );
+
+ if( rc ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG ( OPERATION, DETAIL1,
+ "bdb_psearch_candidates: failed (rc=%d)\n", rc, 0, 0 );
+#else
+ Debug(LDAP_DEBUG_TRACE,
+ "bdb_psearch_candidates: failed (rc=%d)\n",
+ rc, NULL, NULL );
+#endif
+
+ } else {
+#ifdef NEW_LOGGING
+ LDAP_LOG ( OPERATION, DETAIL1,
+ "bdb_psearch_candidates: id=%ld first=%ld last=%ld\n",
+ (long) ids[0], (long) BDB_IDL_FIRST(ids),
+ (long) BDB_IDL_LAST(ids));
+#else
+ Debug(LDAP_DEBUG_TRACE,
+ "bdb_psearch_candidates: id=%ld first=%ld last=%ld\n",
+ (long) ids[0],
+ (long) BDB_IDL_FIRST(ids),
+ (long) BDB_IDL_LAST(ids) );
+#endif
+ }
+
+ return rc;
+}
+
+
#endif /* LDAP_CLIENT_UPDATE */