]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/search.c
ITS#2368 - fix deleting key from range IDL
[openldap] / servers / slapd / back-bdb / search.c
1 /* search.c - search operation */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #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 static void send_pagerequest_response( 
30         Connection      *conn,
31         Operation *op,
32         ID  lastid,
33         int nentries,
34         int tentries );                 
35
36 int
37 bdb_search(
38         BackendDB       *be,
39         Connection      *conn,
40         Operation       *op,
41         struct berval   *base,
42         struct berval   *nbase,
43         int             scope,
44         int             deref,
45         int             slimit,
46         int             tlimit,
47         Filter  *filter,
48         struct berval   *filterstr,
49         AttributeName   *attrs,
50         int             attrsonly )
51 {
52         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
53         int             rc;
54         const char *text = NULL;
55         time_t          stoptime;
56         ID              id, cursor;
57         ID              candidates[BDB_IDL_UM_SIZE];
58         Entry           *e = NULL;
59         BerVarray v2refs = NULL;
60         Entry   *matched = NULL;
61         struct berval   realbase = { 0, NULL };
62         int             nentries = 0;
63         int             manageDSAit;
64         int             tentries = 0;
65         ID              lastid = NOID;
66
67 #if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC)
68         Filter          cookief, csnfnot, csnfeq, csnfand, csnfge;
69         AttributeAssertion aa_ge, aa_eq;
70         int             entry_count = 0;
71         struct berval   latest_entrycsn_bv = { 0, NULL };
72         LDAPControl     *ctrls[SLAP_SEARCH_MAX_CTRLS];
73         int             num_ctrls = 0;
74 #endif
75
76 #ifdef LDAP_SYNC
77         int             rc_sync = 0;
78         int             entry_sync_state = -1;
79         AttributeName   null_attr;
80 #endif
81
82         struct slap_limits_set *limit = NULL;
83         int isroot = 0;
84
85         u_int32_t       locker = 0;
86         DB_LOCK         lock;
87
88 #ifdef NEW_LOGGING
89         LDAP_LOG ( OPERATION, ENTRY, "bdb_back_search\n", 0, 0, 0 );
90 #else
91         Debug( LDAP_DEBUG_TRACE, "=> bdb_back_search\n",
92                 0, 0, 0);
93 #endif
94
95 #ifdef LDAP_CLIENT_UPDATE
96         if ( op->o_clientupdate_type & SLAP_LCUP_PERSIST ) {
97                 bdb_add_psearch_spec( be, conn, op, base, base, scope, deref, slimit,
98                                 tlimit, filter, filterstr, attrs, attrsonly, LDAP_CLIENT_UPDATE );
99                 return LDAP_SUCCESS;
100         }
101 #endif
102 #if defined(LDAP_CLIENT_UPDATE) && defined(LDAP_SYNC)
103         else
104 #endif
105 #ifdef LDAP_SYNC
106         /* psearch needs to be registered before refresh begins */
107         /* psearch and refresh transmission is serialized in send_ldap_ber() */
108         if ( op->o_sync_mode & SLAP_SYNC_PERSIST ) {
109                 bdb_add_psearch_spec( be, conn, op, base, base, scope, deref, slimit,
110                                 tlimit, filter, filterstr, attrs, attrsonly, LDAP_SYNC );
111         }
112         null_attr.an_desc = NULL;
113         null_attr.an_oc = NULL;
114         null_attr.an_name.bv_len = 0;
115         null_attr.an_name.bv_val = NULL;
116 #endif
117
118 #if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC)
119         for ( num_ctrls = 0; num_ctrls < SLAP_SEARCH_MAX_CTRLS; num_ctrls++ )
120                 ctrls[num_ctrls] = NULL;
121         num_ctrls = 0;
122 #endif
123
124
125         manageDSAit = get_manageDSAit( op );
126
127         rc = LOCK_ID (bdb->bi_dbenv, &locker );
128
129         switch(rc) {
130         case 0:
131                 break;
132         default:
133                 send_ldap_result( conn, op, rc=LDAP_OTHER,
134                         NULL, "internal error", NULL, NULL );
135                 return rc;
136         }
137
138         if ( nbase->bv_len == 0 ) {
139                 /* DIT root special case */
140                 e = (Entry *) &slap_entry_root;
141                 rc = 0;
142         } else                                          
143 #ifdef BDB_ALIASES
144         /* get entry with reader lock */
145         if ( deref & LDAP_DEREF_FINDING ) {
146                 e = deref_dn_r( be, nbase-, &err, &matched, &text );
147
148         } else
149 #endif
150         {
151 dn2entry_retry:
152                 rc = bdb_dn2entry_r( be, NULL, nbase, &e, &matched, 0, locker, &lock );
153         }
154
155         switch(rc) {
156         case DB_NOTFOUND:
157         case 0:
158                 break;
159         case LDAP_BUSY:
160                 if (e != NULL) {
161                         bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
162                 }
163                 if (matched != NULL) {
164                         bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
165                 }
166                 send_ldap_result( conn, op, LDAP_BUSY,
167                         NULL, "ldap server busy", NULL, NULL );
168                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
169                 return LDAP_BUSY;
170         case DB_LOCK_DEADLOCK:
171         case DB_LOCK_NOTGRANTED:
172                 goto dn2entry_retry;
173         default:
174                 if (e != NULL) {
175                         bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
176                 }
177                 if (matched != NULL) {
178                         bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
179                 }
180                 send_ldap_result( conn, op, rc=LDAP_OTHER,
181                         NULL, "internal error", NULL, NULL );
182                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
183                 return rc;
184         }
185
186         if ( e == NULL ) {
187                 struct berval matched_dn = { 0, NULL };
188                 BerVarray refs = NULL;
189
190                 if ( matched != NULL ) {
191                         BerVarray erefs;
192                         ber_dupbv( &matched_dn, &matched->e_name );
193
194                         erefs = is_entry_referral( matched )
195                                 ? get_entry_referrals( be, conn, op, matched )
196                                 : NULL;
197
198                         bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
199                         matched = NULL;
200
201                         if( erefs ) {
202                                 refs = referral_rewrite( erefs, &matched_dn,
203                                         base, scope );
204                                 ber_bvarray_free( erefs );
205                         }
206
207                 } else {
208                         refs = referral_rewrite( default_referral,
209                                 NULL, base, scope );
210                 }
211
212                 send_ldap_result( conn, op,     rc=LDAP_REFERRAL ,
213                         matched_dn.bv_val, text, refs, NULL );
214
215                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
216                 if ( refs ) ber_bvarray_free( refs );
217                 if ( matched_dn.bv_val ) ber_memfree( matched_dn.bv_val );
218                 return rc;
219         }
220
221         if (!manageDSAit && e != &slap_entry_root && is_entry_referral( e ) ) {
222                 /* entry is a referral, don't allow add */
223                 struct berval matched_dn;
224                 BerVarray erefs, refs;
225                 
226                 ber_dupbv( &matched_dn, &e->e_name );
227                 erefs = get_entry_referrals( be, conn, op, e );
228                 refs = NULL;
229
230                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
231                 e = NULL;
232
233                 if( erefs ) {
234                         refs = referral_rewrite( erefs, &matched_dn,
235                                 base, scope );
236                         ber_bvarray_free( erefs );
237                 }
238
239 #ifdef NEW_LOGGING
240                 LDAP_LOG ( OPERATION, RESULTS, 
241                         "bdb_search: entry is referral\n", 0, 0, 0 );
242 #else
243                 Debug( LDAP_DEBUG_TRACE, "bdb_search: entry is referral\n",
244                         0, 0, 0 );
245 #endif
246
247                 send_ldap_result( conn, op, LDAP_REFERRAL,
248                         matched_dn.bv_val,
249                         refs ? NULL : "bad referral object",
250                         refs, NULL );
251
252                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
253                 ber_bvarray_free( refs );
254                 ber_memfree( matched_dn.bv_val );
255                 return 1;
256         }
257
258         /* if not root, get appropriate limits */
259         if ( be_isroot( be, &op->o_ndn ) ) {
260                 isroot = 1;
261         } else {
262                 ( void ) get_limits( be, &op->o_ndn, &limit );
263         }
264
265         /* The time/size limits come first because they require very little
266          * effort, so there's no chance the candidates are selected and then 
267          * the request is not honored only because of time/size constraints */
268
269         /* if no time limit requested, use soft limit (unless root!) */
270         if ( isroot ) {
271                 if ( tlimit == 0 ) {
272                         tlimit = -1;    /* allow root to set no limit */
273                 }
274
275                 if ( slimit == 0 ) {
276                         slimit = -1;
277                 }
278
279         } else {
280                 /* if no limit is required, use soft limit */
281                 if ( tlimit <= 0 ) {
282                         tlimit = limit->lms_t_soft;
283
284                 /* if requested limit higher than hard limit, abort */
285                 } else if ( tlimit > limit->lms_t_hard ) {
286                         /* no hard limit means use soft instead */
287                         if ( limit->lms_t_hard == 0
288                                         && limit->lms_t_soft > -1
289                                         && tlimit > limit->lms_t_soft ) {
290                                 tlimit = limit->lms_t_soft;
291
292                         /* positive hard limit means abort */
293                         } else if ( limit->lms_t_hard > 0 ) {
294                                 send_search_result( conn, op, 
295                                                 LDAP_ADMINLIMIT_EXCEEDED,
296                                                 NULL, NULL, NULL, NULL, 0 );
297                                 rc = 0;
298                                 goto done;
299                         }
300                 
301                         /* negative hard limit means no limit */
302                 }
303                 
304                 /* if no limit is required, use soft limit */
305                 if ( slimit <= 0 ) {
306                         if ( get_pagedresults(op) && limit->lms_s_pr != 0 ) {
307                                 slimit = limit->lms_s_pr;
308                         } else {
309                                 slimit = limit->lms_s_soft;
310                         }
311
312                 /* if requested limit higher than hard limit, abort */
313                 } else if ( slimit > limit->lms_s_hard ) {
314                         /* no hard limit means use soft instead */
315                         if ( limit->lms_s_hard == 0
316                                         && limit->lms_s_soft > -1
317                                         && slimit > limit->lms_s_soft ) {
318                                 slimit = limit->lms_s_soft;
319
320                         /* positive hard limit means abort */
321                         } else if ( limit->lms_s_hard > 0 ) {
322                                 send_search_result( conn, op, 
323                                                 LDAP_ADMINLIMIT_EXCEEDED,
324                                                 NULL, NULL, NULL, NULL, 0 );
325                                 rc = 0; 
326                                 goto done;
327                         }
328                         
329                         /* negative hard limit means no limit */
330                 }
331         }
332
333         /* compute it anyway; root does not use it */
334         stoptime = op->o_time + tlimit;
335
336         /* select candidates */
337         if ( scope == LDAP_SCOPE_BASE ) {
338                 rc = base_candidate( be, e, candidates );
339
340         } else {
341                 BDB_IDL_ALL( bdb, candidates );
342                 rc = search_candidates( be, op, e, filter,
343                         scope, deref, candidates );
344         }
345
346         /* need normalized dn below */
347         ber_dupbv( &realbase, &e->e_nname );
348
349         /* start cursor at beginning of candidates.
350          */
351         cursor = 0;
352
353         if ( e != &slap_entry_root ) {
354                 bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
355         }
356         e = NULL;
357
358         if ( candidates[0] == 0 ) {
359 #ifdef NEW_LOGGING
360                 LDAP_LOG ( OPERATION, RESULTS,
361                         "bdb_search: no candidates\n", 0, 0, 0 );
362 #else
363                 Debug( LDAP_DEBUG_TRACE, "bdb_search: no candidates\n",
364                         0, 0, 0 );
365 #endif
366
367                 send_search_result( conn, op,
368                         LDAP_SUCCESS,
369                         NULL, NULL, NULL, NULL, 0 );
370
371                 rc = 1;
372                 goto done;
373         }
374
375         /* if not root and candidates exceed to-be-checked entries, abort */
376         if ( !isroot && limit->lms_s_unchecked != -1 ) {
377                 if ( BDB_IDL_N(candidates) > (unsigned) limit->lms_s_unchecked ) {
378                         send_search_result( conn, op, 
379                                         LDAP_ADMINLIMIT_EXCEEDED,
380                                         NULL, NULL, NULL, NULL, 0 );
381                         rc = 1;
382                         goto done;
383                 }
384         }
385
386         if ( isroot || !limit->lms_s_pr_hide ) {
387                 tentries = BDB_IDL_N(candidates);
388         }
389
390 #ifdef LDAP_CONTROL_PAGEDRESULTS
391         if ( get_pagedresults(op) ) {
392                 if ( op->o_pagedresults_state.ps_cookie == 0 ) {
393                         id = 0;
394                 } else {
395                         if ( op->o_pagedresults_size == 0 ) {
396                                 send_search_result( conn, op, LDAP_SUCCESS,
397                                         NULL, "search abandoned by pagedResult size=0",
398                                         NULL, NULL, 0);
399                                 goto done;
400                         }
401                         for ( id = bdb_idl_first( candidates, &cursor );
402                                 id != NOID && id <= (ID)( op->o_pagedresults_state.ps_cookie );
403                                 id = bdb_idl_next( candidates, &cursor ) );
404                 }
405                 if ( cursor == NOID ) {
406 #ifdef NEW_LOGGING
407                         LDAP_LOG ( OPERATION, RESULTS, 
408                                 "bdb_search: no paged results candidates\n", 
409                         0, 0, 0 );
410 #else
411                         Debug( LDAP_DEBUG_TRACE, 
412                                 "bdb_search: no paged results candidates\n",
413                                 0, 0, 0 );
414 #endif
415                         send_pagerequest_response( conn, op, lastid, 0, 0 );
416
417                         rc = 1;
418                         goto done;
419                 }
420                 goto loop_begin;
421         }
422 #endif
423
424 #ifdef LDAP_CLIENT_UPDATE
425         if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
426                 cookief.f_choice = LDAP_FILTER_AND;
427                 cookief.f_and = &csnfnot;
428                 cookief.f_next = NULL;
429
430                 csnfnot.f_choice = LDAP_FILTER_NOT;
431                 csnfnot.f_not = &csnfeq;
432                 csnfnot.f_next = &csnfand;
433
434                 csnfeq.f_choice = LDAP_FILTER_EQUALITY;
435                 csnfeq.f_ava = &aa_eq;
436                 csnfeq.f_av_desc = slap_schema.si_ad_entryCSN;
437                 ber_dupbv( &csnfeq.f_av_value, &op->o_clientupdate_state );
438
439                 csnfand.f_choice = LDAP_FILTER_AND;
440                 csnfand.f_and = &csnfge;
441                 csnfand.f_next = NULL;
442
443                 csnfge.f_choice = LDAP_FILTER_GE;
444                 csnfge.f_ava = &aa_ge;
445                 csnfge.f_av_desc = slap_schema.si_ad_entryCSN;
446                 ber_dupbv( &csnfge.f_av_value, &op->o_clientupdate_state );
447                 csnfge.f_next = filter;
448         }
449 #endif
450 #if defined(LDAP_CLIENT_UPDATE) && defined(LDAP_SYNC)
451         else
452 #endif
453 #ifdef LDAP_SYNC
454         if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) {
455                 cookief.f_choice = LDAP_FILTER_AND;
456                 cookief.f_and = &csnfnot;
457                 cookief.f_next = NULL;
458
459                 csnfnot.f_choice = LDAP_FILTER_NOT;
460                 csnfnot.f_not = &csnfeq;
461                 csnfnot.f_next = &csnfand;
462
463                 csnfeq.f_choice = LDAP_FILTER_EQUALITY;
464                 csnfeq.f_ava = &aa_eq;
465                 csnfeq.f_av_desc = slap_schema.si_ad_entryCSN;
466                 ber_dupbv( &csnfeq.f_av_value, &op->o_sync_state );
467
468                 csnfand.f_choice = LDAP_FILTER_AND;
469                 csnfand.f_and = &csnfge;
470                 csnfand.f_next = NULL;
471
472                 csnfge.f_choice = LDAP_FILTER_GE;
473                 csnfge.f_ava = &aa_ge;
474                 csnfge.f_av_desc = slap_schema.si_ad_entryCSN;
475                 ber_dupbv( &csnfge.f_av_value, &op->o_sync_state );
476                 csnfge.f_next = filter;
477         }
478 #endif
479
480         for ( id = bdb_idl_first( candidates, &cursor );
481                 id != NOID;
482                 id = bdb_idl_next( candidates, &cursor ) )
483         {
484
485                 int             scopeok = 0;
486
487 loop_begin:
488                 /* check for abandon */
489                 if ( op->o_abandon ) {
490                         rc = 0;
491                         goto done;
492                 }
493
494 #ifdef LDAP_EXOP_X_CANCEL
495                 if ( op->o_cancel ) {
496                         assert( op->o_cancel == SLAP_CANCEL_REQ );
497                         rc = 0;
498                         send_search_result( conn, op, LDAP_CANCELLED,
499                                         NULL, NULL, NULL, NULL, 0 );
500                         op->o_cancel = SLAP_CANCEL_ACK;
501                         goto done;
502                 }
503 #endif
504
505                 /* check time limit */
506                 if ( tlimit != -1 && slap_get_time() > stoptime ) {
507                         send_search_result( conn, op, rc = LDAP_TIMELIMIT_EXCEEDED,
508                                 NULL, NULL, v2refs, NULL, nentries );
509                         goto done;
510                 }
511
512 id2entry_retry:
513                 /* get the entry with reader lock */
514                 rc = bdb_id2entry_r( be, NULL, id, &e, locker, &lock );
515
516                 if (rc == LDAP_BUSY) {
517                         send_ldap_result( conn, op, rc=LDAP_BUSY,
518                                 NULL, "ldap server busy", NULL, NULL );
519                         goto done;
520
521                 } else if ( rc == DB_LOCK_DEADLOCK || rc == DB_LOCK_NOTGRANTED ) {
522                         goto id2entry_retry;    
523                 }
524
525                 if ( e == NULL ) {
526                         if( !BDB_IDL_IS_RANGE(candidates) ) {
527                                 /* only complain for non-range IDLs */
528 #ifdef NEW_LOGGING
529                                 LDAP_LOG ( OPERATION, RESULTS,
530                                         "bdb_search: candidate %ld not found\n", (long) id, 0, 0);
531 #else
532                                 Debug( LDAP_DEBUG_TRACE,
533                                         "bdb_search: candidate %ld not found\n",
534                                         (long) id, 0, 0 );
535 #endif
536                         }
537
538                         goto loop_continue;
539                 }
540
541 #ifdef BDB_SUBENTRIES
542                 if ( is_entry_subentry( e ) ) {
543                         if( scope != LDAP_SCOPE_BASE ) {
544                                 if(!get_subentries_visibility( op )) {
545                                         /* only subentries are visible */
546                                         goto loop_continue;
547                                 }
548
549                         } else if ( get_subentries( op ) &&
550                                 !get_subentries_visibility( op ))
551                         {
552                                 /* only subentries are visible */
553                                 goto loop_continue;
554                         }
555
556                 } else if ( get_subentries_visibility( op )) {
557                         /* only subentries are visible */
558                         goto loop_continue;
559                 }
560 #endif
561
562 #ifdef BDB_ALIASES
563                 if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) {
564                         Entry *matched;
565                         int err;
566                         const char *text;
567                         
568                         e = deref_entry_r( be, e, &err, &matched, &text );
569
570                         if( e == NULL ) {
571                                 e = matched;
572                                 goto loop_continue;
573                         }
574
575                         if( e->e_id == id ) {
576                                 /* circular loop */
577                                 goto loop_continue;
578                         }
579
580                         /* need to skip alias which deref into scope */
581                         if( scope & LDAP_SCOPE_ONELEVEL ) {
582                                 struct berval   pdn;
583                                 
584                                 dnParent( &e->e_nname, &pdn ):
585                                 if ( ber_bvcmp( pdn, &realbase ) ) {
586                                         goto loop_continue;
587                                 }
588
589                         } else if ( dnIsSuffix( &e->e_nname, &realbase ) ) {
590                                 /* alias is within scope */
591 #ifdef NEW_LOGGING
592                                 LDAP_LOG ( OPERATION, RESULTS,
593                                         "bdb_search: \"%s\" in subtree\n", e->edn, 0, 0);
594 #else
595                                 Debug( LDAP_DEBUG_TRACE,
596                                         "bdb_search: \"%s\" in subtree\n",
597                                         e->e_dn, 0, 0 );
598 #endif
599                                 goto loop_continue;
600                         }
601
602                         scopeok = 1;
603                 }
604 #endif
605
606                 /*
607                  * if it's a referral, add it to the list of referrals. only do
608                  * this for non-base searches, and don't check the filter
609                  * explicitly here since it's only a candidate anyway.
610                  */
611                 if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
612                         is_entry_referral( e ) )
613                 {
614                         struct berval   dn;
615
616                         /* check scope */
617                         if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
618                                 if ( !be_issuffix( be, &e->e_nname ) ) {
619                                         dnParent( &e->e_nname, &dn );
620                                         scopeok = dn_match( &dn, &realbase );
621                                 } else {
622                                         scopeok = (realbase.bv_len == 0);
623                                 }
624
625                         } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
626                                 scopeok = dnIsSuffix( &e->e_nname, &realbase );
627
628                         } else {
629                                 scopeok = 1;
630                         }
631
632                         if( scopeok ) {
633                                 BerVarray erefs = get_entry_referrals(
634                                         be, conn, op, e );
635                                 BerVarray refs = referral_rewrite( erefs,
636                                         &e->e_name, NULL,
637                                         scope == LDAP_SCOPE_SUBTREE
638                                                 ? LDAP_SCOPE_SUBTREE
639                                                 : LDAP_SCOPE_BASE );
640
641                                 send_search_reference( be, conn, op,
642                                         e, refs, NULL, &v2refs );
643
644                                 ber_bvarray_free( refs );
645
646                         } else {
647 #ifdef NEW_LOGGING
648                                 LDAP_LOG(OPERATION, DETAIL2, 
649                                         "bdb_search: candidate referral %ld scope not okay\n",
650                                         id, 0, 0 );
651 #else
652                                 Debug( LDAP_DEBUG_TRACE,
653                                         "bdb_search: candidate referral %ld scope not okay\n",
654                                         id, 0, 0 );
655 #endif
656                         }
657
658                         goto loop_continue;
659                 }
660
661                 /* if it matches the filter and scope, send it */
662 #ifdef LDAP_CLIENT_UPDATE
663                 if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
664                         rc = test_filter( be, conn, op, e, &cookief );
665                 } else
666 #endif
667 #ifdef LDAP_SYNC
668                 if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) {
669                         rc_sync = test_filter( be, conn, op, e, &cookief );
670                         rc      = test_filter( be, conn, op, e, filter );
671                         if ( rc == LDAP_COMPARE_TRUE ) {
672                                 if ( rc_sync == LDAP_COMPARE_TRUE ) {
673                                         entry_sync_state = LDAP_SYNC_ADD;
674                                 } else {
675                                         entry_sync_state = LDAP_SYNC_PRESENT;
676                                 }
677                         }
678                 } else
679 #endif
680                 {
681                         rc = test_filter( be, conn, op, e, filter );
682                 }
683
684                 if ( rc == LDAP_COMPARE_TRUE ) {
685                         struct berval   dn;
686
687                         /* check scope */
688                         if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
689                                 if ( be_issuffix( be, &e->e_nname ) ) {
690                                         scopeok = (realbase.bv_len == 0);
691                                 } else {
692                                         dnParent( &e->e_nname, &dn );
693                                         scopeok = dn_match( &dn, &realbase );
694                                 }
695
696                         } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
697                                 scopeok = dnIsSuffix( &e->e_nname, &realbase );
698
699                         } else {
700                                 scopeok = 1;
701                         }
702
703                         if ( scopeok ) {
704                                 /* check size limit */
705                                 if ( --slimit == -1 ) {
706                                         bdb_cache_return_entry_r( bdb->bi_dbenv,
707                                                 &bdb->bi_cache, e, &lock );
708                                         e = NULL;
709                                         send_search_result( conn, op,
710                                                 rc = LDAP_SIZELIMIT_EXCEEDED, NULL, NULL,
711                                                 v2refs, NULL, nentries );
712                                         goto done;
713                                 }
714
715 #ifdef LDAP_CONTROL_PAGEDRESULTS
716                                 if ( get_pagedresults(op) ) {
717                                         if ( nentries >= op->o_pagedresults_size ) {
718                                                 send_pagerequest_response( conn, op,
719                                                         lastid, nentries, tentries );
720                                                 goto done;
721                                         }
722                                         lastid = id;
723                                 }
724 #endif
725
726                                 if (e) {
727                                         int result;
728                                         
729 #if 0   /* noop is masked SLAP_CTRL_UPDATE */
730                                         if( op->o_noop ) {
731                                                 result = 0;
732                                         } else
733 #endif
734                                         {
735 #ifdef LDAP_CLIENT_UPDATE
736                                                 if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
737                                                         rc = bdb_build_lcup_update_ctrl( conn, op, e, ++entry_count, ctrls,
738                                                                         num_ctrls++, &latest_entrycsn_bv, SLAP_LCUP_ENTRY_DELETED_FALSE );
739                                                         if ( rc != LDAP_SUCCESS )
740                                                                 goto done;
741                                                         result = send_search_entry( be, conn, op,
742                                                                         e, attrs, attrsonly, ctrls);
743
744                                                         if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL )
745                                                                 ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val );
746                                                         ch_free( ctrls[--num_ctrls] );
747                                                         ctrls[num_ctrls] = NULL;
748                                                 } else
749 #endif
750 #ifdef LDAP_SYNC
751                                                 if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) {
752                                                         rc = bdb_build_sync_state_ctrl( conn, op, e, entry_sync_state, ctrls,
753                                                                         num_ctrls++, 0, &latest_entrycsn_bv );
754                                                         if ( rc != LDAP_SUCCESS )
755                                                                 goto done;
756
757                                                         if ( rc_sync == LDAP_COMPARE_TRUE ) { /* ADD */
758                                                                 result = send_search_entry( be, conn, op,
759                                                                                 e, attrs, attrsonly, ctrls);
760                                                         } else { /* PRESENT */
761                                                                 result = send_search_entry( be, conn, op,
762                                                                                 e, &null_attr, attrsonly, ctrls);
763                                                         }
764
765                                                         if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL )
766                                                                 ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val );
767                                                         ch_free( ctrls[--num_ctrls] );
768                                                         ctrls[num_ctrls] = NULL;
769                                                 } else
770 #endif
771
772                                                 {
773                                                         result = send_search_entry( be, conn, op,
774                                                                 e, attrs, attrsonly, NULL);
775                                                 }
776                                         }
777
778                                         switch (result) {
779                                         case 0:         /* entry sent ok */
780                                                 nentries++;
781                                                 break;
782                                         case 1:         /* entry not sent */
783                                                 break;
784                                         case -1:        /* connection closed */
785                                                 bdb_cache_return_entry_r(bdb->bi_dbenv,
786                                                         &bdb->bi_cache, e, &lock);
787                                                 e = NULL;
788                                                 rc = LDAP_OTHER;
789                                                 goto done;
790                                         }
791                                 }
792                         } else {
793 #ifdef NEW_LOGGING
794                                 LDAP_LOG ( OPERATION, RESULTS,
795                                         "bdb_search: %ld scope not okay\n", (long) id, 0, 0);
796 #else
797                                 Debug( LDAP_DEBUG_TRACE,
798                                         "bdb_search: %ld scope not okay\n",
799                                         (long) id, 0, 0 );
800 #endif
801                         }
802                 } else {
803 #ifdef NEW_LOGGING
804                         LDAP_LOG ( OPERATION, RESULTS,
805                                 "bdb_search: %ld does not match filter\n", (long) id, 0, 0);
806 #else
807                         Debug( LDAP_DEBUG_TRACE,
808                                 "bdb_search: %ld does not match filter\n",
809                                 (long) id, 0, 0 );
810 #endif
811                 }
812
813 loop_continue:
814                 if( e != NULL ) {
815                         /* free reader lock */
816                         bdb_cache_return_entry_r( bdb->bi_dbenv,
817                                 &bdb->bi_cache, e , &lock);
818                         e = NULL;
819                 }
820
821                 ldap_pvt_thread_yield();
822         }
823
824 #ifdef LDAP_CLIENT_UPDATE
825         if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
826                 bdb_build_lcup_done_ctrl( conn, op, ctrls, num_ctrls++, &latest_entrycsn_bv );
827
828                 send_search_result( conn, op,
829                                 v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
830                                 NULL, NULL, v2refs, ctrls, nentries );
831
832                 ch_free( latest_entrycsn_bv.bv_val );
833                 latest_entrycsn_bv.bv_val = NULL;
834
835                 if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL )
836                                 ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val );
837                 ch_free( ctrls[--num_ctrls] );
838                 ctrls[num_ctrls] = NULL;
839         } else
840 #endif
841 #ifdef LDAP_SYNC
842         if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) {
843                 if ( op->o_sync_mode & SLAP_SYNC_PERSIST ) {
844                         /* refreshAndPersist mode */
845                         bdb_send_ldap_intermediate( conn, op,
846                                 LDAP_SUCCESS, NULL, NULL, NULL, LDAP_SYNC_INFO,
847                                 LDAP_SYNC_REFRESH_DONE, &latest_entrycsn_bv, NULL );
848                 } else {
849                         /* refreshOnly mode */
850                         bdb_build_sync_done_ctrl( conn, op, ctrls, num_ctrls++, 1, &latest_entrycsn_bv );
851                         send_search_result( conn, op,
852                                         v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
853                                         NULL, NULL, v2refs, ctrls, nentries );
854                         if ( ctrls[num_ctrls-1]->ldctl_value.bv_val != NULL )
855                                 ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val );
856                         ch_free( ctrls[--num_ctrls] );
857                         ctrls[num_ctrls] = NULL;
858                 }
859
860                 ch_free( latest_entrycsn_bv.bv_val );
861                 latest_entrycsn_bv.bv_val = NULL;
862         } else
863 #endif
864         {
865                 send_search_result( conn, op,
866                         v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
867                         NULL, NULL, v2refs, NULL, nentries );
868         }
869
870         rc = 0;
871
872 done:
873         if( e != NULL ) {
874                 /* free reader lock */
875                 bdb_cache_return_entry_r ( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
876         }
877
878 #ifdef LDAP_CLIENT_UPDATE
879         if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
880                 if ( csnfeq.f_ava != NULL && csnfeq.f_av_value.bv_val != NULL ) {
881                         ch_free( csnfeq.f_av_value.bv_val );
882                 }
883         
884                 if ( csnfge.f_ava != NULL && csnfge.f_av_value.bv_val != NULL ) {
885                         ch_free( csnfge.f_av_value.bv_val );
886                 }
887         }
888 #endif
889 #if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC)
890         else
891 #endif
892 #ifdef LDAP_SYNC
893         if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) {
894                 if ( csnfeq.f_ava != NULL && csnfeq.f_av_value.bv_val != NULL ) {
895                         ch_free( csnfeq.f_av_value.bv_val );
896                 }
897
898                 if ( csnfge.f_ava != NULL && csnfge.f_av_value.bv_val != NULL ) {
899                         ch_free( csnfge.f_av_value.bv_val );
900                 }
901         }
902 #endif
903
904         LOCK_ID_FREE (bdb->bi_dbenv, locker );
905
906         if( v2refs ) ber_bvarray_free( v2refs );
907         if( realbase.bv_val ) ch_free( realbase.bv_val );
908
909         return rc;
910 }
911
912
913 static int base_candidate(
914         BackendDB       *be,
915         Entry   *e,
916         ID              *ids )
917 {
918 #ifdef NEW_LOGGING
919         LDAP_LOG ( OPERATION, ENTRY,
920                 "base_candidate: base: \"%s\" (0x%08lx)\n", e->e_dn, (long) e->e_id, 0);
921 #else
922         Debug(LDAP_DEBUG_ARGS, "base_candidates: base: \"%s\" (0x%08lx)\n",
923                 e->e_dn, (long) e->e_id, 0);
924 #endif
925
926         ids[0] = 1;
927         ids[1] = e->e_id;
928         return 0;
929 }
930
931 /* Look for "objectClass Present" in this filter.
932  * Also count depth of filter tree while we're at it.
933  */
934 static int oc_filter(
935         Filter *f,
936         int cur,
937         int *max
938 )
939 {
940         int rc = 0;
941
942         if( cur > *max ) *max = cur;
943
944         switch(f->f_choice) {
945         case LDAP_FILTER_PRESENT:
946                 if (f->f_desc == slap_schema.si_ad_objectClass) {
947                         rc = 1;
948                 }
949                 break;
950
951         case LDAP_FILTER_AND:
952         case LDAP_FILTER_OR:
953                 cur++;
954                 for (f=f->f_and; f; f=f->f_next) {
955                         (void) oc_filter(f, cur, max);
956                 }
957                 break;
958
959         default:
960                 break;
961         }
962         return rc;
963 }
964
965 static void search_stack_free( void *key, void *data)
966 {
967         ch_free(data);
968 }
969
970 static void *search_stack(
971         BackendDB *be,
972         Operation *op
973 )
974 {
975         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
976         void *ret = NULL;
977
978         if ( op->o_threadctx ) {
979                 ldap_pvt_thread_pool_getkey( op->o_threadctx, search_stack,
980                         &ret, NULL );
981         } else {
982                 ret = bdb->bi_search_stack;
983         }
984
985         if ( !ret ) {
986                 ret = ch_malloc( bdb->bi_search_stack_depth * BDB_IDL_UM_SIZE * sizeof( ID ) );
987                 if ( op->o_threadctx ) {
988                         ldap_pvt_thread_pool_setkey( op->o_threadctx, search_stack,
989                                 ret, search_stack_free );
990                 } else {
991                         bdb->bi_search_stack = ret;
992                 }
993         }
994         return ret;
995 }
996
997 static int search_candidates(
998         BackendDB *be,
999         Operation *op,
1000         Entry *e,
1001         Filter *filter,
1002         int scope,
1003         int deref,
1004         ID      *ids )
1005 {
1006         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
1007         int rc, depth = 1;
1008         Filter          f, scopef, rf, xf;
1009         ID              *stack;
1010         AttributeAssertion aa_ref;
1011 #ifdef BDB_SUBENTRIES
1012         Filter  sf;
1013         AttributeAssertion aa_subentry;
1014 #endif
1015 #ifdef BDB_ALIASES
1016         Filter  af;
1017         AttributeAssertion aa_alias;
1018 #endif
1019
1020         /*
1021          * This routine takes as input a filter (user-filter)
1022          * and rewrites it as follows:
1023          *      (&(scope=DN)[(objectClass=subentry)]
1024          *              (|[(objectClass=referral)(objectClass=alias)](user-filter))
1025          */
1026
1027 #ifdef NEW_LOGGING
1028         LDAP_LOG ( OPERATION, ENTRY,
1029                 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", 
1030                 e->e_dn, (long) e->e_id, scope);
1031 #else
1032         Debug(LDAP_DEBUG_TRACE,
1033                 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n",
1034                 e->e_dn, (long) e->e_id, scope );
1035 #endif
1036
1037         xf.f_or = filter;
1038         xf.f_choice = LDAP_FILTER_OR;
1039         xf.f_next = NULL;
1040
1041         /* If the user's filter uses objectClass=*,
1042          * these clauses are redundant.
1043          */
1044         if (!oc_filter(filter, 1, &depth) && !get_subentries_visibility(op) ) {
1045                 if( !get_manageDSAit(op) && !get_domainScope(op) ) {
1046                         /* match referral objects */
1047                         struct berval bv_ref = { sizeof("referral")-1, "referral" };
1048                         rf.f_choice = LDAP_FILTER_EQUALITY;
1049                         rf.f_ava = &aa_ref;
1050                         rf.f_av_desc = slap_schema.si_ad_objectClass;
1051                         rf.f_av_value = bv_ref;
1052                         rf.f_next = xf.f_or;
1053                         xf.f_or = &rf;
1054                 }
1055
1056 #ifdef BDB_ALIASES
1057                 if( deref & LDAP_DEREF_SEARCHING ) {
1058                         /* match alias objects */
1059                         struct berval bv_alias = { sizeof("alias")-1, "alias" };
1060                         af.f_choice = LDAP_FILTER_EQUALITY;
1061                         af.f_ava = &aa_alias;
1062                         af.f_av_desc = slap_schema.si_ad_objectClass;
1063                         af.f_av_value = bv_alias;
1064                         af.f_next = xf.f_or;
1065                         xf.f_or = &af;
1066                 }
1067 #endif
1068                 /* We added one of these clauses, filter depth increased */
1069                 if( xf.f_or != filter ) depth++;
1070         }
1071
1072         f.f_next = NULL;
1073         f.f_choice = LDAP_FILTER_AND;
1074         f.f_and = &scopef;
1075         scopef.f_choice = scope == LDAP_SCOPE_SUBTREE
1076                 ? SLAPD_FILTER_DN_SUBTREE
1077                 : SLAPD_FILTER_DN_ONE;
1078         scopef.f_dn = &e->e_nname;
1079         scopef.f_next = xf.f_or == filter ? filter : &xf ;
1080         /* Filter depth increased again, adding scope clause */
1081         depth++;
1082
1083 #ifdef BDB_SUBENTRIES
1084         if( get_subentries_visibility( op ) ) {
1085                 struct berval bv_subentry = { sizeof("SUBENTRY")-1, "SUBENTRY" };
1086                 sf.f_choice = LDAP_FILTER_EQUALITY;
1087                 sf.f_ava = &aa_subentry;
1088                 sf.f_av_desc = slap_schema.si_ad_objectClass;
1089                 sf.f_av_value = bv_subentry;
1090                 sf.f_next = scopef.f_next;
1091                 scopef.f_next = &sf;
1092         }
1093 #endif
1094
1095         /* Allocate IDL stack, plus 1 more for former tmp */
1096         if ( depth+1 > bdb->bi_search_stack_depth ) {
1097                 stack = ch_malloc( (depth + 1) * BDB_IDL_UM_SIZE * sizeof( ID ) );
1098         } else {
1099                 stack = search_stack( be, op );
1100         }
1101
1102         rc = bdb_filter_candidates( be, &f, ids, stack, stack+BDB_IDL_UM_SIZE );
1103
1104         if ( depth+1 > bdb->bi_search_stack_depth ) {
1105                 ch_free( stack );
1106         }
1107
1108         if( rc ) {
1109 #ifdef NEW_LOGGING
1110                 LDAP_LOG ( OPERATION, DETAIL1,
1111                         "bdb_search_candidates: failed (rc=%d)\n", rc, 0, 0  );
1112 #else
1113                 Debug(LDAP_DEBUG_TRACE,
1114                         "bdb_search_candidates: failed (rc=%d)\n",
1115                         rc, NULL, NULL );
1116 #endif
1117
1118         } else {
1119 #ifdef NEW_LOGGING
1120                 LDAP_LOG ( OPERATION, DETAIL1,
1121                         "bdb_search_candidates: id=%ld first=%ld last=%ld\n",
1122                         (long) ids[0], (long) BDB_IDL_FIRST(ids), 
1123                         (long) BDB_IDL_LAST(ids));
1124 #else
1125                 Debug(LDAP_DEBUG_TRACE,
1126                         "bdb_search_candidates: id=%ld first=%ld last=%ld\n",
1127                         (long) ids[0],
1128                         (long) BDB_IDL_FIRST(ids),
1129                         (long) BDB_IDL_LAST(ids) );
1130 #endif
1131         }
1132
1133         return rc;
1134 }
1135
1136 #ifdef LDAP_CONTROL_PAGEDRESULTS
1137 static void
1138 send_pagerequest_response( 
1139         Connection      *conn,
1140         Operation       *op,
1141         ID              lastid,
1142         int             nentries,
1143         int             tentries )
1144 {
1145         LDAPControl     ctrl, *ctrls[2];
1146         char berbuf[LBER_ELEMENT_SIZEOF];
1147         BerElement      *ber = (BerElement *)berbuf;
1148         struct berval   cookie = { 0, NULL };
1149         PagedResultsCookie respcookie;
1150
1151 #ifdef NEW_LOGGING
1152         LDAP_LOG ( OPERATION, ENTRY,
1153                 "send_pagerequest_response: lastid: (0x%08lx) "
1154                 "nentries: (0x%081x)\n", 
1155                 lastid, nentries, NULL );
1156 #else
1157         Debug(LDAP_DEBUG_ARGS, "send_pagerequest_response: lastid: (0x%08lx) "
1158                         "nentries: (0x%081x)\n", lastid, nentries, NULL );
1159 #endif
1160
1161         ctrl.ldctl_value.bv_val = NULL;
1162         ctrls[0] = &ctrl;
1163         ctrls[1] = NULL;
1164
1165         ber_init2( ber, NULL, LBER_USE_DER );
1166
1167         respcookie = ( PagedResultsCookie )lastid;
1168         conn->c_pagedresults_state.ps_cookie = respcookie;
1169         cookie.bv_len = sizeof( respcookie );
1170         cookie.bv_val = (char *)&respcookie;
1171
1172         /*
1173          * FIXME: we should consider sending an estimate of the entries
1174          * left, after appropriate security check is done
1175          */
1176         ber_printf( ber, "{iO}", tentries, &cookie ); 
1177
1178         if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) {
1179                 goto done;
1180         }
1181
1182         ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
1183         ctrls[0]->ldctl_iscritical = 0;
1184
1185         send_search_result( conn, op,
1186                 LDAP_SUCCESS,
1187                 NULL, NULL, NULL, ctrls, nentries );
1188
1189 done:
1190         (void) ber_free_buf( ber );
1191 }                       
1192 #endif
1193
1194 #ifdef LDAP_CLIENT_UPDATE
1195 int
1196 bdb_build_lcup_update_ctrl(
1197         Connection      *conn,
1198         Operation       *op,
1199         Entry           *e,
1200         int             entry_count,
1201         LDAPControl     **ctrls,
1202         int             num_ctrls,
1203         struct berval   *latest_entrycsn_bv,
1204         int             isdeleted       )
1205 {
1206         Attribute* a;
1207         int ret;
1208         int res;
1209         int rc;
1210         const char *text = NULL;
1211
1212         char berbuf[LBER_ELEMENT_SIZEOF];
1213         BerElement *ber = (BerElement *)berbuf;
1214
1215         struct berval entrycsn_bv = { 0, NULL };
1216
1217         ber_init2( ber, 0, LBER_USE_DER );
1218
1219         ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) );
1220
1221         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
1222                 AttributeDescription *desc = a->a_desc;
1223                 if ( desc == slap_schema.si_ad_entryCSN ) {
1224                         ber_dupbv( &entrycsn_bv, &a->a_vals[0] );
1225                         if ( latest_entrycsn_bv->bv_val == NULL ) {
1226                                 ber_dupbv( latest_entrycsn_bv, &entrycsn_bv );
1227                         } else {
1228                                 res = value_match( &ret, desc,
1229                                         desc->ad_type->sat_ordering, 0,
1230                                         &entrycsn_bv, latest_entrycsn_bv, &text );
1231                                 if ( res != LDAP_SUCCESS ) {
1232                                         ret = 0;
1233 #ifdef NEW_LOGGING
1234                                         LDAP_LOG ( OPERATION, RESULTS, 
1235                                                 "bdb_search: value_match failed\n",
1236                                                 0, 0, 0 );
1237 #else
1238                                         Debug( LDAP_DEBUG_TRACE,
1239                                                 "bdb_search: value_match failed\n",
1240                                                 0, 0, 0 );
1241 #endif
1242                                 }
1243
1244                                 if ( ret > 0 ) {
1245                                         ch_free( latest_entrycsn_bv->bv_val );
1246                                         latest_entrycsn_bv->bv_val = NULL;
1247                                         ber_dupbv( latest_entrycsn_bv, &entrycsn_bv );
1248                                 }
1249                         }
1250                 }
1251         }
1252
1253         if ( entry_count % op->o_clientupdate_interval == 0 )
1254                 ber_printf( ber,
1255                         "{bb{sON}N}",
1256                         SLAP_LCUP_STATE_UPDATE_FALSE,
1257                         isdeleted,
1258                         LDAP_CUP_COOKIE_OID, &entrycsn_bv );
1259         else /* Do not send cookie */
1260                 ber_printf( ber,
1261                         "{bbN}",
1262                         SLAP_LCUP_STATE_UPDATE_FALSE,
1263                         isdeleted );
1264
1265         ch_free( entrycsn_bv.bv_val );
1266         entrycsn_bv.bv_val = NULL;
1267
1268         ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_ENTRY_UPDATE;
1269         ctrls[num_ctrls]->ldctl_iscritical = op->o_clientupdate;
1270         ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );
1271
1272         ber_free_buf( ber );
1273
1274         if ( ret < 0 ) {
1275 #ifdef NEW_LOGGING
1276                 LDAP_LOG ( OPERATION, RESULTS, 
1277                         "bdb_build_lcup_ctrl: ber_flatten2 failed\n",
1278                         0, 0, 0 );
1279 #else
1280                 Debug( LDAP_DEBUG_TRACE,
1281                         "bdb_build_lcup_ctrl: ber_flatten2 failed\n",
1282                         0, 0, 0 );
1283 #endif
1284                 send_ldap_result( conn, op, rc=LDAP_OTHER,
1285                         NULL, "internal error", NULL, NULL );
1286                 return ret;
1287         }
1288
1289         return LDAP_SUCCESS;
1290 }
1291
1292 int
1293 bdb_build_lcup_done_ctrl(
1294         Connection      *conn,
1295         Operation       *op,
1296         LDAPControl     **ctrls,
1297         int             num_ctrls,
1298         struct berval   *latest_entrycsn_bv     )
1299 {
1300         int ret, rc;
1301         char berbuf[LBER_ELEMENT_SIZEOF];
1302         BerElement *ber = (BerElement *)berbuf;
1303
1304         ber_init2( ber, NULL, LBER_USE_DER );
1305
1306         ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) );
1307
1308         ber_printf( ber, "{sO", LDAP_CUP_COOKIE_OID, latest_entrycsn_bv );
1309         ber_printf( ber, "N}" );
1310
1311         ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_CLIENT_UPDATE_DONE;
1312         ctrls[num_ctrls]->ldctl_iscritical = op->o_clientupdate;
1313         ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );
1314
1315         ber_free_buf( ber );
1316
1317         if ( ret < 0 ) {
1318 #ifdef NEW_LOGGING
1319                 LDAP_LOG ( OPERATION, RESULTS, 
1320                         "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n", 0, 0, 0 );
1321 #else
1322                 Debug( LDAP_DEBUG_TRACE, "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n",
1323                         0, 0, 0 );
1324 #endif
1325                 send_ldap_result( conn, op, rc=LDAP_OTHER,
1326                         NULL, "internal error", NULL, NULL );
1327                 return ret;
1328         }
1329
1330         return LDAP_SUCCESS;
1331 }
1332 #endif
1333
1334 #ifdef LDAP_SYNC
1335 int
1336 bdb_build_sync_state_ctrl(
1337         Connection      *conn,
1338         Operation       *op,
1339         Entry           *e,
1340         int             entry_sync_state,
1341         LDAPControl     **ctrls,
1342         int             num_ctrls,
1343         int             send_cookie,
1344         struct berval   *latest_entrycsn_bv     )
1345 {
1346         Attribute* a;
1347         int ret;
1348         int res;
1349         int rc;
1350         const char *text = NULL;
1351
1352         char berbuf[LBER_ELEMENT_SIZEOF];
1353         BerElement *ber = (BerElement *)berbuf;
1354
1355         struct berval entryuuid_bv      = { 0, NULL };
1356         struct berval entrycsn_bv       = { 0, NULL };
1357
1358         ber_init2( ber, 0, LBER_USE_DER );
1359
1360         ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) );
1361
1362         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
1363                 AttributeDescription *desc = a->a_desc;
1364                 if ( desc == slap_schema.si_ad_entryCSN ) {
1365                         ber_dupbv( &entrycsn_bv, &a->a_vals[0] );
1366                         if ( latest_entrycsn_bv->bv_val == NULL ) {
1367                                 ber_dupbv( latest_entrycsn_bv, &entrycsn_bv );
1368                         } else {
1369                                 res = value_match( &ret, desc,
1370                                                 desc->ad_type->sat_ordering, 0,
1371                                                 &entrycsn_bv, latest_entrycsn_bv, &text );
1372                                 if ( res != LDAP_SUCCESS ) {
1373                                         ret = 0;
1374 #ifdef NEW_LOGGING
1375                                         LDAP_LOG ( OPERATION, RESULTS,
1376                                                         "bdb_search: value_match failed\n",
1377                                                         0, 0, 0 );
1378 #else
1379                                         Debug( LDAP_DEBUG_TRACE,
1380                                                         "bdb_search: value_match failed\n",
1381                                                         0, 0, 0 );
1382 #endif
1383                                 }
1384                                 if ( ret > 0 ) {
1385                                         ch_free( latest_entrycsn_bv->bv_val );
1386                                         latest_entrycsn_bv->bv_val = NULL;
1387                                         ber_dupbv( latest_entrycsn_bv, &entrycsn_bv );
1388                                 }
1389                         }
1390                 } else if ( desc == slap_schema.si_ad_entryUUID ) {
1391                         ber_dupbv( &entryuuid_bv, &a->a_vals[0] );
1392                 }
1393         }
1394
1395         if ( send_cookie )
1396                 ber_printf( ber, "{eOON}", entry_sync_state, &entryuuid_bv, &entrycsn_bv );
1397         else
1398                 ber_printf( ber, "{eON}", entry_sync_state, &entryuuid_bv );
1399
1400         ch_free( entrycsn_bv.bv_val );
1401         entrycsn_bv.bv_val = NULL;
1402         ch_free( entryuuid_bv.bv_val );
1403         entryuuid_bv.bv_val = NULL;
1404
1405         ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE;
1406         ctrls[num_ctrls]->ldctl_iscritical = op->o_sync;
1407         ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );
1408
1409         ber_free_buf( ber );
1410
1411         if ( ret < 0 ) {
1412 #ifdef NEW_LOGGING
1413                 LDAP_LOG ( OPERATION, RESULTS, 
1414                         "bdb_build_sync_ctrl: ber_flatten2 failed\n",
1415                         0, 0, 0 );
1416 #else
1417                 Debug( LDAP_DEBUG_TRACE,
1418                         "bdb_build_sync_ctrl: ber_flatten2 failed\n",
1419                         0, 0, 0 );
1420 #endif
1421                 send_ldap_result( conn, op, rc=LDAP_OTHER,
1422                         NULL, "internal error", NULL, NULL );
1423                 return ret;
1424         }
1425
1426         return LDAP_SUCCESS;
1427 }
1428
1429 int
1430 bdb_build_sync_done_ctrl(
1431         Connection      *conn,
1432         Operation       *op,
1433         LDAPControl     **ctrls,
1434         int             num_ctrls,
1435         int             send_cookie,
1436         struct berval   *latest_entrycsn_bv     )
1437 {
1438         int ret,rc;
1439         char berbuf[LBER_ELEMENT_SIZEOF];
1440         BerElement *ber = (BerElement *)berbuf;
1441
1442         ber_init2( ber, NULL, LBER_USE_DER );
1443
1444         ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) );
1445
1446         if ( send_cookie ) {
1447                 ber_printf( ber, "{ON}", latest_entrycsn_bv );
1448         } else {
1449                 ber_printf( ber, "{N}" );
1450         }
1451
1452         ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_DONE;
1453         ctrls[num_ctrls]->ldctl_iscritical = op->o_sync;
1454         ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );
1455
1456         ber_free_buf( ber );
1457
1458         if ( ret < 0 ) {
1459 #ifdef NEW_LOGGING
1460                 LDAP_LOG ( OPERATION, RESULTS, 
1461                         "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n", 0, 0, 0 );
1462 #else
1463                 Debug( LDAP_DEBUG_TRACE, "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n",
1464                         0, 0, 0 );
1465 #endif
1466                 send_ldap_result( conn, op, rc=LDAP_OTHER,
1467                         NULL, "internal error", NULL, NULL );
1468                 return ret;
1469         }
1470
1471         return LDAP_SUCCESS;
1472 }
1473
1474 int
1475 bdb_send_ldap_intermediate(
1476         Connection  *conn,
1477         Operation   *op,
1478         ber_int_t   err,
1479         const char  *matched,
1480         const char  *text,
1481         BerVarray   refs,
1482         const char  *rspoid,
1483         int         state,
1484         struct berval *cookie,
1485         LDAPControl **ctrls     )
1486 {
1487         char berbuf[LBER_ELEMENT_SIZEOF];
1488         BerElement *ber = (BerElement *)berbuf;
1489         struct berval rspdata;
1490
1491         int ret, rc;
1492
1493         ber_init2( ber, NULL, LBER_USE_DER );
1494
1495         if ( cookie == NULL )
1496                 ber_printf( ber, "{eN}", state );
1497         else
1498                 ber_printf( ber, "{eON}", state, cookie );
1499
1500         ret = ber_flatten2( ber, &rspdata, 0 );
1501
1502         if ( ret < 0 ) {
1503 #ifdef NEW_LOGGING
1504                 LDAP_LOG ( OPERATION, RESULTS, 
1505                         "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n", 0, 0, 0 );
1506 #else
1507                 Debug( LDAP_DEBUG_TRACE, "bdb_build_lcup_done_ctrl: ber_flatten2 failed\n",
1508                         0, 0, 0 );
1509 #endif
1510                 send_ldap_result( conn, op, rc=LDAP_OTHER,
1511                         NULL, "internal error", NULL, NULL );
1512                 return ret;
1513         }
1514
1515         send_ldap_intermediate_resp( conn, op, err, matched, text, refs, rspoid, &rspdata, ctrls );
1516
1517         ber_free_buf( ber );
1518
1519         return LDAP_SUCCESS;
1520 }
1521 #endif