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