]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/lcup.c
Reorder header inclusion to resolve ITS#2204.
[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
662                                                 BerElement *ber = ber_alloc_t( LBER_USE_DER );
663
664                                                 if ( ber == NULL ) {
665 #ifdef NEW_LOGGING
666                                                         LDAP_LOG ( OPERATION, RESULTS, 
667                                                                 "bdb_search: ber_alloc_t failed\n",
668                                                                 0, 0, 0 );
669 #else
670                                                         Debug( LDAP_DEBUG_TRACE,
671                                                                 "bdb_search: ber_alloc_t failed\n",
672                                                                 0, 0, 0 );
673 #endif
674                                                         send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER,
675                                                                 NULL, "internal error", NULL, NULL );
676                                                         goto done;
677                                                 }
678
679                                                 LDAP_LIST_FIRST(&ps_op->psearch_spec)->entry_count++;
680
681                                                 ctrls[0] = ch_malloc ( sizeof ( LDAPControl ) );
682                                                 ctrls[1] = NULL;
683
684                                                 if ( LDAP_LIST_FIRST(
685                                                         &ps_op->psearch_spec)->entry_count %
686                                                                 ps_op->o_clientupdate_interval == 0 )
687                                                 {
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,
695                                                                                         &entrycsn_bv );
696                                                                         } else {
697                                                                                 res = value_match( &ret, desc,
698                                                                                         desc->ad_type->sat_ordering,
699                                                                                         SLAP_MR_ASSERTION_SYNTAX_MATCH,
700                                                                                         &entrycsn_bv, &latest_entrycsn_bv,
701                                                                                         &text );
702                                                                                 if ( res != LDAP_SUCCESS ) {
703                                                                                         ret = 0;
704 #ifdef NEW_LOGGING
705                                                                                         LDAP_LOG ( OPERATION, RESULTS, 
706                                                                                                 "bdb_search: "
707                                                                                                 "value_match failed\n",
708                                                                                                 0, 0, 0 );
709 #else
710                                                                                         Debug( LDAP_DEBUG_TRACE,
711                                                                                                 "bdb_search: "
712                                                                                                 "value_match failed\n",
713                                                                                                 0, 0, 0 );
714 #endif
715                                                                                 }
716
717                                                                                 if ( ret > 0 ) {
718                                                                                         ch_free(latest_entrycsn_bv.bv_val);
719                                                                                         latest_entrycsn_bv.bv_val = NULL;
720                                                                                         ber_dupbv( &latest_entrycsn_bv,
721                                                                                                 &entrycsn_bv );
722                                                                                 }
723                                                                         }
724                                                                 }
725                                                         }
726
727                                                         if ( psearch_type != LCUP_PSEARCH_BY_DELETE ||
728                                                                 psearch_type != LCUP_PSEARCH_BY_SCOPEOUT )
729                                                         {
730                                                                 ber_printf( ber, "{bb{sON}N}",
731                                                                         SLAP_LCUP_STATE_UPDATE_FALSE,
732                                                                         SLAP_LCUP_ENTRY_DELETED_FALSE,
733                                                                         LCUP_COOKIE_OID, &entrycsn_bv );
734                                                         } else {
735                                                                 ber_printf( ber, "{bb{sON}N}",
736                                                                         SLAP_LCUP_STATE_UPDATE_FALSE,
737                                                                         SLAP_LCUP_ENTRY_DELETED_TRUE,
738                                                                         LCUP_COOKIE_OID, &entrycsn_bv );
739                                                         }
740
741                                                         ch_free( entrycsn_bv.bv_val );
742                                                         entrycsn_bv.bv_val = NULL;
743
744                                                 } else {
745                                                         /* Do not send cookie */
746                                                         if ( psearch_type != LCUP_PSEARCH_BY_DELETE ||
747                                                                 psearch_type != LCUP_PSEARCH_BY_SCOPEOUT )
748                                                         {
749                                                                 ber_printf( ber, "{bbN}",
750                                                                         SLAP_LCUP_STATE_UPDATE_FALSE,
751                                                                         SLAP_LCUP_ENTRY_DELETED_FALSE );
752                                                         } else {
753                                                                 ber_printf( ber, "{bbN}",
754                                                                         SLAP_LCUP_STATE_UPDATE_FALSE,
755                                                                         SLAP_LCUP_ENTRY_DELETED_TRUE );
756                                                         }
757                                                 }
758
759                                                 ctrls[0]->ldctl_oid = LDAP_CONTROL_ENTRY_UPDATE;
760                                                 ctrls[0]->ldctl_iscritical = ps_op->o_clientupdate;
761                                                 ret = ber_flatten( ber, &bv );
762
763                                                 if ( ret < 0 ) {
764 #ifdef NEW_LOGGING
765                                                         LDAP_LOG ( OPERATION, RESULTS, 
766                                                                 "bdb_search: ber_flatten failed\n",
767                                                                 0, 0, 0 );
768 #else
769                                                         Debug( LDAP_DEBUG_TRACE,
770                                                                 "bdb_search: ber_flatten failed\n",
771                                                                 0, 0, 0 );
772 #endif
773                                                         send_ldap_result( ps_conn, ps_op, rc=LDAP_OTHER,
774                                                                 NULL, "internal error", NULL, NULL );
775                                                         goto done;
776                                                 }
777
778                                                 ber_dupbv( &ctrls[0]->ldctl_value, bv );
779                                                 
780                                                 result = send_search_entry( be, ps_conn, ps_op,
781                                                         e, attrs, attrsonly, ctrls);
782
783                                                 ch_free( ctrls[0]->ldctl_value.bv_val );
784                                                 ch_free( ctrls[0] );
785                                                 ber_free( ber, 1 );
786                                                 ber_bvfree( bv );
787
788                                                 if ( psearch_type == LCUP_PSEARCH_BY_MODIFY ) {
789                                                         struct psid_entry* psid_e;
790                                                         LDAP_LIST_FOREACH( psid_e, &op->premodify_list,
791                                                                 link)
792                                                         {
793                                                                 if( psid_e->ps ==
794                                                                         LDAP_LIST_FIRST(&ps_op->psearch_spec))
795                                                                 {
796                                                                         LDAP_LIST_REMOVE(psid_e, link);
797                                                                         break;
798                                                                 }
799                                                         }
800                                                         if (psid_e != NULL) free (psid_e);
801                                                 }
802
803                                         } else if ( psearch_type == LCUP_PSEARCH_BY_PREMODIFY ) {
804                                                 struct psid_entry* psid_e;
805                                                 psid_e = (struct psid_entry *) calloc (1,
806                                                         sizeof(struct psid_entry));
807                                                 psid_e->ps = LDAP_LIST_FIRST(&ps_op->psearch_spec);
808                                                 LDAP_LIST_INSERT_HEAD( &op->premodify_list,
809                                                         psid_e, link );
810
811                                         } else {
812                                                 printf("Error !\n");
813                                         }
814                                 }
815
816                                 switch (result) {
817                                 case 0:         /* entry sent ok */
818                                         nentries++;
819                                         break;
820                                 case 1:         /* entry not sent */
821                                         break;
822                                 case -1:        /* connection closed */
823                                         rc = LDAP_OTHER;
824                                         goto done;
825                                 }
826                         }
827                 } else {
828 #ifdef NEW_LOGGING
829                         LDAP_LOG ( OPERATION, RESULTS,
830                                 "bdb_search: %ld scope not okay\n", (long) id, 0, 0);
831 #else
832                         Debug( LDAP_DEBUG_TRACE,
833                                 "bdb_search: %ld scope not okay\n", (long) id, 0, 0 );
834 #endif
835                 }
836         } else {
837 #ifdef NEW_LOGGING
838                 LDAP_LOG ( OPERATION, RESULTS,
839                         "bdb_search: %ld does match filter\n", (long) id, 0, 0);
840 #else
841                 Debug( LDAP_DEBUG_TRACE,
842                         "bdb_search: %ld does match filter\n",
843                         (long) id, 0, 0 );
844 #endif
845         }
846
847 test_done:
848         rc = LDAP_SUCCESS;
849
850 done:
851         if ( csnfeq.f_ava != NULL && csnfeq.f_av_value.bv_val != NULL ) {
852                 ch_free( csnfeq.f_av_value.bv_val );
853         }
854
855         if ( csnfge.f_ava != NULL && csnfge.f_av_value.bv_val != NULL ) {
856                 ch_free( csnfge.f_av_value.bv_val );
857         }
858
859         LOCK_ID_FREE( bdb->bi_dbenv, locker );
860
861         if( v2refs ) ber_bvarray_free( v2refs );
862         if( realbase.bv_val ) ch_free( realbase.bv_val );
863         if ( psearch_type == LCUP_PSEARCH_BY_DELETE ||
864              psearch_type == LCUP_PSEARCH_BY_SCOPEOUT )
865                 ch_free( attrs[0].an_name.bv_val );
866
867         return rc;
868 }
869
870 static int psearch_base_candidate(
871         BackendDB       *be,
872         Entry   *e,
873         ID              *ids )
874 {
875 #ifdef NEW_LOGGING
876         LDAP_LOG ( OPERATION, ENTRY,
877                 "psearch_base_candidate: base: \"%s\" (0x%08lx)\n", e->e_dn, (long) e->e_id, 0);
878 #else
879         Debug(LDAP_DEBUG_ARGS, "psearch_base_candidates: base: \"%s\" (0x%08lx)\n",
880                 e->e_dn, (long) e->e_id, 0);
881 #endif
882
883         ids[0] = 1;
884         ids[1] = e->e_id;
885         return 0;
886 }
887
888 /* Look for "objectClass Present" in this filter.
889  * Also count depth of filter tree while we're at it.
890  */
891 static int psearch_oc_filter(
892         Filter *f,
893         int cur,
894         int *max
895 )
896 {
897         int rc = 0;
898
899         if( cur > *max ) *max = cur;
900
901         switch(f->f_choice) {
902         case LDAP_FILTER_PRESENT:
903                 if (f->f_desc == slap_schema.si_ad_objectClass) {
904                         rc = 1;
905                 }
906                 break;
907
908         case LDAP_FILTER_AND:
909         case LDAP_FILTER_OR:
910                 cur++;
911                 for (f=f->f_and; f; f=f->f_next) {
912                         (void) psearch_oc_filter(f, cur, max);
913                 }
914                 break;
915
916         default:
917                 break;
918         }
919         return rc;
920 }
921
922 static int psearch_candidates(
923         BackendDB *be,
924         Operation *op,
925         Entry *e,
926         Filter *filter,
927         int scope,
928         int deref,
929         ID      *ids )
930 {
931         int rc, depth = 1;
932         Filter          f, scopef, rf, xf;
933         ID              *stack;
934         AttributeAssertion aa_ref;
935 #ifdef BDB_SUBENTRIES
936         Filter  sf;
937         AttributeAssertion aa_subentry;
938 #endif
939 #ifdef BDB_ALIASES
940         Filter  af;
941         AttributeAssertion aa_alias;
942 #endif
943
944         /*
945          * This routine takes as input a filter (user-filter)
946          * and rewrites it as follows:
947          *      (&(scope=DN)[(objectClass=subentry)]
948          *              (|[(objectClass=referral)(objectClass=alias)](user-filter))
949          */
950
951 #ifdef NEW_LOGGING
952         LDAP_LOG ( OPERATION, ENTRY,
953                 "psearch_candidates: base=\"%s\" (0x%08lx) scope=%d\n", 
954                 e->e_dn, (long) e->e_id, scope);
955 #else
956         Debug(LDAP_DEBUG_TRACE,
957                 "psearch_candidates: base=\"%s\" (0x%08lx) scope=%d\n",
958                 e->e_dn, (long) e->e_id, scope );
959 #endif
960
961         xf.f_or = filter;
962         xf.f_choice = LDAP_FILTER_OR;
963         xf.f_next = NULL;
964
965         /* If the user's filter uses objectClass=*,
966          * these clauses are redundant.
967          */
968         if (!psearch_oc_filter(filter, 1, &depth) && !get_subentries_visibility(op) ) {
969                 if( !get_manageDSAit(op) ) { /* match referrals */
970                         struct berval bv_ref = { sizeof("REFERRAL")-1, "REFERRAL" };
971                         rf.f_choice = LDAP_FILTER_EQUALITY;
972                         rf.f_ava = &aa_ref;
973                         rf.f_av_desc = slap_schema.si_ad_objectClass;
974                         rf.f_av_value = bv_ref;
975                         rf.f_next = xf.f_or;
976                         xf.f_or = &rf;
977                 }
978
979 #ifdef BDB_ALIASES
980                 if( deref & LDAP_DEREF_SEARCHING ) { /* match aliases */
981                         struct berval bv_alias = { sizeof("ALIAS")-1, "ALIAS" };
982                         af.f_choice = LDAP_FILTER_EQUALITY;
983                         af.f_ava = &aa_alias;
984                         af.f_av_desc = slap_schema.si_ad_objectClass;
985                         af.f_av_value = bv_alias;
986                         af.f_next = xf.f_or;
987                         xf.f_or = &af;
988                 }
989 #endif
990                 /* We added one of these clauses, filter depth increased */
991                 if( xf.f_or != filter ) depth++;
992         }
993
994         f.f_next = NULL;
995         f.f_choice = LDAP_FILTER_AND;
996         f.f_and = &scopef;
997         scopef.f_choice = scope == LDAP_SCOPE_SUBTREE
998                 ? SLAPD_FILTER_DN_SUBTREE
999                 : SLAPD_FILTER_DN_ONE;
1000         scopef.f_dn = &e->e_nname;
1001         scopef.f_next = xf.f_or == filter ? filter : &xf ;
1002         /* Filter depth increased again, adding scope clause */
1003         depth++;
1004
1005 #ifdef BDB_SUBENTRIES
1006         if( get_subentries_visibility( op ) ) {
1007                 struct berval bv_subentry = { sizeof("SUBENTRY")-1, "SUBENTRY" };
1008                 sf.f_choice = LDAP_FILTER_EQUALITY;
1009                 sf.f_ava = &aa_subentry;
1010                 sf.f_av_desc = slap_schema.si_ad_objectClass;
1011                 sf.f_av_value = bv_subentry;
1012                 sf.f_next = scopef.f_next;
1013                 scopef.f_next = &sf;
1014         }
1015 #endif
1016
1017         /* Allocate IDL stack, plus 1 more for former tmp */
1018         stack = ch_malloc( (depth + 1) * BDB_IDL_UM_SIZE * sizeof( ID ) );
1019
1020         rc = bdb_filter_candidates( be, &f, ids, stack, stack+BDB_IDL_UM_SIZE );
1021
1022         ch_free( stack );
1023
1024         if( rc ) {
1025 #ifdef NEW_LOGGING
1026                 LDAP_LOG ( OPERATION, DETAIL1,
1027                         "bdb_psearch_candidates: failed (rc=%d)\n", rc, 0, 0  );
1028 #else
1029                 Debug(LDAP_DEBUG_TRACE,
1030                         "bdb_psearch_candidates: failed (rc=%d)\n",
1031                         rc, NULL, NULL );
1032 #endif
1033
1034         } else {
1035 #ifdef NEW_LOGGING
1036                 LDAP_LOG ( OPERATION, DETAIL1,
1037                         "bdb_psearch_candidates: id=%ld first=%ld last=%ld\n",
1038                         (long) ids[0], (long) BDB_IDL_FIRST(ids), 
1039                         (long) BDB_IDL_LAST(ids));
1040 #else
1041                 Debug(LDAP_DEBUG_TRACE,
1042                         "bdb_psearch_candidates: id=%ld first=%ld last=%ld\n",
1043                         (long) ids[0],
1044                         (long) BDB_IDL_FIRST(ids),
1045                         (long) BDB_IDL_LAST(ids) );
1046 #endif
1047         }
1048
1049         return rc;
1050 }
1051
1052
1053 #endif /* LDAP_CLIENT_UPDATE */