]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/search.c
182cbbd6732707568215c2854040a1bf5bb38f68
[openldap] / servers / slapd / back-bdb / search.c
1 /* search.c - search operation */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21
22 #include "back-bdb.h"
23 #include "idl.h"
24
25 static int base_candidate(
26         BackendDB       *be,
27         Entry   *e,
28         ID              *ids );
29
30 static int search_candidates(
31         Operation *stackop,     /* op with the current threadctx/slab cache */
32         Operation *sop,         /* search op */
33         SlapReply *rs,
34         Entry *e,
35         u_int32_t locker,
36         ID      *ids,
37         ID      *scopes );
38
39 static int parse_paged_cookie( Operation *op, SlapReply *rs );
40
41 static void send_paged_response( 
42         Operation *op,
43         SlapReply *rs,
44         ID  *lastid,
45         int tentries );
46
47 static int bdb_pfid_cmp( const void *v_id1, const void *v_id2 );
48 static ID* bdb_id_dup( Operation *op, ID *id );
49
50 /* Dereference aliases for a single alias entry. Return the final
51  * dereferenced entry on success, NULL on any failure.
52  */
53 static Entry * deref_base (
54         Operation *op,
55         SlapReply *rs,
56         Entry *e,
57         Entry **matched,
58         u_int32_t locker,
59         DB_LOCK *lock,
60         ID      *tmp,
61         ID      *visited )
62 {
63         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
64         struct berval ndn;
65         EntryInfo *ei;
66         DB_LOCK lockr;
67
68         rs->sr_err = LDAP_ALIAS_DEREF_PROBLEM;
69         rs->sr_text = "maximum deref depth exceeded";
70
71         while (BDB_IDL_N(tmp) < op->o_bd->be_max_deref_depth) {
72                 /* Remember the last entry we looked at, so we can
73                  * report broken links
74                  */
75                 *matched = e;
76
77                 /* If this is part of a subtree or onelevel search,
78                  * have we seen this ID before? If so, quit.
79                  */
80                 if ( visited && bdb_idl_insert( visited, e->e_id ) ) {
81                         e = NULL;
82                         break;
83                 }
84
85                 /* If we've seen this ID during this deref iteration,
86                  * we've hit a loop.
87                  */
88                 if ( bdb_idl_insert( tmp, e->e_id ) ) {
89                         rs->sr_err = LDAP_ALIAS_PROBLEM;
90                         rs->sr_text = "circular alias";
91                         e = NULL;
92                         break;
93                 }
94
95                 /* If there was a problem getting the aliasedObjectName,
96                  * get_alias_dn will have set the error status.
97                  */
98                 if ( get_alias_dn(e, &ndn, &rs->sr_err, &rs->sr_text) ) {
99                         e = NULL;
100                         break;
101                 }
102
103                 rs->sr_err = bdb_dn2entry( op, NULL, &ndn, &ei,
104                         0, locker, &lockr );
105
106                 if ( ei ) {
107                         e = ei->bei_e;
108                 } else {
109                         e = NULL;
110                 }
111
112                 if (!e) {
113                         rs->sr_err = LDAP_ALIAS_PROBLEM;
114                         rs->sr_text = "aliasedObject not found";
115                         break;
116                 }
117
118                 /* Free the previous entry, continue to work with the
119                  * one we just retrieved.
120                  */
121                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache,
122                         *matched, lock);
123                 *lock = lockr;
124
125                 /* We found a regular entry. Return this to the caller. The
126                  * entry is still locked for Read.
127                  */
128                 if (!is_entry_alias(e)) {
129                         rs->sr_err = LDAP_SUCCESS;
130                         rs->sr_text = NULL;
131                         break;
132                 }
133         }
134         return e;
135 }
136
137 /* Look for and dereference all aliases within the search scope. Adds
138  * the dereferenced entries to the "ids" list. Requires "stack" to be
139  * able to hold 8 levels of DB_SIZE IDLs. Of course we're hardcoded to
140  * require a minimum of 8 UM_SIZE IDLs so this is never a problem.
141  */
142 static int search_aliases(
143         Operation *op,
144         SlapReply *rs,
145         Entry *e,
146         u_int32_t locker,
147         ID *ids,
148         ID *scopes,
149         ID *stack )
150 {
151         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
152         ID *aliases, *curscop, *subscop, *visited, *newsubs, *oldsubs, *tmp;
153         ID cursora, ida, cursoro, ido, *subscop2;
154         Entry *matched, *a;
155         EntryInfo *ei;
156         struct berval bv_alias = BER_BVC( "alias" );
157         AttributeAssertion aa_alias;
158         Filter  af;
159         DB_LOCK locka, lockr;
160         int first = 1;
161
162         aliases = stack;        /* IDL of all aliases in the database */
163         curscop = aliases + BDB_IDL_DB_SIZE;    /* Aliases in the current scope */
164         subscop = curscop + BDB_IDL_DB_SIZE;    /* The current scope */
165         visited = subscop + BDB_IDL_DB_SIZE;    /* IDs we've seen in this search */
166         newsubs = visited + BDB_IDL_DB_SIZE;    /* New subtrees we've added */
167         oldsubs = newsubs + BDB_IDL_DB_SIZE;    /* Subtrees added previously */
168         tmp = oldsubs + BDB_IDL_DB_SIZE;        /* Scratch space for deref_base() */
169
170         /* A copy of subscop, because subscop gets clobbered by
171          * the bdb_idl_union/intersection routines
172          */
173         subscop2 = tmp + BDB_IDL_DB_SIZE;
174
175         af.f_choice = LDAP_FILTER_EQUALITY;
176         af.f_ava = &aa_alias;
177         af.f_av_desc = slap_schema.si_ad_objectClass;
178         af.f_av_value = bv_alias;
179         af.f_next = NULL;
180
181         /* Find all aliases in database */
182         BDB_IDL_ZERO( aliases );
183         rs->sr_err = bdb_filter_candidates( op, &af, aliases,
184                 curscop, visited );
185         if (rs->sr_err != LDAP_SUCCESS) {
186                 return rs->sr_err;
187         }
188         oldsubs[0] = 1;
189         oldsubs[1] = e->e_id;
190
191         BDB_IDL_ZERO( ids );
192         BDB_IDL_ZERO( visited );
193         BDB_IDL_ZERO( newsubs );
194
195         cursoro = 0;
196         ido = bdb_idl_first( oldsubs, &cursoro );
197
198         for (;;) {
199                 /* Set curscop to only the aliases in the current scope. Start with
200                  * all the aliases, obtain the IDL for the current scope, and then
201                  * get the intersection of these two IDLs. Add the current scope
202                  * to the cumulative list of candidates.
203                  */
204                 BDB_IDL_CPY( curscop, aliases );
205                 rs->sr_err = bdb_dn2idl( op, e, subscop,
206                         subscop2+BDB_IDL_DB_SIZE );
207                 if (first) {
208                         first = 0;
209                 } else {
210                         bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, e, &locka);
211                 }
212                 BDB_IDL_CPY(subscop2, subscop);
213                 rs->sr_err = bdb_idl_intersection(curscop, subscop);
214                 bdb_idl_union( ids, subscop2 );
215
216                 /* Dereference all of the aliases in the current scope. */
217                 cursora = 0;
218                 for (ida = bdb_idl_first(curscop, &cursora); ida != NOID;
219                         ida = bdb_idl_next(curscop, &cursora))
220                 {
221                         ei = NULL;
222 retry1:
223                         rs->sr_err = bdb_cache_find_id(op, NULL,
224                                 ida, &ei, 0, locker, &lockr );
225                         if (rs->sr_err != LDAP_SUCCESS) {
226                                 if ( rs->sr_err == DB_LOCK_DEADLOCK ||
227                                         rs->sr_err == DB_LOCK_NOTGRANTED ) goto retry1;
228                                 continue;
229                         }
230                         a = ei->bei_e;
231
232                         /* This should only happen if the curscop IDL has maxed out and
233                          * turned into a range that spans IDs indiscriminately
234                          */
235                         if (!is_entry_alias(a)) {
236                                 bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache,
237                                         a, &lockr);
238                                 continue;
239                         }
240
241                         /* Actually dereference the alias */
242                         BDB_IDL_ZERO(tmp);
243                         a = deref_base( op, rs, a, &matched, locker, &lockr,
244                                 tmp, visited );
245                         if (a) {
246                                 /* If the target was not already in our current candidates,
247                                  * make note of it in the newsubs list. Also
248                                  * set it in the scopes list so that bdb_search
249                                  * can check it.
250                                  */
251                                 if (bdb_idl_insert(ids, a->e_id) == 0) {
252                                         bdb_idl_insert(newsubs, a->e_id);
253                                         bdb_idl_insert(scopes, a->e_id);
254                                 }
255                                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache,
256                                         a, &lockr);
257
258                         } else if (matched) {
259                                 /* Alias could not be dereferenced, or it deref'd to
260                                  * an ID we've already seen. Ignore it.
261                                  */
262                                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache,
263                                         matched, &lockr );
264                                 rs->sr_text = NULL;
265                         }
266                 }
267                 /* If this is a OneLevel search, we're done; oldsubs only had one
268                  * ID in it. For a Subtree search, oldsubs may be a list of scope IDs.
269                  */
270                 if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) break;
271 nextido:
272                 ido = bdb_idl_next( oldsubs, &cursoro );
273                 
274                 /* If we're done processing the old scopes, did we add any new
275                  * scopes in this iteration? If so, go back and do those now.
276                  */
277                 if (ido == NOID) {
278                         if (BDB_IDL_IS_ZERO(newsubs)) break;
279                         BDB_IDL_CPY(oldsubs, newsubs);
280                         BDB_IDL_ZERO(newsubs);
281                         cursoro = 0;
282                         ido = bdb_idl_first( oldsubs, &cursoro );
283                 }
284
285                 /* Find the entry corresponding to the next scope. If it can't
286                  * be found, ignore it and move on. This should never happen;
287                  * we should never see the ID of an entry that doesn't exist.
288                  * Set the name so that the scope's IDL can be retrieved.
289                  */
290                 ei = NULL;
291 sameido:
292                 rs->sr_err = bdb_cache_find_id(op, NULL, ido, &ei,
293                         0, locker, &locka );
294                 if ( rs->sr_err != LDAP_SUCCESS ) {
295                         if ( rs->sr_err == DB_LOCK_DEADLOCK ||
296                                 rs->sr_err == DB_LOCK_NOTGRANTED )
297                                 goto sameido;
298                         goto nextido;
299                 }
300                 e = ei->bei_e;
301         }
302         return rs->sr_err;
303 }
304
305 #define is_sync_protocol(op)    \
306         ((op)->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST)
307
308 #define IS_BDB_REPLACE(type) (( type == LDAP_PSEARCH_BY_DELETE ) || \
309         ( type == LDAP_PSEARCH_BY_SCOPEOUT ))
310 #define IS_PSEARCH (op != sop)
311 #define IS_POST_SEARCH ( op->ors_post_search_id != NOID )
312
313 static Operation *
314 bdb_drop_psearch( Operation *op, ber_int_t msgid )
315 {
316         Operation       *ps_list;
317         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
318
319         LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
320                 if ( ps_list->o_connid == op->o_connid ) {
321                         if ( ps_list->o_msgid == msgid ) {
322                                 ps_list->o_abandon = 1;
323                                 LDAP_LIST_REMOVE( ps_list, o_ps_link );
324                                 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
325                                 LDAP_STAILQ_REMOVE( &op->o_conn->c_ops, ps_list,
326                                         slap_op, o_next );
327                                 LDAP_STAILQ_NEXT( ps_list, o_next ) = NULL;
328                                 op->o_conn->c_n_ops_executing--;
329                                 op->o_conn->c_n_ops_completed++;
330                                 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
331                                 return ps_list;
332                         }
333                 }
334         }
335
336         return NULL;
337 }
338
339 int
340 bdb_abandon( Operation *op, SlapReply *rs )
341 {
342         Operation       *ps;
343         void            *saved_tmpmemctx;
344
345         ps = bdb_drop_psearch( op, op->oq_abandon.rs_msgid );
346         if ( ps ) {
347                 saved_tmpmemctx = ps->o_tmpmemctx;
348
349                 if (!BER_BVISNULL(&ps->o_req_dn)) {
350                         slap_sl_free(ps->o_req_dn.bv_val, ps->o_tmpmemctx );
351                 }
352                 if (!BER_BVISNULL(&ps->o_req_ndn)) {
353                         slap_sl_free(ps->o_req_ndn.bv_val, ps->o_tmpmemctx );
354                 }
355                 if (!BER_BVISNULL(&ps->ors_filterstr)) {
356                         ps->o_tmpfree(ps->ors_filterstr.bv_val, ps->o_tmpmemctx);
357                 }
358                 if (ps->ors_filter != NULL) {
359                         filter_free_x(ps, ps->ors_filter);
360                 }
361                 if (ps->ors_attrs != NULL) {
362                         ps->o_tmpfree(ps->ors_attrs, ps->o_tmpmemctx);
363                 }
364
365                 slap_op_free ( ps );
366
367                 if ( saved_tmpmemctx ) {
368                         slap_sl_mem_destroy( NULL, saved_tmpmemctx );
369                 }
370
371                 return LDAP_SUCCESS;
372         }
373         return LDAP_UNAVAILABLE;
374 }
375
376 int
377 bdb_cancel( Operation *op, SlapReply *rs )
378 {
379         Operation       *ps;
380         void            *saved_tmpmemctx;
381
382         ps = bdb_drop_psearch( op, op->oq_cancel.rs_msgid );
383         if ( ps ) {
384                 saved_tmpmemctx = ps->o_tmpmemctx;
385
386                 rs->sr_err = LDAP_CANCELLED;
387                 send_ldap_result( ps, rs );
388
389                 if (!BER_BVISNULL(&ps->o_req_dn)) {
390                         slap_sl_free(ps->o_req_dn.bv_val, ps->o_tmpmemctx );
391                 }
392                 if (!BER_BVISNULL(&ps->o_req_ndn)) {
393                         slap_sl_free(ps->o_req_ndn.bv_val, ps->o_tmpmemctx );
394                 }
395                 if (!BER_BVISNULL(&ps->ors_filterstr)) {
396                         ps->o_tmpfree(ps->ors_filterstr.bv_val, ps->o_tmpmemctx);
397                 }
398                 if (ps->ors_filter != NULL) {
399                         filter_free_x(ps, ps->ors_filter);
400                 }
401                 if (ps->ors_attrs != NULL) {
402                         ps->o_tmpfree(ps->ors_attrs, ps->o_tmpmemctx);
403                 }
404
405                 slap_op_free ( ps );
406
407                 if ( saved_tmpmemctx ) {
408                         slap_sl_mem_destroy( NULL, saved_tmpmemctx );
409                 }
410
411                 return LDAP_SUCCESS;
412         }
413         return LDAP_UNAVAILABLE;
414 }
415
416 int bdb_search( Operation *op, SlapReply *rs )
417 {
418         int rc;
419         struct pc_entry *pce = NULL;
420         struct pc_entry *tmp_pce = NULL;
421         Entry ps_e = {0};
422         Attribute *a;
423
424         ps_e.e_private = NULL;
425         ldap_pvt_thread_mutex_init( &op->o_pcmutex );
426         LDAP_TAILQ_INIT( &op->o_ps_pre_candidates );
427         LDAP_TAILQ_INIT( &op->o_ps_post_candidates );
428
429         op->ors_post_search_id = NOID;
430         rc = bdb_do_search( op, rs, op, NULL, 0 );
431
432         ldap_pvt_thread_mutex_lock( &op->o_pcmutex );
433         pce = LDAP_TAILQ_FIRST( &op->o_ps_post_candidates );
434         ldap_pvt_thread_mutex_unlock( &op->o_pcmutex );
435
436         while ( rc == LDAP_SUCCESS && pce &&
437                         op->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST ) {
438
439                 ps_e.e_id = op->ors_post_search_id = pce->pc_id;
440                 if ( op->o_sync_csn.bv_val ) {
441                         ch_free( op->o_sync_csn.bv_val );
442                         op->o_sync_csn.bv_val = NULL;
443                 }
444                 ber_dupbv( &op->o_sync_csn, &pce->pc_csn );
445                 ber_dupbv( &ps_e.e_name, &pce->pc_ename );
446                 ber_dupbv( &ps_e.e_nname, &pce->pc_enname );
447                 a = ch_calloc( 1, sizeof( Attribute ));
448                 a->a_desc = slap_schema.si_ad_entryUUID;
449                 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
450                 ber_dupbv( &a->a_vals[0], &pce->pc_entryUUID );
451                 a->a_nvals = a->a_vals;
452                 a->a_next = NULL;
453                 ps_e.e_attrs = a;
454
455                 rc = bdb_do_search( op, rs, op, &ps_e, 0 );
456
457                 tmp_pce = pce;
458                 ldap_pvt_thread_mutex_lock( &op->o_pcmutex );
459                 pce = LDAP_TAILQ_NEXT( pce, pc_link );
460                 LDAP_TAILQ_REMOVE( &op->o_ps_post_candidates, tmp_pce, pc_link );
461                 ldap_pvt_thread_mutex_unlock( &op->o_pcmutex );
462
463                 ch_free( tmp_pce->pc_csn.bv_val );
464                 ch_free( tmp_pce->pc_entryUUID.bv_val );
465                 ch_free( tmp_pce->pc_ename.bv_val );
466                 ch_free( tmp_pce->pc_enname.bv_val );
467                 ch_free( tmp_pce );     
468                 entry_clean( &ps_e );
469         }
470         return rc;
471 }
472
473 #define BDB_PSEARCH_MAX_WAIT 3
474 int bdb_psearch( Operation *op, SlapReply *rs, Operation *sop,
475         Entry *ps_e, int ps_type )
476 {
477         int     rc;
478         struct pc_entry *pce = NULL;
479         struct pc_entry *p = NULL;
480         int num_retries = 0;
481
482         op->ors_post_search_id = NOID;
483
484         switch (ps_type) {
485         case LDAP_PSEARCH_BY_PREMODIFY:
486         case LDAP_PSEARCH_BY_PREDELETE:
487
488                 if ( !op->o_ps_send_wait ) {
489                         if ( sop->o_refresh_in_progress ) {
490                                 pce = (struct pc_entry *) ch_calloc(
491                                                         1, sizeof( struct pc_entry ));
492                                 pce->pc_id = ps_e->e_id;
493                                 ldap_pvt_thread_mutex_lock( &sop->o_pcmutex );
494                                 if ( LDAP_TAILQ_EMPTY( &sop->o_ps_pre_candidates )) {
495                                         LDAP_TAILQ_INSERT_HEAD(
496                                                         &sop->o_ps_pre_candidates, pce, pc_link );
497                                 } else {
498                                         LDAP_TAILQ_FOREACH( p,
499                                                         &sop->o_ps_pre_candidates, pc_link ) {
500                                                 if ( p->pc_id > pce->pc_id )
501                                                         break;
502                                         }
503
504                                         if ( p ) {
505                                                 LDAP_TAILQ_INSERT_BEFORE( p, pce, pc_link );
506                                         } else {
507                                                 LDAP_TAILQ_INSERT_TAIL(
508                                                                 &sop->o_ps_pre_candidates,
509                                                                 pce, pc_link );
510                                         }
511                                 }
512                                 ldap_pvt_thread_mutex_unlock( &sop->o_pcmutex );
513                         } else {
514                                 rc = bdb_do_search( op, rs, sop, ps_e, ps_type );
515                                 return rc;
516                         }
517                 } else {
518                         pce = op->o_ps_send_wait;
519                 }
520
521                 /* Wait until refresh search send the entry */
522                 while ( !pce->pc_sent ) {
523                         if ( sop->o_refresh_in_progress ) {
524                                 if ( num_retries == BDB_PSEARCH_MAX_WAIT ) {
525                                         op->o_ps_send_wait = pce;
526                                         return LDAP_BUSY;
527                                 }
528                                 ldap_pvt_thread_yield();
529                                 bdb_trans_backoff( ++num_retries );
530                         } else {
531                                 break;
532                         }
533                 }
534
535                 op->o_ps_send_wait = NULL;
536
537                 if ( !sop->o_refresh_in_progress && !pce->pc_sent ) {
538                         /* refresh ended without processing pce */
539                         /* need to perform psearch for ps_e */
540                         ldap_pvt_thread_mutex_lock( &sop->o_pcmutex );
541                         LDAP_TAILQ_REMOVE( &sop->o_ps_pre_candidates, pce, pc_link );
542                         ldap_pvt_thread_mutex_unlock( &sop->o_pcmutex );
543                         ch_free( pce );
544                         rc = bdb_do_search( op, rs, sop, ps_e, ps_type );
545                         return rc;
546                 } else {
547                         /* the pce entry was sent in the refresh phase */
548                         if ( ps_type == LDAP_PSEARCH_BY_PREMODIFY ) {
549                                 struct psid_entry* psid_e;
550                                 psid_e = (struct psid_entry *) ch_calloc(1,
551                                                         sizeof(struct psid_entry));
552                                 psid_e->ps_op = sop;
553                                 LDAP_LIST_INSERT_HEAD( &op->o_pm_list, psid_e, ps_link );
554                         }
555
556                         ldap_pvt_thread_mutex_lock( &sop->o_pcmutex );
557                         LDAP_TAILQ_REMOVE( &sop->o_ps_pre_candidates, pce, pc_link );
558                         ldap_pvt_thread_mutex_unlock( &sop->o_pcmutex );
559                         ch_free( pce );
560                         return LDAP_SUCCESS;
561                 } 
562                 break;
563         case LDAP_PSEARCH_BY_DELETE:
564         case LDAP_PSEARCH_BY_SCOPEOUT:
565         case LDAP_PSEARCH_BY_ADD:
566         case LDAP_PSEARCH_BY_MODIFY:
567                 ldap_pvt_thread_mutex_lock( &op->o_pcmutex );
568                 if ( sop->o_refresh_in_progress ||
569                                 !LDAP_TAILQ_EMPTY( &sop->o_ps_post_candidates )) {
570                         pce = (struct pc_entry *) ch_calloc( 1, sizeof( struct pc_entry ));
571                         pce->pc_id = ps_e->e_id;
572                         ber_dupbv( &pce->pc_csn, &op->o_sync_csn );
573                         if ( ps_type == LDAP_PSEARCH_BY_DELETE ) {
574                                 Attribute *a;
575                                 for ( a = ps_e->e_attrs; a != NULL; a = a->a_next ) {
576                                         AttributeDescription *desc = a->a_desc;
577                                         if ( desc == slap_schema.si_ad_entryUUID ) {
578                                                 ber_dupbv( &pce->pc_entryUUID, &a->a_nvals[0] );
579                                         }
580                                 }
581                         }       
582                         ber_dupbv( &pce->pc_ename, &ps_e->e_name ); 
583                         ber_dupbv( &pce->pc_enname, &ps_e->e_nname ); 
584                         LDAP_TAILQ_INSERT_TAIL( &sop->o_ps_post_candidates, pce, pc_link );
585                         ldap_pvt_thread_mutex_unlock( &op->o_pcmutex );
586                 } else {
587                         ldap_pvt_thread_mutex_unlock( &op->o_pcmutex );
588                         rc = bdb_do_search( op, rs, sop, ps_e, ps_type );
589                         return rc;
590                 }
591                 break;
592         default:
593                 Debug( LDAP_DEBUG_TRACE, "do_psearch: invalid psearch type\n",
594                                 0, 0, 0 );
595                 return LDAP_OTHER;
596         }
597 }
598
599 /* For persistent searches, op is the currently executing operation,
600  * sop is the persistent search. For regular searches, sop = op.
601  */
602 int
603 bdb_do_search( Operation *op, SlapReply *rs, Operation *sop,
604         Entry *ps_e, int ps_type )
605 {
606         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
607         time_t          stoptime;
608         ID              id, cursor;
609         ID              candidates[BDB_IDL_UM_SIZE];
610         ID              scopes[BDB_IDL_DB_SIZE];
611         Entry           *e = NULL, base, e_root = {0};
612         Entry           *matched = NULL;
613         EntryInfo       *ei, ei_root = {0};
614         struct berval   realbase = BER_BVNULL;
615         int             manageDSAit;
616         int             tentries = 0;
617         ID              lastid = NOID;
618         AttributeName   *attrs;
619
620         Filter          contextcsnand, contextcsnle, cookief, csnfnot,
621                         csnfeq, csnfand, csnfge;
622         AttributeAssertion aa_ge, aa_eq, aa_le;
623         struct berval   *search_context_csn = NULL;
624         DB_LOCK         ctxcsn_lock;
625         LDAPControl     *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
626         int             num_ctrls = 0;
627         AttributeName   uuid_attr[2];
628         int             rc_sync = 0;
629         int             entry_sync_state = -1;
630         AttributeName   null_attr;
631         int             no_sync_state_change = 0;
632
633         u_int32_t       locker = 0;
634         DB_LOCK         lock;
635
636         Operation       *ps_list;
637         int                     sync_send_present_mode = 1;
638         int                     match;
639         MatchingRule *mr;
640         const char *text;
641         int                     slog_found = 0;
642
643         struct pc_entry *pce = NULL;
644         BerVarray       syncUUID_set = NULL;
645         int                     syncUUID_set_cnt = 0;
646
647         struct  bdb_op_info     *opinfo = NULL;
648         DB_TXN                  *ltid = NULL;
649
650         Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_search) "\n", 0, 0, 0);
651         attrs = sop->oq_search.rs_attrs;
652
653         opinfo = (struct bdb_op_info *) op->o_private;
654
655         if ( !IS_POST_SEARCH && !IS_PSEARCH &&
656                         sop->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST ) {
657                 struct slap_session_entry *sent;
658                 if ( sop->o_sync_state.sid >= 0 ) {
659                         LDAP_LIST_FOREACH( sent, &bdb->bi_session_list, se_link ) {
660                                 if ( sent->se_id == sop->o_sync_state.sid ) {
661                                         sop->o_sync_slog_size = sent->se_size;
662                                         break;
663                                 }
664                         }
665                 }
666         }
667
668         /* psearch needs to be registered before refresh begins */
669         if ( !IS_POST_SEARCH && !IS_PSEARCH &&
670                         sop->o_sync_mode & SLAP_SYNC_PERSIST ) {
671                 sop->o_refresh_in_progress = 1;
672                 ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock );
673                 LDAP_LIST_INSERT_HEAD( &bdb->bi_psearch_list, sop, o_ps_link );
674                 ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock );
675
676         } else if ( !IS_POST_SEARCH && !IS_PSEARCH &&
677                                 sop->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST
678                                 && sop->o_sync_slog_size >= 0 )
679         {
680                 ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock );
681                 LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
682                         if ( ps_list->o_sync_slog_size >= 0 ) {
683                                 if ( ps_list->o_sync_state.sid == sop->o_sync_state.sid ) {
684                                         slog_found = 1;
685                                         break;
686                                 }
687                         }
688                 }
689
690                 if ( slog_found ) {
691                         if ( ps_list->o_sync_slog_omitcsn.bv_len != 0 ) {
692                                 mr = slap_schema.si_ad_entryCSN->ad_type->sat_ordering;
693                                 if ( sop->o_sync_state.ctxcsn &&
694                                         sop->o_sync_state.ctxcsn->bv_val != NULL )
695                                 {
696                                         value_match( &match, slap_schema.si_ad_entryCSN, mr,
697                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
698                                                 sop->o_sync_state.ctxcsn,
699                                                 &ps_list->o_sync_slog_omitcsn,
700                                                 &text );
701                                 } else {
702                                         match = -1;
703                                 }
704                                 if ( match >= 0 ) {
705                                         sync_send_present_mode = 0;
706                                 }
707                         } else {
708                                 sync_send_present_mode = 0;
709                         }
710                 } else if ( sop->o_sync_slog_size >= 0 ) {
711                         LDAP_LIST_INSERT_HEAD( &bdb->bi_psearch_list, sop, o_ps_link );
712                 } else {
713                         sop->o_sync_state.sid = -1;
714                 }
715                 ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock );
716         }
717
718         null_attr.an_desc = NULL;
719         null_attr.an_oc = NULL;
720         null_attr.an_oc_exclude = 0;
721         BER_BVZERO( &null_attr.an_name );
722
723         for( num_ctrls = 0; num_ctrls < SLAP_MAX_RESPONSE_CONTROLS; num_ctrls++ ) {
724                 ctrls[num_ctrls] = NULL;
725         }
726         num_ctrls = 0;
727
728         if ( IS_PSEARCH && IS_BDB_REPLACE(ps_type)) {
729                 attrs = uuid_attr;
730                 attrs[0].an_desc = NULL;
731                 attrs[0].an_oc = NULL;
732                 attrs[0].an_oc_exclude = 0;
733                 BER_BVZERO( &attrs[0].an_name );
734         }
735
736         manageDSAit = get_manageDSAit( sop );
737
738         /* Sync control overrides manageDSAit */
739         if ( !IS_PSEARCH && sop->o_sync_mode & SLAP_SYNC_REFRESH ) {
740                 if ( manageDSAit == SLAP_NO_CONTROL ) {
741                         manageDSAit = SLAP_CRITICAL_CONTROL;
742                 }
743         } else if ( IS_PSEARCH ) {
744                 if ( manageDSAit == SLAP_NO_CONTROL ) {
745                         manageDSAit = SLAP_CRITICAL_CONTROL;
746                 }
747         }
748
749         if ( opinfo && opinfo->boi_txn ) {
750                 ltid = opinfo->boi_txn;
751                 locker = TXN_ID( ltid );
752         } else {
753                 rs->sr_err = LOCK_ID( bdb->bi_dbenv, &locker );
754
755                 switch(rs->sr_err) {
756                 case 0:
757                         break;
758                 default:
759                         send_ldap_error( sop, rs, LDAP_OTHER, "internal error" );
760                         return rs->sr_err;
761                 }
762         }
763
764         if ( IS_POST_SEARCH ) {
765                 cursor = 0;
766                 candidates[0] = 1;
767                 candidates[1] = op->ors_post_search_id;
768                 search_context_csn = ber_dupbv( NULL, &op->o_sync_csn );        
769                 goto loop_start;
770         }
771
772         if ( sop->o_req_ndn.bv_len == 0 ) {
773                 /* DIT root special case */
774                 ei_root.bei_e = &e_root;
775                 ei_root.bei_parent = &ei_root;
776                 e_root.e_private = &ei_root;
777                 e_root.e_id = 0;
778                 BER_BVSTR( &e_root.e_nname, "" );
779                 BER_BVSTR( &e_root.e_name, "" );
780                 ei = &ei_root;
781                 rs->sr_err = LDAP_SUCCESS;
782         } else {
783 dn2entry_retry:
784                 /* get entry with reader lock */
785                 rs->sr_err = bdb_dn2entry( op, ltid, &sop->o_req_ndn, &ei,
786                         1, locker, &lock );
787         }
788
789         switch(rs->sr_err) {
790         case DB_NOTFOUND:
791                 matched = ei->bei_e;
792                 break;
793         case 0:
794                 e = ei->bei_e;
795                 break;
796         case LDAP_BUSY:
797                 send_ldap_error( sop, rs, LDAP_BUSY, "ldap server busy" );
798                 if ( !opinfo )
799                         LOCK_ID_FREE (bdb->bi_dbenv, locker );
800                 return LDAP_BUSY;
801         case DB_LOCK_DEADLOCK:
802         case DB_LOCK_NOTGRANTED:
803                 goto dn2entry_retry;
804         default:
805                 send_ldap_error( sop, rs, LDAP_OTHER, "internal error" );
806                 if ( !opinfo )
807                         LOCK_ID_FREE (bdb->bi_dbenv, locker );
808                 return rs->sr_err;
809         }
810
811         if ( e && (op->ors_deref & LDAP_DEREF_FINDING) && is_entry_alias(e) ) {
812                 BDB_IDL_ZERO(candidates);
813                 e = deref_base( op, rs, e, &matched, locker, &lock,
814                         candidates, NULL );
815         }
816
817         if ( e == NULL ) {
818                 struct berval matched_dn = BER_BVNULL;
819
820                 if ( matched != NULL ) {
821                         BerVarray erefs;
822                         ber_dupbv( &matched_dn, &matched->e_name );
823
824                         erefs = is_entry_referral( matched )
825                                 ? get_entry_referrals( op, matched )
826                                 : NULL;
827
828                         bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache,
829                                 matched, &lock);
830                         matched = NULL;
831
832                         if( erefs ) {
833                                 rs->sr_ref = referral_rewrite( erefs, &matched_dn,
834                                         &sop->o_req_dn, sop->oq_search.rs_scope );
835                                 ber_bvarray_free( erefs );
836                         }
837
838                 } else {
839                         rs->sr_ref = referral_rewrite( default_referral,
840                                 NULL, &sop->o_req_dn, sop->oq_search.rs_scope );
841                 }
842
843                 rs->sr_err = LDAP_REFERRAL;
844                 rs->sr_matched = matched_dn.bv_val;
845                 send_ldap_result( sop, rs );
846
847                 if ( !opinfo )
848                         LOCK_ID_FREE (bdb->bi_dbenv, locker );
849                 if ( rs->sr_ref ) {
850                         ber_bvarray_free( rs->sr_ref );
851                         rs->sr_ref = NULL;
852                 }
853                 if ( matched_dn.bv_val ) {
854                         ber_memfree( matched_dn.bv_val );
855                         rs->sr_matched = NULL;
856                 }
857                 return rs->sr_err;
858         }
859
860         if ( !manageDSAit && e != &e_root && is_entry_referral( e ) ) {
861                 /* entry is a referral, don't allow add */
862                 struct berval matched_dn;
863                 BerVarray erefs;
864                 
865                 ber_dupbv( &matched_dn, &e->e_name );
866                 erefs = get_entry_referrals( op, e );
867
868                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
869                 e = NULL;
870
871                 if( erefs ) {
872                         rs->sr_ref = referral_rewrite( erefs, &matched_dn,
873                                 &sop->o_req_dn, sop->oq_search.rs_scope );
874                         ber_bvarray_free( erefs );
875                 }
876
877                 Debug( LDAP_DEBUG_TRACE,
878                         LDAP_XSTRING(bdb_search) ": entry is referral\n",
879                         0, 0, 0 );
880
881                 if (!rs->sr_ref) rs->sr_text = "bad_referral object";
882                 rs->sr_err = LDAP_REFERRAL;
883                 rs->sr_matched = matched_dn.bv_val;
884                 send_ldap_result( sop, rs );
885
886                 if ( !opinfo )
887                         LOCK_ID_FREE (bdb->bi_dbenv, locker );
888                 ber_bvarray_free( rs->sr_ref );
889                 rs->sr_ref = NULL;
890                 ber_memfree( matched_dn.bv_val );
891                 rs->sr_matched = NULL;
892                 return 1;
893         }
894
895         if ( get_assert( op ) &&
896                 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
897         {
898                 rs->sr_err = LDAP_ASSERTION_FAILED;
899                 send_ldap_result( sop, rs );
900                 return 1;
901         }
902
903         /* compute it anyway; root does not use it */
904         stoptime = op->o_time + sop->ors_tlimit;
905
906         /* need normalized dn below */
907         ber_dupbv( &realbase, &e->e_nname );
908
909         /* Copy info to base, must free entry before accessing the database
910          * in search_candidates, to avoid deadlocks.
911          */
912         base.e_private = e->e_private;
913         base.e_nname = realbase;
914         base.e_id = e->e_id;
915
916         if ( e != &e_root ) {
917                 bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
918         }
919         e = NULL;
920
921         if ( !IS_PSEARCH ) {
922                 rs->sr_err = bdb_get_commit_csn( sop, rs, &search_context_csn,
923                         locker, &ctxcsn_lock );
924
925                 if ( rs->sr_err != LDAP_SUCCESS ) {
926                         send_ldap_error( sop, rs, rs->sr_err,
927                                 "error in csn management in search" );
928                         goto done;
929                 }
930
931                 if ( sop->o_sync_mode != SLAP_SYNC_NONE &&
932                         sop->o_sync_state.ctxcsn &&
933                         sop->o_sync_state.ctxcsn->bv_val &&
934                         ber_bvcmp( &sop->o_sync_state.ctxcsn[0], search_context_csn ) == 0 )
935                 {
936                         bdb_cache_entry_db_unlock( bdb->bi_dbenv, &ctxcsn_lock );
937                         goto nochange;
938                 }
939         } else {
940                 search_context_csn = ber_dupbv( NULL, &op->o_sync_csn );        
941         }
942
943         /* select candidates */
944         if ( sop->oq_search.rs_scope == LDAP_SCOPE_BASE ) {
945                 rs->sr_err = base_candidate( op->o_bd, &base, candidates );
946
947         } else {
948                 BDB_IDL_ZERO( candidates );
949                 BDB_IDL_ZERO( scopes );
950                 rs->sr_err = search_candidates( op, sop, rs, &base,
951                         locker, candidates, scopes );
952         }
953
954         if ( !IS_PSEARCH && sop->o_sync_mode != SLAP_SYNC_NONE ) {
955                 bdb_cache_entry_db_unlock( bdb->bi_dbenv, &ctxcsn_lock );
956         }
957
958         /* start cursor at beginning of candidates.
959          */
960         cursor = 0;
961         if (IS_PSEARCH) {
962                 if ( !BDB_IDL_IS_RANGE( candidates ) ) {
963                         cursor = bdb_idl_search( candidates, ps_e->e_id );
964                         if ( candidates[cursor] != ps_e->e_id ) {
965                                 rs->sr_err = LDAP_SUCCESS;
966                                 goto done;
967                         }
968                 } else if ( ps_e->e_id < BDB_IDL_RANGE_FIRST( candidates ) ||
969                         ps_e->e_id > BDB_IDL_RANGE_LAST( candidates ))
970                 {
971                         rs->sr_err = LDAP_SUCCESS;
972                         goto done;
973                 }
974                 candidates[0] = 1;
975                 candidates[1] = ps_e->e_id;
976         }
977
978         if ( candidates[0] == 0 ) {
979                 Debug( LDAP_DEBUG_TRACE,
980                         LDAP_XSTRING(bdb_search) ": no candidates\n",
981                         0, 0, 0 );
982
983                 goto nochange;
984         }
985
986         /* if not root and candidates exceed to-be-checked entries, abort */
987         if ( sop->ors_limit     /* isroot == FALSE */ &&
988                 sop->ors_limit->lms_s_unchecked != -1 &&
989                 BDB_IDL_N(candidates) > (unsigned) sop->ors_limit->lms_s_unchecked )
990         {
991                 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
992                 send_ldap_result( sop, rs );
993                 rs->sr_err = LDAP_SUCCESS;
994                 goto done;
995         }
996
997         if ( sop->ors_limit == NULL     /* isroot == TRUE */ ||
998                 !sop->ors_limit->lms_s_pr_hide )
999         {
1000                 tentries = BDB_IDL_N(candidates);
1001         }
1002
1003         if ( get_pagedresults( sop ) > SLAP_NO_CONTROL ) {
1004                 /* deferred cookie parsing */
1005                 rs->sr_err = parse_paged_cookie( sop, rs );
1006                 if ( rs->sr_err != LDAP_SUCCESS ) {
1007                         send_ldap_result( sop, rs );
1008                         goto done;
1009                 }
1010
1011                 if ( (ID)( sop->o_pagedresults_state.ps_cookie ) == 0 ) {
1012                         id = bdb_idl_first( candidates, &cursor );
1013
1014                 } else {
1015                         if ( sop->o_pagedresults_size == 0 ) {
1016                                 rs->sr_err = LDAP_SUCCESS;
1017                                 rs->sr_text = "search abandoned by pagedResult size=0";
1018                                 send_ldap_result( sop, rs );
1019                                 goto done;
1020                         }
1021                         for ( id = bdb_idl_first( candidates, &cursor );
1022                                 id != NOID &&
1023                                         id <= (ID)( sop->o_pagedresults_state.ps_cookie );
1024                                 id = bdb_idl_next( candidates, &cursor ) )
1025                         {
1026                                 /* empty */;
1027                         }
1028                 }
1029
1030                 if ( cursor == NOID ) {
1031                         Debug( LDAP_DEBUG_TRACE, 
1032                                 LDAP_XSTRING(bdb_search)
1033                                 ": no paged results candidates\n",
1034                                 0, 0, 0 );
1035                         send_paged_response( sop, rs, &lastid, 0 );
1036
1037                         rs->sr_err = LDAP_OTHER;
1038                         goto done;
1039                 }
1040                 goto loop_begin;
1041         }
1042
1043         if (( sop->o_sync_mode & SLAP_SYNC_REFRESH ) || IS_PSEARCH ) {
1044                 int match;
1045
1046                 cookief.f_choice = LDAP_FILTER_AND;
1047                 cookief.f_and = &csnfnot;
1048                 cookief.f_next = NULL;
1049
1050                 csnfnot.f_choice = LDAP_FILTER_NOT;
1051                 csnfnot.f_not = &csnfeq;
1052                 csnfnot.f_next = &csnfand;
1053
1054                 csnfeq.f_choice = LDAP_FILTER_EQUALITY;
1055                 csnfeq.f_ava = &aa_eq;
1056                 csnfeq.f_av_desc = slap_schema.si_ad_entryCSN;
1057                 if ( sop->o_sync_state.ctxcsn != NULL ) {
1058                         csnfeq.f_av_value = *sop->o_sync_state.ctxcsn;
1059                 } else {
1060                         csnfeq.f_av_value = slap_empty_bv;
1061                 }
1062
1063                 csnfand.f_choice = LDAP_FILTER_AND;
1064                 csnfand.f_and = &csnfge;
1065                 csnfand.f_next = NULL;
1066
1067                 csnfge.f_choice = LDAP_FILTER_GE;
1068                 csnfge.f_ava = &aa_ge;
1069                 csnfge.f_av_desc = slap_schema.si_ad_entryCSN;
1070                 if ( sop->o_sync_state.ctxcsn != NULL ) {
1071                         csnfge.f_av_value = *sop->o_sync_state.ctxcsn;
1072                 } else {
1073                         csnfge.f_av_value = slap_empty_bv;
1074                 }
1075
1076                 if ( search_context_csn && !IS_PSEARCH ) {
1077                         csnfge.f_next = &contextcsnand;
1078
1079                         contextcsnand.f_choice = LDAP_FILTER_AND;
1080                         contextcsnand.f_and = &contextcsnle;
1081                         contextcsnand.f_next = NULL;
1082         
1083                         contextcsnle.f_choice = LDAP_FILTER_LE;
1084                         contextcsnle.f_ava = &aa_le;
1085                         contextcsnle.f_av_desc = slap_schema.si_ad_entryCSN;
1086                         contextcsnle.f_av_value = *search_context_csn;
1087                         contextcsnle.f_next = sop->oq_search.rs_filter;
1088
1089                         mr = slap_schema.si_ad_entryCSN->ad_type->sat_ordering;
1090                         if ( sop->o_sync_state.ctxcsn &&
1091                                 sop->o_sync_state.ctxcsn->bv_val != NULL )
1092                         {
1093                                 value_match( &match, slap_schema.si_ad_entryCSN, mr,
1094                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1095                                                 &sop->o_sync_state.ctxcsn[0], search_context_csn,
1096                                                 &text );
1097                         } else {
1098                                 match = -1;
1099                         }
1100                         no_sync_state_change = ( match >= 0 );
1101                 } else {
1102                         csnfge.f_next = sop->oq_search.rs_filter;
1103                 }
1104         }
1105
1106 loop_start:
1107
1108         for ( id = bdb_idl_first( candidates, &cursor );
1109                   id != NOID && !no_sync_state_change;
1110                 id = bdb_idl_next( candidates, &cursor ) )
1111         {
1112                 int scopeok = 0;
1113                 ID* idhole = NULL;
1114
1115 loop_begin:
1116
1117                 if ( !IS_POST_SEARCH ) {
1118                         idhole = (ID*) avl_find( sop->o_psearch_finished,
1119                                                                          (caddr_t)&id, bdb_pfid_cmp );
1120                         if ( idhole ) {
1121                                 avl_delete( &sop->o_psearch_finished,
1122                                                         (caddr_t)idhole, bdb_pfid_cmp );
1123                                 sop->o_tmpfree( idhole, sop->o_tmpmemctx );
1124                                 goto loop_continue;
1125                         }
1126
1127                         if ( sop->o_refresh_in_progress ) {
1128                                 ldap_pvt_thread_mutex_lock( &sop->o_pcmutex );
1129                                 pce = LDAP_TAILQ_FIRST( &sop->o_ps_pre_candidates );    
1130                                 while ( pce && pce->pc_sent ) {
1131                                         pce = LDAP_TAILQ_NEXT( pce, pc_link );
1132                                 }
1133                                 ldap_pvt_thread_mutex_unlock( &sop->o_pcmutex );
1134                                 if ( pce ) {
1135                                         ID pos;
1136                                         if ( BDB_IDL_IS_RANGE( candidates ) ) {
1137                                                 if ( pce->pc_id >= candidates[1] &&
1138                                                          pce->pc_id <= candidates[2] &&
1139                                                          pce->pc_id > cursor-1 ) {
1140                                                         id = pce->pc_id;
1141                                                         cursor--;
1142                                                         avl_insert( &sop->o_psearch_finished,
1143                                                                                 (caddr_t)bdb_id_dup( sop, &pce->pc_id ),
1144                                                                                 bdb_pfid_cmp, avl_dup_error );
1145                                                 } else {
1146                                                         pce->pc_sent = 1;
1147                                                 }
1148                                         } else {
1149                                                 pos = bdb_idl_search(candidates, pce->pc_id);
1150                                                 if ( pos > cursor-1 && pos <= candidates[0] ) {
1151                                                         id = pce->pc_id;
1152                                                         cursor--;
1153                                                         avl_insert( &sop->o_psearch_finished,
1154                                                                                 (caddr_t)bdb_id_dup( sop, &pce->pc_id ),
1155                                                                                 bdb_pfid_cmp, avl_dup_error );
1156                                                 } else {
1157                                                         pce->pc_sent = 1;
1158                                                 }
1159                                         }
1160                                 }
1161                         }
1162                 }
1163
1164                 /* check for abandon */
1165                 if ( sop->o_abandon ) {
1166                         if ( sop != op ) {
1167                                 bdb_drop_psearch( sop, sop->o_msgid );
1168                         }
1169                         rs->sr_err = LDAP_SUCCESS;
1170                         goto done;
1171                 }
1172
1173                 if ( sop->o_cancel ) {
1174                         assert( sop->o_cancel == SLAP_CANCEL_REQ );
1175                         rs->sr_err = LDAP_CANCELLED;
1176                         send_ldap_result( sop, rs );
1177                         sop->o_cancel = SLAP_CANCEL_ACK;
1178                         rs->sr_err = LDAP_SUCCESS;
1179                         goto done;
1180                 }
1181
1182                 /* check time limit */
1183                 if ( sop->ors_tlimit != SLAP_NO_LIMIT
1184                                 && slap_get_time() > stoptime )
1185                 {
1186                         rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
1187                         rs->sr_ref = rs->sr_v2ref;
1188                         send_ldap_result( sop, rs );
1189                         rs->sr_err = LDAP_SUCCESS;
1190                         goto done;
1191                 }
1192
1193                 if (!IS_PSEARCH) {
1194 id2entry_retry:
1195                         /* get the entry with reader lock */
1196                         ei = NULL;
1197                         rs->sr_err = bdb_cache_find_id( op, ltid,
1198                                 id, &ei, 0, locker, &lock );
1199
1200                         if (rs->sr_err == LDAP_BUSY) {
1201                                 rs->sr_text = "ldap server busy";
1202                                 send_ldap_result( sop, rs );
1203                                 goto done;
1204
1205                         } else if ( rs->sr_err == DB_LOCK_DEADLOCK
1206                                 || rs->sr_err == DB_LOCK_NOTGRANTED )
1207                         {
1208                                 goto id2entry_retry;    
1209                         }
1210
1211                         if ( ei && rs->sr_err == LDAP_SUCCESS ) {
1212                                 e = ei->bei_e;
1213                         } else {
1214                                 e = NULL;
1215                         }
1216
1217                         if ( e == NULL ) {
1218                                 if ( IS_POST_SEARCH ) {
1219                                         /* send LDAP_SYNC_DELETE */
1220                                         rs->sr_entry = e = ps_e;
1221                                         goto post_search_no_entry;
1222                                 } else if( !BDB_IDL_IS_RANGE(candidates) ) {
1223                                         /* only complain for non-range IDLs */
1224                                         Debug( LDAP_DEBUG_TRACE,
1225                                                 LDAP_XSTRING(bdb_search)
1226                                                 ": candidate %ld not found\n",
1227                                                 (long) id, 0, 0 );
1228                                 }
1229
1230                                 goto loop_continue;
1231                         }
1232                 } else {
1233                         e = ps_e;
1234                 }
1235
1236                 rs->sr_entry = e;
1237
1238 #ifdef BDB_SUBENTRIES
1239                 /* FIXME: send all but syncrepl */
1240 #if 0
1241                 if ( !is_sync_protocol( sop ) )
1242 #endif
1243                 {
1244                         if ( is_entry_subentry( e ) ) {
1245                                 if( sop->oq_search.rs_scope != LDAP_SCOPE_BASE ) {
1246                                         if(!get_subentries_visibility( sop )) {
1247                                                 /* only subentries are visible */
1248                                                 goto loop_continue;
1249                                         }
1250
1251                                 } else if ( get_subentries( sop ) &&
1252                                         !get_subentries_visibility( sop ))
1253                                 {
1254                                         /* only subentries are visible */
1255                                         goto loop_continue;
1256                                 }
1257
1258                         } else if ( get_subentries_visibility( sop )) {
1259                                 /* only subentries are visible */
1260                                 goto loop_continue;
1261                         }
1262                 }
1263 #endif /* BDB_SUBENTRIES */
1264
1265                 /* Does this candidate actually satisfy the search scope?
1266                  *
1267                  * Note that we don't lock access to the bei_parent pointer.
1268                  * Since only leaf nodes can be deleted, the parent of any
1269                  * node will always be a valid node. Also since we have
1270                  * a Read lock on the data, it cannot be renamed out of the
1271                  * scope while we are looking at it, and unless we're using
1272                  * BDB_HIER, its parents cannot be moved either.
1273                  */
1274                 switch( sop->ors_scope ) {
1275                 case LDAP_SCOPE_BASE:
1276                         /* This is always true, yes? */
1277                         if ( id == base.e_id ) scopeok = 1;
1278                         break;
1279
1280                 case LDAP_SCOPE_ONELEVEL:
1281                         if ( ei->bei_parent->bei_id == base.e_id ) scopeok = 1;
1282                         break;
1283
1284 #ifdef LDAP_SCOPE_CHILDREN
1285                 case LDAP_SCOPE_CHILDREN:
1286                         if ( id == base.e_id ) break;
1287                         /* Fall-thru */
1288 #endif
1289                 case LDAP_SCOPE_SUBTREE: {
1290                         EntryInfo *tmp;
1291                         for ( tmp = BEI(e); tmp; tmp = tmp->bei_parent ) {
1292                                 if ( tmp->bei_id == base.e_id ) {
1293                                         scopeok = 1;
1294                                         break;
1295                                 }
1296                         }
1297                         } break;
1298                 }
1299
1300                 /* aliases were already dereferenced in candidate list */
1301                 if ( sop->ors_deref & LDAP_DEREF_SEARCHING ) {
1302                         /* but if the search base is an alias, and we didn't
1303                          * deref it when finding, return it.
1304                          */
1305                         if ( is_entry_alias(e) &&
1306                                 ((sop->ors_deref & LDAP_DEREF_FINDING) ||
1307                                         !bvmatch(&e->e_nname, &op->o_req_ndn)))
1308                         {
1309                                 goto loop_continue;
1310                         }
1311
1312                         /* scopes is only non-empty for onelevel or subtree */
1313                         if ( !scopeok && BDB_IDL_N(scopes) ) {
1314                                 unsigned x;
1315                                 if ( sop->ors_scope == LDAP_SCOPE_ONELEVEL ) {
1316                                         x = bdb_idl_search( scopes, e->e_id );
1317                                         if ( scopes[x] == e->e_id ) scopeok = 1;
1318                                 } else {
1319                                         /* subtree, walk up the tree */
1320                                         EntryInfo *tmp = BEI(e);
1321                                         for (;tmp->bei_parent; tmp=tmp->bei_parent) {
1322                                                 x = bdb_idl_search( scopes, tmp->bei_id );
1323                                                 if ( scopes[x] == tmp->bei_id ) {
1324                                                         scopeok = 1;
1325                                                         break;
1326                                                 }
1327                                         }
1328                                 }
1329                         }
1330                 }
1331
1332                 /* Not in scope, ignore it */
1333                 if ( !IS_POST_SEARCH && !scopeok ) {
1334                         Debug( LDAP_DEBUG_TRACE,
1335                                 LDAP_XSTRING(bdb_search)
1336                                 ": %ld scope not okay\n",
1337                                 (long) id, 0, 0 );
1338                         goto loop_continue;
1339                 }
1340
1341                 /*
1342                  * if it's a referral, add it to the list of referrals. only do
1343                  * this for non-base searches, and don't check the filter
1344                  * explicitly here since it's only a candidate anyway.
1345                  */
1346                 if ( !manageDSAit && sop->oq_search.rs_scope != LDAP_SCOPE_BASE
1347                         && is_entry_referral( e ) )
1348                 {
1349                         BerVarray erefs = get_entry_referrals( sop, e );
1350                         rs->sr_ref = referral_rewrite( erefs, &e->e_name, NULL,
1351                                 sop->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL
1352                                         ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );
1353
1354                         send_search_reference( sop, rs );
1355
1356                         ber_bvarray_free( rs->sr_ref );
1357                         ber_bvarray_free( erefs );
1358                         rs->sr_ref = NULL;
1359
1360                         goto loop_continue;
1361                 }
1362
1363                 if ( !manageDSAit && is_entry_glue( e )) {
1364                         goto loop_continue;
1365                 }
1366
1367                 /* if it matches the filter and scope, send it */
1368                 if (IS_PSEARCH) {
1369                         if (ps_type != LDAP_PSEARCH_BY_SCOPEOUT) {
1370                                 rs->sr_err = test_filter( sop, rs->sr_entry, &cookief );
1371                         } else {
1372                                 rs->sr_err = LDAP_COMPARE_TRUE;
1373                         }
1374
1375                 } else {
1376                         if ( !IS_POST_SEARCH ) {
1377                                 if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) {
1378                                         rc_sync = test_filter( sop, rs->sr_entry, &cookief );
1379                                         rs->sr_err = test_filter( sop, rs->sr_entry,
1380                                                                                 &contextcsnand );
1381                                         if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
1382                                                 if ( rc_sync == LDAP_COMPARE_TRUE ) {
1383                                                         if ( no_sync_state_change ) {
1384                                                                 Debug( LDAP_DEBUG_TRACE,
1385                                                                         LDAP_XSTRING(bdb_search) ": "
1386                                                                         "error in context csn management\n",
1387                                                                         0, 0, 0 );
1388                                                         }
1389                                                         entry_sync_state = LDAP_SYNC_ADD;
1390
1391                                                 } else {
1392                                                         if ( no_sync_state_change ) {
1393                                                                 goto loop_continue;
1394                                                         }
1395                                                         entry_sync_state = LDAP_SYNC_PRESENT;
1396                                                 }
1397                                         }
1398                                 } else {
1399                                         rs->sr_err = test_filter( sop,
1400                                                 rs->sr_entry, sop->oq_search.rs_filter );
1401                                 }
1402                         } else {
1403                                 if ( scopeok ) {
1404                                         rs->sr_err = test_filter( sop,
1405                                                 rs->sr_entry, sop->oq_search.rs_filter );
1406                                 } else {
1407                                         rs->sr_err = LDAP_COMPARE_TRUE;
1408                                 }
1409                         }
1410                 }
1411
1412                 if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
1413                         /* check size limit */
1414                         if ( --sop->ors_slimit == -1 &&
1415                                 sop->o_sync_slog_size == -1 )
1416                         {
1417                                 if (!IS_PSEARCH) {
1418                                         bdb_cache_return_entry_r( bdb->bi_dbenv,
1419                                                 &bdb->bi_cache, e, &lock );
1420                                 }
1421                                 e = NULL;
1422                                 rs->sr_entry = NULL;
1423                                 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
1424                                 rs->sr_ref = rs->sr_v2ref;
1425                                 send_ldap_result( sop, rs );
1426                                 rs->sr_err = LDAP_SUCCESS;
1427                                 goto done;
1428                         }
1429
1430                         if ( get_pagedresults(sop) > SLAP_NO_CONTROL ) {
1431                                 if ( rs->sr_nentries >= sop->o_pagedresults_size ) {
1432                                         send_paged_response( sop, rs, &lastid, tentries );
1433                                         goto done;
1434                                 }
1435                                 lastid = id;
1436                         }
1437
1438                         if (e) {
1439                                 /* safe default */
1440                                 int result = -1;
1441                                 
1442                                 if (IS_PSEARCH || IS_POST_SEARCH) {
1443                                         int premodify_found = 0;
1444
1445                                         if ( IS_POST_SEARCH ||
1446                                                  ps_type == LDAP_PSEARCH_BY_ADD ||
1447                                                  ps_type == LDAP_PSEARCH_BY_DELETE ||
1448                                                  ps_type == LDAP_PSEARCH_BY_MODIFY ||
1449                                                  ps_type == LDAP_PSEARCH_BY_SCOPEOUT )
1450                                         {
1451                                                 if ( !IS_POST_SEARCH &&
1452                                                          ps_type == LDAP_PSEARCH_BY_MODIFY ) {
1453                                                         struct psid_entry* psid_e;
1454                                                         LDAP_LIST_FOREACH( psid_e,
1455                                                                 &op->o_pm_list, ps_link)
1456                                                         {
1457                                                                 if( psid_e->ps_op == sop ) {
1458                                                                         premodify_found = 1;
1459                                                                         LDAP_LIST_REMOVE(psid_e, ps_link);
1460                                                                         break;
1461                                                                 }
1462                                                         }
1463                                                         if (psid_e != NULL) free (psid_e);
1464                                                 }
1465
1466                                                 if ( IS_POST_SEARCH ) {
1467                                                         if ( scopeok ) {
1468                                                                 entry_sync_state = LDAP_SYNC_ADD;
1469                                                         } else {
1470 post_search_no_entry:
1471                                                                 entry_sync_state = LDAP_SYNC_DELETE;
1472                                                         }
1473                                                 } else if ( ps_type == LDAP_PSEARCH_BY_ADD ) {
1474                                                         entry_sync_state = LDAP_SYNC_ADD;
1475                                                 } else if ( ps_type == LDAP_PSEARCH_BY_DELETE ) {
1476                                                         entry_sync_state = LDAP_SYNC_DELETE;
1477                                                 } else if ( ps_type == LDAP_PSEARCH_BY_MODIFY ) {
1478                                                         if ( premodify_found ) {
1479                                                                 entry_sync_state = LDAP_SYNC_MODIFY;
1480                                                         } else {
1481                                                                 entry_sync_state = LDAP_SYNC_ADD;
1482                                                         }
1483                                                 } else if ( ps_type == LDAP_PSEARCH_BY_SCOPEOUT ) {
1484                                                         entry_sync_state = LDAP_SYNC_DELETE;
1485                                                 } else {
1486                                                         rs->sr_err = LDAP_OTHER;
1487                                                         goto done;
1488                                                 }
1489
1490                                                 if ( sop->o_sync_slog_size != -1 ) {
1491                                                         if ( entry_sync_state == LDAP_SYNC_DELETE ) {
1492                                                                 result = slap_add_session_log( op, sop, e );
1493                                                         } else {
1494                                                                 result = 1;
1495                                                         }
1496                                                 } else {
1497                                                         struct berval cookie;
1498                                                         slap_compose_sync_cookie( sop, &cookie,
1499                                                                 search_context_csn,
1500                                                                 sop->o_sync_state.sid,
1501                                                                 sop->o_sync_state.rid );
1502                                                         rs->sr_err = slap_build_sync_state_ctrl(
1503                                                                 sop, rs, e, entry_sync_state, ctrls,
1504                                                                 num_ctrls++, 1, &cookie );
1505                                                         if ( rs->sr_err != LDAP_SUCCESS ) goto done;
1506                                                         if (!(IS_POST_SEARCH &&
1507                                                                 entry_sync_state == LDAP_SYNC_DELETE)) {
1508                                                                 rs->sr_attrs = attrs;
1509                                                         } else {
1510                                                                 rs->sr_attrs = NULL;
1511                                                         }
1512                                                         rs->sr_operational_attrs = NULL;
1513                                                         rs->sr_ctrls = ctrls;
1514                                                         rs->sr_flags = 0;
1515                                                         result = send_search_entry( sop, rs );
1516                                                         if ( cookie.bv_val ) ch_free( cookie.bv_val );  
1517                                                         slap_sl_free(
1518                                                                 ctrls[num_ctrls-1]->ldctl_value.bv_val,
1519                                                                 sop->o_tmpmemctx );
1520                                                         slap_sl_free( ctrls[--num_ctrls],
1521                                                                 sop->o_tmpmemctx );
1522                                                         ctrls[num_ctrls] = NULL;
1523                                                         rs->sr_ctrls = NULL;
1524                                                 }
1525
1526                                         } else if ( ps_type == LDAP_PSEARCH_BY_PREMODIFY ) {
1527                                                 struct psid_entry* psid_e;
1528                                                 psid_e = (struct psid_entry *) ch_calloc(1,
1529                                                         sizeof(struct psid_entry));
1530                                                 psid_e->ps_op = sop;
1531                                                 LDAP_LIST_INSERT_HEAD( &op->o_pm_list,
1532                                                         psid_e, ps_link );
1533
1534                                         } else {
1535                                                 Debug( LDAP_DEBUG_TRACE,
1536                                                         LDAP_XSTRING(bdb_search)
1537                                                         ": invalid ps_type (%d) \n",
1538                                                         ps_type, 0, 0);
1539                                         }
1540
1541                                 } else {
1542                                         if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) {
1543                                                 if ( rc_sync == LDAP_COMPARE_TRUE ) { /* ADD */
1544                                                         rs->sr_err = slap_build_sync_state_ctrl(
1545                                                                 sop, rs, e, entry_sync_state, ctrls,
1546                                                                 num_ctrls++, 0, NULL );
1547                                                         if ( rs->sr_err != LDAP_SUCCESS ) goto done;
1548                                                         rs->sr_ctrls = ctrls;
1549                                                         rs->sr_attrs = sop->oq_search.rs_attrs;
1550                                                         rs->sr_operational_attrs = NULL;
1551                                                         rs->sr_flags = 0;
1552                                                         result = send_search_entry( sop, rs );
1553                                                         slap_sl_free(
1554                                                                 ctrls[num_ctrls-1]->ldctl_value.bv_val,
1555                                                                 sop->o_tmpmemctx );
1556                                                         slap_sl_free( ctrls[--num_ctrls],
1557                                                                 sop->o_tmpmemctx );
1558                                                         ctrls[num_ctrls] = NULL;
1559                                                         rs->sr_ctrls = NULL;
1560
1561                                                 } else { /* PRESENT */
1562                                                         if ( sync_send_present_mode ) {
1563                                                                 result = slap_build_syncUUID_set( sop,
1564                                                                         &syncUUID_set, e );
1565                                                                 if ( result <= 0 ) {
1566                                                                         result = -1;    
1567                                                                 } else {
1568                                                                         syncUUID_set_cnt++;
1569                                                                         if ( syncUUID_set_cnt ==
1570                                                                                 SLAP_SYNCUUID_SET_SIZE )
1571                                                                         {
1572                                                                                 rs->sr_err = LDAP_SUCCESS;
1573                                                                                 rs->sr_rspoid = LDAP_SYNC_INFO;
1574                                                                                 rs->sr_ctrls = NULL;
1575                                                                                 result = slap_send_syncinfo( sop, rs,
1576                                                                                         LDAP_TAG_SYNC_ID_SET,
1577                                                                                         NULL, 0, syncUUID_set, 0 );
1578                                                                                 if ( result != LDAP_SUCCESS ) {
1579                                                                                         result = -1;
1580                                                                                 }
1581                                                                                 ber_bvarray_free_x( syncUUID_set,
1582                                                                                         sop->o_tmpmemctx );
1583                                                                                 syncUUID_set = NULL;
1584                                                                                 syncUUID_set_cnt = 0;
1585                                                                         }
1586                                                                 }
1587
1588                                                         } else {
1589                                                                 result = 1;
1590                                                         }
1591                                                 }
1592
1593                                         } else {
1594                                                 rs->sr_attrs = sop->oq_search.rs_attrs;
1595                                                 rs->sr_operational_attrs = NULL;
1596                                                 rs->sr_ctrls = NULL;
1597                                                 rs->sr_flags = 0;
1598                                                 rs->sr_err = LDAP_SUCCESS;
1599                                                 result = send_search_entry( sop, rs );
1600                                         }
1601                                 }
1602
1603                                 switch (result) {
1604                                 case 0:         /* entry sent ok */
1605                                         break;
1606                                 case 1:         /* entry not sent */
1607                                         break;
1608                                 case -1:        /* connection closed */
1609                                         if (!IS_PSEARCH) {
1610                                                 bdb_cache_return_entry_r(bdb->bi_dbenv,
1611                                                         &bdb->bi_cache, e, &lock);
1612                                         }
1613                                         e = NULL;
1614                                         rs->sr_entry = NULL;
1615                                         rs->sr_err = LDAP_OTHER;
1616                                         goto done;
1617                                 }
1618                         }
1619
1620                 } else {
1621                         Debug( LDAP_DEBUG_TRACE,
1622                                 LDAP_XSTRING(bdb_search)
1623                                 ": %ld does not match filter\n",
1624                                 (long) id, 0, 0 );
1625                 }
1626
1627 loop_continue:
1628                 if( e != NULL ) {
1629                         /* free reader lock */
1630                         if (!IS_PSEARCH) {
1631                                 if (!(IS_POST_SEARCH &&
1632                                                  entry_sync_state == LDAP_SYNC_DELETE)) {
1633                                         bdb_cache_return_entry_r( bdb->bi_dbenv,
1634                                                 &bdb->bi_cache, e , &lock );
1635                                         if ( sop->o_nocaching ) {
1636                                                 bdb_cache_delete_entry( bdb, ei, locker, &lock );
1637                                         }
1638                                 }
1639                         }
1640                         e = NULL;
1641                         rs->sr_entry = NULL;
1642                 }
1643                 
1644                 if ( sop->o_refresh_in_progress ) {
1645                         if ( pce ) {
1646                                 pce->pc_sent = 1;
1647                         }
1648                 }
1649
1650                 ldap_pvt_thread_yield();
1651         }
1652
1653         if ( syncUUID_set_cnt > 0 ) {
1654                 rs->sr_err = LDAP_SUCCESS;
1655                 rs->sr_rspoid = LDAP_SYNC_INFO;
1656                 rs->sr_ctrls = NULL;
1657                 slap_send_syncinfo( sop, rs, LDAP_TAG_SYNC_ID_SET,
1658                         NULL, 0, syncUUID_set, 0 );
1659                 ber_bvarray_free_x( syncUUID_set, sop->o_tmpmemctx );
1660                 syncUUID_set_cnt = 0;
1661         }
1662
1663 nochange:
1664         if (!IS_PSEARCH && !IS_POST_SEARCH) {
1665                 if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) {
1666                         if ( sop->o_sync_mode & SLAP_SYNC_PERSIST ) {
1667                                 struct berval cookie;
1668                                 slap_compose_sync_cookie( sop, &cookie, search_context_csn,
1669                                         sop->o_sync_state.sid, sop->o_sync_state.rid );
1670
1671                                 if ( sync_send_present_mode ) {
1672                                         rs->sr_err = LDAP_SUCCESS;
1673                                         rs->sr_rspoid = LDAP_SYNC_INFO;
1674                                         rs->sr_ctrls = NULL;
1675                                         slap_send_syncinfo( sop, rs,
1676                                                 LDAP_TAG_SYNC_REFRESH_PRESENT, &cookie, 1, NULL, 0 );
1677
1678                                 } else {
1679                                         if ( !no_sync_state_change ) {
1680                                                 int slog_found = 0;
1681                                                 ldap_pvt_thread_rdwr_rlock( &bdb->bi_pslist_rwlock );
1682                                                 LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list,
1683                                                         o_ps_link )
1684                                                 {
1685                                                         if ( ps_list->o_sync_slog_size > 0 ) {
1686                                                                 if ( ps_list->o_sync_state.sid ==
1687                                                                         sop->o_sync_state.sid )
1688                                                                 {
1689                                                                         slog_found = 1;
1690                                                                         break;
1691                                                                 }
1692                                                         }
1693                                                 }
1694                 
1695                                                 if ( slog_found ) {
1696                                                         rs->sr_err = LDAP_SUCCESS;
1697                                                         rs->sr_rspoid = NULL;
1698                                                         rs->sr_ctrls = NULL;
1699                                                         slap_send_session_log( op, ps_list, rs );
1700                                                 }
1701                                                 ldap_pvt_thread_rdwr_runlock( &bdb->bi_pslist_rwlock );
1702                                         }
1703
1704                                         rs->sr_err = LDAP_SUCCESS;
1705                                         rs->sr_rspoid = LDAP_SYNC_INFO;
1706                                         rs->sr_ctrls = NULL;
1707                                         slap_send_syncinfo( sop, rs,
1708                                                 LDAP_TAG_SYNC_REFRESH_DELETE, &cookie, 1, NULL, 0 );
1709                                 }
1710
1711                                 if ( cookie.bv_val ) ch_free( cookie.bv_val );
1712
1713                         } else {
1714                                 /* refreshOnly mode */
1715                                 struct berval cookie;
1716                                 slap_compose_sync_cookie( sop, &cookie, search_context_csn,
1717                                         sop->o_sync_state.sid, sop->o_sync_state.rid );
1718
1719                                 if ( sync_send_present_mode ) {
1720                                         slap_build_sync_done_ctrl( sop, rs, ctrls,
1721                                                 num_ctrls++, 1, &cookie, LDAP_SYNC_REFRESH_PRESENTS );
1722
1723                                 } else {
1724                                         if ( !no_sync_state_change ) {
1725                                                 int slog_found = 0;
1726                                                 ldap_pvt_thread_rdwr_rlock( &bdb->bi_pslist_rwlock );
1727                                                 LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list,
1728                                                         o_ps_link )
1729                                                 {
1730                                                         if ( ps_list->o_sync_slog_size > 0 ) {
1731                                                                 if ( ps_list->o_sync_state.sid ==
1732                                                                                 sop->o_sync_state.sid ) {
1733                                                                         slog_found = 1;
1734                                                                         break;
1735                                                                 }
1736                                                         }
1737                                                 }
1738                 
1739                                                 if ( slog_found ) {
1740                                                         slap_send_session_log( op, ps_list, rs );
1741                                                 }
1742                                                 ldap_pvt_thread_rdwr_runlock( &bdb->bi_pslist_rwlock );
1743                                         }
1744
1745                                         slap_build_sync_done_ctrl( sop, rs, ctrls,
1746                                                 num_ctrls++, 1, &cookie, LDAP_SYNC_REFRESH_DELETES );
1747                                 }
1748
1749                                 rs->sr_ctrls = ctrls;
1750                                 rs->sr_ref = rs->sr_v2ref;
1751                                 rs->sr_err = (rs->sr_v2ref == NULL)
1752                                         ? LDAP_SUCCESS : LDAP_REFERRAL;
1753                                 rs->sr_rspoid = NULL;
1754                                 send_ldap_result( sop, rs );
1755                                 if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL ) {
1756                                         slap_sl_free( ctrls[num_ctrls-1]->ldctl_value.bv_val,
1757                                                 sop->o_tmpmemctx );
1758                                 }
1759                                 slap_sl_free( ctrls[--num_ctrls], sop->o_tmpmemctx );
1760                                 ctrls[num_ctrls] = NULL;
1761                                 if ( cookie.bv_val ) ch_free( cookie.bv_val );  
1762                         }
1763
1764                 } else {
1765                         rs->sr_ctrls = NULL;
1766                         rs->sr_ref = rs->sr_v2ref;
1767                         rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL;
1768                         rs->sr_rspoid = NULL;
1769                         if ( get_pagedresults(sop) > SLAP_NO_CONTROL ) {
1770                                 send_paged_response( sop, rs, NULL, 0 );
1771                         } else {
1772                                 send_ldap_result( sop, rs );
1773                         }
1774                 }
1775         }
1776
1777         if ( sop->o_refresh_in_progress ) {
1778                 sop->o_refresh_in_progress = 0;
1779         }
1780
1781         rs->sr_err = LDAP_SUCCESS;
1782
1783 done:
1784         if ( sop->o_psearch_finished ) {
1785                 avl_free( sop->o_psearch_finished, ch_free );
1786         }
1787
1788         if( !IS_PSEARCH && e != NULL ) {
1789                 /* free reader lock */
1790                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
1791         }
1792
1793         if ( !opinfo )
1794                 LOCK_ID_FREE( bdb->bi_dbenv, locker );
1795
1796         ber_bvfree( search_context_csn );
1797
1798         if( rs->sr_v2ref ) {
1799                 ber_bvarray_free( rs->sr_v2ref );
1800                 rs->sr_v2ref = NULL;
1801         }
1802         if( realbase.bv_val ) ch_free( realbase.bv_val );
1803
1804         return rs->sr_err;
1805 }
1806
1807
1808 static int base_candidate(
1809         BackendDB       *be,
1810         Entry   *e,
1811         ID              *ids )
1812 {
1813         Debug(LDAP_DEBUG_ARGS, "base_candidates: base: \"%s\" (0x%08lx)\n",
1814                 e->e_nname.bv_val, (long) e->e_id, 0);
1815
1816         ids[0] = 1;
1817         ids[1] = e->e_id;
1818         return 0;
1819 }
1820
1821 /* Look for "objectClass Present" in this filter.
1822  * Also count depth of filter tree while we're at it.
1823  */
1824 static int oc_filter(
1825         Filter *f,
1826         int cur,
1827         int *max )
1828 {
1829         int rc = 0;
1830
1831         assert( f );
1832
1833         if( cur > *max ) *max = cur;
1834
1835         switch( f->f_choice ) {
1836         case LDAP_FILTER_PRESENT:
1837                 if (f->f_desc == slap_schema.si_ad_objectClass) {
1838                         rc = 1;
1839                 }
1840                 break;
1841
1842         case LDAP_FILTER_AND:
1843         case LDAP_FILTER_OR:
1844                 cur++;
1845                 for ( f=f->f_and; f; f=f->f_next ) {
1846                         (void) oc_filter(f, cur, max);
1847                 }
1848                 break;
1849
1850         default:
1851                 break;
1852         }
1853         return rc;
1854 }
1855
1856 static void search_stack_free( void *key, void *data )
1857 {
1858         ber_memfree_x(data, NULL);
1859 }
1860
1861 static void *search_stack( Operation *op )
1862 {
1863         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
1864         void *ret = NULL;
1865
1866         if ( op->o_threadctx ) {
1867                 ldap_pvt_thread_pool_getkey( op->o_threadctx, search_stack,
1868                         &ret, NULL );
1869         } else {
1870                 ret = bdb->bi_search_stack;
1871         }
1872
1873         if ( !ret ) {
1874                 ret = ch_malloc( bdb->bi_search_stack_depth * BDB_IDL_UM_SIZE
1875                         * sizeof( ID ) );
1876                 if ( op->o_threadctx ) {
1877                         ldap_pvt_thread_pool_setkey( op->o_threadctx, search_stack,
1878                                 ret, search_stack_free );
1879                 } else {
1880                         bdb->bi_search_stack = ret;
1881                 }
1882         }
1883         return ret;
1884 }
1885
1886 static int search_candidates(
1887         Operation *stackop,
1888         Operation *op,
1889         SlapReply *rs,
1890         Entry *e,
1891         u_int32_t locker,
1892         ID      *ids,
1893         ID      *scopes )
1894 {
1895         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
1896         int rc, depth = 1;
1897         Filter          f, rf, xf, nf;
1898         ID              *stack;
1899         AttributeAssertion aa_ref;
1900 #ifdef BDB_SUBENTRIES
1901         Filter  sf;
1902         AttributeAssertion aa_subentry;
1903 #endif
1904
1905         /*
1906          * This routine takes as input a filter (user-filter)
1907          * and rewrites it as follows:
1908          *      (&(scope=DN)[(objectClass=subentry)]
1909          *              (|[(objectClass=referral)(objectClass=alias)](user-filter))
1910          */
1911
1912         Debug(LDAP_DEBUG_TRACE,
1913                 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n",
1914                 e->e_nname.bv_val, (long) e->e_id, op->oq_search.rs_scope );
1915
1916         xf.f_or = op->oq_search.rs_filter;
1917         xf.f_choice = LDAP_FILTER_OR;
1918         xf.f_next = NULL;
1919
1920         /* If the user's filter uses objectClass=*,
1921          * these clauses are redundant.
1922          */
1923         if (!oc_filter(op->oq_search.rs_filter, 1, &depth)
1924                 && !get_subentries_visibility(op)
1925                 && !is_sync_protocol(op) )
1926         {
1927                 if( !get_manageDSAit(op) && !get_domainScope(op) ) {
1928                         /* match referral objects */
1929                         struct berval bv_ref = BER_BVC( "referral" );
1930                         rf.f_choice = LDAP_FILTER_EQUALITY;
1931                         rf.f_ava = &aa_ref;
1932                         rf.f_av_desc = slap_schema.si_ad_objectClass;
1933                         rf.f_av_value = bv_ref;
1934                         rf.f_next = xf.f_or;
1935                         xf.f_or = &rf;
1936                         depth++;
1937                 }
1938         }
1939
1940         f.f_next = NULL;
1941         f.f_choice = LDAP_FILTER_AND;
1942         f.f_and = &nf;
1943         /* Dummy; we compute scope separately now */
1944         nf.f_choice = SLAPD_FILTER_COMPUTED;
1945         nf.f_result = LDAP_SUCCESS;
1946         nf.f_next = ( xf.f_or == op->oq_search.rs_filter )
1947                 ? op->oq_search.rs_filter : &xf ;
1948         /* Filter depth increased again, adding dummy clause */
1949         depth++;
1950
1951 #ifdef BDB_SUBENTRIES
1952         if( get_subentries_visibility( op ) ) {
1953                 struct berval bv_subentry = BER_BVC( "subentry" );
1954                 sf.f_choice = LDAP_FILTER_EQUALITY;
1955                 sf.f_ava = &aa_subentry;
1956                 sf.f_av_desc = slap_schema.si_ad_objectClass;
1957                 sf.f_av_value = bv_subentry;
1958                 sf.f_next = nf.f_next;
1959                 nf.f_next = &sf;
1960         }
1961 #endif
1962
1963         /* Allocate IDL stack, plus 1 more for former tmp */
1964         if ( depth+1 > bdb->bi_search_stack_depth ) {
1965                 stack = ch_malloc( (depth + 1) * BDB_IDL_UM_SIZE * sizeof( ID ) );
1966         } else {
1967                 stack = search_stack( stackop );
1968         }
1969
1970         if( op->ors_deref & LDAP_DEREF_SEARCHING ) {
1971                 rc = search_aliases( op, rs, e, locker, ids, scopes, stack );
1972         } else {
1973                 rc = bdb_dn2idl( op, e, ids, stack );
1974         }
1975
1976         if ( rc == LDAP_SUCCESS ) {
1977                 rc = bdb_filter_candidates( op, &f, ids,
1978                         stack, stack+BDB_IDL_UM_SIZE );
1979         }
1980
1981         if ( depth+1 > bdb->bi_search_stack_depth ) {
1982                 ch_free( stack );
1983         }
1984
1985         if( rc ) {
1986                 Debug(LDAP_DEBUG_TRACE,
1987                         "bdb_search_candidates: failed (rc=%d)\n",
1988                         rc, NULL, NULL );
1989
1990         } else {
1991                 Debug(LDAP_DEBUG_TRACE,
1992                         "bdb_search_candidates: id=%ld first=%ld last=%ld\n",
1993                         (long) ids[0],
1994                         (long) BDB_IDL_FIRST(ids),
1995                         (long) BDB_IDL_LAST(ids) );
1996         }
1997
1998         return rc;
1999 }
2000
2001 static int
2002 parse_paged_cookie( Operation *op, SlapReply *rs )
2003 {
2004         LDAPControl     **c;
2005         int             rc = LDAP_SUCCESS;
2006         ber_tag_t       tag;
2007         ber_int_t       size;
2008         BerElement      *ber;
2009         struct berval   cookie = BER_BVNULL;
2010
2011         /* this function must be invoked only if the pagedResults
2012          * control has been detected, parsed and partially checked
2013          * by the frontend */
2014         assert( get_pagedresults( op ) > SLAP_NO_CONTROL );
2015
2016         /* look for the appropriate ctrl structure */
2017         for ( c = op->o_ctrls; c[0] != NULL; c++ ) {
2018                 if ( strcmp( c[0]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 )
2019                 {
2020                         break;
2021                 }
2022         }
2023
2024         if ( c[0] == NULL ) {
2025                 rs->sr_text = "missing pagedResults control";
2026                 return LDAP_PROTOCOL_ERROR;
2027         }
2028
2029         /* Tested by frontend */
2030         assert( c[0]->ldctl_value.bv_len > 0 );
2031
2032         /* Parse the control value
2033          *      realSearchControlValue ::= SEQUENCE {
2034          *              size    INTEGER (0..maxInt),
2035          *                              -- requested page size from client
2036          *                              -- result set size estimate from server
2037          *              cookie  OCTET STRING
2038          * }
2039          */
2040         ber = ber_init( &c[0]->ldctl_value );
2041         if ( ber == NULL ) {
2042                 rs->sr_text = "internal error";
2043                 return LDAP_OTHER;
2044         }
2045
2046         tag = ber_scanf( ber, "{im}", &size, &cookie );
2047
2048         /* Tested by frontend */
2049         assert( tag != LBER_ERROR );
2050         assert( size >= 0 );
2051
2052         /* cookie decoding/checks deferred to backend... */
2053         if ( cookie.bv_len ) {
2054                 PagedResultsCookie reqcookie;
2055                 if( cookie.bv_len != sizeof( reqcookie ) ) {
2056                         /* bad cookie */
2057                         rs->sr_text = "paged results cookie is invalid";
2058                         rc = LDAP_PROTOCOL_ERROR;
2059                         goto done;
2060                 }
2061
2062                 AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie ));
2063
2064                 if ( reqcookie > op->o_pagedresults_state.ps_cookie ) {
2065                         /* bad cookie */
2066                         rs->sr_text = "paged results cookie is invalid";
2067                         rc = LDAP_PROTOCOL_ERROR;
2068                         goto done;
2069
2070                 } else if ( reqcookie < op->o_pagedresults_state.ps_cookie ) {
2071                         rs->sr_text = "paged results cookie is invalid or old";
2072                         rc = LDAP_UNWILLING_TO_PERFORM;
2073                         goto done;
2074                 }
2075
2076         } else {
2077                 /* Initial request.  Initialize state. */
2078 #if 0
2079                 if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) {
2080                         /* There's another pagedResults control on the
2081                          * same connection; reject new pagedResults controls 
2082                          * (allowed by RFC2696) */
2083                         rs->sr_text = "paged results cookie unavailable; try later";
2084                         rc = LDAP_UNWILLING_TO_PERFORM;
2085                         goto done;
2086                 }
2087 #endif
2088                 op->o_pagedresults_state.ps_cookie = 0;
2089                 op->o_pagedresults_state.ps_count = 0;
2090         }
2091
2092 done:;
2093         (void)ber_free( ber, 1 );
2094
2095         return rc;
2096 }
2097
2098 static void
2099 send_paged_response( 
2100         Operation       *op,
2101         SlapReply       *rs,
2102         ID              *lastid,
2103         int             tentries )
2104 {
2105         LDAPControl     ctrl, *ctrls[2];
2106         BerElementBuffer berbuf;
2107         BerElement      *ber = (BerElement *)&berbuf;
2108         PagedResultsCookie respcookie;
2109         struct berval cookie;
2110
2111         Debug(LDAP_DEBUG_ARGS,
2112                 "send_paged_response: lastid=0x%08lx nentries=%d\n", 
2113                 lastid ? *lastid : 0, rs->sr_nentries, NULL );
2114
2115         BER_BVZERO( &ctrl.ldctl_value );
2116         ctrls[0] = &ctrl;
2117         ctrls[1] = NULL;
2118
2119         ber_init2( ber, NULL, LBER_USE_DER );
2120
2121         if ( lastid ) {
2122                 respcookie = ( PagedResultsCookie )(*lastid);
2123                 cookie.bv_len = sizeof( respcookie );
2124                 cookie.bv_val = (char *)&respcookie;
2125
2126         } else {
2127                 respcookie = ( PagedResultsCookie )0;
2128                 BER_BVSTR( &cookie, "" );
2129         }
2130
2131         op->o_conn->c_pagedresults_state.ps_cookie = respcookie;
2132         op->o_conn->c_pagedresults_state.ps_count =
2133                 op->o_pagedresults_state.ps_count + rs->sr_nentries;
2134
2135         /* return size of 0 -- no estimate */
2136         ber_printf( ber, "{iO}", 0, &cookie ); 
2137
2138         if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) {
2139                 goto done;
2140         }
2141
2142         ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
2143         ctrls[0]->ldctl_iscritical = 0;
2144
2145         rs->sr_ctrls = ctrls;
2146         rs->sr_err = LDAP_SUCCESS;
2147         send_ldap_result( op, rs );
2148         rs->sr_ctrls = NULL;
2149
2150 done:
2151         (void) ber_free_buf( ber );
2152 }
2153
2154 static int
2155 bdb_pfid_cmp( const void *v_id1, const void *v_id2 )
2156 {
2157     const ID *p1 = v_id1, *p2 = v_id2;
2158         return *p1 - *p2;
2159 }
2160
2161 static ID*
2162 bdb_id_dup( Operation *op, ID *id )
2163 {
2164         ID *new;
2165         new = ch_malloc( sizeof(ID) );
2166         *new = *id;
2167         return new;
2168 }