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