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