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