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