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