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