]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/search.c
LCUP Response Control Code
[openldap] / servers / slapd / back-bdb / search.c
1 /* search.c - search operation */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 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         BackendDB *be,
23         Operation *op,
24         Entry *e,
25         Filter *filter,
26         int scope,
27         int deref,
28         ID      *ids );
29
30 int
31 bdb_search(
32         BackendDB       *be,
33         Connection      *conn,
34         Operation       *op,
35         struct berval   *base,
36         struct berval   *nbase,
37         int             scope,
38         int             deref,
39         int             slimit,
40         int             tlimit,
41         Filter  *filter,
42         struct berval   *filterstr,
43         AttributeName   *attrs,
44         int             attrsonly )
45 {
46         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
47         int             rc;
48         const char *text = NULL;
49         time_t          stoptime;
50         ID              id, cursor;
51         ID              candidates[BDB_IDL_UM_SIZE];
52         Entry           *e = NULL;
53         BerVarray v2refs = NULL;
54         Entry   *matched = NULL;
55         struct berval   realbase = { 0, NULL };
56         int             nentries = 0;
57         int             manageDSAit;
58
59 #ifdef LDAP_CLIENT_UPDATE
60         Filter lcupf, csnfnot, csnfeq, csnfand, csnfge;
61         AttributeAssertion aa_ge, aa_eq;
62         int             entry_count = 0;
63         struct berval entrycsn_bv = { 0, NULL };
64         struct berval latest_entrycsn_bv = { 0, NULL };
65 #endif /* LDAP_CLIENT_UPDATE */
66
67         struct slap_limits_set *limit = NULL;
68         int isroot = 0;
69
70 #ifdef SLAP_X_FILTER_HASSUBORDINATES
71         int             filter_hasSubordinates = 0;
72 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
73
74         u_int32_t       locker;
75         DB_LOCK         lock;
76
77 #ifdef NEW_LOGGING
78         LDAP_LOG ( OPERATION, ENTRY, "bdb_back_search\n", 0, 0, 0 );
79 #else
80         Debug( LDAP_DEBUG_TRACE, "=> bdb_back_search\n",
81                 0, 0, 0);
82 #endif
83
84         manageDSAit = get_manageDSAit( op );
85
86         rc = LOCK_ID (bdb->bi_dbenv, &locker );
87         switch(rc) {
88         case 0:
89                 break;
90         default:
91                 send_ldap_result( conn, op, rc=LDAP_OTHER,
92                         NULL, "internal error", NULL, NULL );
93                 return rc;
94         }
95
96         if ( nbase->bv_len == 0 ) {
97                 /* DIT root special case */
98                 e = (Entry *) &slap_entry_root;
99                 rc = 0;
100         } else                                          
101 #ifdef BDB_ALIASES
102         /* get entry with reader lock */
103         if ( deref & LDAP_DEREF_FINDING ) {
104                 e = deref_dn_r( be, nbase-, &err, &matched, &text );
105
106         } else
107 #endif
108         {
109 dn2entry_retry:
110                 rc = bdb_dn2entry_r( be, NULL, nbase, &e, &matched, 0, locker, &lock );
111         }
112
113         switch(rc) {
114         case DB_NOTFOUND:
115         case 0:
116                 break;
117         case LDAP_BUSY:
118                 if (e != NULL) {
119                         bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
120                 }
121                 if (matched != NULL) {
122                         bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
123                 }
124                 send_ldap_result( conn, op, LDAP_BUSY,
125                         NULL, "ldap server busy", NULL, NULL );
126                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
127                 return LDAP_BUSY;
128         case DB_LOCK_DEADLOCK:
129         case DB_LOCK_NOTGRANTED:
130                 goto dn2entry_retry;
131         default:
132                 if (e != NULL) {
133                         bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
134                 }
135                 if (matched != NULL) {
136                         bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
137                 }
138                 send_ldap_result( conn, op, rc=LDAP_OTHER,
139                         NULL, "internal error", NULL, NULL );
140                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
141                 return rc;
142         }
143
144         if ( e == NULL ) {
145                 struct berval matched_dn = { 0, NULL };
146                 BerVarray refs = NULL;
147
148                 if ( matched != NULL ) {
149                         BerVarray erefs;
150                         ber_dupbv( &matched_dn, &matched->e_name );
151
152                         erefs = is_entry_referral( matched )
153                                 ? get_entry_referrals( be, conn, op, matched )
154                                 : NULL;
155
156                         bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
157                         matched = NULL;
158
159                         if( erefs ) {
160                                 refs = referral_rewrite( erefs, &matched_dn,
161                                         base, scope );
162                                 ber_bvarray_free( erefs );
163                         }
164
165                 } else {
166                         refs = referral_rewrite( default_referral,
167                                 NULL, base, scope );
168                 }
169
170                 send_ldap_result( conn, op,     rc=LDAP_REFERRAL ,
171                         matched_dn.bv_val, text, refs, NULL );
172
173                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
174                 if ( refs ) ber_bvarray_free( refs );
175                 if ( matched_dn.bv_val ) ber_memfree( matched_dn.bv_val );
176                 return rc;
177         }
178
179         if (!manageDSAit && e != &slap_entry_root && is_entry_referral( e ) ) {
180                 /* entry is a referral, don't allow add */
181                 struct berval matched_dn;
182                 BerVarray erefs, refs;
183                 
184                 ber_dupbv( &matched_dn, &e->e_name );
185                 erefs = get_entry_referrals( be, conn, op, e );
186                 refs = NULL;
187
188                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
189                 e = NULL;
190
191                 if( erefs ) {
192                         refs = referral_rewrite( erefs, &matched_dn,
193                                 base, scope );
194                         ber_bvarray_free( erefs );
195                 }
196
197 #ifdef NEW_LOGGING
198                 LDAP_LOG ( OPERATION, RESULTS, 
199                         "bdb_search: entry is referral\n", 0, 0, 0 );
200 #else
201                 Debug( LDAP_DEBUG_TRACE, "bdb_search: entry is referral\n",
202                         0, 0, 0 );
203 #endif
204
205                 send_ldap_result( conn, op, LDAP_REFERRAL,
206                         matched_dn.bv_val,
207                         refs ? NULL : "bad referral object",
208                         refs, NULL );
209
210                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
211                 ber_bvarray_free( refs );
212                 ber_memfree( matched_dn.bv_val );
213                 return 1;
214         }
215
216         /* if not root, get appropriate limits */
217         if ( be_isroot( be, &op->o_ndn ) ) {
218                 isroot = 1;
219         } else {
220                 ( void ) get_limits( be, &op->o_ndn, &limit );
221         }
222
223         /* The time/size limits come first because they require very little
224          * effort, so there's no chance the candidates are selected and then 
225          * the request is not honored only because of time/size constraints */
226
227         /* if no time limit requested, use soft limit (unless root!) */
228         if ( isroot ) {
229                 if ( tlimit == 0 ) {
230                         tlimit = -1;    /* allow root to set no limit */
231                 }
232
233                 if ( slimit == 0 ) {
234                         slimit = -1;
235                 }
236
237         } else {
238                 /* if no limit is required, use soft limit */
239                 if ( tlimit <= 0 ) {
240                         tlimit = limit->lms_t_soft;
241
242                 /* if requested limit higher than hard limit, abort */
243                 } else if ( tlimit > limit->lms_t_hard ) {
244                         /* no hard limit means use soft instead */
245                         if ( limit->lms_t_hard == 0 && tlimit > limit->lms_t_soft ) {
246                                 tlimit = limit->lms_t_soft;
247
248                         /* positive hard limit means abort */
249                         } else if ( limit->lms_t_hard > 0 ) {
250                                 send_search_result( conn, op, 
251                                                 LDAP_UNWILLING_TO_PERFORM,
252                                                 NULL, NULL, NULL, NULL, 0 );
253                                 rc = 0;
254                                 goto done;
255                         }
256                 
257                         /* negative hard limit means no limit */
258                 }
259                 
260                 /* if no limit is required, use soft limit */
261                 if ( slimit <= 0 ) {
262                         slimit = limit->lms_s_soft;
263
264                 /* if requested limit higher than hard limit, abort */
265                 } else if ( slimit > limit->lms_s_hard ) {
266                         /* no hard limit means use soft instead */
267                         if ( limit->lms_s_hard == 0 && slimit > limit->lms_s_soft ) {
268                                 slimit = limit->lms_s_soft;
269
270                         /* positive hard limit means abort */
271                         } else if ( limit->lms_s_hard > 0 ) {
272                                 send_search_result( conn, op, 
273                                                 LDAP_UNWILLING_TO_PERFORM,
274                                                 NULL, NULL, NULL, NULL, 0 );
275                                 rc = 0; 
276                                 goto done;
277                         }
278                         
279                         /* negative hard limit means no limit */
280                 }
281         }
282
283         /* compute it anyway; root does not use it */
284         stoptime = op->o_time + tlimit;
285
286         /* select candidates */
287         if ( scope == LDAP_SCOPE_BASE ) {
288                 rc = base_candidate( be, e, candidates );
289
290         } else {
291                 BDB_IDL_ALL( bdb, candidates );
292                 rc = search_candidates( be, op, e, filter,
293                         scope, deref, candidates );
294         }
295
296         /* need normalized dn below */
297         ber_dupbv( &realbase, &e->e_nname );
298
299         /* start cursor at beginning of candidates.
300          */
301         cursor = 0;
302
303         if ( e != &slap_entry_root ) {
304                 bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
305         }
306         e = NULL;
307
308         if ( candidates[0] == 0 ) {
309 #ifdef NEW_LOGGING
310         LDAP_LOG ( OPERATION, RESULTS, "bdb_search: no candidates\n", 0, 0, 0 );
311 #else
312                 Debug( LDAP_DEBUG_TRACE, "bdb_search: no candidates\n",
313                         0, 0, 0 );
314 #endif
315
316                 send_search_result( conn, op,
317                         LDAP_SUCCESS,
318                         NULL, NULL, NULL, NULL, 0 );
319
320                 rc = 1;
321                 goto done;
322         }
323
324         /* if not root and candidates exceed to-be-checked entries, abort */
325         if ( !isroot && limit->lms_s_unchecked != -1 ) {
326                 if ( BDB_IDL_N(candidates) > (unsigned) limit->lms_s_unchecked ) {
327                         send_search_result( conn, op, 
328                                         LDAP_ADMINLIMIT_EXCEEDED,
329                                         NULL, NULL, NULL, NULL, 0 );
330                         rc = 1;
331                         goto done;
332                 }
333         }
334
335 #ifdef SLAP_X_FILTER_HASSUBORDINATES
336         /*
337          * is hasSubordinates used in the filter ?
338          * FIXME: we may compute this directly when parsing the filter
339          */
340         filter_hasSubordinates = filter_has_subordinates( filter );
341 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
342
343 #ifdef LDAP_CLIENT_UPDATE
344         if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
345                 lcupf.f_choice = LDAP_FILTER_AND;
346                 lcupf.f_and = &csnfnot;
347                 lcupf.f_next = NULL;
348
349                 csnfnot.f_choice = LDAP_FILTER_NOT;
350                 csnfnot.f_not = &csnfeq;
351                 csnfnot.f_next = &csnfand;
352
353                 csnfeq.f_choice = LDAP_FILTER_EQUALITY;
354                 csnfeq.f_ava = &aa_eq;
355                 csnfeq.f_av_desc = slap_schema.si_ad_entryCSN;
356                 ber_dupbv( &csnfeq.f_av_value, &op->o_clientupdate_state );
357
358                 csnfand.f_choice = LDAP_FILTER_AND;
359                 csnfand.f_and = &csnfge;
360                 csnfand.f_next = NULL;
361
362                 csnfge.f_choice = LDAP_FILTER_GE;
363                 csnfge.f_ava = &aa_ge;
364                 csnfge.f_av_desc = slap_schema.si_ad_entryCSN;
365                 ber_dupbv( &csnfge.f_av_value, &op->o_clientupdate_state );
366                 csnfge.f_next = filter;
367         }
368 #endif /* LDAP_CLIENT_UPDATE */
369
370         for ( id = bdb_idl_first( candidates, &cursor );
371                 id != NOID;
372                 id = bdb_idl_next( candidates, &cursor ) )
373         {
374                 int             scopeok = 0;
375 #ifdef SLAP_X_FILTER_HASSUBORDINATES
376                 Attribute       *hasSubordinates = NULL;
377 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
378
379                 /* check for abandon */
380                 if ( op->o_abandon ) {
381                         rc = 0;
382                         goto done;
383                 }
384
385                 /* check time limit */
386                 if ( tlimit != -1 && slap_get_time() > stoptime ) {
387                         send_search_result( conn, op, rc = LDAP_TIMELIMIT_EXCEEDED,
388                                 NULL, NULL, v2refs, NULL, nentries );
389                         goto done;
390                 }
391
392 id2entry_retry:
393                 /* get the entry with reader lock */
394                 rc = bdb_id2entry_r( be, NULL, id, &e, locker, &lock );
395
396                 if (rc == LDAP_BUSY) {
397                         send_ldap_result( conn, op, rc=LDAP_BUSY,
398                                 NULL, "ldap server busy", NULL, NULL );
399                         goto done;
400
401                 } else if ( rc == DB_LOCK_DEADLOCK || rc == DB_LOCK_NOTGRANTED ) {
402                         goto id2entry_retry;    
403                 }
404
405                 if ( e == NULL ) {
406                         if( !BDB_IDL_IS_RANGE(candidates) ) {
407                                 /* only complain for non-range IDLs */
408 #ifdef NEW_LOGGING
409                                 LDAP_LOG ( OPERATION, RESULTS,
410                                         "bdb_search: candidate %ld not found\n", (long) id, 0, 0);
411 #else
412                                 Debug( LDAP_DEBUG_TRACE,
413                                         "bdb_search: candidate %ld not found\n",
414                                         (long) id, 0, 0 );
415 #endif
416                         }
417
418                         goto loop_continue;
419                 }
420
421 #ifdef BDB_SUBENTRIES
422                 if ( is_entry_subentry( e ) ) {
423                         if( scope != LDAP_SCOPE_BASE ) {
424                                 if(!get_subentries_visibility( op )) {
425                                         /* only subentries are visible */
426                                         goto loop_continue;
427                                 }
428
429                         } else if ( get_subentries( op ) &&
430                                 !get_subentries_visibility( op ))
431                         {
432                                 /* only subentries are visible */
433                                 goto loop_continue;
434                         }
435
436                 } else if ( get_subentries_visibility( op )) {
437                         /* only subentries are visible */
438                         goto loop_continue;
439                 }
440 #endif
441
442 #ifdef BDB_ALIASES
443                 if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) {
444                         Entry *matched;
445                         int err;
446                         const char *text;
447                         
448                         e = deref_entry_r( be, e, &err, &matched, &text );
449
450                         if( e == NULL ) {
451                                 e = matched;
452                                 goto loop_continue;
453                         }
454
455                         if( e->e_id == id ) {
456                                 /* circular loop */
457                                 goto loop_continue;
458                         }
459
460                         /* need to skip alias which deref into scope */
461                         if( scope & LDAP_SCOPE_ONELEVEL ) {
462                                 struct berval   pdn;
463                                 
464                                 dnParent( &e->e_nname, &pdn ):
465                                 if ( ber_bvcmp( pdn, &realbase ) ) {
466                                         goto loop_continue;
467                                 }
468
469                         } else if ( dnIsSuffix( &e->e_nname, &realbase ) ) {
470                                 /* alias is within scope */
471 #ifdef NEW_LOGGING
472                                 LDAP_LOG ( OPERATION, RESULTS,
473                                         "bdb_search: \"%s\" in subtree\n", e->edn, 0, 0);
474 #else
475                                 Debug( LDAP_DEBUG_TRACE,
476                                         "bdb_search: \"%s\" in subtree\n",
477                                         e->e_dn, 0, 0 );
478 #endif
479                                 goto loop_continue;
480                         }
481
482                         scopeok = 1;
483                 }
484 #endif
485
486                 /*
487                  * if it's a referral, add it to the list of referrals. only do
488                  * this for non-base searches, and don't check the filter
489                  * explicitly here since it's only a candidate anyway.
490                  */
491                 if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
492                         is_entry_referral( e ) )
493                 {
494                         struct berval   dn;
495
496                         /* check scope */
497                         if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
498                                 if ( !be_issuffix( be, &e->e_nname ) ) {
499                                         dnParent( &e->e_nname, &dn );
500                                         scopeok = dn_match( &dn, &realbase );
501                                 } else {
502                                         scopeok = (realbase.bv_len == 0);
503                                 }
504
505                         } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
506                                 scopeok = dnIsSuffix( &e->e_nname, &realbase );
507
508                         } else {
509                                 scopeok = 1;
510                         }
511
512                         if( scopeok ) {
513                                 BerVarray erefs = get_entry_referrals(
514                                         be, conn, op, e );
515                                 BerVarray refs = referral_rewrite( erefs,
516                                         &e->e_name, NULL,
517                                         scope == LDAP_SCOPE_SUBTREE
518                                                 ? LDAP_SCOPE_SUBTREE
519                                                 : LDAP_SCOPE_BASE );
520
521                                 send_search_reference( be, conn, op,
522                                         e, refs, NULL, &v2refs );
523
524                                 ber_bvarray_free( refs );
525
526                         } else {
527 #ifdef NEW_LOGGING
528                                 LDAP_LOG(OPERATION, DETAIL2, 
529                                         "bdb_search: candidate referral %ld scope not okay\n",
530                                         id, 0, 0 );
531 #else
532                                 Debug( LDAP_DEBUG_TRACE,
533                                         "bdb_search: candidate referral %ld scope not okay\n",
534                                         id, 0, 0 );
535 #endif
536                         }
537
538                         goto loop_continue;
539                 }
540
541 #ifdef SLAP_X_FILTER_HASSUBORDINATES
542                 /*
543                  * if hasSubordinates is used in the filter,
544                  * append it to the entry's attributes
545                  */
546                 if ( filter_hasSubordinates ) {
547                         int     hs;
548
549                         rc = bdb_hasSubordinates( be, conn, op, e, &hs);
550                         if ( rc != LDAP_SUCCESS ) {
551                                 goto loop_continue;
552                         }
553
554                         hasSubordinates = slap_operational_hasSubordinate(
555                                 hs == LDAP_COMPARE_TRUE );
556
557                         if ( hasSubordinates == NULL ) {
558                                 goto loop_continue;
559                         }
560
561                         hasSubordinates->a_next = e->e_attrs;
562                         e->e_attrs = hasSubordinates;
563                 }
564 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
565
566                 /* if it matches the filter and scope, send it */
567 #ifdef LDAP_CLIENT_UPDATE
568                 if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
569                         rc = test_filter( be, conn, op, e, &lcupf );
570                 } else
571 #endif /* LDAP_CLIENT_UPDATE */
572                 {
573                         rc = test_filter( be, conn, op, e, filter );
574                 }
575
576 #ifdef SLAP_X_FILTER_HASSUBORDINATES
577                 if ( hasSubordinates ) {
578                         /*
579                          * FIXME: this is fairly inefficient, because 
580                          * if hasSubordinates is among the required
581                          * attrs, it will be added again later;
582                          * maybe we should leave it and check
583                          * check later if it's already present,
584                          * if required
585                          */
586                         e->e_attrs = e->e_attrs->a_next;
587                         attr_free( hasSubordinates );
588                 }
589 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
590
591                 if ( rc == LDAP_COMPARE_TRUE ) {
592                         struct berval   dn;
593
594                         /* check scope */
595                         if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
596                                 if ( be_issuffix( be, &e->e_nname ) ) {
597                                         scopeok = (realbase.bv_len == 0);
598                                 } else {
599                                         dnParent( &e->e_nname, &dn );
600                                         scopeok = dn_match( &dn, &realbase );
601                                 }
602
603                         } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
604                                 scopeok = dnIsSuffix( &e->e_nname, &realbase );
605
606                         } else {
607                                 scopeok = 1;
608                         }
609
610                         if ( scopeok ) {
611                                 /* check size limit */
612                                 if ( --slimit == -1 ) {
613                                         bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
614                                         e = NULL;
615                                         send_search_result( conn, op,
616                                                 rc = LDAP_SIZELIMIT_EXCEEDED, NULL, NULL,
617                                                 v2refs, NULL, nentries );
618                                         goto done;
619                                 }
620
621                                 if (e) {
622                                         int result;
623                                         
624 #if 0   /* noop is masked SLAP_CTRL_UPDATE */
625                                         if( op->o_noop ) {
626                                                 result = 0;
627                                         } else {
628 #endif
629 #ifdef LDAP_CLIENT_UPDATE
630                                                 if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
631                                                         Attribute* a;
632                                                         int ret;
633                                                         int res;
634                                                         const char *text = NULL;
635                                                         LDAPControl *ctrls[2];
636                                                         struct berval *bv;
637
638                                                         BerElement *ber = ber_alloc_t( LBER_USE_DER );
639
640                                                         if ( ber == NULL ) {
641 #ifdef NEW_LOGGING
642                                                                 LDAP_LOG ( OPERATION, RESULTS, 
643                                                                         "bdb_search: ber_alloc_t failed\n", 0, 0, 0 );
644 #else
645                                                                 Debug( LDAP_DEBUG_TRACE, "bdb_search: ber_alloc_t failed\n",
646                                                                         0, 0, 0 );
647 #endif
648                                                                 send_ldap_result( conn, op, rc=LDAP_OTHER,
649                                                                         NULL, "internal error", NULL, NULL );
650                                                                 goto done;
651                                                         }
652
653                                                         entry_count++;
654
655                                                         ctrls[0] = ch_malloc ( sizeof ( LDAPControl ) );
656                                                         ctrls[1] = NULL;
657
658                                                         if ( entry_count % op->o_clientupdate_interval == 0 ) {
659                                                                 /* Send cookie */
660                                                                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
661                                                                         AttributeDescription *desc = a->a_desc;
662                                                                         if ( !strcmp( desc->ad_cname.bv_val, "entryCSN" ) ) {
663                                                                                 ber_dupbv( &entrycsn_bv, &a->a_vals[0] );
664                                                                                 if ( latest_entrycsn_bv.bv_val == NULL ) {
665                                                                                         ber_dupbv( &latest_entrycsn_bv, &entrycsn_bv );
666                                                                                 } else {
667                                                                                         res = value_match( &ret, desc, desc->ad_type->sat_ordering, SLAP_MR_ASSERTION_SYNTAX_MATCH, &entrycsn_bv, &latest_entrycsn_bv, &text );
668                                                                                         if ( res != LDAP_SUCCESS ) {
669                                                                                                 ret = 0;
670 #ifdef NEW_LOGGING
671                                                                                                 LDAP_LOG ( OPERATION, RESULTS, 
672                                                                                                         "bdb_search: value_match failed\n", 0, 0, 0 );
673 #else
674                                                                                                 Debug( LDAP_DEBUG_TRACE, "bdb_search: value_match failed\n",
675                                                                                                         0, 0, 0 );
676 #endif
677                                                                                         }
678
679                                                                                         if ( ret > 0 ) {
680                                                                                                 ch_free( latest_entrycsn_bv.bv_val );
681                                                                                                 latest_entrycsn_bv.bv_val = NULL;
682                                                                                                 ber_dupbv( &latest_entrycsn_bv, &entrycsn_bv );
683                                                                                         }
684                                                                                 }
685                                                                         }
686                                                                 }
687
688                                                                 ber_printf( ber, "{{b}" /*}*/, SLAP_LCUP_STATE_UPDATE_FALSE );
689                                                                 ber_printf( ber, "{b}",  SLAP_LCUP_ENTRY_DELETED_FALSE );
690                                                                 ber_printf( ber, "{sO" /*}*/, LCUP_COOKIE_OID, &entrycsn_bv );
691                                                                 ber_printf( ber, /*{{*/ "N}N}" );
692
693                                                                 ch_free( entrycsn_bv.bv_val );
694                                                                 entrycsn_bv.bv_val = NULL;
695                                                         } else {
696                                                                 /* Do not send cookie */
697                                                                 ber_printf( ber, "{{b}" /*}*/, SLAP_LCUP_STATE_UPDATE_FALSE );
698                                                                 ber_printf( ber, /*{*/ "{b}N}",  SLAP_LCUP_ENTRY_DELETED_FALSE );
699                                                         }
700
701                                                         ctrls[0]->ldctl_oid = LDAP_CONTROL_ENTRY_UPDATE;
702                                                         ctrls[0]->ldctl_iscritical = op->o_clientupdate;
703                                                         ret = ber_flatten( ber, &bv );
704
705                                                         if ( ret < 0 ) {
706 #ifdef NEW_LOGGING
707                                                                 LDAP_LOG ( OPERATION, RESULTS, 
708                                                                         "bdb_search: ber_flatten failed\n", 0, 0, 0 );
709 #else
710                                                                 Debug( LDAP_DEBUG_TRACE, "bdb_search: ber_flatten failed\n",
711                                                                         0, 0, 0 );
712 #endif
713                                                                 send_ldap_result( conn, op, rc=LDAP_OTHER,
714                                                                         NULL, "internal error", NULL, NULL );
715                                                                 goto done;
716                                                         }
717
718                                                         ber_dupbv( &ctrls[0]->ldctl_value, bv );
719                                                         
720                                                         result = send_search_entry( be, conn, op,
721                                                                 e, attrs, attrsonly, ctrls);
722
723                                                         ch_free( ctrls[0]->ldctl_value.bv_val );
724                                                         ch_free( ctrls[0] );
725                                                         ber_free( ber, 1 );
726                                                         ber_bvfree( bv );
727                                                 } else {
728 #endif /* LDAP_CLIENT_UPDATE */
729                                                         result = send_search_entry( be, conn, op,
730                                                                 e, attrs, attrsonly, NULL);
731 #ifdef LDAP_CLIENT_UPDATE
732                                                 }
733 #endif /* LDAP_CLIENT_UPDATE */
734 #if 0
735                                         }
736 #endif
737
738                                         switch (result) {
739                                         case 0:         /* entry sent ok */
740                                                 nentries++;
741                                                 break;
742                                         case 1:         /* entry not sent */
743                                                 break;
744                                         case -1:        /* connection closed */
745                                                 bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
746                                                 e = NULL;
747                                                 rc = LDAP_OTHER;
748                                                 goto done;
749                                         }
750                                 }
751                         } else {
752 #ifdef NEW_LOGGING
753                                 LDAP_LOG ( OPERATION, RESULTS,
754                                         "bdb_search: %ld scope not okay\n", (long) id, 0, 0);
755 #else
756                                 Debug( LDAP_DEBUG_TRACE,
757                                         "bdb_search: %ld scope not okay\n",
758                                         (long) id, 0, 0 );
759 #endif
760                         }
761                 } else {
762 #ifdef NEW_LOGGING
763                         LDAP_LOG ( OPERATION, RESULTS,
764                                 "bdb_search: %ld does match filter\n", (long) id, 0, 0);
765 #else
766                         Debug( LDAP_DEBUG_TRACE,
767                                 "bdb_search: %ld does match filter\n",
768                                 (long) id, 0, 0 );
769 #endif
770                 }
771
772 loop_continue:
773                 if( e != NULL ) {
774                         /* free reader lock */
775                         bdb_cache_return_entry_r( bdb->bi_dbenv,
776                                 &bdb->bi_cache, e , &lock);
777                         e = NULL;
778                 }
779
780                 ldap_pvt_thread_yield();
781         }
782 #ifdef LDAP_CLIENT_UPDATE
783         if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
784                 int ret;
785                 LDAPControl *ctrls[2];
786                 BerElement *ber = ber_alloc_t( LBER_USE_DER );
787                 struct berval *bv;
788
789                 if ( ber == NULL ) {
790 #ifdef NEW_LOGGING
791                         LDAP_LOG ( OPERATION, RESULTS, 
792                                 "bdb_search: ber_alloc_t failed\n", 0, 0, 0 );
793 #else
794                         Debug( LDAP_DEBUG_TRACE, "bdb_search: ber_alloc_t failed\n",
795                                 0, 0, 0 );
796 #endif
797                         send_ldap_result( conn, op, rc=LDAP_OTHER,
798                                 NULL, "internal error", NULL, NULL );
799                         goto done;
800                 }
801
802                 ctrls[0] = ch_malloc ( sizeof ( LDAPControl ) );
803                 ctrls[1] = NULL;
804
805                 ber_printf( ber, "{sO", LCUP_COOKIE_OID, &latest_entrycsn_bv );
806                 ber_printf( ber, "N}" );
807
808                 ctrls[0]->ldctl_oid = LDAP_CONTROL_CLIENT_UPDATE_DONE;
809                 ctrls[0]->ldctl_iscritical = op->o_clientupdate;
810                 ret = ber_flatten( ber, &bv );
811
812                 if ( ret < 0 ) {
813 #ifdef NEW_LOGGING
814                         LDAP_LOG ( OPERATION, RESULTS, 
815                                 "bdb_search: ber_flatten failed\n", 0, 0, 0 );
816 #else
817                         Debug( LDAP_DEBUG_TRACE, "bdb_search: ber_flatten failed\n",
818                                 0, 0, 0 );
819 #endif
820                         send_ldap_result( conn, op, rc=LDAP_OTHER,
821                                 NULL, "internal error", NULL, NULL );
822                         goto done;
823                 }
824
825                 ber_dupbv( &ctrls[0]->ldctl_value, bv );
826
827                 send_search_result( conn, op,
828                         v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
829                         NULL, NULL, v2refs, ctrls, nentries );
830
831                 ch_free( latest_entrycsn_bv.bv_val );
832                 latest_entrycsn_bv.bv_val = NULL;
833                 ch_free( ctrls[0]->ldctl_value.bv_val );
834                 ch_free( ctrls[0] );
835                 ber_free( ber, 1 );
836                 ber_bvfree( bv );
837         } else {
838 #endif /* LDAP_CLIENT_UPDATE */
839                 send_search_result( conn, op,
840                         v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
841                         NULL, NULL, v2refs, NULL, nentries );
842 #ifdef LDAP_CLIENT_UPDATE
843         }
844 #endif /* LDAP_CLIENT_UPDATE */
845
846         rc = 0;
847
848 done:
849         if( e != NULL ) {
850                 /* free reader lock */
851                 bdb_cache_return_entry_r ( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
852         }
853
854         if ( csnfeq.f_av_value.bv_val != NULL ) {
855                 ch_free( csnfeq.f_av_value.bv_val );
856         }
857         
858         if ( csnfge.f_av_value.bv_val != NULL ) {
859                 ch_free( csnfge.f_av_value.bv_val );
860         }
861
862         LOCK_ID_FREE (bdb->bi_dbenv, locker );
863
864         if( v2refs ) ber_bvarray_free( v2refs );
865         if( realbase.bv_val ) ch_free( realbase.bv_val );
866
867         return rc;
868 }
869
870
871 static int base_candidate(
872         BackendDB       *be,
873         Entry   *e,
874         ID              *ids )
875 {
876 #ifdef NEW_LOGGING
877         LDAP_LOG ( OPERATION, ENTRY,
878                 "base_candidate: base: \"%s\" (0x%08lx)\n", e->e_dn, (long) e->e_id, 0);
879 #else
880         Debug(LDAP_DEBUG_ARGS, "base_candidates: base: \"%s\" (0x%08lx)\n",
881                 e->e_dn, (long) e->e_id, 0);
882 #endif
883
884         ids[0] = 1;
885         ids[1] = e->e_id;
886         return 0;
887 }
888
889 /* Look for "objectClass Present" in this filter.
890  * Also count depth of filter tree while we're at it.
891  */
892 static int oc_filter(
893         Filter *f,
894         int cur,
895         int *max
896 )
897 {
898         int rc = 0;
899
900         if( cur > *max ) *max = cur;
901
902         switch(f->f_choice) {
903         case LDAP_FILTER_PRESENT:
904                 if (f->f_desc == slap_schema.si_ad_objectClass) {
905                         rc = 1;
906                 }
907                 break;
908
909         case LDAP_FILTER_AND:
910         case LDAP_FILTER_OR:
911                 cur++;
912                 for (f=f->f_and; f; f=f->f_next) {
913                         (void) oc_filter(f, cur, max);
914                 }
915                 break;
916
917         default:
918                 break;
919         }
920         return rc;
921 }
922
923 static int search_candidates(
924         BackendDB *be,
925         Operation *op,
926         Entry *e,
927         Filter *filter,
928         int scope,
929         int deref,
930         ID      *ids )
931 {
932         int rc, depth = 1;
933         Filter          f, scopef, rf, xf;
934         ID              *stack;
935         AttributeAssertion aa_ref;
936 #ifdef BDB_SUBENTRIES
937         Filter  sf;
938         AttributeAssertion aa_subentry;
939 #endif
940 #ifdef BDB_ALIASES
941         Filter  af;
942         AttributeAssertion aa_alias;
943 #endif
944
945         /*
946          * This routine takes as input a filter (user-filter)
947          * and rewrites it as follows:
948          *      (&(scope=DN)[(objectClass=subentry)]
949          *              (|[(objectClass=referral)(objectClass=alias)](user-filter))
950          */
951
952 #ifdef NEW_LOGGING
953         LDAP_LOG ( OPERATION, ENTRY,
954                 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", 
955                 e->e_dn, (long) e->e_id, scope);
956 #else
957         Debug(LDAP_DEBUG_TRACE,
958                 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n",
959                 e->e_dn, (long) e->e_id, scope );
960 #endif
961
962         xf.f_or = filter;
963         xf.f_choice = LDAP_FILTER_OR;
964         xf.f_next = NULL;
965
966         /* If the user's filter uses objectClass=*,
967          * these clauses are redundant.
968          */
969         if (!oc_filter(filter, 1, &depth) && !get_subentries_visibility(op) ) {
970                 if( !get_manageDSAit(op) ) { /* match referrals */
971                         struct berval bv_ref = { sizeof("REFERRAL")-1, "REFERRAL" };
972                         rf.f_choice = LDAP_FILTER_EQUALITY;
973                         rf.f_ava = &aa_ref;
974                         rf.f_av_desc = slap_schema.si_ad_objectClass;
975                         rf.f_av_value = bv_ref;
976                         rf.f_next = xf.f_or;
977                         xf.f_or = &rf;
978                 }
979
980 #ifdef BDB_ALIASES
981                 if( deref & LDAP_DEREF_SEARCHING ) { /* match aliases */
982                         struct berval bv_alias = { sizeof("ALIAS")-1, "ALIAS" };
983                         af.f_choice = LDAP_FILTER_EQUALITY;
984                         af.f_ava = &aa_alias;
985                         af.f_av_desc = slap_schema.si_ad_objectClass;
986                         af.f_av_value = bv_alias;
987                         af.f_next = xf.f_or;
988                         xf.f_or = &af;
989                 }
990 #endif
991                 /* We added one of these clauses, filter depth increased */
992                 if( xf.f_or != filter ) depth++;
993         }
994
995         f.f_next = NULL;
996         f.f_choice = LDAP_FILTER_AND;
997         f.f_and = &scopef;
998         scopef.f_choice = scope == LDAP_SCOPE_SUBTREE
999                 ? SLAPD_FILTER_DN_SUBTREE
1000                 : SLAPD_FILTER_DN_ONE;
1001         scopef.f_dn = &e->e_nname;
1002         scopef.f_next = xf.f_or == filter ? filter : &xf ;
1003         /* Filter depth increased again, adding scope clause */
1004         depth++;
1005
1006 #ifdef BDB_SUBENTRIES
1007         if( get_subentries_visibility( op ) ) {
1008                 struct berval bv_subentry = { sizeof("SUBENTRY")-1, "SUBENTRY" };
1009                 sf.f_choice = LDAP_FILTER_EQUALITY;
1010                 sf.f_ava = &aa_subentry;
1011                 sf.f_av_desc = slap_schema.si_ad_objectClass;
1012                 sf.f_av_value = bv_subentry;
1013                 sf.f_next = scopef.f_next;
1014                 scopef.f_next = &sf;
1015         }
1016 #endif
1017
1018         /* Allocate IDL stack, plus 1 more for former tmp */
1019         stack = ch_malloc( (depth + 1) * BDB_IDL_UM_SIZE * sizeof( ID ) );
1020
1021         rc = bdb_filter_candidates( be, &f, ids, stack, stack+BDB_IDL_UM_SIZE );
1022
1023         ch_free( stack );
1024
1025         if( rc ) {
1026 #ifdef NEW_LOGGING
1027                 LDAP_LOG ( OPERATION, DETAIL1,
1028                         "bdb_search_candidates: failed (rc=%d)\n", rc, 0, 0  );
1029 #else
1030                 Debug(LDAP_DEBUG_TRACE,
1031                         "bdb_search_candidates: failed (rc=%d)\n",
1032                         rc, NULL, NULL );
1033 #endif
1034
1035         } else {
1036 #ifdef NEW_LOGGING
1037                 LDAP_LOG ( OPERATION, DETAIL1,
1038                         "bdb_search_candidates: id=%ld first=%ld last=%ld\n",
1039                         (long) ids[0], (long) BDB_IDL_FIRST(ids), 
1040                         (long) BDB_IDL_LAST(ids));
1041 #else
1042                 Debug(LDAP_DEBUG_TRACE,
1043                         "bdb_search_candidates: id=%ld first=%ld last=%ld\n",
1044                         (long) ids[0],
1045                         (long) BDB_IDL_FIRST(ids),
1046                         (long) BDB_IDL_LAST(ids) );
1047 #endif
1048         }
1049
1050         return rc;
1051 }
1052