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