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