]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/search.c
Patch: Delete the buggy surrogate parent code (ITS#1815)
[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,
311                         "bdb_search: no candidates\n", 0, 0, 0 );
312 #else
313                 Debug( LDAP_DEBUG_TRACE, "bdb_search: no candidates\n",
314                         0, 0, 0 );
315 #endif
316
317                 send_search_result( conn, op,
318                         LDAP_SUCCESS,
319                         NULL, NULL, NULL, NULL, 0 );
320
321                 rc = 1;
322                 goto done;
323         }
324
325         /* if not root and candidates exceed to-be-checked entries, abort */
326         if ( !isroot && limit->lms_s_unchecked != -1 ) {
327                 if ( BDB_IDL_N(candidates) > (unsigned) limit->lms_s_unchecked ) {
328                         send_search_result( conn, op, 
329                                         LDAP_ADMINLIMIT_EXCEEDED,
330                                         NULL, NULL, NULL, NULL, 0 );
331                         rc = 1;
332                         goto done;
333                 }
334         }
335
336 #ifdef SLAP_X_FILTER_HASSUBORDINATES
337         /*
338          * is hasSubordinates used in the filter ?
339          * FIXME: we may compute this directly when parsing the filter
340          */
341         filter_hasSubordinates = filter_has_subordinates( filter );
342 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
343
344 #ifdef LDAP_CLIENT_UPDATE
345         if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
346                 lcupf.f_choice = LDAP_FILTER_AND;
347                 lcupf.f_and = &csnfnot;
348                 lcupf.f_next = NULL;
349
350                 csnfnot.f_choice = LDAP_FILTER_NOT;
351                 csnfnot.f_not = &csnfeq;
352                 csnfnot.f_next = &csnfand;
353
354                 csnfeq.f_choice = LDAP_FILTER_EQUALITY;
355                 csnfeq.f_ava = &aa_eq;
356                 csnfeq.f_av_desc = slap_schema.si_ad_entryCSN;
357                 ber_dupbv( &csnfeq.f_av_value, &op->o_clientupdate_state );
358
359                 csnfand.f_choice = LDAP_FILTER_AND;
360                 csnfand.f_and = &csnfge;
361                 csnfand.f_next = NULL;
362
363                 csnfge.f_choice = LDAP_FILTER_GE;
364                 csnfge.f_ava = &aa_ge;
365                 csnfge.f_av_desc = slap_schema.si_ad_entryCSN;
366                 ber_dupbv( &csnfge.f_av_value, &op->o_clientupdate_state );
367                 csnfge.f_next = filter;
368         }
369 #endif /* LDAP_CLIENT_UPDATE */
370
371         for ( id = bdb_idl_first( candidates, &cursor );
372                 id != NOID;
373                 id = bdb_idl_next( candidates, &cursor ) )
374         {
375                 int             scopeok = 0;
376 #ifdef SLAP_X_FILTER_HASSUBORDINATES
377                 Attribute       *hasSubordinates = NULL;
378 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
379
380                 /* check for abandon */
381                 if ( op->o_abandon ) {
382                         rc = 0;
383                         goto done;
384                 }
385
386                 /* check time limit */
387                 if ( tlimit != -1 && slap_get_time() > stoptime ) {
388                         send_search_result( conn, op, rc = LDAP_TIMELIMIT_EXCEEDED,
389                                 NULL, NULL, v2refs, NULL, nentries );
390                         goto done;
391                 }
392
393 id2entry_retry:
394                 /* get the entry with reader lock */
395                 rc = bdb_id2entry_r( be, NULL, id, &e, locker, &lock );
396
397                 if (rc == LDAP_BUSY) {
398                         send_ldap_result( conn, op, rc=LDAP_BUSY,
399                                 NULL, "ldap server busy", NULL, NULL );
400                         goto done;
401
402                 } else if ( rc == DB_LOCK_DEADLOCK || rc == DB_LOCK_NOTGRANTED ) {
403                         goto id2entry_retry;    
404                 }
405
406                 if ( e == NULL ) {
407                         if( !BDB_IDL_IS_RANGE(candidates) ) {
408                                 /* only complain for non-range IDLs */
409 #ifdef NEW_LOGGING
410                                 LDAP_LOG ( OPERATION, RESULTS,
411                                         "bdb_search: candidate %ld not found\n", (long) id, 0, 0);
412 #else
413                                 Debug( LDAP_DEBUG_TRACE,
414                                         "bdb_search: candidate %ld not found\n",
415                                         (long) id, 0, 0 );
416 #endif
417                         }
418
419                         goto loop_continue;
420                 }
421
422 #ifdef BDB_SUBENTRIES
423                 if ( is_entry_subentry( e ) ) {
424                         if( scope != LDAP_SCOPE_BASE ) {
425                                 if(!get_subentries_visibility( op )) {
426                                         /* only subentries are visible */
427                                         goto loop_continue;
428                                 }
429
430                         } else if ( get_subentries( op ) &&
431                                 !get_subentries_visibility( op ))
432                         {
433                                 /* only subentries are visible */
434                                 goto loop_continue;
435                         }
436
437                 } else if ( get_subentries_visibility( op )) {
438                         /* only subentries are visible */
439                         goto loop_continue;
440                 }
441 #endif
442
443 #ifdef BDB_ALIASES
444                 if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) {
445                         Entry *matched;
446                         int err;
447                         const char *text;
448                         
449                         e = deref_entry_r( be, e, &err, &matched, &text );
450
451                         if( e == NULL ) {
452                                 e = matched;
453                                 goto loop_continue;
454                         }
455
456                         if( e->e_id == id ) {
457                                 /* circular loop */
458                                 goto loop_continue;
459                         }
460
461                         /* need to skip alias which deref into scope */
462                         if( scope & LDAP_SCOPE_ONELEVEL ) {
463                                 struct berval   pdn;
464                                 
465                                 dnParent( &e->e_nname, &pdn ):
466                                 if ( ber_bvcmp( pdn, &realbase ) ) {
467                                         goto loop_continue;
468                                 }
469
470                         } else if ( dnIsSuffix( &e->e_nname, &realbase ) ) {
471                                 /* alias is within scope */
472 #ifdef NEW_LOGGING
473                                 LDAP_LOG ( OPERATION, RESULTS,
474                                         "bdb_search: \"%s\" in subtree\n", e->edn, 0, 0);
475 #else
476                                 Debug( LDAP_DEBUG_TRACE,
477                                         "bdb_search: \"%s\" in subtree\n",
478                                         e->e_dn, 0, 0 );
479 #endif
480                                 goto loop_continue;
481                         }
482
483                         scopeok = 1;
484                 }
485 #endif
486
487                 /*
488                  * if it's a referral, add it to the list of referrals. only do
489                  * this for non-base searches, and don't check the filter
490                  * explicitly here since it's only a candidate anyway.
491                  */
492                 if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
493                         is_entry_referral( e ) )
494                 {
495                         struct berval   dn;
496
497                         /* check scope */
498                         if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
499                                 if ( !be_issuffix( be, &e->e_nname ) ) {
500                                         dnParent( &e->e_nname, &dn );
501                                         scopeok = dn_match( &dn, &realbase );
502                                 } else {
503                                         scopeok = (realbase.bv_len == 0);
504                                 }
505
506                         } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
507                                 scopeok = dnIsSuffix( &e->e_nname, &realbase );
508
509                         } else {
510                                 scopeok = 1;
511                         }
512
513                         if( scopeok ) {
514                                 BerVarray erefs = get_entry_referrals(
515                                         be, conn, op, e );
516                                 BerVarray refs = referral_rewrite( erefs,
517                                         &e->e_name, NULL,
518                                         scope == LDAP_SCOPE_SUBTREE
519                                                 ? LDAP_SCOPE_SUBTREE
520                                                 : LDAP_SCOPE_BASE );
521
522                                 send_search_reference( be, conn, op,
523                                         e, refs, NULL, &v2refs );
524
525                                 ber_bvarray_free( refs );
526
527                         } else {
528 #ifdef NEW_LOGGING
529                                 LDAP_LOG(OPERATION, DETAIL2, 
530                                         "bdb_search: candidate referral %ld scope not okay\n",
531                                         id, 0, 0 );
532 #else
533                                 Debug( LDAP_DEBUG_TRACE,
534                                         "bdb_search: candidate referral %ld scope not okay\n",
535                                         id, 0, 0 );
536 #endif
537                         }
538
539                         goto loop_continue;
540                 }
541
542 #ifdef SLAP_X_FILTER_HASSUBORDINATES
543                 /*
544                  * if hasSubordinates is used in the filter,
545                  * append it to the entry's attributes
546                  */
547                 if ( filter_hasSubordinates ) {
548                         int     hs;
549
550                         rc = bdb_hasSubordinates( be, conn, op, e, &hs);
551                         if ( rc != LDAP_SUCCESS ) {
552                                 goto loop_continue;
553                         }
554
555                         hasSubordinates = slap_operational_hasSubordinate(
556                                 hs == LDAP_COMPARE_TRUE );
557
558                         if ( hasSubordinates == NULL ) {
559                                 goto loop_continue;
560                         }
561
562                         hasSubordinates->a_next = e->e_attrs;
563                         e->e_attrs = hasSubordinates;
564                 }
565 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
566
567                 /* if it matches the filter and scope, send it */
568 #ifdef LDAP_CLIENT_UPDATE
569                 if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
570                         rc = test_filter( be, conn, op, e, &lcupf );
571                 } else
572 #endif /* LDAP_CLIENT_UPDATE */
573                 {
574                         rc = test_filter( be, conn, op, e, filter );
575                 }
576
577 #ifdef SLAP_X_FILTER_HASSUBORDINATES
578                 if ( hasSubordinates ) {
579                         /*
580                          * FIXME: this is fairly inefficient, because 
581                          * if hasSubordinates is among the required
582                          * attrs, it will be added again later;
583                          * maybe we should leave it and check
584                          * check later if it's already present,
585                          * if required
586                          */
587                         e->e_attrs = e->e_attrs->a_next;
588                         attr_free( hasSubordinates );
589                 }
590 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
591
592                 if ( rc == LDAP_COMPARE_TRUE ) {
593                         struct berval   dn;
594
595                         /* check scope */
596                         if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
597                                 if ( be_issuffix( be, &e->e_nname ) ) {
598                                         scopeok = (realbase.bv_len == 0);
599                                 } else {
600                                         dnParent( &e->e_nname, &dn );
601                                         scopeok = dn_match( &dn, &realbase );
602                                 }
603
604                         } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
605                                 scopeok = dnIsSuffix( &e->e_nname, &realbase );
606
607                         } else {
608                                 scopeok = 1;
609                         }
610
611                         if ( scopeok ) {
612                                 /* check size limit */
613                                 if ( --slimit == -1 ) {
614                                         bdb_cache_return_entry_r( bdb->bi_dbenv,
615                                                 &bdb->bi_cache, e, &lock );
616                                         e = NULL;
617                                         send_search_result( conn, op,
618                                                 rc = LDAP_SIZELIMIT_EXCEEDED, NULL, NULL,
619                                                 v2refs, NULL, nentries );
620                                         goto done;
621                                 }
622
623                                 if (e) {
624                                         int result;
625                                         
626 #if 0   /* noop is masked SLAP_CTRL_UPDATE */
627                                         if( op->o_noop ) {
628                                                 result = 0;
629                                         } else
630 #endif
631                                         {
632 #ifdef LDAP_CLIENT_UPDATE
633                                                 if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
634                                                         Attribute* a;
635                                                         int ret;
636                                                         int res;
637                                                         const char *text = NULL;
638                                                         LDAPControl *ctrls[2];
639                                                         struct berval *bv;
640
641                                                         BerElement *ber = ber_alloc_t( LBER_USE_DER );
642
643                                                         if ( ber == NULL ) {
644 #ifdef NEW_LOGGING
645                                                                 LDAP_LOG ( OPERATION, RESULTS, 
646                                                                         "bdb_search: ber_alloc_t failed\n",
647                                                                         0, 0, 0 );
648 #else
649                                                                 Debug( LDAP_DEBUG_TRACE,
650                                                                         "bdb_search: ber_alloc_t failed\n",
651                                                                         0, 0, 0 );
652 #endif
653                                                                 send_ldap_result( conn, op, rc=LDAP_OTHER,
654                                                                         NULL, "internal error", NULL, NULL );
655                                                                 goto done;
656                                                         }
657
658                                                         entry_count++;
659
660                                                         ctrls[0] = ch_malloc ( sizeof ( LDAPControl ) );
661                                                         ctrls[1] = NULL;
662
663                                                         if ( entry_count % op->o_clientupdate_interval == 0 ) {
664                                                                 /* Send cookie */
665                                                                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
666                                                                         AttributeDescription *desc = a->a_desc;
667                                                                         if ( desc == slap_schema.si_ad_entryCSN ) {
668                                                                                 ber_dupbv( &entrycsn_bv, &a->a_vals[0] );
669                                                                                 if ( latest_entrycsn_bv.bv_val == NULL ) {
670                                                                                         ber_dupbv( &latest_entrycsn_bv, &entrycsn_bv );
671                                                                                 } else {
672                                                                                         res = value_match( &ret, desc,
673                                                                                                 desc->ad_type->sat_ordering,
674                                                                                                 SLAP_MR_ASSERTION_SYNTAX_MATCH,
675                                                                                                 &entrycsn_bv, &latest_entrycsn_bv, &text );
676                                                                                         if ( res != LDAP_SUCCESS ) {
677                                                                                                 ret = 0;
678 #ifdef NEW_LOGGING
679                                                                                                 LDAP_LOG ( OPERATION, RESULTS, 
680                                                                                                         "bdb_search: value_match failed\n",
681                                                                                                         0, 0, 0 );
682 #else
683                                                                                                 Debug( LDAP_DEBUG_TRACE,
684                                                                                                         "bdb_search: value_match failed\n",
685                                                                                                         0, 0, 0 );
686 #endif
687                                                                                         }
688
689                                                                                         if ( ret > 0 ) {
690                                                                                                 ch_free( latest_entrycsn_bv.bv_val );
691                                                                                                 latest_entrycsn_bv.bv_val = NULL;
692                                                                                                 ber_dupbv( &latest_entrycsn_bv,
693                                                                                                         &entrycsn_bv );
694                                                                                         }
695                                                                                 }
696                                                                         }
697                                                                 }
698
699                                                                 ber_printf( ber,
700                                                                         "{bb{sON}N}",
701                                                                         SLAP_LCUP_STATE_UPDATE_FALSE,
702                                                                         SLAP_LCUP_ENTRY_DELETED_FALSE,
703                                                                         LCUP_COOKIE_OID, &entrycsn_bv );
704
705                                                                 ch_free( entrycsn_bv.bv_val );
706                                                                 entrycsn_bv.bv_val = NULL;
707
708                                                         } else {
709                                                                 /* Do not send cookie */
710                                                                 ber_printf( ber,
711                                                                         "{bbN}",
712                                                                         SLAP_LCUP_STATE_UPDATE_FALSE,
713                                                                         SLAP_LCUP_ENTRY_DELETED_FALSE );
714                                                         }
715
716                                                         ctrls[0]->ldctl_oid = LDAP_CONTROL_ENTRY_UPDATE;
717                                                         ctrls[0]->ldctl_iscritical = op->o_clientupdate;
718                                                         ret = ber_flatten( ber, &bv );
719
720                                                         if ( ret < 0 ) {
721 #ifdef NEW_LOGGING
722                                                                 LDAP_LOG ( OPERATION, RESULTS, 
723                                                                         "bdb_search: ber_flatten failed\n",
724                                                                         0, 0, 0 );
725 #else
726                                                                 Debug( LDAP_DEBUG_TRACE,
727                                                                         "bdb_search: ber_flatten failed\n",
728                                                                         0, 0, 0 );
729 #endif
730                                                                 send_ldap_result( conn, op, rc=LDAP_OTHER,
731                                                                         NULL, "internal error", NULL, NULL );
732                                                                 goto done;
733                                                         }
734
735                                                         ber_dupbv( &ctrls[0]->ldctl_value, bv );
736                                                         
737                                                         result = send_search_entry( be, conn, op,
738                                                                 e, attrs, attrsonly, ctrls);
739
740                                                         ch_free( ctrls[0]->ldctl_value.bv_val );
741                                                         ch_free( ctrls[0] );
742                                                         ber_free( ber, 1 );
743                                                         ber_bvfree( bv );
744                                                 } else
745 #endif /* LDAP_CLIENT_UPDATE */
746                                                 {
747                                                         result = send_search_entry( be, conn, op,
748                                                                 e, attrs, attrsonly, NULL);
749                                                 }
750                                         }
751
752                                         switch (result) {
753                                         case 0:         /* entry sent ok */
754                                                 nentries++;
755                                                 break;
756                                         case 1:         /* entry not sent */
757                                                 break;
758                                         case -1:        /* connection closed */
759                                                 bdb_cache_return_entry_r(bdb->bi_dbenv,
760                                                         &bdb->bi_cache, e, &lock);
761                                                 e = NULL;
762                                                 rc = LDAP_OTHER;
763                                                 goto done;
764                                         }
765                                 }
766                         } else {
767 #ifdef NEW_LOGGING
768                                 LDAP_LOG ( OPERATION, RESULTS,
769                                         "bdb_search: %ld scope not okay\n", (long) id, 0, 0);
770 #else
771                                 Debug( LDAP_DEBUG_TRACE,
772                                         "bdb_search: %ld scope not okay\n",
773                                         (long) id, 0, 0 );
774 #endif
775                         }
776                 } else {
777 #ifdef NEW_LOGGING
778                         LDAP_LOG ( OPERATION, RESULTS,
779                                 "bdb_search: %ld does match filter\n", (long) id, 0, 0);
780 #else
781                         Debug( LDAP_DEBUG_TRACE,
782                                 "bdb_search: %ld does match filter\n",
783                                 (long) id, 0, 0 );
784 #endif
785                 }
786
787 loop_continue:
788                 if( e != NULL ) {
789                         /* free reader lock */
790                         bdb_cache_return_entry_r( bdb->bi_dbenv,
791                                 &bdb->bi_cache, e , &lock);
792                         e = NULL;
793                 }
794
795                 ldap_pvt_thread_yield();
796         }
797
798 #ifdef LDAP_CLIENT_UPDATE
799         if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
800                 int ret;
801                 LDAPControl *ctrls[2];
802                 BerElement *ber = ber_alloc_t( LBER_USE_DER );
803                 struct berval *bv;
804
805                 if ( ber == NULL ) {
806 #ifdef NEW_LOGGING
807                         LDAP_LOG ( OPERATION, RESULTS, 
808                                 "bdb_search: ber_alloc_t failed\n", 0, 0, 0 );
809 #else
810                         Debug( LDAP_DEBUG_TRACE, "bdb_search: ber_alloc_t failed\n",
811                                 0, 0, 0 );
812 #endif
813                         send_ldap_result( conn, op, rc=LDAP_OTHER,
814                                 NULL, "internal error", NULL, NULL );
815                         goto done;
816                 }
817
818                 ctrls[0] = ch_malloc ( sizeof ( LDAPControl ) );
819                 ctrls[1] = NULL;
820
821                 ber_printf( ber, "{sO", LCUP_COOKIE_OID, &latest_entrycsn_bv );
822                 ber_printf( ber, "N}" );
823
824                 ctrls[0]->ldctl_oid = LDAP_CONTROL_CLIENT_UPDATE_DONE;
825                 ctrls[0]->ldctl_iscritical = op->o_clientupdate;
826                 ret = ber_flatten( ber, &bv );
827
828                 if ( ret < 0 ) {
829 #ifdef NEW_LOGGING
830                         LDAP_LOG ( OPERATION, RESULTS, 
831                                 "bdb_search: ber_flatten failed\n", 0, 0, 0 );
832 #else
833                         Debug( LDAP_DEBUG_TRACE, "bdb_search: ber_flatten failed\n",
834                                 0, 0, 0 );
835 #endif
836                         send_ldap_result( conn, op, rc=LDAP_OTHER,
837                                 NULL, "internal error", NULL, NULL );
838                         goto done;
839                 }
840
841                 ber_dupbv( &ctrls[0]->ldctl_value, bv );
842
843                 send_search_result( conn, op,
844                         v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
845                         NULL, NULL, v2refs, ctrls, nentries );
846
847                 ch_free( latest_entrycsn_bv.bv_val );
848                 latest_entrycsn_bv.bv_val = NULL;
849                 ch_free( ctrls[0]->ldctl_value.bv_val );
850                 ch_free( ctrls[0] );
851                 ber_free( ber, 1 );
852                 ber_bvfree( bv );
853         } else
854 #endif /* LDAP_CLIENT_UPDATE */
855         {
856                 send_search_result( conn, op,
857                         v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
858                         NULL, NULL, v2refs, NULL, nentries );
859         }
860
861         rc = 0;
862
863 done:
864         if( e != NULL ) {
865                 /* free reader lock */
866                 bdb_cache_return_entry_r ( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
867         }
868
869 #ifdef LDAP_CLIENT_UDATE
870         if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
871                 if ( csnfeq.f_ava != NULL && csnfeq.f_av_value.bv_val != NULL ) {
872                         ch_free( csnfeq.f_av_value.bv_val );
873                 }
874         
875                 if ( csnfge.f_ava != NULL && csnfge.f_av_value.bv_val != NULL ) {
876                         ch_free( csnfge.f_av_value.bv_val );
877                 }
878         }
879 #endif /* LDAP_CLIENT_UPDATE */
880
881         LOCK_ID_FREE (bdb->bi_dbenv, locker );
882
883         if( v2refs ) ber_bvarray_free( v2refs );
884         if( realbase.bv_val ) ch_free( realbase.bv_val );
885
886         return rc;
887 }
888
889
890 static int base_candidate(
891         BackendDB       *be,
892         Entry   *e,
893         ID              *ids )
894 {
895 #ifdef NEW_LOGGING
896         LDAP_LOG ( OPERATION, ENTRY,
897                 "base_candidate: base: \"%s\" (0x%08lx)\n", e->e_dn, (long) e->e_id, 0);
898 #else
899         Debug(LDAP_DEBUG_ARGS, "base_candidates: base: \"%s\" (0x%08lx)\n",
900                 e->e_dn, (long) e->e_id, 0);
901 #endif
902
903         ids[0] = 1;
904         ids[1] = e->e_id;
905         return 0;
906 }
907
908 /* Look for "objectClass Present" in this filter.
909  * Also count depth of filter tree while we're at it.
910  */
911 static int oc_filter(
912         Filter *f,
913         int cur,
914         int *max
915 )
916 {
917         int rc = 0;
918
919         if( cur > *max ) *max = cur;
920
921         switch(f->f_choice) {
922         case LDAP_FILTER_PRESENT:
923                 if (f->f_desc == slap_schema.si_ad_objectClass) {
924                         rc = 1;
925                 }
926                 break;
927
928         case LDAP_FILTER_AND:
929         case LDAP_FILTER_OR:
930                 cur++;
931                 for (f=f->f_and; f; f=f->f_next) {
932                         (void) oc_filter(f, cur, max);
933                 }
934                 break;
935
936         default:
937                 break;
938         }
939         return rc;
940 }
941
942 static int search_candidates(
943         BackendDB *be,
944         Operation *op,
945         Entry *e,
946         Filter *filter,
947         int scope,
948         int deref,
949         ID      *ids )
950 {
951         int rc, depth = 1;
952         Filter          f, scopef, rf, xf;
953         ID              *stack;
954         AttributeAssertion aa_ref;
955 #ifdef BDB_SUBENTRIES
956         Filter  sf;
957         AttributeAssertion aa_subentry;
958 #endif
959 #ifdef BDB_ALIASES
960         Filter  af;
961         AttributeAssertion aa_alias;
962 #endif
963
964         /*
965          * This routine takes as input a filter (user-filter)
966          * and rewrites it as follows:
967          *      (&(scope=DN)[(objectClass=subentry)]
968          *              (|[(objectClass=referral)(objectClass=alias)](user-filter))
969          */
970
971 #ifdef NEW_LOGGING
972         LDAP_LOG ( OPERATION, ENTRY,
973                 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", 
974                 e->e_dn, (long) e->e_id, scope);
975 #else
976         Debug(LDAP_DEBUG_TRACE,
977                 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n",
978                 e->e_dn, (long) e->e_id, scope );
979 #endif
980
981         xf.f_or = filter;
982         xf.f_choice = LDAP_FILTER_OR;
983         xf.f_next = NULL;
984
985         /* If the user's filter uses objectClass=*,
986          * these clauses are redundant.
987          */
988         if (!oc_filter(filter, 1, &depth) && !get_subentries_visibility(op) ) {
989                 if( !get_manageDSAit(op) ) { /* match referrals */
990                         struct berval bv_ref = { sizeof("REFERRAL")-1, "REFERRAL" };
991                         rf.f_choice = LDAP_FILTER_EQUALITY;
992                         rf.f_ava = &aa_ref;
993                         rf.f_av_desc = slap_schema.si_ad_objectClass;
994                         rf.f_av_value = bv_ref;
995                         rf.f_next = xf.f_or;
996                         xf.f_or = &rf;
997                 }
998
999 #ifdef BDB_ALIASES
1000                 if( deref & LDAP_DEREF_SEARCHING ) { /* match aliases */
1001                         struct berval bv_alias = { sizeof("ALIAS")-1, "ALIAS" };
1002                         af.f_choice = LDAP_FILTER_EQUALITY;
1003                         af.f_ava = &aa_alias;
1004                         af.f_av_desc = slap_schema.si_ad_objectClass;
1005                         af.f_av_value = bv_alias;
1006                         af.f_next = xf.f_or;
1007                         xf.f_or = &af;
1008                 }
1009 #endif
1010                 /* We added one of these clauses, filter depth increased */
1011                 if( xf.f_or != filter ) depth++;
1012         }
1013
1014         f.f_next = NULL;
1015         f.f_choice = LDAP_FILTER_AND;
1016         f.f_and = &scopef;
1017         scopef.f_choice = scope == LDAP_SCOPE_SUBTREE
1018                 ? SLAPD_FILTER_DN_SUBTREE
1019                 : SLAPD_FILTER_DN_ONE;
1020         scopef.f_dn = &e->e_nname;
1021         scopef.f_next = xf.f_or == filter ? filter : &xf ;
1022         /* Filter depth increased again, adding scope clause */
1023         depth++;
1024
1025 #ifdef BDB_SUBENTRIES
1026         if( get_subentries_visibility( op ) ) {
1027                 struct berval bv_subentry = { sizeof("SUBENTRY")-1, "SUBENTRY" };
1028                 sf.f_choice = LDAP_FILTER_EQUALITY;
1029                 sf.f_ava = &aa_subentry;
1030                 sf.f_av_desc = slap_schema.si_ad_objectClass;
1031                 sf.f_av_value = bv_subentry;
1032                 sf.f_next = scopef.f_next;
1033                 scopef.f_next = &sf;
1034         }
1035 #endif
1036
1037         /* Allocate IDL stack, plus 1 more for former tmp */
1038         stack = ch_malloc( (depth + 1) * BDB_IDL_UM_SIZE * sizeof( ID ) );
1039
1040         rc = bdb_filter_candidates( be, &f, ids, stack, stack+BDB_IDL_UM_SIZE );
1041
1042         ch_free( stack );
1043
1044         if( rc ) {
1045 #ifdef NEW_LOGGING
1046                 LDAP_LOG ( OPERATION, DETAIL1,
1047                         "bdb_search_candidates: failed (rc=%d)\n", rc, 0, 0  );
1048 #else
1049                 Debug(LDAP_DEBUG_TRACE,
1050                         "bdb_search_candidates: failed (rc=%d)\n",
1051                         rc, NULL, NULL );
1052 #endif
1053
1054         } else {
1055 #ifdef NEW_LOGGING
1056                 LDAP_LOG ( OPERATION, DETAIL1,
1057                         "bdb_search_candidates: id=%ld first=%ld last=%ld\n",
1058                         (long) ids[0], (long) BDB_IDL_FIRST(ids), 
1059                         (long) BDB_IDL_LAST(ids));
1060 #else
1061                 Debug(LDAP_DEBUG_TRACE,
1062                         "bdb_search_candidates: id=%ld first=%ld last=%ld\n",
1063                         (long) ids[0],
1064                         (long) BDB_IDL_FIRST(ids),
1065                         (long) BDB_IDL_LAST(ids) );
1066 #endif
1067         }
1068
1069         return rc;
1070 }
1071