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