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