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