]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/lcup.c
Addition of servers/slapd/lcup.c and servers/slapd/back-bdb/lcup.c for persistent...
[openldap] / servers / slapd / back-bdb / lcup.c
1 /* lcup.c - lcup operations */
2 /*
3  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10
11 #include "back-bdb.h"
12 #include "idl.h"
13 #include "external.h"
14
15 #ifdef LDAP_CLIENT_UPDATE
16
17 int
18 bdb_abandon(
19         BackendDB       *be,
20         Connection      *conn,
21         ber_int_t       id )
22 {
23         Operation       *ps_list;
24         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
25
26         LDAP_LIST_FOREACH ( ps_list, &bdb->psearch_list, link ) {
27                 if ( ps_list->o_connid == conn->c_connid ) {
28                         if ( ps_list->o_msgid == id ) {
29                                 ps_list->o_abandon = 1;
30                                 LDAP_LIST_REMOVE( ps_list, link );
31                                 slap_op_free ( ps_list );
32                                 return LDAP_SUCCESS;
33                         }
34                 }
35         }
36         return LDAP_UNAVAILABLE;
37 }
38
39 int
40 bdb_add_psearch_spec(
41         BackendDB       *be,
42         Connection      *conn,
43         Operation       *op,
44         struct berval   *base,
45         struct berval   *nbase,
46         int             scope,
47         int             deref,
48         int             slimit,
49         int             tlimit,
50         Filter          *filter,
51         struct berval   *fstr,
52         AttributeName   *attrs,
53         int             attrsonly )
54 {
55         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
56
57         LDAP_LIST_FIRST(&op->psearch_spec) = (struct lcup_search_spec *)
58                         calloc ( 1, sizeof ( struct lcup_search_spec ) );
59
60         LDAP_LIST_FIRST(&op->psearch_spec)->op = op;
61
62         LDAP_LIST_FIRST(&op->psearch_spec)->base = ber_dupbv(NULL, base);
63         LDAP_LIST_FIRST(&op->psearch_spec)->nbase = ber_dupbv(NULL, nbase);
64
65         LDAP_LIST_FIRST(&op->psearch_spec)->scope = scope;
66         LDAP_LIST_FIRST(&op->psearch_spec)->deref = deref;
67         LDAP_LIST_FIRST(&op->psearch_spec)->slimit = slimit;
68         LDAP_LIST_FIRST(&op->psearch_spec)->tlimit = tlimit;
69
70         LDAP_LIST_FIRST(&op->psearch_spec)->filter = filter;
71         LDAP_LIST_FIRST(&op->psearch_spec)->filterstr = ber_dupbv(NULL, fstr);
72         LDAP_LIST_FIRST(&op->psearch_spec)->attrs = attrs;
73
74         LDAP_LIST_FIRST(&op->psearch_spec)->attrsonly = attrsonly;
75
76         LDAP_LIST_FIRST(&op->psearch_spec)->entry_count = 0;
77
78         LDAP_LIST_INSERT_HEAD( &bdb->psearch_list, op, link );
79 }
80
81 int
82 bdb_psearch(
83         BackendDB       *be,
84         Connection      *conn,
85         Operation       *op,
86         Operation       *ps_op,
87         Entry           *entry,
88         int             psearch_type )
89 {
90         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
91         int             rc;
92         const char *text = NULL;
93         time_t          stoptime;
94         unsigned        cursor;
95         ID              id;
96         ID              candidates[BDB_IDL_UM_SIZE];
97         Entry           *e = NULL;
98         BerVarray v2refs = NULL;
99         Entry   *matched = NULL;
100         struct berval   realbase = { 0, NULL };
101         int             nentries = 0;
102         int             manageDSAit;
103
104         Filter lcupf, csnfnot, csnfeq, csnfand, csnfge;
105         AttributeAssertion aa_ge, aa_eq;
106         struct berval entrycsn_bv = { 0, NULL };
107         struct berval latest_entrycsn_bv = { 0, NULL };
108
109         struct slap_limits_set *limit = NULL;
110         int isroot = 0;
111         int scopeok = 0;
112
113 #ifdef SLAP_X_FILTER_HASSUBORDINATES
114         int             filter_hasSubordinates = 0;
115         Attribute       *hasSubordinates = NULL;
116 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
117
118         u_int32_t       locker;
119         DB_LOCK         lock;
120
121         Connection      *ps_conn   = ps_op->o_conn;
122         struct berval   *base      = LDAP_LIST_FIRST(&ps_op->psearch_spec)->base;
123         struct berval   *nbase     = LDAP_LIST_FIRST(&ps_op->psearch_spec)->nbase;
124         int             scope      = LDAP_LIST_FIRST(&ps_op->psearch_spec)->scope;
125         int             deref      = LDAP_LIST_FIRST(&ps_op->psearch_spec)->deref;
126         int             slimit     = LDAP_LIST_FIRST(&ps_op->psearch_spec)->slimit;
127         int             tlimit     = LDAP_LIST_FIRST(&ps_op->psearch_spec)->tlimit;
128         Filter          *filter    = LDAP_LIST_FIRST(&ps_op->psearch_spec)->filter;
129         struct berval   *filterstr = LDAP_LIST_FIRST(&ps_op->psearch_spec)->filterstr;
130         int             attrsonly  = LDAP_LIST_FIRST(&ps_op->psearch_spec)->attrsonly;
131         AttributeName   *attrs;
132
133         if ( psearch_type != LCUP_PSEARCH_BY_DELETE &&
134                                 psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) {
135                 attrs     = LDAP_LIST_FIRST(&ps_op->psearch_spec)->attrs;
136         } else {
137                 attrs     = uuid_attr;
138         }
139
140 #ifdef NEW_LOGGING
141         LDAP_LOG ( OPERATION, ENTRY, "bdb_back_search\n", 0, 0, 0 );
142 #else
143         Debug( LDAP_DEBUG_TRACE, "=> bdb_back_search\n",
144                 0, 0, 0);
145 #endif
146
147         manageDSAit = get_manageDSAit( ps_op );
148
149         rc = LOCK_ID (bdb->bi_dbenv, &locker );
150         switch(rc) {
151         case 0:
152                 break;
153         default:
154                 send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER,
155                         NULL, "internal error", NULL, NULL );
156                 return rc;
157         }
158
159         if ( nbase->bv_len == 0 ) {
160                 /* DIT root special case */
161                 e = (Entry *) &slap_entry_root;
162                 rc = 0;
163         } else                                          
164 #ifdef BDB_ALIASES
165         /* get entry with reader lock */
166         if ( deref & LDAP_DEREF_FINDING ) {
167                 e = deref_dn_r( be, nbase-, &err, &matched, &text );
168
169         } else
170 #endif
171         {
172 dn2entry_retry:
173                 rc = bdb_dn2entry_r( be, NULL, nbase, &e, &matched, 0, locker, &lock );
174         }
175
176         switch(rc) {
177         case DB_NOTFOUND:
178         case 0:
179                 break;
180         case LDAP_BUSY:
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( ps_conn, ps_op, LDAP_BUSY,
188                         NULL, "ldap server busy", NULL, NULL );
189                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
190                 return LDAP_BUSY;
191         case DB_LOCK_DEADLOCK:
192         case DB_LOCK_NOTGRANTED:
193                 goto dn2entry_retry;
194         default:
195                 if (e != NULL) {
196                         bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
197                 }
198                 if (matched != NULL) {
199                         bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
200                 }
201                 send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER,
202                         NULL, "internal error", NULL, NULL );
203                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
204                 return rc;
205         }
206
207         if ( e == NULL ) {
208                 struct berval matched_dn = { 0, NULL };
209                 BerVarray refs = NULL;
210
211                 if ( matched != NULL ) {
212                         BerVarray erefs;
213                         ber_dupbv( &matched_dn, &matched->e_name );
214
215                         erefs = is_entry_referral( matched )
216                                 ? get_entry_referrals( be, ps_conn, ps_op, matched )
217                                 : NULL;
218
219                         bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
220                         matched = NULL;
221
222                         if( erefs ) {
223                                 refs = referral_rewrite( erefs, &matched_dn,
224                                         base, scope );
225                                 ber_bvarray_free( erefs );
226                         }
227
228                 } else {
229                         refs = referral_rewrite( default_referral,
230                                 NULL, base, scope );
231                 }
232
233                 send_ldap_result( ps_conn, ps_op,       rc=LDAP_REFERRAL ,
234                         matched_dn.bv_val, text, refs, NULL );
235
236                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
237                 if ( refs ) ber_bvarray_free( refs );
238                 if ( matched_dn.bv_val ) ber_memfree( matched_dn.bv_val );
239                 return rc;
240         }
241
242         if (!manageDSAit && e != &slap_entry_root && is_entry_referral( e ) ) {
243                 /* entry is a referral, don't allow add */
244                 struct berval matched_dn;
245                 BerVarray erefs, refs;
246                 
247                 ber_dupbv( &matched_dn, &e->e_name );
248                 erefs = get_entry_referrals( be, ps_conn, ps_op, e );
249                 refs = NULL;
250
251                 bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
252                 e = NULL;
253
254                 if( erefs ) {
255                         refs = referral_rewrite( erefs, &matched_dn,
256                                 base, scope );
257                         ber_bvarray_free( erefs );
258                 }
259
260 #ifdef NEW_LOGGING
261                 LDAP_LOG ( OPERATION, RESULTS, 
262                         "bdb_search: entry is referral\n", 0, 0, 0 );
263 #else
264                 Debug( LDAP_DEBUG_TRACE, "bdb_search: entry is referral\n",
265                         0, 0, 0 );
266 #endif
267
268                 send_ldap_result( ps_conn, ps_op, LDAP_REFERRAL,
269                         matched_dn.bv_val,
270                         refs ? NULL : "bad referral object",
271                         refs, NULL );
272
273                 LOCK_ID_FREE (bdb->bi_dbenv, locker );
274                 ber_bvarray_free( refs );
275                 ber_memfree( matched_dn.bv_val );
276                 return 1;
277         }
278
279         /* if not root, get appropriate limits */
280         if ( be_isroot( be, &ps_op->o_ndn ) ) {
281                 isroot = 1;
282         } else {
283                 ( void ) get_limits( be, &ps_op->o_ndn, &limit );
284         }
285
286         /* The time/size limits come first because they require very little
287          * effort, so there's no chance the candidates are selected and then 
288          * the request is not honored only because of time/size constraints */
289
290         /* if no time limit requested, use soft limit (unless root!) */
291         if ( isroot ) {
292                 if ( tlimit == 0 ) {
293                         tlimit = -1;    /* allow root to set no limit */
294                 }
295
296                 if ( slimit == 0 ) {
297                         slimit = -1;
298                 }
299
300         } else {
301                 /* if no limit is required, use soft limit */
302                 if ( tlimit <= 0 ) {
303                         tlimit = limit->lms_t_soft;
304
305                 /* if requested limit higher than hard limit, abort */
306                 } else if ( tlimit > limit->lms_t_hard ) {
307                         /* no hard limit means use soft instead */
308                         if ( limit->lms_t_hard == 0 && tlimit > limit->lms_t_soft ) {
309                                 tlimit = limit->lms_t_soft;
310
311                         /* positive hard limit means abort */
312                         } else if ( limit->lms_t_hard > 0 ) {
313                                 send_search_result( ps_conn, ps_op, 
314                                                 LDAP_UNWILLING_TO_PERFORM,
315                                                 NULL, NULL, NULL, NULL, 0 );
316                                 rc = 0;
317                                 goto done;
318                         }
319                 
320                         /* negative hard limit means no limit */
321                 }
322                 
323                 /* if no limit is required, use soft limit */
324                 if ( slimit <= 0 ) {
325                         slimit = limit->lms_s_soft;
326
327                 /* if requested limit higher than hard limit, abort */
328                 } else if ( slimit > limit->lms_s_hard ) {
329                         /* no hard limit means use soft instead */
330                         if ( limit->lms_s_hard == 0 && slimit > limit->lms_s_soft ) {
331                                 slimit = limit->lms_s_soft;
332
333                         /* positive hard limit means abort */
334                         } else if ( limit->lms_s_hard > 0 ) {
335                                 send_search_result( ps_conn, ps_op, 
336                                                 LDAP_UNWILLING_TO_PERFORM,
337                                                 NULL, NULL, NULL, NULL, 0 );
338                                 rc = 0; 
339                                 goto done;
340                         }
341                         
342                         /* negative hard limit means no limit */
343                 }
344         }
345
346         /* compute it anyway; root does not use it */
347         stoptime = ps_op->o_time + tlimit;
348
349         /* candidates = { e } */
350         candidates[0] = 1;
351         candidates[1] = entry->e_id;
352
353         /* need normalized dn below */
354         ber_dupbv( &realbase, &e->e_nname );
355
356         if ( e != &slap_entry_root ) {
357                 bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
358         }
359         e = NULL;
360
361         if ( candidates[0] == 0 ) {
362 #ifdef NEW_LOGGING
363                 LDAP_LOG ( OPERATION, RESULTS,
364                         "bdb_search: no candidates\n", 0, 0, 0 );
365 #else
366                 Debug( LDAP_DEBUG_TRACE, "bdb_search: no candidates\n",
367                         0, 0, 0 );
368 #endif
369
370                 send_search_result( ps_conn, ps_op,
371                         LDAP_SUCCESS,
372                         NULL, NULL, NULL, NULL, 0 );
373
374                 rc = 1;
375                 goto done;
376         }
377
378         /* if not root and candidates exceed to-be-checked entries, abort */
379         if ( !isroot && limit->lms_s_unchecked != -1 ) {
380                 if ( BDB_IDL_N(candidates) > (unsigned) limit->lms_s_unchecked ) {
381                         send_search_result( ps_conn, ps_op, 
382                                         LDAP_ADMINLIMIT_EXCEEDED,
383                                         NULL, NULL, NULL, NULL, 0 );
384                         rc = 1;
385                         goto done;
386                 }
387         }
388
389 #ifdef SLAP_X_FILTER_HASSUBORDINATES
390         /*
391          * is hasSubordinates used in the filter ?
392          * FIXME: we may compute this directly when parsing the filter
393          */
394         filter_hasSubordinates = filter_has_subordinates( filter );
395 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
396
397         lcupf.f_choice = LDAP_FILTER_AND;
398         lcupf.f_and = &csnfnot;
399         lcupf.f_next = NULL;
400
401         csnfnot.f_choice = LDAP_FILTER_NOT;
402         csnfnot.f_not = &csnfeq;
403         csnfnot.f_next = &csnfand;
404
405         csnfeq.f_choice = LDAP_FILTER_EQUALITY;
406         csnfeq.f_ava = &aa_eq;
407         csnfeq.f_av_desc = slap_schema.si_ad_entryCSN;
408         ber_dupbv( &csnfeq.f_av_value, &ps_op->o_clientupdate_state );
409
410         csnfand.f_choice = LDAP_FILTER_AND;
411         csnfand.f_and = &csnfge;
412         csnfand.f_next = NULL;
413
414         csnfge.f_choice = LDAP_FILTER_GE;
415         csnfge.f_ava = &aa_ge;
416         csnfge.f_av_desc = slap_schema.si_ad_entryCSN;
417         ber_dupbv( &csnfge.f_av_value, &ps_op->o_clientupdate_state );
418         csnfge.f_next = filter;
419
420         if ( !BDB_IDL_IS_RANGE( candidates ) ) {
421                 cursor = bdb_idl_search( candidates, entry->e_id );
422                 if ( candidates[cursor] != entry->e_id ) {
423                         rc = LDAP_SUCCESS;
424                         goto done;
425                 }
426         } else {
427                 if ( entry->e_id < BDB_IDL_RANGE_FIRST(candidates) &&
428                      entry->e_id > BDB_IDL_RANGE_LAST(candidates) ) {
429                         rc = LDAP_SUCCESS;
430                         goto done;
431                 }
432         }
433
434         id = entry->e_id;
435
436         /* check for abandon */
437         if ( ps_op->o_abandon ) {
438                 rc = 0;
439                 goto done;
440         }
441
442         /* check time limit */
443         if ( tlimit != -1 && slap_get_time() > stoptime ) {
444                 send_search_result( ps_conn, ps_op, rc = LDAP_TIMELIMIT_EXCEEDED,
445                         NULL, NULL, v2refs, NULL, nentries );
446                 goto done;
447         }
448
449         e = entry;
450
451 #ifdef BDB_SUBENTRIES
452         if ( is_entry_subentry( e ) ) {
453                 if( scope != LDAP_SCOPE_BASE ) {
454                         if(!get_subentries_visibility( ps_op )) {
455                                 /* only subentries are visible */
456                                 goto test_done;
457                         }
458
459                 } else if ( get_subentries( ps_op ) &&
460                         !get_subentries_visibility( ps_op ))
461                 {
462                         /* only subentries are visible */
463                         goto test_done;
464                 }
465
466         } else if ( get_subentries_visibility( ps_op )) {
467                 /* only subentries are visible */
468                 goto test_done;
469         }
470 #endif
471
472 #ifdef BDB_ALIASES
473         if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) {
474                 Entry *matched;
475                 int err;
476                 const char *text;
477                 
478                 e = deref_entry_r( be, e, &err, &matched, &text );
479
480                 if( e == NULL ) {
481                         e = matched;
482                         goto test_done;
483                 }
484
485                 if( e->e_id == id ) {
486                         /* circular loop */
487                         goto test_done;
488                 }
489
490                 /* need to skip alias which deref into scope */
491                 if( scope & LDAP_SCOPE_ONELEVEL ) {
492                         struct berval   pdn;
493                         
494                         dnParent( &e->e_nname, &pdn ):
495                         if ( ber_bvcmp( pdn, &realbase ) ) {
496                                 goto test_done;
497                         }
498
499                 } else if ( dnIsSuffix( &e->e_nname, &realbase ) ) {
500                         /* alias is within scope */
501 #ifdef NEW_LOGGING
502                         LDAP_LOG ( OPERATION, RESULTS,
503                                 "bdb_search: \"%s\" in subtree\n", e->edn, 0, 0);
504 #else
505                         Debug( LDAP_DEBUG_TRACE,
506                                 "bdb_search: \"%s\" in subtree\n",
507                                 e->e_dn, 0, 0 );
508 #endif
509                         goto test_done;
510                 }
511
512                 scopeok = 1;
513         }
514 #endif
515
516         /*
517          * if it's a referral, add it to the list of referrals. only do
518          * this for non-base searches, and don't check the filter
519          * explicitly here since it's only a candidate anyway.
520          */
521         if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
522                 is_entry_referral( e ) )
523         {
524                 struct berval   dn;
525
526                 /* check scope */
527                 if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
528                         if ( !be_issuffix( be, &e->e_nname ) ) {
529                                 dnParent( &e->e_nname, &dn );
530                                 scopeok = dn_match( &dn, &realbase );
531                         } else {
532                                 scopeok = (realbase.bv_len == 0);
533                         }
534
535                 } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
536                         scopeok = dnIsSuffix( &e->e_nname, &realbase );
537
538                 } else {
539                         scopeok = 1;
540                 }
541
542                 if( scopeok ) {
543                         BerVarray erefs = get_entry_referrals(
544                                 be, ps_conn, ps_op, e );
545                         BerVarray refs = referral_rewrite( erefs,
546                                 &e->e_name, NULL,
547                                 scope == LDAP_SCOPE_SUBTREE
548                                         ? LDAP_SCOPE_SUBTREE
549                                         : LDAP_SCOPE_BASE );
550
551                         send_search_reference( be, ps_conn, ps_op,
552                                 e, refs, NULL, &v2refs );
553
554                         ber_bvarray_free( refs );
555
556                 } else {
557 #ifdef NEW_LOGGING
558                         LDAP_LOG(OPERATION, DETAIL2, 
559                                 "bdb_search: candidate referral %ld scope not okay\n",
560                                 id, 0, 0 );
561 #else
562                         Debug( LDAP_DEBUG_TRACE,
563                                 "bdb_search: candidate referral %ld scope not okay\n",
564                                 id, 0, 0 );
565 #endif
566                 }
567
568                 goto test_done;
569         }
570
571 #ifdef SLAP_X_FILTER_HASSUBORDINATES
572         /*
573          * if hasSubordinates is used in the filter,
574          * append it to the entry's attributes
575          */
576         if ( filter_hasSubordinates ) {
577                 int     hs;
578
579                 rc = bdb_hasSubordinates( be, ps_conn, ps_op, e, &hs);
580                 if ( rc != LDAP_SUCCESS ) {
581                         goto test_done;
582                 }
583
584                 hasSubordinates = slap_operational_hasSubordinate(
585                         hs == LDAP_COMPARE_TRUE );
586
587                 if ( hasSubordinates == NULL ) {
588                         goto test_done;
589                 }
590
591                 hasSubordinates->a_next = e->e_attrs;
592                 e->e_attrs = hasSubordinates;
593         }
594 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
595
596         if ( psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) {
597                 rc = test_filter( be, ps_conn, ps_op, e, &lcupf );
598         } else {
599                 rc = LDAP_COMPARE_TRUE;
600         }
601
602 #ifdef SLAP_X_FILTER_HASSUBORDINATES
603         if ( hasSubordinates ) {
604                 /*
605                  * FIXME: this is fairly inefficient, because 
606                  * if hasSubordinates is among the required
607                  * attrs, it will be added again later;
608                  * maybe we should leave it and check
609                  * check later if it's already present,
610                  * if required
611                  */
612                 e->e_attrs = e->e_attrs->a_next;
613                 attr_free( hasSubordinates );
614         }
615 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
616
617         if ( rc == LDAP_COMPARE_TRUE ) {
618                 struct berval   dn;
619
620                 /* check scope */
621                 if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
622                         if ( be_issuffix( be, &e->e_nname ) ) {
623                                 scopeok = (realbase.bv_len == 0);
624                         } else {
625                                 dnParent( &e->e_nname, &dn );
626                                 scopeok = dn_match( &dn, &realbase );
627                         }
628
629                 } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
630                         scopeok = dnIsSuffix( &e->e_nname, &realbase );
631
632                 } else {
633                         scopeok = 1;
634                 }
635
636                 if ( scopeok ) {
637                         /* check size limit */
638                         if ( --slimit == -1 ) {
639                                 send_search_result( ps_conn, ps_op,
640                                         rc = LDAP_SIZELIMIT_EXCEEDED, NULL, NULL,
641                                         v2refs, NULL, nentries );
642                                 goto done;
643                         }
644
645                         if (e) {
646                                 int result;
647                                 
648 #if 0   /* noop is masked SLAP_CTRL_UPDATE */
649                                 if( ps_op->o_noop ) {
650                                         result = 0;
651                                 } else
652 #endif
653                                 {
654                                         if ( psearch_type == LCUP_PSEARCH_BY_ADD ||
655                                              psearch_type == LCUP_PSEARCH_BY_DELETE ||
656                                              psearch_type == LCUP_PSEARCH_BY_MODIFY ||
657                                              psearch_type == LCUP_PSEARCH_BY_SCOPEOUT ) {
658                                                 Attribute* a;
659                                                 int ret;
660                                                 int res;
661                                                 const char *text = NULL;
662                                                 LDAPControl *ctrls[2];
663                                                 struct berval *bv;
664
665                                                 BerElement *ber = ber_alloc_t( LBER_USE_DER );
666
667                                                 if ( ber == NULL ) {
668 #ifdef NEW_LOGGING
669                                                         LDAP_LOG ( OPERATION, RESULTS, 
670                                                                 "bdb_search: ber_alloc_t failed\n",
671                                                                 0, 0, 0 );
672 #else
673                                                         Debug( LDAP_DEBUG_TRACE,
674                                                                 "bdb_search: ber_alloc_t failed\n",
675                                                                 0, 0, 0 );
676 #endif
677                                                         send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER,
678                                                                 NULL, "internal error", NULL, NULL );
679                                                         goto done;
680                                                 }
681
682                                                 LDAP_LIST_FIRST(&ps_op->psearch_spec)->entry_count++;
683
684                                                 ctrls[0] = ch_malloc ( sizeof ( LDAPControl ) );
685                                                 ctrls[1] = NULL;
686
687                                                 if ( LDAP_LIST_FIRST(&ps_op->psearch_spec)->entry_count % ps_op->o_clientupdate_interval == 0 ) {
688                                                         /* Send cookie */
689                                                         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
690                                                                 AttributeDescription *desc = a->a_desc;
691                                                                 if ( desc == slap_schema.si_ad_entryCSN ) {
692                                                                         ber_dupbv( &entrycsn_bv, &a->a_vals[0] );
693                                                                         if ( latest_entrycsn_bv.bv_val == NULL ) {
694                                                                                 ber_dupbv( &latest_entrycsn_bv, &entrycsn_bv );
695                                                                         } else {
696                                                                                 res = value_match( &ret, desc,
697                                                                                         desc->ad_type->sat_ordering,
698                                                                                         SLAP_MR_ASSERTION_SYNTAX_MATCH,
699                                                                                         &entrycsn_bv, &latest_entrycsn_bv, &text );
700                                                                                 if ( res != LDAP_SUCCESS ) {
701                                                                                         ret = 0;
702 #ifdef NEW_LOGGING
703                                                                                         LDAP_LOG ( OPERATION, RESULTS, 
704                                                                                                 "bdb_search: value_match failed\n",
705                                                                                                 0, 0, 0 );
706 #else
707                                                                                         Debug( LDAP_DEBUG_TRACE,
708                                                                                                 "bdb_search: value_match failed\n",
709                                                                                                 0, 0, 0 );
710 #endif
711                                                                                 }
712
713                                                                                 if ( ret > 0 ) {
714                                                                                         ch_free( latest_entrycsn_bv.bv_val );
715                                                                                         latest_entrycsn_bv.bv_val = NULL;
716                                                                                         ber_dupbv( &latest_entrycsn_bv,
717                                                                                                 &entrycsn_bv );
718                                                                                 }
719                                                                         }
720                                                                 }
721                                                         }
722
723                                                         if ( psearch_type != LCUP_PSEARCH_BY_DELETE || psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) {
724                                                                 ber_printf( ber,
725                                                                         "{bb{sON}N}",
726                                                                         SLAP_LCUP_STATE_UPDATE_FALSE,
727                                                                         SLAP_LCUP_ENTRY_DELETED_FALSE,
728                                                                         LCUP_COOKIE_OID, &entrycsn_bv );
729                                                         } else {
730                                                                 ber_printf( ber,
731                                                                         "{bb{sON}N}",
732                                                                         SLAP_LCUP_STATE_UPDATE_FALSE,
733                                                                         SLAP_LCUP_ENTRY_DELETED_TRUE,
734                                                                         LCUP_COOKIE_OID, &entrycsn_bv );
735                                                         }
736
737                                                         ch_free( entrycsn_bv.bv_val );
738                                                         entrycsn_bv.bv_val = NULL;
739
740                                                 } else {
741                                                         /* Do not send cookie */
742                                                         if ( psearch_type != LCUP_PSEARCH_BY_DELETE || psearch_type != LCUP_PSEARCH_BY_SCOPEOUT ) {
743                                                                 ber_printf( ber,
744                                                                         "{bbN}",
745                                                                         SLAP_LCUP_STATE_UPDATE_FALSE,
746                                                                         SLAP_LCUP_ENTRY_DELETED_FALSE );
747                                                         } else {
748                                                                 ber_printf( ber,
749                                                                         "{bbN}",
750                                                                         SLAP_LCUP_STATE_UPDATE_FALSE,
751                                                                         SLAP_LCUP_ENTRY_DELETED_TRUE );
752                                                         }
753                                                 }
754
755                                                 ctrls[0]->ldctl_oid = LDAP_CONTROL_ENTRY_UPDATE;
756                                                 ctrls[0]->ldctl_iscritical = ps_op->o_clientupdate;
757                                                 ret = ber_flatten( ber, &bv );
758
759                                                 if ( ret < 0 ) {
760 #ifdef NEW_LOGGING
761                                                         LDAP_LOG ( OPERATION, RESULTS, 
762                                                                 "bdb_search: ber_flatten failed\n",
763                                                                 0, 0, 0 );
764 #else
765                                                         Debug( LDAP_DEBUG_TRACE,
766                                                                 "bdb_search: ber_flatten failed\n",
767                                                                 0, 0, 0 );
768 #endif
769                                                         send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER,
770                                                                 NULL, "internal error", NULL, NULL );
771                                                         goto done;
772                                                 }
773
774                                                 ber_dupbv( &ctrls[0]->ldctl_value, bv );
775                                                 
776                                                 result = send_search_entry( be, ps_conn, ps_op,
777                                                         e, attrs, attrsonly, ctrls);
778
779                                                 ch_free( ctrls[0]->ldctl_value.bv_val );
780                                                 ch_free( ctrls[0] );
781                                                 ber_free( ber, 1 );
782                                                 ber_bvfree( bv );
783
784                                                 if ( psearch_type == LCUP_PSEARCH_BY_MODIFY ) {
785                                                         struct psid_entry* psid_e;
786                                                         LDAP_LIST_FOREACH( psid_e, &op->premodify_list, link) {
787                                                                 if (psid_e->ps == LDAP_LIST_FIRST(&ps_op->psearch_spec)) {
788                                                                         LDAP_LIST_REMOVE(psid_e, link);
789                                                                         break;
790                                                                 }
791                                                         }
792                                                         if (psid_e != NULL) 
793                                                                 free (psid_e);
794                                                 }
795                                         } else if ( psearch_type == LCUP_PSEARCH_BY_PREMODIFY ) {
796                                                 struct psid_entry* psid_e;
797                                                 psid_e = (struct psid_entry *) calloc (1, sizeof (struct psid_entry));
798                                                 psid_e->ps = LDAP_LIST_FIRST(&ps_op->psearch_spec);
799                                                 LDAP_LIST_INSERT_HEAD( &op->premodify_list, psid_e, link );
800                                         }
801                                         else
802                                         {
803                                                 printf("Error !\n");
804                                         }
805                                 }
806
807                                 switch (result) {
808                                 case 0:         /* entry sent ok */
809                                         nentries++;
810                                         break;
811                                 case 1:         /* entry not sent */
812                                         break;
813                                 case -1:        /* connection closed */
814                                         rc = LDAP_OTHER;
815                                         goto done;
816                                 }
817                         }
818                 } else {
819 #ifdef NEW_LOGGING
820                         LDAP_LOG ( OPERATION, RESULTS,
821                                 "bdb_search: %ld scope not okay\n", (long) id, 0, 0);
822 #else
823                         Debug( LDAP_DEBUG_TRACE,
824                                 "bdb_search: %ld scope not okay\n",
825                                 (long) id, 0, 0 );
826 #endif
827                 }
828         } else {
829 #ifdef NEW_LOGGING
830                 LDAP_LOG ( OPERATION, RESULTS,
831                         "bdb_search: %ld does match filter\n", (long) id, 0, 0);
832 #else
833                 Debug( LDAP_DEBUG_TRACE,
834                         "bdb_search: %ld does match filter\n",
835                         (long) id, 0, 0 );
836 #endif
837         }
838
839 test_done:
840         rc = LDAP_SUCCESS;
841
842 done:
843         if ( csnfeq.f_ava != NULL && csnfeq.f_av_value.bv_val != NULL ) {
844                 ch_free( csnfeq.f_av_value.bv_val );
845         }
846         
847         if ( csnfge.f_ava != NULL && csnfge.f_av_value.bv_val != NULL ) {
848                 ch_free( csnfge.f_av_value.bv_val );
849         }
850
851         LOCK_ID_FREE (bdb->bi_dbenv, locker );
852
853         if( v2refs ) ber_bvarray_free( v2refs );
854         if( realbase.bv_val ) ch_free( realbase.bv_val );
855
856         return rc;
857 }
858
859 #endif /* LDAP_CLIENT_UPDATE */