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