]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/search.c
5fc72c5818c302a377ac7d0daeabfb1f450971d6
[openldap] / servers / slapd / back-bdb / search.c
1 /* search.c - search operation */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12
13 #include "back-bdb.h"
14 #include "idl.h"
15 #include "external.h"
16
17 static int base_candidate(
18         BackendDB       *be,
19         Entry   *e,
20         ID              *ids );
21 static int search_candidates(
22         Operation *stackop,     /* op with the current threadctx/slab cache */
23         Operation *sop,         /* search op */
24         SlapReply *rs,
25         Entry *e,
26         u_int32_t locker,
27         ID      *ids,
28         ID      *scopes );
29 static void send_pagerequest_response( 
30         Operation *op,
31         SlapReply *rs,
32         ID  lastid,
33         int tentries );
34
35 /* Dereference aliases for a single alias entry. Return the final
36  * dereferenced entry on success, NULL on any failure.
37  */
38 static Entry * deref_base (
39         Operation *op,
40         SlapReply *rs,
41         Entry *e,
42         Entry **matched,
43         u_int32_t locker,
44         DB_LOCK *lock,
45         ID      *tmp,
46         ID      *visited )
47 {
48         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
49         struct berval ndn;
50         EntryInfo *ei;
51         DB_LOCK lockr;
52
53         rs->sr_err = LDAP_ALIAS_DEREF_PROBLEM;
54         rs->sr_text = "maximum deref depth exceeded";
55
56         while (BDB_IDL_N(tmp) < op->o_bd->be_max_deref_depth) {
57
58                 /* Remember the last entry we looked at, so we can
59                  * report broken links
60                  */
61                 *matched = e;
62
63                 /* If this is part of a subtree or onelevel search,
64                  * have we seen this ID before? If so, quit.
65                  */
66                 if ( visited && bdb_idl_insert( visited, e->e_id ) ) {
67                         e = NULL;
68                         break;
69                 }
70
71                 /* If we've seen this ID during this deref iteration,
72                  * we've hit a loop.
73                  */
74                 if ( bdb_idl_insert( tmp, e->e_id ) ) {
75                         rs->sr_err = LDAP_ALIAS_PROBLEM;
76                         rs->sr_text = "circular alias";
77                         e = NULL;
78                         break;
79                 }
80
81                 /* If there was a problem getting the aliasedObjectName,
82                  * get_alias_dn will have set the error status.
83                  */
84                 if ( get_alias_dn(e, &ndn, &rs->sr_err, &rs->sr_text) ) {
85                         e = NULL;
86                         break;
87                 }
88
89                 rs->sr_err = bdb_dn2entry( op, NULL, &ndn, &ei,
90                         0, locker, &lockr );
91
92                 if ( ei ) e = ei->bei_e;
93                 else    e = NULL;
94
95                 if (!e) {
96                         rs->sr_err = LDAP_ALIAS_PROBLEM;
97                         rs->sr_text = "aliasedObject not found";
98                         break;
99                 }
100
101                 /* Free the previous entry, continue to work with the
102                  * one we just retrieved.
103                  */
104                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache,
105                         *matched, lock);
106                 *lock = lockr;
107
108                 /* We found a regular entry. Return this to the caller. The
109                  * entry is still locked for Read.
110                  */
111                 if (!is_entry_alias(e)) {
112                         rs->sr_err = LDAP_SUCCESS;
113                         rs->sr_text = NULL;
114                         break;
115                 }
116         }
117         return e;
118 }
119
120 /* Look for and dereference all aliases within the search scope. Adds
121  * the dereferenced entries to the "ids" list. Requires "stack" to be
122  * able to hold 8 levels of DB_SIZE IDLs. Of course we're hardcoded to
123  * require a minimum of 8 UM_SIZE IDLs so this is never a problem.
124  */
125 static int search_aliases(
126         Operation *op,
127         SlapReply *rs,
128         Entry *e,
129         u_int32_t locker,
130         ID *ids,
131         ID *scopes,
132         ID *stack
133 )
134 {
135         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
136         ID *aliases, *curscop, *subscop, *visited, *newsubs, *oldsubs, *tmp;
137         ID cursora, ida, cursoro, ido, *subscop2;
138         Entry *matched, *a;
139         EntryInfo *ei;
140         struct berval bv_alias = { sizeof("alias")-1, "alias" };
141         AttributeAssertion aa_alias;
142         Filter  af;
143         DB_LOCK locka, lockr;
144         int first = 1;
145
146         aliases = stack;        /* IDL of all aliases in the database */
147         curscop = aliases + BDB_IDL_DB_SIZE;    /* Aliases in the current scope */
148         subscop = curscop + BDB_IDL_DB_SIZE;    /* The current scope */
149         visited = subscop + BDB_IDL_DB_SIZE;    /* IDs we've seen in this search */
150         newsubs = visited + BDB_IDL_DB_SIZE;    /* New subtrees we've added */
151         oldsubs = newsubs + BDB_IDL_DB_SIZE;    /* Subtrees added previously */
152         tmp = oldsubs + BDB_IDL_DB_SIZE;        /* Scratch space for deref_base() */
153
154         /* A copy of subscop, because subscop gets clobbered by
155          * the bdb_idl_union/intersection routines
156          */
157         subscop2 = tmp + BDB_IDL_DB_SIZE;
158
159         af.f_choice = LDAP_FILTER_EQUALITY;
160         af.f_ava = &aa_alias;
161         af.f_av_desc = slap_schema.si_ad_objectClass;
162         af.f_av_value = bv_alias;
163         af.f_next = NULL;
164
165         /* Find all aliases in database */
166         BDB_IDL_ZERO( aliases );
167         rs->sr_err = bdb_filter_candidates( op, &af, aliases,
168                 curscop, visited );
169         if (rs->sr_err != LDAP_SUCCESS) {
170                 return rs->sr_err;
171         }
172         oldsubs[0] = 1;
173         oldsubs[1] = e->e_id;
174
175         BDB_IDL_ZERO( ids );
176         BDB_IDL_ZERO( visited );
177         BDB_IDL_ZERO( newsubs );
178
179         cursoro = 0;
180         ido = bdb_idl_first( oldsubs, &cursoro );
181
182         for (;;) {
183                 /* Set curscop to only the aliases in the current scope. Start with
184                  * all the aliases, obtain the IDL for the current scope, and then
185                  * get the intersection of these two IDLs. Add the current scope
186                  * to the cumulative list of candidates.
187                  */
188                 BDB_IDL_CPY( curscop, aliases );
189                 rs->sr_err = bdb_dn2idl( op, e, subscop,
190                                         subscop2+BDB_IDL_DB_SIZE );
191                 if (first) {
192                         first = 0;
193                 } else {
194                         bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, e, &locka);
195                 }
196                 BDB_IDL_CPY(subscop2, subscop);
197                 rs->sr_err = bdb_idl_intersection(curscop, subscop);
198                 bdb_idl_union( ids, subscop2 );
199
200                 /* Dereference all of the aliases in the current scope. */
201                 cursora = 0;
202                 for (ida = bdb_idl_first(curscop, &cursora); ida != NOID;
203                         ida = bdb_idl_next(curscop, &cursora))
204                 {
205                         ei = NULL;
206                         rs->sr_err = bdb_cache_find_id(op, NULL,
207                                 ida, &ei, 0, locker, &lockr );
208                         if (rs->sr_err != LDAP_SUCCESS) {
209                                 continue;
210                         }
211                         a = ei->bei_e;
212
213                         /* This should only happen if the curscop IDL has maxed out and
214                          * turned into a range that spans IDs indiscriminately
215                          */
216                         if (!is_entry_alias(a)) {
217                                 bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache,
218                                         a, &lockr);
219                                 continue;
220                         }
221
222                         /* Actually dereference the alias */
223                         BDB_IDL_ZERO(tmp);
224                         a = deref_base( op, rs, a, &matched, locker, &lockr,
225                                 tmp, visited );
226                         if (a) {
227                                 /* If the target was not already in our current candidates,
228                                  * make note of it in the newsubs list. Also
229                                  * set it in the scopes list so that bdb_search
230                                  * can check it.
231                                  */
232                                 if (bdb_idl_insert(ids, a->e_id) == 0) {
233                                         bdb_idl_insert(newsubs, a->e_id);
234                                         bdb_idl_insert(scopes, a->e_id);
235                                 }
236                                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache,
237                                         a, &lockr);
238
239                         } else if (matched) {
240                                 /* Alias could not be dereferenced, or it deref'd to
241                                  * an ID we've already seen. Ignore it.
242                                  */
243                                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache,
244                                         matched, &lockr );
245                                 rs->sr_text = NULL;
246                         }
247                 }
248                 /* If this is a OneLevel search, we're done; oldsubs only had one
249                  * ID in it. For a Subtree search, oldsubs may be a list of scope IDs.
250                  */
251                 if (op->ors_scope != LDAP_SCOPE_SUBTREE) break;
252 nextido:
253                 ido = bdb_idl_next( oldsubs, &cursoro );
254                 
255                 /* If we're done processing the old scopes, did we add any new
256                  * scopes in this iteration? If so, go back and do those now.
257                  */
258                 if (ido == NOID) {
259                         if (BDB_IDL_IS_ZERO(newsubs)) break;
260                         BDB_IDL_CPY(oldsubs, newsubs);
261                         BDB_IDL_ZERO(newsubs);
262                         cursoro = 0;
263                         ido = bdb_idl_first( oldsubs, &cursoro );
264                 }
265
266                 /* Find the entry corresponding to the next scope. If it can't
267                  * be found, ignore it and move on. This should never happen;
268                  * we should never see the ID of an entry that doesn't exist.
269                  * Set the name so that the scope's IDL can be retrieved.
270                  */
271                 ei = NULL;
272                 rs->sr_err = bdb_cache_find_id(op, NULL, ido, &ei,
273                         0, locker, &locka );
274                 if (rs->sr_err != LDAP_SUCCESS) goto nextido;
275                 e = ei->bei_e;
276         }
277         return rs->sr_err;
278 }
279
280 static
281 int is_sync_protocol( Operation *op )
282 {
283         if ( op->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST )
284                 return 1;
285         return 0;
286 }
287         
288 #define IS_BDB_REPLACE(type) (( type == LDAP_PSEARCH_BY_DELETE ) || \
289         ( type == LDAP_PSEARCH_BY_SCOPEOUT ))
290 #define IS_PSEARCH (op != sop)
291
292 int
293 bdb_abandon( Operation *op, SlapReply *rs )
294 {
295         Operation       *ps_list;
296         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
297
298         LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
299                 if ( ps_list->o_connid == op->o_connid ) {
300                         if ( ps_list->o_msgid == op->oq_abandon.rs_msgid ) {
301                                 ps_list->o_abandon = 1;
302                                 LDAP_LIST_REMOVE( ps_list, o_ps_link );
303                                 slap_op_free ( ps_list );
304                                 return LDAP_SUCCESS;
305                         }
306                 }
307         }
308         return LDAP_UNAVAILABLE;
309 }
310
311 int
312 bdb_cancel( Operation *op, SlapReply *rs )
313 {
314         Operation       *ps_list;
315         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
316
317         LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
318                 if ( ps_list->o_connid == op->o_connid ) {
319                         if ( ps_list->o_msgid == op->oq_cancel.rs_msgid ) {
320                                 ps_list->o_cancel = SLAP_CANCEL_DONE;
321                                 LDAP_LIST_REMOVE( ps_list, o_ps_link );
322
323 #if 0
324                                 bdb_build_sync_done_ctrl( conn, ps_list, ps_list->ctrls,
325                                         1, &latest_entrycsn_bv );
326                                 send_ldap_result( conn, ps_list, LDAP_CANCELLED,
327                                         NULL, NULL, NULL, ps_list->ctrls, ps_list->nentries);
328 #endif
329                                 rs->sr_err = LDAP_CANCELLED;
330                                 send_ldap_result( ps_list, rs );
331
332                                 if ( ps_list->o_tmpmemctx ) {
333                                         sl_mem_destroy( NULL, ps_list->o_tmpmemctx );
334                                 }
335
336                                 slap_op_free ( ps_list );
337                                 return LDAP_SUCCESS;
338                         }
339                 }
340         }
341         return LDAP_UNAVAILABLE;
342 }
343
344 int bdb_search( Operation *op, SlapReply *rs )
345 {
346         return bdb_do_search( op, rs, op, NULL, 0 );
347 }
348
349 /* For persistent searches, op is the currently executing operation,
350  * sop is the persistent search. For regular searches, sop = op.
351  */
352 int
353 bdb_do_search( Operation *op, SlapReply *rs, Operation *sop,
354         Entry *ps_e, int ps_type )
355 {
356         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
357         time_t          stoptime;
358         ID              id, cursor;
359         ID              candidates[BDB_IDL_UM_SIZE];
360         ID              scopes[BDB_IDL_DB_SIZE];
361         Entry           *e = NULL, base;
362         Entry   *matched = NULL;
363         EntryInfo       *ei;
364         struct berval   realbase = { 0, NULL };
365         int             manageDSAit;
366         int             tentries = 0;
367         ID              lastid = NOID;
368         AttributeName   *attrs;
369
370         Filter          contextcsnand, contextcsnle, cookief, csnfnot, csnfeq, csnfand, csnfge;
371         Filter          omitcsnf, omitcsnfle;
372         AttributeAssertion aa_ge, aa_eq, aa_le;
373         int             entry_count = 0;
374         struct berval *search_context_csn = NULL;
375         struct berval ctxcsn_rdn = { 0, NULL };
376         struct berval ctxcsn_ndn = { 0, NULL };
377         EntryInfo       *ctxcsn_ei;
378         Entry           *ctxcsn_e;
379         DB_LOCK         ctxcsn_lock;
380         Attribute       *csn_a;
381 #if 0
382         struct berval   entrycsn_bv = { 0, NULL };
383 #endif
384         LDAPControl     *ctrls[SLAP_SEARCH_MAX_CTRLS];
385         int             num_ctrls = 0;
386         AttributeName   uuid_attr[2];
387         int             rc_sync = 0;
388         int             entry_sync_state = -1;
389         AttributeName   null_attr;
390         int             no_sync_state_change = 0;
391         struct slap_limits_set *limit = NULL;
392         int isroot = 0;
393
394         u_int32_t       locker = 0;
395         DB_LOCK         lock;
396
397 #ifdef NEW_LOGGING
398         LDAP_LOG( OPERATION, ENTRY, "bdb_back_search\n", 0, 0, 0 );
399 #else
400         Debug( LDAP_DEBUG_TRACE, "=> bdb_back_search\n",
401                 0, 0, 0);
402 #endif
403         attrs = sop->oq_search.rs_attrs;
404
405         /* psearch needs to be registered before refresh begins */
406         /* psearch and refresh transmission is serialized in send_ldap_ber() */
407         if ( !IS_PSEARCH && sop->o_sync_mode & SLAP_SYNC_PERSIST ) {
408                 LDAP_LIST_INSERT_HEAD( &bdb->bi_psearch_list, sop, o_ps_link );
409         }
410         null_attr.an_desc = NULL;
411         null_attr.an_oc = NULL;
412         null_attr.an_name.bv_len = 0;
413         null_attr.an_name.bv_val = NULL;
414
415         for ( num_ctrls = 0; num_ctrls < SLAP_SEARCH_MAX_CTRLS; num_ctrls++ ) {
416                 ctrls[num_ctrls] = NULL;
417         }
418         num_ctrls = 0;
419
420         if ( IS_PSEARCH && IS_BDB_REPLACE(ps_type)) {
421                 attrs = uuid_attr;
422                 attrs[0].an_desc = NULL;
423                 attrs[0].an_oc = NULL;
424                 attrs[0].an_name.bv_len = 0;
425                 attrs[0].an_name.bv_val = NULL;
426         }
427
428         manageDSAit = get_manageDSAit( sop );
429
430         /* Sync control overrides manageDSAit */
431
432         if ( !IS_PSEARCH && sop->o_sync_mode & SLAP_SYNC_REFRESH ) {
433                 if ( manageDSAit == SLAP_NO_CONTROL )
434                         manageDSAit = SLAP_CRITICAL_CONTROL;
435         } else if ( IS_PSEARCH ) {
436                 if ( manageDSAit == SLAP_NO_CONTROL )
437                         manageDSAit = SLAP_CRITICAL_CONTROL;
438         }
439
440         rs->sr_err = LOCK_ID (bdb->bi_dbenv, &locker );
441
442         switch(rs->sr_err) {
443         case 0:
444                 break;
445         default:
446                 send_ldap_error( sop, rs, LDAP_OTHER, "internal error" );
447                 return rs->sr_err;
448         }
449
450         if ( sop->o_req_ndn.bv_len == 0 ) {
451                 /* DIT root special case */
452                 e = (Entry *) &slap_entry_root;
453                 rs->sr_err = 0;
454         } else {
455 dn2entry_retry:
456                 /* get entry with reader lock */
457                 rs->sr_err = bdb_dn2entry( op, NULL, &sop->o_req_ndn, &ei,
458                         1, locker, &lock );
459         }
460
461         switch(rs->sr_err) {
462         case DB_NOTFOUND:
463                 matched = ei->bei_e; break;
464         case 0:
465                 e = ei->bei_e; break;
466         case LDAP_BUSY:
467                 send_ldap_error( sop, rs, LDAP_BUSY, "ldap server busy" );
468                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
469                 return LDAP_BUSY;
470         case DB_LOCK_DEADLOCK:
471         case DB_LOCK_NOTGRANTED:
472                 goto dn2entry_retry;
473         default:
474                 send_ldap_error( sop, rs, LDAP_OTHER, "internal error" );
475                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
476                 return rs->sr_err;
477         }
478
479         if ( e && (op->ors_deref & LDAP_DEREF_FINDING) && is_entry_alias(e) ) {
480                 BDB_IDL_ZERO(candidates);
481                 e = deref_base( op, rs, e, &matched, locker, &lock,
482                         candidates, NULL );
483         }
484
485         if ( e == NULL ) {
486                 struct berval matched_dn = { 0, NULL };
487
488                 if ( matched != NULL ) {
489                         BerVarray erefs;
490                         ber_dupbv( &matched_dn, &matched->e_name );
491
492                         erefs = is_entry_referral( matched )
493                                 ? get_entry_referrals( op, matched )
494                                 : NULL;
495
496                         bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache,
497                                 matched, &lock);
498                         matched = NULL;
499
500                         if( erefs ) {
501                                 rs->sr_ref = referral_rewrite( erefs, &matched_dn,
502                                         &sop->o_req_dn, sop->oq_search.rs_scope );
503                                 ber_bvarray_free( erefs );
504                         }
505
506                 } else {
507                         rs->sr_ref = referral_rewrite( default_referral,
508                                 NULL, &sop->o_req_dn, sop->oq_search.rs_scope );
509                 }
510
511                 rs->sr_err=LDAP_REFERRAL;
512                 rs->sr_matched = matched_dn.bv_val;
513                 send_ldap_result( sop, rs );
514
515                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
516                 if ( rs->sr_ref ) {
517                         ber_bvarray_free( rs->sr_ref );
518                         rs->sr_ref = NULL;
519                 }
520                 if ( matched_dn.bv_val ) {
521                         ber_memfree( matched_dn.bv_val );
522                         rs->sr_matched = NULL;
523                 }
524                 return rs->sr_err;
525         }
526
527         if (!manageDSAit && e != &slap_entry_root && is_entry_referral( e ) ) {
528                 /* entry is a referral, don't allow add */
529                 struct berval matched_dn;
530                 BerVarray erefs;
531                 
532                 ber_dupbv( &matched_dn, &e->e_name );
533                 erefs = get_entry_referrals( op, e );
534
535                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
536                 e = NULL;
537
538                 if( erefs ) {
539                         rs->sr_ref = referral_rewrite( erefs, &matched_dn,
540                                 &sop->o_req_dn, sop->oq_search.rs_scope );
541                         ber_bvarray_free( erefs );
542                 }
543
544 #ifdef NEW_LOGGING
545                 LDAP_LOG ( OPERATION, RESULTS, 
546                         "bdb_search: entry is referral\n", 0, 0, 0 );
547 #else
548                 Debug( LDAP_DEBUG_TRACE, "bdb_search: entry is referral\n",
549                         0, 0, 0 );
550 #endif
551
552                 if (!rs->sr_ref) rs->sr_text = "bad_referral object";
553                 rs->sr_err = LDAP_REFERRAL;
554                 rs->sr_matched = matched_dn.bv_val;
555                 send_ldap_result( sop, rs );
556
557                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
558                 ber_bvarray_free( rs->sr_ref );
559                 rs->sr_ref = NULL;
560                 ber_memfree( matched_dn.bv_val );
561                 rs->sr_matched = NULL;
562                 return 1;
563         }
564
565         if ( get_assert( op ) &&
566                 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
567         {
568                 rs->sr_err = LDAP_ASSERTION_FAILED;
569                 send_ldap_result( sop, rs );
570                 return 1;
571         }
572
573         /* if not root, get appropriate limits */
574         if ( be_isroot( op->o_bd, &sop->o_ndn ) ) {
575                 isroot = 1;
576         } else {
577                 ( void ) get_limits( op->o_bd, &sop->o_ndn, &limit );
578         }
579
580         /* The time/size limits come first because they require very little
581          * effort, so there's no chance the candidates are selected and then 
582          * the request is not honored only because of time/size constraints */
583
584         /* if no time limit requested, use soft limit (unless root!) */
585         if ( isroot ) {
586                 if ( sop->oq_search.rs_tlimit == 0 ) {
587                         sop->oq_search.rs_tlimit = -1;  /* allow root to set no limit */
588                 }
589
590                 if ( sop->oq_search.rs_slimit == 0 ) {
591                         sop->oq_search.rs_slimit = -1;
592                 }
593
594         } else {
595                 /* if no limit is required, use soft limit */
596                 if ( sop->oq_search.rs_tlimit <= 0 ) {
597                         sop->oq_search.rs_tlimit = limit->lms_t_soft;
598
599                 /* if requested limit higher than hard limit, abort */
600                 } else if ( sop->oq_search.rs_tlimit > limit->lms_t_hard ) {
601                         /* no hard limit means use soft instead */
602                         if ( limit->lms_t_hard == 0
603                                         && limit->lms_t_soft > -1
604                                         && sop->oq_search.rs_tlimit > limit->lms_t_soft ) {
605                                 sop->oq_search.rs_tlimit = limit->lms_t_soft;
606
607                         /* positive hard limit means abort */
608                         } else if ( limit->lms_t_hard > 0 ) {
609                                 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
610                                 send_ldap_result( sop, rs );
611                                 rs->sr_err = 0;
612                                 goto done;
613                         }
614                 
615                         /* negative hard limit means no limit */
616                 }
617                 
618                 /* if no limit is required, use soft limit */
619                 if ( sop->oq_search.rs_slimit <= 0 ) {
620                         if ( get_pagedresults(sop) && limit->lms_s_pr != 0 ) {
621                                 sop->oq_search.rs_slimit = limit->lms_s_pr;
622                         } else {
623                                 sop->oq_search.rs_slimit = limit->lms_s_soft;
624                         }
625
626                 /* if requested limit higher than hard limit, abort */
627                 } else if ( sop->oq_search.rs_slimit > limit->lms_s_hard ) {
628                         /* no hard limit means use soft instead */
629                         if ( limit->lms_s_hard == 0
630                                         && limit->lms_s_soft > -1
631                                         && sop->oq_search.rs_slimit > limit->lms_s_soft ) {
632                                 sop->oq_search.rs_slimit = limit->lms_s_soft;
633
634                         /* positive hard limit means abort */
635                         } else if ( limit->lms_s_hard > 0 ) {
636                                 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
637                                 send_ldap_result( sop, rs );
638                                 rs->sr_err = 0; 
639                                 goto done;
640                         }
641                         
642                         /* negative hard limit means no limit */
643                 }
644         }
645
646         /* compute it anyway; root does not use it */
647         stoptime = op->o_time + sop->oq_search.rs_tlimit;
648
649         /* need normalized dn below */
650         ber_dupbv( &realbase, &e->e_nname );
651
652         /* Copy info to base, must free entry before accessing the database
653          * in search_candidates, to avoid deadlocks.
654          */
655         base.e_private = e->e_private;
656         base.e_nname = realbase;
657         base.e_id = e->e_id;
658
659         if ( e != &slap_entry_root ) {
660                 bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
661         }
662         e = NULL;
663
664         if ( sop->o_sync_mode != SLAP_SYNC_NONE ) {
665                 if ( sop->o_bd->syncinfo ) {
666                         char substr[67];
667                         sprintf( substr, "cn=syncrepl%d", sop->o_bd->syncinfo->id );
668                         ber_str2bv( substr, strlen( substr ), 0, &ctxcsn_rdn );
669                         build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], &ctxcsn_rdn );
670                 } else {
671                         ber_str2bv( "cn=ldapsync", strlen("cn=ldapsync"), 0, &ctxcsn_rdn );
672                         build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], &ctxcsn_rdn );
673                 }
674
675 ctxcsn_retry :
676                 rs->sr_err = bdb_dn2entry( op, NULL, &ctxcsn_ndn, &ctxcsn_ei, 0, locker, &ctxcsn_lock );
677
678                 switch(rs->sr_err) {
679                 case 0:
680                         e = ei->bei_e; break;
681                 case LDAP_BUSY:
682                         send_ldap_error( sop, rs, LDAP_BUSY, "ldap server busy" );
683                         LOCK_ID_FREE (bdb->bi_dbenv, locker );
684                         return LDAP_BUSY;
685                 case DB_LOCK_DEADLOCK:
686                 case DB_LOCK_NOTGRANTED:
687                         goto ctxcsn_retry;
688                 case DB_NOTFOUND:
689                         send_ldap_error( sop, rs, LDAP_OTHER, "context csn entry not present" );
690                         LOCK_ID_FREE( bdb->bi_dbenv, locker );
691                         return rs->sr_err;
692                 default:
693                         send_ldap_error( sop, rs, LDAP_OTHER, "internal error" );
694                         LOCK_ID_FREE (bdb->bi_dbenv, locker );
695                         return rs->sr_err;
696                 }
697
698                 if ( ctxcsn_ei ) {
699                         ctxcsn_e = ctxcsn_ei->bei_e;
700                 }
701
702                 if ( ctxcsn_e ) {
703                         if ( sop->o_bd->syncinfo ) {
704                                 csn_a = attr_find( ctxcsn_e->e_attrs, slap_schema.si_ad_syncreplCookie );
705                         } else {
706                                 csn_a = attr_find( ctxcsn_e->e_attrs, slap_schema.si_ad_contextCSN );
707                         }
708                         if ( csn_a ) {
709                                 search_context_csn = ber_dupbv( NULL, &csn_a->a_vals[0] );
710                         } else {
711                                 search_context_csn = NULL;
712                         }
713                 } else {
714                         search_context_csn = NULL;
715                 }
716         }
717
718         /* select candidates */
719         if ( sop->oq_search.rs_scope == LDAP_SCOPE_BASE ) {
720                 rs->sr_err = base_candidate( op->o_bd, &base, candidates );
721
722         } else {
723                 BDB_IDL_ZERO( candidates );
724                 BDB_IDL_ZERO( scopes );
725                 rs->sr_err = search_candidates( op, sop, rs, &base, locker, candidates, scopes );
726         }
727
728         if ( sop->o_sync_mode != SLAP_SYNC_NONE ) {
729                 bdb_cache_entry_db_unlock( bdb->bi_dbenv, &ctxcsn_lock );
730         }
731
732         /* start cursor at beginning of candidates.
733          */
734         cursor = 0;
735         if (IS_PSEARCH) {
736                 if ( !BDB_IDL_IS_RANGE( candidates ) ) {
737                         cursor = bdb_idl_search( candidates, ps_e->e_id );
738                         if ( candidates[cursor] != ps_e->e_id ) {
739                                 rs->sr_err = LDAP_SUCCESS;
740                                 goto done;
741                         }
742                 } else {
743                         if ( ps_e->e_id < BDB_IDL_RANGE_FIRST(candidates)
744                            || ps_e->e_id > BDB_IDL_RANGE_LAST(candidates)){
745                                 rs->sr_err = LDAP_SUCCESS;
746                                 goto done;
747                         }
748                 }
749                 candidates[0] = 1;
750                 candidates[1] = ps_e->e_id;
751         }
752
753         if ( candidates[0] == 0 ) {
754 #ifdef NEW_LOGGING
755                 LDAP_LOG ( OPERATION, RESULTS,
756                         "bdb_search: no candidates\n", 0, 0, 0 );
757 #else
758                 Debug( LDAP_DEBUG_TRACE, "bdb_search: no candidates\n",
759                         0, 0, 0 );
760 #endif
761
762                 rs->sr_err = LDAP_SUCCESS;
763                 send_ldap_result( sop, rs );
764                 rs->sr_err = 1;
765                 goto done;
766         }
767
768         /* if not root and candidates exceed to-be-checked entries, abort */
769         if ( !isroot && limit->lms_s_unchecked != -1 ) {
770                 if ( BDB_IDL_N(candidates) > (unsigned) limit->lms_s_unchecked ) {
771                         rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
772                         send_ldap_result( sop, rs );
773                         rs->sr_err = 1;
774                         goto done;
775                 }
776         }
777
778         if ( isroot || !limit->lms_s_pr_hide ) {
779                 tentries = BDB_IDL_N(candidates);
780         }
781
782 #ifdef LDAP_CONTROL_PAGEDRESULTS
783         if ( get_pagedresults(sop) ) {
784                 if ( sop->o_pagedresults_state.ps_cookie == 0 ) {
785                         id = 0;
786                 } else {
787                         if ( sop->o_pagedresults_size == 0 ) {
788                                 rs->sr_err = LDAP_SUCCESS;
789                                 rs->sr_text = "search abandoned by pagedResult size=0";
790                                 send_ldap_result( sop, rs );
791                                 goto done;
792                         }
793                         for ( id = bdb_idl_first( candidates, &cursor );
794                                 id != NOID && id <= (ID)( sop->o_pagedresults_state.ps_cookie );
795                                 id = bdb_idl_next( candidates, &cursor ) );
796                 }
797                 if ( cursor == NOID ) {
798 #ifdef NEW_LOGGING
799                         LDAP_LOG ( OPERATION, RESULTS, 
800                                 "bdb_search: no paged results candidates\n", 
801                         0, 0, 0 );
802 #else
803                         Debug( LDAP_DEBUG_TRACE, 
804                                 "bdb_search: no paged results candidates\n",
805                                 0, 0, 0 );
806 #endif
807                         send_pagerequest_response( sop, rs, lastid, 0 );
808
809                         rs->sr_err = 1;
810                         goto done;
811                 }
812                 goto loop_begin;
813         }
814 #endif
815
816         if ( (sop->o_sync_mode & SLAP_SYNC_REFRESH) || IS_PSEARCH )
817         {
818                 MatchingRule    *mr;
819                 const char              *text;
820                 int                             match;
821
822                 cookief.f_choice = LDAP_FILTER_AND;
823                 cookief.f_and = &csnfnot;
824                 cookief.f_next = NULL;
825
826                 csnfnot.f_choice = LDAP_FILTER_NOT;
827                 csnfnot.f_not = &csnfeq;
828                 csnfnot.f_next = &csnfand;
829
830                 csnfeq.f_choice = LDAP_FILTER_EQUALITY;
831                 csnfeq.f_ava = &aa_eq;
832                 csnfeq.f_av_desc = slap_schema.si_ad_entryCSN;
833                 csnfeq.f_av_value = sop->o_sync_state;
834
835                 csnfand.f_choice = LDAP_FILTER_AND;
836                 csnfand.f_and = &csnfge;
837                 csnfand.f_next = NULL;
838
839                 csnfge.f_choice = LDAP_FILTER_GE;
840                 csnfge.f_ava = &aa_ge;
841                 csnfge.f_av_desc = slap_schema.si_ad_entryCSN;
842                 csnfge.f_av_value = sop->o_sync_state;
843
844                 if ( search_context_csn && !IS_PSEARCH ) {
845                         csnfge.f_next = &contextcsnand;
846
847                         contextcsnand.f_choice = LDAP_FILTER_AND;
848                         contextcsnand.f_and = &contextcsnle;
849                         contextcsnand.f_next = NULL;
850         
851                         contextcsnle.f_choice = LDAP_FILTER_LE;
852                         contextcsnle.f_ava = &aa_le;
853                         contextcsnle.f_av_desc = slap_schema.si_ad_entryCSN;
854                         contextcsnle.f_av_value = *search_context_csn;
855                         contextcsnle.f_next = sop->oq_search.rs_filter;
856
857                         mr = slap_schema.si_ad_entryCSN->ad_type->sat_ordering;
858                         if ( sop->o_sync_state.bv_len != 0 ) {
859                                 value_match( &match, slap_schema.si_ad_entryCSN, mr,
860                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
861                                                         &sop->o_sync_state, search_context_csn, &text );
862                         } else {
863                                 match = -1;
864                         }
865                         no_sync_state_change = !match;
866                 } else {
867                         csnfge.f_next = sop->oq_search.rs_filter;
868                 }
869         }
870
871         for ( id = bdb_idl_first( candidates, &cursor );
872                 id != NOID;
873                 id = bdb_idl_next( candidates, &cursor ) )
874         {
875                 int             scopeok = 0;
876
877 loop_begin:
878                 /* check for abandon */
879                 if ( sop->o_abandon ) {
880                         rs->sr_err = 0;
881                         goto done;
882                 }
883
884 #ifdef LDAP_EXOP_X_CANCEL
885                 if ( sop->o_cancel ) {
886                         assert( sop->o_cancel == SLAP_CANCEL_REQ );
887                         rs->sr_err = LDAP_CANCELLED;
888                         send_ldap_result( sop, rs );
889                         sop->o_cancel = SLAP_CANCEL_ACK;
890                         rs->sr_err = 0;
891                         goto done;
892                 }
893 #endif
894
895                 /* check time limit */
896                 if ( sop->oq_search.rs_tlimit != -1 && slap_get_time() > stoptime ) {
897                         rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
898                         rs->sr_ref = rs->sr_v2ref;
899                         send_ldap_result( sop, rs );
900                         goto done;
901                 }
902
903
904                 if (!IS_PSEARCH) {
905 id2entry_retry:
906                         /* get the entry with reader lock */
907                         ei = NULL;
908                         rs->sr_err = bdb_cache_find_id( op, NULL,
909                                 id, &ei, 0, locker, &lock );
910
911                         if (rs->sr_err == LDAP_BUSY) {
912                                 rs->sr_text = "ldap server busy";
913                                 send_ldap_result( sop, rs );
914                                 goto done;
915
916                         } else if ( rs->sr_err == DB_LOCK_DEADLOCK
917                                 || rs->sr_err == DB_LOCK_NOTGRANTED )
918                         {
919                                 goto id2entry_retry;    
920                         }
921
922                         if ( ei && rs->sr_err == 0 ) {
923                                 e = ei->bei_e;
924                         } else {
925                                 e = NULL;
926                         }
927
928                         if ( e == NULL ) {
929                                 if( !BDB_IDL_IS_RANGE(candidates) ) {
930                                         /* only complain for non-range IDLs */
931 #ifdef NEW_LOGGING
932                                         LDAP_LOG ( OPERATION, RESULTS,
933                                                 "bdb_search: candidate %ld not found\n",
934                                                 (long) id, 0, 0);
935 #else
936                                         Debug( LDAP_DEBUG_TRACE,
937                                                 "bdb_search: candidate %ld not found\n",
938                                                 (long) id, 0, 0 );
939 #endif
940                                 }
941
942                                 goto loop_continue;
943                         }
944                 } else {
945                         e = ps_e;
946                 }
947
948                 rs->sr_entry = e;
949 #ifdef BDB_SUBENTRIES
950                 /* FIXME: send all but syncrepl
951                 if ( !is_sync_protocol( sop ) ) {
952                 */
953                         if ( is_entry_subentry( e ) ) {
954                                 if( sop->oq_search.rs_scope != LDAP_SCOPE_BASE ) {
955                                         if(!get_subentries_visibility( sop )) {
956                                                 /* only subentries are visible */
957                                                 goto loop_continue;
958                                         }
959
960                                 } else if ( get_subentries( sop ) &&
961                                         !get_subentries_visibility( sop ))
962                                 {
963                                         /* only subentries are visible */
964                                         goto loop_continue;
965                                 }
966
967                         } else if ( get_subentries_visibility( sop )) {
968                                 /* only subentries are visible */
969                                 goto loop_continue;
970                         }
971                 /*
972                 }
973                 */
974 #endif
975
976                 /* Does this candidate actually satisfy the search scope?
977                  *
978                  * Note that we don't lock access to the bei_parent pointer.
979                  * Since only leaf nodes can be deleted, the parent of any
980                  * node will always be a valid node. Also since we have
981                  * a Read lock on the data, it cannot be renamed out of the
982                  * scope while we are looking at it, and unless we're using
983                  * BDB_HIER, its parents cannot be moved either.
984                  */
985                 switch( sop->ors_scope ) {
986                 case LDAP_SCOPE_BASE:
987                         /* This is always true, yes? */
988                         if ( id == base.e_id )
989                                 scopeok = 1;
990                         break;
991                 case LDAP_SCOPE_ONELEVEL:
992                         if ( ei->bei_parent->bei_id == base.e_id )
993                                 scopeok = 1;
994                         break;
995                 case LDAP_SCOPE_SUBTREE:
996                         { EntryInfo *tmp;
997                         for ( tmp = BEI(e); tmp->bei_parent;
998                                 tmp = tmp->bei_parent ) {
999                                 if ( tmp->bei_id == base.e_id ) {
1000                                         scopeok = 1;
1001                                         break;
1002                                 }
1003                         } }
1004                         break;
1005                 }
1006
1007 #ifdef BDB_ALIASES
1008                 /* aliases were already dereferenced in candidate list */
1009                 if ( sop->ors_deref & LDAP_DEREF_SEARCHING ) {
1010                         /* but if the search base is an alias, and we didn't
1011                          * deref it when finding, return it.
1012                          */
1013                         if ( is_entry_alias(e) &&
1014                                 ((sop->ors_deref & LDAP_DEREF_FINDING)
1015                                   || !bvmatch(&e->e_nname, &op->o_req_ndn)))
1016                         {
1017                                 goto loop_continue;
1018                         }
1019
1020                         /* scopes is only non-empty for onelevel or subtree */
1021                         if ( !scopeok && BDB_IDL_N(scopes) ) {
1022                                 unsigned x;
1023                                 if ( sop->ors_scope == LDAP_SCOPE_ONELEVEL ) {
1024                                         x = bdb_idl_search( scopes,
1025                                                 e->e_id );
1026                                         if ( scopes[x] == e->e_id )
1027                                                 scopeok = 1;
1028                                 } else {
1029                                 /* subtree, walk up the tree */
1030                                         EntryInfo *tmp = BEI(e);
1031                                         for (;tmp->bei_parent;
1032                                                 tmp=tmp->bei_parent) {
1033                                                 x = bdb_idl_search(
1034                                                         scopes, tmp->bei_id );
1035                                                 if ( scopes[x] == tmp->bei_id ) {
1036                                                         scopeok = 1;
1037                                                         break;
1038                                                 }
1039                                         }
1040                                 }
1041                         }
1042                 }
1043 #endif
1044
1045                 /* Not in scope, ignore it */
1046                 if ( !scopeok ) {
1047 #ifdef NEW_LOGGING
1048                         LDAP_LOG ( OPERATION, RESULTS,
1049                                 "bdb_search: %ld scope not okay\n",
1050                                 (long) id, 0, 0);
1051 #else
1052                         Debug( LDAP_DEBUG_TRACE,
1053                                 "bdb_search: %ld scope not okay\n",
1054                                 (long) id, 0, 0 );
1055 #endif
1056                         goto loop_continue;
1057                 }
1058
1059                 /*
1060                  * if it's a referral, add it to the list of referrals. only do
1061                  * this for non-base searches, and don't check the filter
1062                  * explicitly here since it's only a candidate anyway.
1063                  */
1064                 if ( !manageDSAit && sop->oq_search.rs_scope != LDAP_SCOPE_BASE
1065                         && is_entry_referral( e ) )
1066                 {
1067                         BerVarray erefs = get_entry_referrals( sop, e );
1068                         rs->sr_ref = referral_rewrite( erefs,
1069                                 &e->e_name, NULL,
1070                                 sop->oq_search.rs_scope == LDAP_SCOPE_SUBTREE
1071                                         ? LDAP_SCOPE_SUBTREE
1072                                         : LDAP_SCOPE_BASE );
1073
1074                         send_search_reference( sop, rs );
1075
1076                         ber_bvarray_free( rs->sr_ref );
1077                         ber_bvarray_free( erefs );
1078                         rs->sr_ref = NULL;
1079
1080                         goto loop_continue;
1081                 }
1082
1083                 if ( !manageDSAit && is_entry_glue( e )) {
1084                         goto loop_continue;
1085                 }
1086
1087                 /* if it matches the filter and scope, send it */
1088                 if (IS_PSEARCH) {
1089                         if (ps_type != LDAP_PSEARCH_BY_SCOPEOUT) {
1090                                 rs->sr_err = test_filter( sop, rs->sr_entry, &cookief );
1091                         } else {
1092                                 rs->sr_err = LDAP_COMPARE_TRUE;
1093                         }
1094                 } else {
1095                         if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) {
1096                                 rc_sync = test_filter( sop, rs->sr_entry, &cookief );
1097                                 rs->sr_err = test_filter( sop,
1098                                         rs->sr_entry, &contextcsnand );
1099                                 if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
1100                                         if ( rc_sync == LDAP_COMPARE_TRUE ) {
1101                                                 if ( no_sync_state_change ) {
1102 #ifdef NEW_LOGGING
1103                                                         LDAP_LOG ( OPERATION, RESULTS,
1104                                                                 "bdb_search: error in context csn management\n",
1105                                                                 0, 0, 0 );
1106 #else
1107                                                         Debug( LDAP_DEBUG_TRACE,
1108                                                                 "bdb_search: error in context csn management\n",
1109                                                                 0, 0, 0 );
1110 #endif
1111                                                 }
1112                                                 entry_sync_state = LDAP_SYNC_ADD;
1113                                         } else {
1114                                                 if ( no_sync_state_change ) {
1115                                                         goto loop_continue;
1116                                                 }
1117                                                 entry_sync_state = LDAP_SYNC_PRESENT;
1118                                         }
1119                                 }
1120                         } else {
1121                                 rs->sr_err = test_filter( sop,
1122                                         rs->sr_entry, sop->oq_search.rs_filter );
1123                         }
1124                 }
1125
1126                 if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
1127                         /* check size limit */
1128                         if ( --sop->oq_search.rs_slimit == -1 ) {
1129                                 if (!IS_PSEARCH) {
1130                                         bdb_cache_return_entry_r( bdb->bi_dbenv,
1131                                                 &bdb->bi_cache, e, &lock );
1132                                 }
1133                                 e = NULL;
1134                                 rs->sr_entry = NULL;
1135                                 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
1136                                 rs->sr_ref = rs->sr_v2ref;
1137                                 send_ldap_result( sop, rs );
1138                                 goto done;
1139                         }
1140
1141 #ifdef LDAP_CONTROL_PAGEDRESULTS
1142                         if ( get_pagedresults(sop) ) {
1143                                 if ( rs->sr_nentries >= sop->o_pagedresults_size ) {
1144                                         send_pagerequest_response( sop, rs,
1145                                                 lastid, tentries );
1146                                         goto done;
1147                                 }
1148                                 lastid = id;
1149                         }
1150 #endif
1151
1152                         if (e) {
1153                                 /* safe default */
1154                                 int result = -1;
1155                                 
1156 #if 0   /* noop is masked SLAP_CTRL_UPDATE */
1157                                 if( op->o_noop ) {
1158                                         result = 0;
1159                                 } else
1160 #endif
1161                                 if (IS_PSEARCH) {
1162                                         int premodify_found = 0;
1163                                         int entry_sync_state;
1164
1165                                         if ( ps_type == LDAP_PSEARCH_BY_ADD ||
1166                                                  ps_type == LDAP_PSEARCH_BY_DELETE ||
1167                                                  ps_type == LDAP_PSEARCH_BY_MODIFY ||
1168                                                  ps_type == LDAP_PSEARCH_BY_SCOPEOUT )
1169                                         {
1170                                                 if ( ps_type == LDAP_PSEARCH_BY_MODIFY ) {
1171                                                         struct psid_entry* psid_e;
1172                                                         LDAP_LIST_FOREACH( psid_e,
1173                                                                 &op->o_pm_list, ps_link)
1174                                                         {
1175                                                                 if( psid_e->ps_op == sop ) {
1176                                                                         premodify_found = 1;
1177                                                                         LDAP_LIST_REMOVE(psid_e, ps_link);
1178                                                                         break;
1179                                                                 }
1180                                                         }
1181                                                         if (psid_e != NULL) free (psid_e);
1182                                                 }
1183                                                 if ( ps_type == LDAP_PSEARCH_BY_ADD ) {
1184                                                         entry_sync_state = LDAP_SYNC_ADD;
1185                                                 } else if ( ps_type == LDAP_PSEARCH_BY_DELETE ) {
1186                                                         entry_sync_state = LDAP_SYNC_DELETE;
1187                                                 } else if ( ps_type == LDAP_PSEARCH_BY_MODIFY ) {
1188                                                         if ( premodify_found ) {
1189                                                                 entry_sync_state = LDAP_SYNC_MODIFY;
1190                                                         } else {
1191                                                                 entry_sync_state = LDAP_SYNC_ADD;
1192                                                         }
1193                                                 } else if ( ps_type == LDAP_PSEARCH_BY_SCOPEOUT )
1194                                                         entry_sync_state = LDAP_SYNC_DELETE;
1195                                                 else {
1196                                                         rs->sr_err = 1;
1197                                                         goto done;
1198                                                 }
1199                                                 rs->sr_err = bdb_build_sync_state_ctrl( sop,
1200                                                         rs, e, entry_sync_state, ctrls,
1201                                                         num_ctrls++, 1, search_context_csn );
1202                                                 if ( rs->sr_err != LDAP_SUCCESS ) goto done;
1203                                                 rs->sr_attrs = attrs;
1204                                                 rs->sr_ctrls = ctrls;
1205                                                 result = send_search_entry( sop, rs );
1206                                                 ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val );
1207                                                 ch_free( ctrls[--num_ctrls] );
1208                                                 ctrls[num_ctrls] = NULL;
1209                                                 rs->sr_ctrls = NULL;
1210
1211                                         } else if ( ps_type == LDAP_PSEARCH_BY_PREMODIFY ) {
1212                                                 struct psid_entry* psid_e;
1213                                                 psid_e = (struct psid_entry *) calloc (1,
1214                                                         sizeof(struct psid_entry));
1215                                                 psid_e->ps_op = sop;
1216                                                 LDAP_LIST_INSERT_HEAD( &op->o_pm_list,
1217                                                         psid_e, ps_link );
1218
1219                                         } else {
1220                                                 printf("Error !\n");
1221                                         }
1222                                 } else {
1223                                         if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) {
1224                                                 rs->sr_err = bdb_build_sync_state_ctrl( sop,
1225                                                         rs, e, entry_sync_state, ctrls,
1226                                                         num_ctrls++, 0, search_context_csn );
1227                                                 if ( rs->sr_err != LDAP_SUCCESS ) goto done;
1228
1229                                                 rs->sr_ctrls = ctrls;
1230                                                 if ( rc_sync == LDAP_COMPARE_TRUE ) { /* ADD */
1231                                                         rs->sr_attrs = sop->oq_search.rs_attrs;
1232                                                 } else { /* PRESENT */
1233                                                         rs->sr_attrs = &null_attr;
1234                                                 }
1235                                                 result = send_search_entry( sop, rs );
1236                                                 ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val );
1237                                                 ch_free( ctrls[--num_ctrls] );
1238                                                 ctrls[num_ctrls] = NULL;
1239                                                 rs->sr_ctrls = NULL;
1240                                         } else {
1241                                                 rs->sr_attrs = sop->oq_search.rs_attrs;
1242                                                 rs->sr_ctrls = NULL;
1243                                                 result = send_search_entry( sop, rs );
1244                                         }
1245                                 }
1246
1247                                 switch (result) {
1248                                 case 0:         /* entry sent ok */
1249                                         break;
1250                                 case 1:         /* entry not sent */
1251                                         break;
1252                                 case -1:        /* connection closed */
1253                                         if (!IS_PSEARCH)
1254                                         bdb_cache_return_entry_r(bdb->bi_dbenv,
1255                                                 &bdb->bi_cache, e, &lock);
1256                                         e = NULL;
1257                                         rs->sr_entry = NULL;
1258                                         rs->sr_err = LDAP_OTHER;
1259                                         goto done;
1260                                 }
1261                         }
1262                 } else {
1263 #ifdef NEW_LOGGING
1264                         LDAP_LOG ( OPERATION, RESULTS,
1265                                 "bdb_search: %ld does not match filter\n", (long) id, 0, 0);
1266 #else
1267                         Debug( LDAP_DEBUG_TRACE,
1268                                 "bdb_search: %ld does not match filter\n",
1269                                 (long) id, 0, 0 );
1270 #endif
1271                 }
1272
1273 loop_continue:
1274                 if( e != NULL ) {
1275                         /* free reader lock */
1276                         if (!IS_PSEARCH) {
1277                                 bdb_cache_return_entry_r( bdb->bi_dbenv,
1278                                         &bdb->bi_cache, e , &lock);
1279                         }
1280                         e = NULL;
1281                         rs->sr_entry = NULL;
1282                 }
1283
1284                 ldap_pvt_thread_yield();
1285         }
1286
1287         if (!IS_PSEARCH) {
1288                 if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) {
1289                         rs->sr_err = LDAP_SUCCESS;
1290                         rs->sr_rspoid = LDAP_SYNC_INFO;
1291                         rs->sr_ctrls = NULL;
1292                         bdb_send_ldap_intermediate( sop, rs,
1293                                 LDAP_SYNC_STATE_MODE_DONE, search_context_csn );
1294
1295                         /* If changelog is supported, this is where to process it */
1296         
1297                         if ( sop->o_sync_mode & SLAP_SYNC_PERSIST ) {
1298                                 /* refreshAndPersist mode */
1299                                 bdb_send_ldap_intermediate( sop, rs,
1300                                         LDAP_SYNC_LOG_MODE_DONE, search_context_csn );
1301                         } else {
1302                                 /* refreshOnly mode */
1303                                 bdb_build_sync_done_ctrl( sop, rs, ctrls,
1304                                         num_ctrls++, 1, search_context_csn );
1305                                 rs->sr_ctrls = ctrls;
1306                                 rs->sr_ref = rs->sr_v2ref;
1307                                 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL;
1308                                 send_ldap_result( sop, rs );
1309                                 if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL ) {
1310                                         ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val );
1311                                 }
1312                                 ch_free( ctrls[--num_ctrls] );
1313                                 ctrls[num_ctrls] = NULL;
1314                         }
1315                 } else {
1316                         rs->sr_ctrls = NULL;
1317                         rs->sr_ref = rs->sr_v2ref;
1318                         rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL;
1319                         send_ldap_result( sop, rs );
1320                 }
1321         }
1322
1323         rs->sr_err = LDAP_SUCCESS;
1324
1325 done:
1326         if( !IS_PSEARCH && e != NULL ) {
1327                 /* free reader lock */
1328                 bdb_cache_return_entry_r ( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
1329         }
1330
1331         LOCK_ID_FREE (bdb->bi_dbenv, locker );
1332
1333         if( rs->sr_v2ref ) {
1334                 ber_bvarray_free( rs->sr_v2ref );
1335                 rs->sr_v2ref = NULL;
1336         }
1337         if( realbase.bv_val ) ch_free( realbase.bv_val );
1338
1339         return rs->sr_err;
1340 }
1341
1342
1343 static int base_candidate(
1344         BackendDB       *be,
1345         Entry   *e,
1346         ID              *ids )
1347 {
1348 #ifdef NEW_LOGGING
1349         LDAP_LOG ( OPERATION, ENTRY,
1350                 "base_candidate: base: \"%s\" (0x%08lx)\n",
1351                 e->e_nname.bv_val, (long) e->e_id, 0);
1352 #else
1353         Debug(LDAP_DEBUG_ARGS, "base_candidates: base: \"%s\" (0x%08lx)\n",
1354                 e->e_nname.bv_val, (long) e->e_id, 0);
1355 #endif
1356
1357         ids[0] = 1;
1358         ids[1] = e->e_id;
1359         return 0;
1360 }
1361
1362 /* Look for "objectClass Present" in this filter.
1363  * Also count depth of filter tree while we're at it.
1364  */
1365 static int oc_filter(
1366         Filter *f,
1367         int cur,
1368         int *max
1369 )
1370 {
1371         int rc = 0;
1372
1373         if( cur > *max ) *max = cur;
1374
1375         switch(f->f_choice) {
1376         case LDAP_FILTER_PRESENT:
1377                 if (f->f_desc == slap_schema.si_ad_objectClass) {
1378                         rc = 1;
1379                 }
1380                 break;
1381
1382         case LDAP_FILTER_AND:
1383         case LDAP_FILTER_OR:
1384                 cur++;
1385                 for (f=f->f_and; f; f=f->f_next) {
1386                         (void) oc_filter(f, cur, max);
1387                 }
1388                 break;
1389
1390         default:
1391                 break;
1392         }
1393         return rc;
1394 }
1395
1396 static void search_stack_free( void *key, void *data )
1397 {
1398         ber_memfree_x(data, NULL);
1399 }
1400
1401 static void *search_stack(
1402         Operation *op
1403 )
1404 {
1405         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
1406         void *ret = NULL;
1407
1408         if ( op->o_threadctx ) {
1409                 ldap_pvt_thread_pool_getkey( op->o_threadctx, search_stack,
1410                         &ret, NULL );
1411         } else {
1412                 ret = bdb->bi_search_stack;
1413         }
1414
1415         if ( !ret ) {
1416                 ret = ch_malloc( bdb->bi_search_stack_depth * BDB_IDL_UM_SIZE
1417                         * sizeof( ID ) );
1418                 if ( op->o_threadctx ) {
1419                         ldap_pvt_thread_pool_setkey( op->o_threadctx, search_stack,
1420                                 ret, search_stack_free );
1421                 } else {
1422                         bdb->bi_search_stack = ret;
1423                 }
1424         }
1425         return ret;
1426 }
1427
1428 static int search_candidates(
1429         Operation *stackop,
1430         Operation *op,
1431         SlapReply *rs,
1432         Entry *e,
1433         u_int32_t locker,
1434         ID      *ids,
1435         ID      *scopes )
1436 {
1437         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
1438         int rc, depth = 1;
1439         Filter          f, rf, xf, nf;
1440         ID              *stack;
1441         AttributeAssertion aa_ref;
1442 #ifdef BDB_SUBENTRIES
1443         Filter  sf;
1444         AttributeAssertion aa_subentry;
1445 #endif
1446
1447         /*
1448          * This routine takes as input a filter (user-filter)
1449          * and rewrites it as follows:
1450          *      (&(scope=DN)[(objectClass=subentry)]
1451          *              (|[(objectClass=referral)(objectClass=alias)](user-filter))
1452          */
1453
1454 #ifdef NEW_LOGGING
1455         LDAP_LOG ( OPERATION, ENTRY,
1456                 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", 
1457                 e->e_nname.bv_val, (long) e->e_id, op->oq_search.rs_scope);
1458 #else
1459         Debug(LDAP_DEBUG_TRACE,
1460                 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n",
1461                 e->e_nname.bv_val, (long) e->e_id, op->oq_search.rs_scope );
1462 #endif
1463
1464         xf.f_or = op->oq_search.rs_filter;
1465         xf.f_choice = LDAP_FILTER_OR;
1466         xf.f_next = NULL;
1467
1468         /* If the user's filter uses objectClass=*,
1469          * these clauses are redundant.
1470          */
1471         if (!oc_filter(op->oq_search.rs_filter, 1, &depth)
1472                 && !get_subentries_visibility(op)
1473                 && !is_sync_protocol(op) )
1474         {
1475                 if( !get_manageDSAit(op) && !get_domainScope(op) ) {
1476                         /* match referral objects */
1477                         struct berval bv_ref = { sizeof("referral")-1, "referral" };
1478                         rf.f_choice = LDAP_FILTER_EQUALITY;
1479                         rf.f_ava = &aa_ref;
1480                         rf.f_av_desc = slap_schema.si_ad_objectClass;
1481                         rf.f_av_value = bv_ref;
1482                         rf.f_next = xf.f_or;
1483                         xf.f_or = &rf;
1484                         depth++;
1485                 }
1486         }
1487
1488         f.f_next = NULL;
1489         f.f_choice = LDAP_FILTER_AND;
1490         f.f_and = &nf;
1491         /* Dummy; we compute scope separately now */
1492         nf.f_choice = SLAPD_FILTER_COMPUTED;
1493         nf.f_result = LDAP_SUCCESS;
1494         nf.f_next = xf.f_or == op->oq_search.rs_filter
1495                 ? op->oq_search.rs_filter : &xf ;
1496         /* Filter depth increased again, adding dummy clause */
1497         depth++;
1498
1499 #ifdef BDB_SUBENTRIES
1500         if( get_subentries_visibility( op ) ) {
1501                 struct berval bv_subentry = { sizeof("SUBENTRY")-1, "SUBENTRY" };
1502                 sf.f_choice = LDAP_FILTER_EQUALITY;
1503                 sf.f_ava = &aa_subentry;
1504                 sf.f_av_desc = slap_schema.si_ad_objectClass;
1505                 sf.f_av_value = bv_subentry;
1506                 sf.f_next = nf.f_next;
1507                 nf.f_next = &sf;
1508         }
1509 #endif
1510
1511         /* Allocate IDL stack, plus 1 more for former tmp */
1512         if ( depth+1 > bdb->bi_search_stack_depth ) {
1513                 stack = ch_malloc( (depth + 1) * BDB_IDL_UM_SIZE * sizeof( ID ) );
1514         } else {
1515                 stack = search_stack( stackop );
1516         }
1517
1518         if( op->ors_deref & LDAP_DEREF_SEARCHING ) {
1519                 rc = search_aliases( op, rs, e, locker, ids, scopes, stack );
1520         } else {
1521                 rc = bdb_dn2idl( op, e, ids, stack );
1522         }
1523
1524         if ( rc == LDAP_SUCCESS ) {
1525                 rc = bdb_filter_candidates( op, &f, ids,
1526                         stack, stack+BDB_IDL_UM_SIZE );
1527         }
1528
1529         if ( depth+1 > bdb->bi_search_stack_depth ) {
1530                 ch_free( stack );
1531         }
1532
1533         if( rc ) {
1534 #ifdef NEW_LOGGING
1535                 LDAP_LOG ( OPERATION, DETAIL1,
1536                         "bdb_search_candidates: failed (rc=%d)\n", rc, 0, 0  );
1537 #else
1538                 Debug(LDAP_DEBUG_TRACE,
1539                         "bdb_search_candidates: failed (rc=%d)\n",
1540                         rc, NULL, NULL );
1541 #endif
1542
1543         } else {
1544 #ifdef NEW_LOGGING
1545                 LDAP_LOG ( OPERATION, DETAIL1,
1546                         "bdb_search_candidates: id=%ld first=%ld last=%ld\n",
1547                         (long) ids[0], (long) BDB_IDL_FIRST(ids), 
1548                         (long) BDB_IDL_LAST(ids));
1549 #else
1550                 Debug(LDAP_DEBUG_TRACE,
1551                         "bdb_search_candidates: id=%ld first=%ld last=%ld\n",
1552                         (long) ids[0],
1553                         (long) BDB_IDL_FIRST(ids),
1554                         (long) BDB_IDL_LAST(ids) );
1555 #endif
1556         }
1557
1558         return rc;
1559 }
1560
1561 #ifdef LDAP_CONTROL_PAGEDRESULTS
1562 static void
1563 send_pagerequest_response( 
1564         Operation       *op,
1565         SlapReply       *rs,
1566         ID              lastid,
1567         int             tentries )
1568 {
1569         LDAPControl     ctrl, *ctrls[2];
1570         char berbuf[LBER_ELEMENT_SIZEOF];
1571         BerElement      *ber = (BerElement *)berbuf;
1572         struct berval   cookie = { 0, NULL };
1573         PagedResultsCookie respcookie;
1574
1575 #ifdef NEW_LOGGING
1576         LDAP_LOG ( OPERATION, ENTRY,
1577                 "send_pagerequest_response: lastid: (0x%08lx) "
1578                 "nentries: (0x%081x)\n", 
1579                 lastid, rs->sr_nentries, NULL );
1580 #else
1581         Debug(LDAP_DEBUG_ARGS, "send_pagerequest_response: lastid: (0x%08lx) "
1582                         "nentries: (0x%081x)\n", lastid, rs->sr_nentries, NULL );
1583 #endif
1584
1585         ctrl.ldctl_value.bv_val = NULL;
1586         ctrls[0] = &ctrl;
1587         ctrls[1] = NULL;
1588
1589         ber_init2( ber, NULL, LBER_USE_DER );
1590
1591         respcookie = ( PagedResultsCookie )lastid;
1592         op->o_conn->c_pagedresults_state.ps_cookie = respcookie;
1593         cookie.bv_len = sizeof( respcookie );
1594         cookie.bv_val = (char *)&respcookie;
1595
1596         /*
1597          * FIXME: we should consider sending an estimate of the entries
1598          * left, after appropriate security check is done
1599          */
1600         ber_printf( ber, "{iO}", tentries, &cookie ); 
1601
1602         if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) {
1603                 goto done;
1604         }
1605
1606         ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
1607         ctrls[0]->ldctl_iscritical = 0;
1608
1609         rs->sr_ctrls = ctrls;
1610         rs->sr_err = LDAP_SUCCESS;
1611         send_ldap_result( op, rs );
1612
1613 done:
1614         (void) ber_free_buf( ber );
1615 }                       
1616 #endif
1617
1618 int
1619 bdb_build_sync_state_ctrl(
1620         Operation       *op,
1621         SlapReply       *rs,
1622         Entry           *e,
1623         int                     entry_sync_state,
1624         LDAPControl     **ctrls,
1625         int                     num_ctrls,
1626         int                     send_cookie,
1627         struct berval   *csn)
1628 {
1629         Attribute* a;
1630         int ret;
1631         int res;
1632         const char *text = NULL;
1633
1634         char berbuf[LBER_ELEMENT_SIZEOF];
1635         BerElement *ber = (BerElement *)berbuf;
1636
1637         struct berval entryuuid_bv      = { 0, NULL };
1638
1639         ber_init2( ber, 0, LBER_USE_DER );
1640
1641         ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) );
1642
1643         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
1644                 AttributeDescription *desc = a->a_desc;
1645                 if ( desc == slap_schema.si_ad_entryUUID ) {
1646                         ber_dupbv( &entryuuid_bv, &a->a_vals[0] );
1647                 }
1648         }
1649
1650         if ( send_cookie && csn ) {
1651                 ber_printf( ber, "{eOON}",
1652                         entry_sync_state, &entryuuid_bv, csn );
1653         } else {
1654                 ber_printf( ber, "{eON}",
1655                         entry_sync_state, &entryuuid_bv );
1656         }
1657
1658         ch_free( entryuuid_bv.bv_val );
1659         entryuuid_bv.bv_val = NULL;
1660
1661         ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE;
1662         ctrls[num_ctrls]->ldctl_iscritical = op->o_sync;
1663         ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );
1664
1665         ber_free_buf( ber );
1666
1667         if ( ret < 0 ) {
1668 #ifdef NEW_LOGGING
1669                 LDAP_LOG ( OPERATION, RESULTS, 
1670                         "bdb_build_sync_ctrl: ber_flatten2 failed\n",
1671                         0, 0, 0 );
1672 #else
1673                 Debug( LDAP_DEBUG_TRACE,
1674                         "bdb_build_sync_ctrl: ber_flatten2 failed\n",
1675                         0, 0, 0 );
1676 #endif
1677                 send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
1678                 return ret;
1679         }
1680
1681         return LDAP_SUCCESS;
1682 }
1683
1684 int
1685 bdb_build_sync_done_ctrl(
1686         Operation       *op,
1687         SlapReply       *rs,
1688         LDAPControl     **ctrls,
1689         int             num_ctrls,
1690         int             send_cookie,
1691         struct berval   *csn )
1692 {
1693         int ret;
1694         char berbuf[LBER_ELEMENT_SIZEOF];
1695         BerElement *ber = (BerElement *)berbuf;
1696
1697         ber_init2( ber, NULL, LBER_USE_DER );
1698
1699         ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) );
1700
1701         if ( send_cookie && csn ) {
1702                 ber_printf( ber, "{ON}", csn );
1703         } else {
1704                 ber_printf( ber, "{N}" );
1705         }
1706
1707         ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_DONE;
1708         ctrls[num_ctrls]->ldctl_iscritical = op->o_sync;
1709         ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );
1710
1711         ber_free_buf( ber );
1712
1713         if ( ret < 0 ) {
1714 #ifdef NEW_LOGGING
1715                 LDAP_LOG ( OPERATION, RESULTS, 
1716                         "bdb_build_sync_done_ctrl: ber_flatten2 failed\n",
1717                         0, 0, 0 );
1718 #else
1719                 Debug( LDAP_DEBUG_TRACE,
1720                         "bdb_build_sync_done_ctrl: ber_flatten2 failed\n",
1721                         0, 0, 0 );
1722 #endif
1723                 send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
1724                 return ret;
1725         }
1726
1727         return LDAP_SUCCESS;
1728 }
1729
1730 int
1731 bdb_send_ldap_intermediate(
1732         Operation   *op,
1733         SlapReply   *rs,
1734         int         state,
1735         struct berval *cookie )
1736 {
1737         char berbuf[LBER_ELEMENT_SIZEOF];
1738         BerElement *ber = (BerElement *)berbuf;
1739         struct berval rspdata;
1740
1741         int ret;
1742
1743         ber_init2( ber, NULL, LBER_USE_DER );
1744
1745         if ( cookie == NULL ) {
1746                 ber_printf( ber, "{eN}", state );
1747         } else {
1748                 ber_printf( ber, "{eON}", state, cookie );
1749         }
1750
1751         ret = ber_flatten2( ber, &rspdata, 0 );
1752
1753         if ( ret < 0 ) {
1754 #ifdef NEW_LOGGING
1755                 LDAP_LOG ( OPERATION, RESULTS, 
1756                         "bdb_send_ldap_intermediate: ber_flatten2 failed\n",
1757                         0, 0, 0 );
1758 #else
1759                 Debug( LDAP_DEBUG_TRACE,
1760                         "bdb_send_ldap_intermediate: ber_flatten2 failed\n",
1761                         0, 0, 0 );
1762 #endif
1763                 send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
1764                 return ret;
1765         }
1766
1767         rs->sr_rspdata = &rspdata;
1768         send_ldap_intermediate( op, rs );
1769         rs->sr_rspdata = NULL;
1770         ber_free_buf( ber );
1771
1772         return LDAP_SUCCESS;
1773 }