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