]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-bdb/lcup.c
Plug memory leak
[openldap] / servers / slapd / back-bdb / lcup.c
index 9cf1a1479efe43b1bdc6daea421cac907bb5579e..77dbd632ebae8722cd525cce16efcc33aa2eb628 100644 (file)
@@ -1,4 +1,5 @@
 /* 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,
@@ -47,15 +61,15 @@ bdb_add_psearch_spec(
        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;
 
@@ -110,11 +124,6 @@ bdb_psearch(
        int isroot = 0;
        int scopeok = 0;
 
-#ifdef SLAP_X_FILTER_HASSUBORDINATES
-       int             filter_hasSubordinates = 0;
-       Attribute       *hasSubordinates = NULL;
-#endif /* SLAP_X_FILTER_HASSUBORDINATES */
-
        u_int32_t       locker;
        DB_LOCK         lock;
 
@@ -126,15 +135,23 @@ bdb_psearch(
        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
@@ -153,6 +170,9 @@ bdb_psearch(
        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;
        }
 
@@ -179,28 +199,38 @@ dn2entry_retry:
                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;
        }
 
@@ -216,7 +246,8 @@ dn2entry_retry:
                                ? 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 ) {
@@ -233,9 +264,12 @@ dn2entry_retry:
                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_FREEbdb->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;
        }
 
@@ -258,7 +292,7 @@ dn2entry_retry:
                }
 
 #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",
@@ -270,9 +304,12 @@ dn2entry_retry:
                        refs ? NULL : "bad referral object",
                        refs, NULL );
 
-               LOCK_ID_FREE (bdb->bi_dbenv, locker );
+               LOCK_ID_FREEbdb->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;
        }
 
@@ -346,6 +383,28 @@ dn2entry_retry:
        /* 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;
@@ -378,22 +437,13 @@ dn2entry_retry:
        /* 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;
                }
        }
 
-#ifdef SLAP_X_FILTER_HASSUBORDINATES
-       /*
-        * is hasSubordinates used in the filter ?
-        * FIXME: we may compute this directly when parsing the filter
-        */
-       filter_hasSubordinates = filter_has_subordinates( filter );
-#endif /* SLAP_X_FILTER_HASSUBORDINATES */
-
        lcupf.f_choice = LDAP_FILTER_AND;
        lcupf.f_and = &csnfnot;
        lcupf.f_next = NULL;
@@ -417,20 +467,6 @@ dn2entry_retry:
        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 */
@@ -568,52 +604,12 @@ dn2entry_retry:
                goto test_done;
        }
 
-#ifdef SLAP_X_FILTER_HASSUBORDINATES
-       /*
-        * if hasSubordinates is used in the filter,
-        * append it to the entry's attributes
-        */
-       if ( filter_hasSubordinates ) {
-               int     hs;
-
-               rc = bdb_hasSubordinates( be, ps_conn, ps_op, e, &hs);
-               if ( rc != LDAP_SUCCESS ) {
-                       goto test_done;
-               }
-
-               hasSubordinates = slap_operational_hasSubordinate(
-                       hs == LDAP_COMPARE_TRUE );
-
-               if ( hasSubordinates == NULL ) {
-                       goto test_done;
-               }
-
-               hasSubordinates->a_next = e->e_attrs;
-               e->e_attrs = hasSubordinates;
-       }
-#endif /* SLAP_X_FILTER_HASSUBORDINATES */
-
        if ( psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) {
                rc = test_filter( be, ps_conn, ps_op, e, &lcupf );
        } else {
                rc = LDAP_COMPARE_TRUE;
        }
 
-#ifdef SLAP_X_FILTER_HASSUBORDINATES
-       if ( hasSubordinates ) {
-               /*
-                * FIXME: this is fairly inefficient, because 
-                * if hasSubordinates is among the required
-                * attrs, it will be added again later;
-                * maybe we should leave it and check
-                * check later if it's already present,
-                * if required
-                */
-               e->e_attrs = e->e_attrs->a_next;
-               attr_free( hasSubordinates );
-       }
-#endif /* SLAP_X_FILTER_HASSUBORDINATES */
-
        if ( rc == LDAP_COMPARE_TRUE ) {
                struct berval   dn;
 
@@ -654,64 +650,59 @@ dn2entry_retry:
                                        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 );
@@ -720,15 +711,15 @@ dn2entry_retry:
                                                                }
                                                        }
 
-                                                       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 );
@@ -739,14 +730,14 @@ dn2entry_retry:
 
                                                } 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 );
                                                        }
@@ -754,16 +745,17 @@ dn2entry_retry:
 
                                                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,
@@ -771,35 +763,36 @@ dn2entry_retry:
                                                        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");
                                        }
                                }
@@ -821,8 +814,7 @@ dn2entry_retry:
                                "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 {
@@ -843,17 +835,203 @@ done:
        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_FREEbdb->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 = &af;
+               }
+#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 */