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