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