]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/search.c
62fdb4521a5be1b4d74eba46c79108c9eaa53d54
[openldap] / servers / slapd / back-ldbm / search.c
1 /* search.c - ldbm backend search function */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/string.h>
13 #include <ac/socket.h>
14
15 #include "slap.h"
16 #include "back-ldbm.h"
17 #include "proto-back-ldbm.h"
18
19 static ID_BLOCK *base_candidate(
20         Backend *be, Entry *e );
21
22 static ID_BLOCK *search_candidates(
23         Backend *be, Entry *e, Filter *filter,
24         int scope, int deref, int manageDSAit );
25
26
27 int
28 ldbm_back_search(
29     Operation   *op,
30     SlapReply   *rs )
31 {
32         struct ldbminfo *li = (struct ldbminfo *) op->o_bd->be_private;
33         int             rc, err;
34         const char *text = NULL;
35         time_t          stoptime;
36         ID_BLOCK                *candidates;
37         ID              id, cursor;
38         Entry           *e;
39         Entry   *matched = NULL;
40         struct berval   realbase = { 0, NULL };
41         int             manageDSAit = get_manageDSAit( op );
42         int             cscope = LDAP_SCOPE_DEFAULT;
43         int             nentries = 0;
44
45 #ifdef LDAP_CACHING
46         Entry           cache_base_entry; 
47 #endif /* LDAP_CACHING */
48
49         struct slap_limits_set *limit = NULL;
50         int isroot = 0;
51                 
52 #ifdef NEW_LOGGING
53         LDAP_LOG( BACK_LDBM, ENTRY, "ldbm_back_search: enter\n", 0, 0, 0 );
54 #else
55         Debug(LDAP_DEBUG_TRACE, "=> ldbm_back_search\n", 0, 0, 0);
56 #endif
57
58         /* grab giant lock for reading */
59         ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);
60
61 #ifndef LDAP_CACHING
62         if ( op->o_req_ndn.bv_len == 0 ) {
63                 /* DIT root special case */
64                 e = (Entry *) &slap_entry_root;
65
66                 /* need normalized dn below */
67                 ber_dupbv( &realbase, &e->e_nname );
68
69 #else /* LDAP_CACHING */
70         if ( op->o_caching_on || op->o_req_ndn.bv_len == 0 ) {
71                 if (op->o_req_ndn.bv_len == 0) {
72                     e = (Entry *) &slap_entry_root;
73                     /* need normalized dn below */
74                     ber_dupbv( &realbase, &e->e_nname );
75                 } else {
76                         if ((op->oq_search.rs_scope == LDAP_SCOPE_BASE) 
77                                         && (e = dn2entry_r( op->o_bd, &op->o_req_ndn, &matched )))
78                         {
79                                 candidates = base_candidate(op->o_bd, e);
80                                 cache_return_entry_r( &li->li_cache, e );
81                                 goto searchit;
82                         }
83                         cache_base_entry.e_nname = op->o_req_ndn;
84                         e = &cache_base_entry;
85                 }
86 #endif /* LDAP_CACHING */
87
88                 candidates = search_candidates( op->o_bd, e, op->oq_search.rs_filter,
89                                 op->oq_search.rs_scope, op->oq_search.rs_deref,
90                                 manageDSAit || get_domainScope(op) );
91
92                 goto searchit;
93                 
94         } else if ( op->oq_search.rs_deref & LDAP_DEREF_FINDING ) {
95                 /* deref dn and get entry with reader lock */
96                 e = deref_dn_r( op->o_bd, &op->o_req_ndn, &rs->sr_err, &matched, &rs->sr_text );
97
98                 if( rs->sr_err == LDAP_NO_SUCH_OBJECT ) rs->sr_err = LDAP_REFERRAL;
99
100         } else {
101                 /* get entry with reader lock */
102                 e = dn2entry_r( op->o_bd, &op->o_req_ndn, &matched );
103                 rs->sr_err = e != NULL ? LDAP_SUCCESS : LDAP_REFERRAL;
104                 rs->sr_text = NULL;
105         }
106
107         if ( e == NULL ) {
108                 struct berval matched_dn = { 0, NULL };
109
110                 if ( matched != NULL ) {
111                         BerVarray erefs;
112                         ber_dupbv( &matched_dn, &matched->e_name );
113
114                         erefs = is_entry_referral( matched )
115                                 ? get_entry_referrals( op, matched )
116                                 : NULL;
117
118                         cache_return_entry_r( &li->li_cache, matched );
119
120                         if( erefs ) {
121                                 rs->sr_ref = referral_rewrite( erefs, &matched_dn,
122                                         &op->o_req_dn, op->oq_search.rs_scope );
123
124                                 ber_bvarray_free( erefs );
125                         }
126
127                 } else {
128                         rs->sr_ref = referral_rewrite( default_referral,
129                                 NULL, &op->o_req_dn, op->oq_search.rs_scope );
130                 }
131
132                 ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
133
134                 rs->sr_matched = matched_dn.bv_val;
135                 send_ldap_result( op, rs );
136
137                 ber_bvarray_free( rs->sr_ref );
138                 ber_memfree( matched_dn.bv_val );
139                 return 1;
140         }
141
142         if (!manageDSAit && is_entry_referral( e ) ) {
143                 /* entry is a referral, don't allow add */
144                 struct berval matched_dn;
145                 BerVarray erefs;
146
147                 ber_dupbv( &matched_dn, &e->e_name );
148                 erefs = get_entry_referrals( op, e );
149                 rs->sr_ref = NULL;
150
151                 cache_return_entry_r( &li->li_cache, e );
152                 ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
153
154 #ifdef NEW_LOGGING
155                 LDAP_LOG( BACK_LDBM, INFO,
156                         "ldbm_search: entry (%s) is a referral.\n",
157                         e->e_dn, 0, 0 );
158 #else
159                 Debug( LDAP_DEBUG_TRACE,
160                         "ldbm_search: entry is referral\n",
161                         0, 0, 0 );
162 #endif
163
164                 if( erefs ) {
165                         rs->sr_ref = referral_rewrite( erefs, &matched_dn,
166                                 &op->o_req_dn, op->oq_search.rs_scope );
167
168                         ber_bvarray_free( erefs );
169                 }
170
171                 rs->sr_matched = matched_dn.bv_val;
172                 if( rs->sr_ref ) {
173                         rs->sr_err = LDAP_REFERRAL;
174                         send_ldap_result( op, rs );
175                         ber_bvarray_free( rs->sr_ref );
176
177                 } else {
178                         send_ldap_error( op, rs, LDAP_OTHER,
179                         "bad referral object" );
180                 }
181
182                 ber_memfree( matched_dn.bv_val );
183                 return 1;
184         }
185
186         if ( is_entry_alias( e ) ) {
187                 /* don't deref */
188                 op->oq_search.rs_deref = LDAP_DEREF_NEVER;
189         }
190
191         if ( op->oq_search.rs_scope == LDAP_SCOPE_BASE ) {
192                 cscope = LDAP_SCOPE_BASE;
193                 candidates = base_candidate( op->o_bd, e );
194
195         } else {
196                 cscope = ( op->oq_search.rs_scope != LDAP_SCOPE_SUBTREE )
197                         ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE;
198                 candidates = search_candidates( op->o_bd, e, op->oq_search.rs_filter,
199                     op->oq_search.rs_scope, op->oq_search.rs_deref, manageDSAit );
200         }
201
202         /* need normalized dn below */
203         ber_dupbv( &realbase, &e->e_nname );
204
205         cache_return_entry_r( &li->li_cache, e );
206
207 searchit:
208         if ( candidates == NULL ) {
209                 /* no candidates */
210 #ifdef NEW_LOGGING
211                 LDAP_LOG( BACK_LDBM, INFO,
212                         "ldbm_search: no candidates\n" , 0, 0, 0);
213 #else
214                 Debug( LDAP_DEBUG_TRACE, "ldbm_search: no candidates\n",
215                         0, 0, 0 );
216 #endif
217 #ifdef LDAP_CACHING
218                 if ( op->o_caching_on ) {
219                         ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
220                 }
221 #endif /* LDAP_CACHING */
222
223                 rs->sr_err = LDAP_SUCCESS;
224                 send_search_result( op, rs );
225
226 #ifdef LDAP_CACHING
227                 if ( op->o_caching_on ) {
228                         ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);
229                 }
230 #endif /* LDAP_CACHING */
231
232                 rc = 1;
233                 goto done;
234         }
235
236         /* if not root, get appropriate limits */
237 #ifndef LDAP_CACHING
238         if ( be_isroot( op->o_bd, &op->o_ndn ) )
239 #else /* LDAP_CACHING */
240         if ( op->o_caching_on || be_isroot( op->o_bd, &op->o_ndn ) )
241 #endif /* LDAP_CACHING */
242         {
243                 /*
244                  * FIXME: I'd consider this dangerous if someone
245                  * uses isroot for anything but handling limits
246                  */
247                 isroot = 1;
248         } else {
249                 ( void ) get_limits( op->o_bd, &op->o_ndn, &limit );
250         }
251
252         /* if candidates exceed to-be-checked entries, abort */
253         if ( !isroot && limit->lms_s_unchecked != -1 ) {
254                 if ( ID_BLOCK_NIDS( candidates ) > (unsigned) limit->lms_s_unchecked ) {
255                         send_ldap_error( op, rs, LDAP_ADMINLIMIT_EXCEEDED,
256                                         NULL );
257                         rc = 0;
258                         goto done;
259                 }
260         }
261         
262         /* if root an no specific limit is required, allow unlimited search */
263         if ( isroot ) {
264                 if ( op->oq_search.rs_tlimit == 0 ) {
265                         op->oq_search.rs_tlimit = -1;
266                 }
267
268                 if ( op->oq_search.rs_slimit == 0 ) {
269                         op->oq_search.rs_slimit = -1;
270                 }
271
272         } else {
273                 /* if no limit is required, use soft limit */
274                 if ( op->oq_search.rs_tlimit <= 0 ) {
275                         op->oq_search.rs_tlimit = limit->lms_t_soft;
276                 
277                 /* if requested limit higher than hard limit, abort */
278                 } else if ( op->oq_search.rs_tlimit > limit->lms_t_hard ) {
279                         /* no hard limit means use soft instead */
280                         if ( limit->lms_t_hard == 0
281                                         && limit->lms_t_soft > -1
282                                         && op->oq_search.rs_tlimit > limit->lms_t_soft ) {
283                                 op->oq_search.rs_tlimit = limit->lms_t_soft;
284                         
285                         /* positive hard limit means abort */
286                         } else if ( limit->lms_t_hard > 0 ) {
287                                 send_ldap_error( op, rs,
288                                                 LDAP_ADMINLIMIT_EXCEEDED,
289                                                 NULL );
290                                 rc = 0; 
291                                 goto done;
292                         }
293
294                         /* negative hard limit means no limit */
295                 }
296
297                 /* if no limit is required, use soft limit */
298                 if ( op->oq_search.rs_slimit <= 0 ) {
299                         op->oq_search.rs_slimit = limit->lms_s_soft;
300
301                 /* if requested limit higher than hard limit, abort */
302                 } else if ( op->oq_search.rs_slimit > limit->lms_s_hard ) {
303                         /* no hard limit means use soft instead */
304                         if ( limit->lms_s_hard == 0
305                                         && limit->lms_s_soft > -1
306                                         && op->oq_search.rs_slimit > limit->lms_s_soft ) {
307                                 op->oq_search.rs_slimit = limit->lms_s_soft;
308
309                         /* positive hard limit means abort */
310                         } else if ( limit->lms_s_hard > 0 ) {
311                                 send_ldap_error( op, rs,
312                                                 LDAP_ADMINLIMIT_EXCEEDED,
313                                                 NULL );
314                                 rc = 0;
315                                 goto done;
316                         }
317
318                         /* negative hard limit means no limit */
319                 }
320         }
321
322         /* compute it anyway; root does not use it */
323         stoptime = op->o_time + op->oq_search.rs_tlimit;
324         rs->sr_attrs = op->oq_search.rs_attrs;
325
326         for ( id = idl_firstid( candidates, &cursor ); id != NOID;
327             id = idl_nextid( candidates, &cursor ) )
328         {
329                 int scopeok = 0;
330                 int result = 0;
331
332                 /* check for abandon */
333                 if ( op->o_abandon ) {
334                         rc = 0;
335                         goto done;
336                 }
337
338                 /* check time limit */
339                 if ( op->oq_search.rs_tlimit != -1 && slap_get_time() > stoptime ) {
340                         rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
341                         rs->sr_nentries = nentries;
342                         send_search_result( op, rs );
343                         rc = 0;
344                         goto done;
345                 }
346
347                 /* get the entry with reader lock */
348                 e = id2entry_r( op->o_bd, id );
349
350                 if ( e == NULL ) {
351 #ifdef NEW_LOGGING
352                         LDAP_LOG( BACK_LDBM, INFO,
353                                 "ldbm_search: candidate %ld not found.\n", id, 0, 0 );
354 #else
355                         Debug( LDAP_DEBUG_TRACE,
356                                 "ldbm_search: candidate %ld not found\n",
357                                 id, 0, 0 );
358 #endif
359
360                         goto loop_continue;
361                 }
362
363                 rs->sr_entry = e;
364 #ifdef LDAP_CACHING
365                 if ( !op->o_caching_on ) {
366 #endif /* LDAP_CACHING */
367
368                 if ( op->oq_search.rs_deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) {
369                         Entry *matched;
370                         int err;
371                         const char *text;
372                         
373                         e = deref_entry_r( op->o_bd, e, &err, &matched, &text );
374
375                         if( e == NULL ) {
376                                 e = matched;
377                                 goto loop_continue;
378                         }
379
380                         if( e->e_id == id ) {
381                                 /* circular loop */
382                                 goto loop_continue;
383                         }
384
385                         /* need to skip alias which deref into scope */
386                         if( op->oq_search.rs_scope & LDAP_SCOPE_ONELEVEL ) {
387                                 struct berval pdn;
388                                 dnParent( &e->e_nname, &pdn );
389                                 if ( ber_bvcmp( &pdn, &realbase ) ) {
390                                         goto loop_continue;
391                                 }
392
393                         } else if ( dnIsSuffix( &e->e_nname, &realbase ) ) {
394                                 /* alias is within scope */
395 #ifdef NEW_LOGGING
396                                 LDAP_LOG( BACK_LDBM, DETAIL1,
397                                         "ldbm_search: alias \"%s\" in subtree\n", e->e_dn, 0, 0 );
398 #else
399                                 Debug( LDAP_DEBUG_TRACE,
400                                         "ldbm_search: alias \"%s\" in subtree\n",
401                                         e->e_dn, 0, 0 );
402 #endif
403
404                                 goto loop_continue;
405                         }
406
407                         rs->sr_entry = e;
408
409                         scopeok = 1;
410                 }
411
412                 /*
413                  * if it's a referral, add it to the list of referrals. only do
414                  * this for non-base searches, and don't check the filter
415                  * explicitly here since it's only a candidate anyway.
416                  */
417                 if ( !manageDSAit && op->oq_search.rs_scope != LDAP_SCOPE_BASE &&
418                         is_entry_referral( e ) )
419                 {
420                         struct berval   dn;
421
422                         /* check scope */
423                         if ( !scopeok && op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL ) {
424                                 if ( !be_issuffix( op->o_bd, &e->e_nname ) ) {
425                                         dnParent( &e->e_nname, &dn );
426                                         scopeok = dn_match( &dn, &realbase );
427                                 } else {
428                                         scopeok = (realbase.bv_len == 0);
429                                 }
430
431                         } else if ( !scopeok && op->oq_search.rs_scope == LDAP_SCOPE_SUBTREE ) {
432                                 scopeok = dnIsSuffix( &e->e_nname, &realbase );
433
434                         } else {
435                                 scopeok = 1;
436                         }
437
438                         if( scopeok ) {
439                                 BerVarray erefs = get_entry_referrals( op, e );
440                                 rs->sr_ref = referral_rewrite( erefs,
441                                         &e->e_name, NULL,
442                                         op->oq_search.rs_scope == LDAP_SCOPE_SUBTREE
443                                                 ? LDAP_SCOPE_SUBTREE
444                                                 : LDAP_SCOPE_BASE );
445
446                                 send_search_reference( op, rs );
447
448                                 ber_bvarray_free( rs->sr_ref );
449                                 rs->sr_ref = NULL;
450
451                         } else {
452 #ifdef NEW_LOGGING
453                                 LDAP_LOG( BACK_LDBM, DETAIL2,
454                                         "ldbm_search: candidate referral %ld scope not okay\n",
455                                         id, 0, 0 );
456 #else
457                                 Debug( LDAP_DEBUG_TRACE,
458                                         "ldbm_search: candidate referral %ld scope not okay\n",
459                                         id, 0, 0 );
460 #endif
461                         }
462
463                         goto loop_continue;
464                 }
465
466 #ifdef LDAP_CACHING
467                 }
468 #endif /* LDAP_CACHING */
469
470                 /* if it matches the filter and scope, send it */
471                 result = test_filter( op, e, op->oq_search.rs_filter );
472
473                 if ( result == LDAP_COMPARE_TRUE ) {
474                         struct berval   dn;
475
476                         /* check scope */
477                         if ( !scopeok && op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL ) {
478                                 if ( !be_issuffix( op->o_bd, &e->e_nname ) ) {
479                                         dnParent( &e->e_nname, &dn );
480                                         scopeok = dn_match( &dn, &realbase );
481                                 } else {
482                                         scopeok = (realbase.bv_len == 0);
483                                 }
484
485                         } else if ( !scopeok && op->oq_search.rs_scope == LDAP_SCOPE_SUBTREE ) {
486                                 scopeok = dnIsSuffix( &e->e_nname, &realbase );
487
488                         } else {
489                                 scopeok = 1;
490                         }
491
492                         if ( scopeok ) {
493                                 /* check size limit */
494                                 if ( --op->oq_search.rs_slimit == -1 ) {
495                                         cache_return_entry_r( &li->li_cache, e );
496                                         rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
497                                         rs->sr_nentries = nentries;
498                                         send_search_result( op, rs );
499                                         rc = 0;
500                                         goto done;
501                                 }
502
503                                 if (e) {
504
505 #ifdef LDAP_CACHING
506                                         if ( op->o_caching_on ) {
507                                                 ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
508                                                 cache_return_entry_r( &li->li_cache, e );
509                                         }
510 #endif /* LDAP_CACHING */
511
512                                         result = send_search_entry( op, rs );
513
514 #ifdef LDAP_CACHING
515                                         if ( op->o_caching_on ) {
516                                                 ldap_pvt_thread_rdwr_rlock( &li->li_giant_rwlock );
517                                         }
518 #endif /* LDAP_CACHING */
519
520
521                                         switch (result) {
522                                         case 0:         /* entry sent ok */
523                                                 nentries++;
524                                                 break;
525                                         case 1:         /* entry not sent */
526                                                 break;
527                                         case -1:        /* connection closed */
528                                                 cache_return_entry_r( &li->li_cache, e );
529                                                 rc = 0;
530                                                 goto done;
531                                         }
532                                 }
533                         } else {
534 #ifdef NEW_LOGGING
535                                 LDAP_LOG( BACK_LDBM, DETAIL2,
536                                         "ldbm_search: candidate entry %ld scope not okay\n", 
537                                         id, 0, 0 );
538 #else
539                                 Debug( LDAP_DEBUG_TRACE,
540                                         "ldbm_search: candidate entry %ld scope not okay\n",
541                                         id, 0, 0 );
542 #endif
543                         }
544
545                 } else {
546 #ifdef NEW_LOGGING
547                         LDAP_LOG( BACK_LDBM, DETAIL2,
548                                 "ldbm_search: candidate entry %ld does not match filter\n", 
549                                 id, 0, 0 );
550 #else
551                         Debug( LDAP_DEBUG_TRACE,
552                                 "ldbm_search: candidate entry %ld does not match filter\n",
553                                 id, 0, 0 );
554 #endif
555                 }
556
557 loop_continue:
558                 if( e != NULL ) {
559                         /* free reader lock */
560 #ifndef LDAP_CACHING
561                         cache_return_entry_r( &li->li_cache, e );
562 #else /* LDAP_CACHING */
563                         if ( !op->o_caching_on ) {
564                                 cache_return_entry_r( &li->li_cache, e );
565                         }
566 #endif /* LDAP_CACHING */
567                 }
568
569                 ldap_pvt_thread_yield();
570         }
571
572         rs->sr_err = rs->sr_v2ref ? LDAP_REFERRAL : LDAP_SUCCESS;
573         rs->sr_ref = rs->sr_v2ref;
574         rs->sr_nentries = nentries;
575         send_search_result( op, rs );
576
577         rc = 0;
578
579 done:
580         ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
581
582         if( candidates != NULL )
583                 idl_free( candidates );
584
585         if( rs->sr_v2ref ) ber_bvarray_free( rs->sr_v2ref );
586         if( realbase.bv_val ) free( realbase.bv_val );
587
588         return rc;
589 }
590
591 static ID_BLOCK *
592 base_candidate(
593     Backend     *be,
594         Entry   *e )
595 {
596         ID_BLOCK                *idl;
597
598 #ifdef NEW_LOGGING
599         LDAP_LOG( BACK_LDBM, ENTRY, "base_candidate: base (%s)\n", e->e_dn, 0, 0 );
600 #else
601         Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n",
602                 e->e_dn, 0, 0);
603 #endif
604
605
606         idl = idl_alloc( 1 );
607         idl_insert( &idl, e->e_id, 1 );
608
609         return( idl );
610 }
611
612 static ID_BLOCK *
613 search_candidates(
614     Backend     *be,
615     Entry       *e,
616     Filter      *filter,
617     int         scope,
618         int             deref,
619         int             manageDSAit )
620 {
621         ID_BLOCK                *candidates;
622         Filter          f, fand, rf, af, xf;
623     AttributeAssertion aa_ref, aa_alias;
624         struct berval bv_ref = { sizeof("referral")-1, "referral" };
625         struct berval bv_alias = { sizeof("alias")-1, "alias" };
626
627 #ifdef NEW_LOGGING
628         LDAP_LOG( BACK_LDBM, DETAIL1,
629                    "search_candidates: base (%s) scope %d deref %d\n",
630                    e->e_ndn, scope, deref );
631 #else
632         Debug(LDAP_DEBUG_TRACE,
633                 "search_candidates: base=\"%s\" s=%d d=%d\n",
634                 e->e_ndn, scope, deref );
635 #endif
636
637
638         xf.f_or = filter;
639         xf.f_choice = LDAP_FILTER_OR;
640         xf.f_next = NULL;
641
642         if( !manageDSAit ) {
643                 /* match referrals */
644                 rf.f_choice = LDAP_FILTER_EQUALITY;
645                 rf.f_ava = &aa_ref;
646                 rf.f_av_desc = slap_schema.si_ad_objectClass;
647                 rf.f_av_value = bv_ref;
648                 rf.f_next = xf.f_or;
649                 xf.f_or = &rf;
650         }
651
652         if( deref & LDAP_DEREF_SEARCHING ) {
653                 /* match aliases */
654                 af.f_choice = LDAP_FILTER_EQUALITY;
655                 af.f_ava = &aa_alias;
656                 af.f_av_desc = slap_schema.si_ad_objectClass;
657                 af.f_av_value = bv_alias;
658                 af.f_next = xf.f_or;
659                 xf.f_or = &af;
660         }
661
662         f.f_next = NULL;
663         f.f_choice = LDAP_FILTER_AND;
664         f.f_and = &fand;
665         fand.f_choice = scope == LDAP_SCOPE_SUBTREE
666                 ? SLAPD_FILTER_DN_SUBTREE
667                 : SLAPD_FILTER_DN_ONE;
668         fand.f_dn = &e->e_nname;
669         fand.f_next = xf.f_or == filter ? filter : &xf ;
670
671         candidates = filter_candidates( be, &f );
672
673         return( candidates );
674 }