]> git.sur5r.net Git - openldap/blob - servers/slapd/filterentry.c
Use attr_valfind instead of value_find_ex to optimize lookups
[openldap] / servers / slapd / filterentry.c
1 /* filterentry.c - apply a filter to an entry */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2007 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30
31 #include <ac/socket.h>
32 #include <ac/string.h>
33
34 #include "slap.h"
35
36 #ifdef LDAP_COMP_MATCH
37 #include "component.h"
38 #endif
39
40 static int      test_filter_and( Operation *op, Entry *e, Filter *flist );
41 static int      test_filter_or( Operation *op, Entry *e, Filter *flist );
42 static int      test_substrings_filter( Operation *op, Entry *e, Filter *f);
43 static int      test_ava_filter( Operation *op,
44         Entry *e, AttributeAssertion *ava, int type );
45 static int      test_mra_filter( Operation *op,
46         Entry *e, MatchingRuleAssertion *mra );
47 static int      test_presence_filter( Operation *op,
48         Entry *e, AttributeDescription *desc );
49
50
51 /*
52  * test_filter - test a filter against a single entry.
53  * returns:
54  *              LDAP_COMPARE_TRUE               filter matched
55  *              LDAP_COMPARE_FALSE              filter did not match
56  *              SLAPD_COMPARE_UNDEFINED filter is undefined
57  *      or an ldap result code indicating error
58  */
59
60 int
61 test_filter(
62     Operation   *op,
63     Entry       *e,
64     Filter      *f )
65 {
66         int     rc;
67         Debug( LDAP_DEBUG_FILTER, "=> test_filter\n", 0, 0, 0 );
68
69         if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
70                 Debug( LDAP_DEBUG_FILTER, "    UNDEFINED\n", 0, 0, 0 );
71                 rc = SLAPD_COMPARE_UNDEFINED;
72                 goto out;
73         }
74
75         switch ( f->f_choice ) {
76         case SLAPD_FILTER_COMPUTED:
77                 Debug( LDAP_DEBUG_FILTER, "    COMPUTED %s (%d)\n",
78                         f->f_result == LDAP_COMPARE_FALSE ? "false" :
79                         f->f_result == LDAP_COMPARE_TRUE ? "true" :
80                         f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" : "error",
81                         f->f_result, 0 );
82
83                 rc = f->f_result;
84                 break;
85
86         case LDAP_FILTER_EQUALITY:
87                 Debug( LDAP_DEBUG_FILTER, "    EQUALITY\n", 0, 0, 0 );
88                 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_EQUALITY );
89                 break;
90
91         case LDAP_FILTER_SUBSTRINGS:
92                 Debug( LDAP_DEBUG_FILTER, "    SUBSTRINGS\n", 0, 0, 0 );
93                 rc = test_substrings_filter( op, e, f );
94                 break;
95
96         case LDAP_FILTER_GE:
97                 Debug( LDAP_DEBUG_FILTER, "    GE\n", 0, 0, 0 );
98                 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_GE );
99                 break;
100
101         case LDAP_FILTER_LE:
102                 Debug( LDAP_DEBUG_FILTER, "    LE\n", 0, 0, 0 );
103                 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_LE );
104                 break;
105
106         case LDAP_FILTER_PRESENT:
107                 Debug( LDAP_DEBUG_FILTER, "    PRESENT\n", 0, 0, 0 );
108                 rc = test_presence_filter( op, e, f->f_desc );
109                 break;
110
111         case LDAP_FILTER_APPROX:
112                 Debug( LDAP_DEBUG_FILTER, "    APPROX\n", 0, 0, 0 );
113                 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_APPROX );
114                 break;
115
116         case LDAP_FILTER_AND:
117                 Debug( LDAP_DEBUG_FILTER, "    AND\n", 0, 0, 0 );
118                 rc = test_filter_and( op, e, f->f_and );
119                 break;
120
121         case LDAP_FILTER_OR:
122                 Debug( LDAP_DEBUG_FILTER, "    OR\n", 0, 0, 0 );
123                 rc = test_filter_or( op, e, f->f_or );
124                 break;
125
126         case LDAP_FILTER_NOT:
127                 Debug( LDAP_DEBUG_FILTER, "    NOT\n", 0, 0, 0 );
128                 rc = test_filter( op, e, f->f_not );
129
130                 /* Flip true to false and false to true
131                  * but leave Undefined alone.
132                  */
133                 switch( rc ) {
134                 case LDAP_COMPARE_TRUE:
135                         rc = LDAP_COMPARE_FALSE;
136                         break;
137                 case LDAP_COMPARE_FALSE:
138                         rc = LDAP_COMPARE_TRUE;
139                         break;
140                 }
141                 break;
142
143         case LDAP_FILTER_EXT:
144                 Debug( LDAP_DEBUG_FILTER, "    EXT\n", 0, 0, 0 );
145                 rc = test_mra_filter( op, e, f->f_mra );
146                 break;
147
148         default:
149                 Debug( LDAP_DEBUG_ANY, "    unknown filter type %lu\n",
150                     f->f_choice, 0, 0 );
151                 rc = LDAP_PROTOCOL_ERROR;
152         }
153 out:
154         Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
155         return( rc );
156 }
157
158 static int test_mra_filter(
159         Operation *op,
160         Entry *e,
161         MatchingRuleAssertion *mra )
162 {
163         Attribute       *a;
164         void            *memctx;
165         BER_MEMFREE_FN  *memfree;
166 #ifdef LDAP_COMP_MATCH
167         int i, num_attr_vals = 0;
168 #endif
169
170         if ( op == NULL ) {
171                 memctx = NULL;
172                 memfree = slap_sl_free;
173         } else {
174                 memctx = op->o_tmpmemctx;
175                 memfree = op->o_tmpfree;
176         }
177
178         if ( mra->ma_desc ) {
179                 /*
180                  * if ma_desc is available, then we're filtering for
181                  * one attribute, and SEARCH permissions can be checked
182                  * directly.
183                  */
184                 if ( !access_allowed( op, e,
185                         mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
186                 {
187                         return LDAP_INSUFFICIENT_ACCESS;
188                 }
189
190                 if ( mra->ma_desc == slap_schema.si_ad_entryDN ) {
191                         int ret, rc;
192                         const char *text;
193
194                         rc = value_match( &ret, slap_schema.si_ad_entryDN, mra->ma_rule,
195                                 SLAP_MR_EXT, &e->e_nname, &mra->ma_value, &text );
196         
197         
198                         if( rc != LDAP_SUCCESS ) return rc;
199                         if ( ret == 0 ) return LDAP_COMPARE_TRUE;
200                         return LDAP_COMPARE_FALSE;
201                 }
202
203                 for ( a = attrs_find( e->e_attrs, mra->ma_desc );
204                         a != NULL;
205                         a = attrs_find( a->a_next, mra->ma_desc ) )
206                 {
207                         struct berval   *bv;
208                         int             normalize_attribute = 0;
209
210 #ifdef LDAP_COMP_MATCH
211                         /* Component Matching */
212                         if ( mra->ma_cf && mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) {
213                                 num_attr_vals = 0;
214                                 if ( !a->a_comp_data ) {
215                                         num_attr_vals = a->a_numvals;
216                                         if ( num_attr_vals <= 0 ) {
217                                                 /* no attribute value */
218                                                 return LDAP_INAPPROPRIATE_MATCHING;
219                                         }
220                                         num_attr_vals++;
221
222                                         /* following malloced will be freed by comp_tree_free () */
223                                         a->a_comp_data = malloc( sizeof( ComponentData ) +
224                                                 sizeof( ComponentSyntaxInfo* )*num_attr_vals );
225
226                                         if ( !a->a_comp_data ) return LDAP_NO_MEMORY;
227                                         a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)
228                                                 ((char*)a->a_comp_data + sizeof(ComponentData));
229                                         a->a_comp_data->cd_tree[num_attr_vals - 1] =
230                                                 (ComponentSyntaxInfo*) NULL;
231                                         a->a_comp_data->cd_mem_op =
232                                                 nibble_mem_allocator( 1024*16, 1024 );
233                                 }
234                         }
235 #endif
236
237                         /* If ma_rule is not the same as the attribute's
238                          * normal rule, then we can't use the a_nvals.
239                          */
240                         if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
241                                 bv = a->a_nvals;
242
243                         } else {
244                                 bv = a->a_vals;
245                                 normalize_attribute = 1;
246                         }
247 #ifdef LDAP_COMP_MATCH
248                         i = 0;
249 #endif
250                         for ( ; !BER_BVISNULL( bv ); bv++ ) {
251                                 int ret;
252                                 int rc;
253                                 const char *text;
254         
255 #ifdef LDAP_COMP_MATCH
256                                 if ( mra->ma_cf &&
257                                         mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
258                                 {
259                                         /* Check if decoded component trees are already linked */
260                                         if ( num_attr_vals ) {
261                                                 a->a_comp_data->cd_tree[i] = attr_converter(
262                                                         a, a->a_desc->ad_type->sat_syntax, bv );
263                                         }
264                                         /* decoding error */
265                                         if ( !a->a_comp_data->cd_tree[i] ) {
266                                                 return LDAP_OPERATIONS_ERROR;
267                                         }
268                                         rc = value_match( &ret, a->a_desc, mra->ma_rule,
269                                                 SLAP_MR_COMPONENT,
270                                                 (struct berval*)a->a_comp_data->cd_tree[i++],
271                                                 (void*)mra, &text );
272                                 } else 
273 #endif
274                                 {
275                                         struct berval   nbv = BER_BVNULL;
276
277                                         if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
278                                                 /*
279                                 
280                                 Document: RFC 4511
281
282                                     4.5.1. Search Request 
283                                         ...
284                                     If the type field is present and the matchingRule is present, 
285                                     the matchValue is compared against entry attributes of the 
286                                     specified type. In this case, the matchingRule MUST be one 
287                                     suitable for use with the specified type (see [RFC4517]), 
288                                     otherwise the filter item is Undefined.  
289
290
291                                 In this case, since the matchingRule requires the assertion
292                                 value to be normalized, we normalize the attribute value
293                                 according to the syntax of the matchingRule.
294
295                                 This should likely be done inside value_match(), by passing
296                                 the appropriate flags, but this is not done at present.
297                                 See ITS#3406.
298                                                  */
299                                                 if ( mra->ma_rule->smr_normalize(
300                                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
301                                                                 mra->ma_rule->smr_syntax,
302                                                                 mra->ma_rule,
303                                                                 bv, &nbv, memctx ) != LDAP_SUCCESS )
304                                                 {
305                                                         /* FIXME: stop processing? */
306                                                         continue;
307                                                 }
308
309                                         } else {
310                                                 nbv = *bv;
311                                         }
312
313                                         rc = value_match( &ret, a->a_desc, mra->ma_rule,
314                                                 SLAP_MR_EXT, &nbv, &mra->ma_value, &text );
315
316                                         if ( nbv.bv_val != bv->bv_val ) {
317                                                 memfree( nbv.bv_val, memctx );
318                                         }
319                                 }
320
321                                 if ( rc != LDAP_SUCCESS ) return rc;
322                                 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
323                         }
324                 }
325
326         } else {
327                 /*
328                  * No attribute description: test all
329                  */
330                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
331                         struct berval   *bv, value;
332                         const char      *text = NULL;
333                         int             rc;
334                         int             normalize_attribute = 0;
335
336                         /* check if matching is appropriate */
337                         if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type ) ) {
338                                 continue;
339                         }
340
341                         /* normalize for equality */
342                         rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule,
343                                 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
344                                 &mra->ma_value, &value, &text, memctx );
345                         if ( rc != LDAP_SUCCESS ) continue;
346
347                         /* check search access */
348                         if ( !access_allowed( op, e,
349                                 a->a_desc, &value, ACL_SEARCH, NULL ) )
350                         {
351                                 memfree( value.bv_val, memctx );
352                                 continue;
353                         }
354 #ifdef LDAP_COMP_MATCH
355                         /* Component Matching */
356                         if ( mra->ma_cf &&
357                                 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
358                         {
359                                 int ret;
360
361                                 rc = value_match( &ret, a->a_desc, mra->ma_rule,
362                                         SLAP_MR_COMPONENT,
363                                         (struct berval*)a, (void*)mra, &text );
364                                 if ( rc != LDAP_SUCCESS ) break;
365         
366                                 if ( ret == 0 ) {
367                                         rc = LDAP_COMPARE_TRUE;
368                                         break;
369                                 }
370
371                         }
372 #endif
373
374                         /* check match */
375                         if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
376                                 bv = a->a_nvals;
377
378                         } else {
379                                 bv = a->a_vals;
380                                 normalize_attribute = 1;
381                         }
382
383                         for ( ; !BER_BVISNULL( bv ); bv++ ) {
384                                 int             ret;
385                                 struct berval   nbv = BER_BVNULL;
386
387                                 if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
388                                         /* see comment above */
389                                         if ( mra->ma_rule->smr_normalize(
390                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
391                                                         mra->ma_rule->smr_syntax,
392                                                         mra->ma_rule,
393                                                         bv, &nbv, memctx ) != LDAP_SUCCESS )
394                                         {
395                                                 /* FIXME: stop processing? */
396                                                 continue;
397                                         }
398
399                                 } else {
400                                         nbv = *bv;
401                                 }
402
403                                 rc = value_match( &ret, a->a_desc, mra->ma_rule,
404                                         SLAP_MR_EXT, &nbv, &value, &text );
405
406                                 if ( nbv.bv_val != bv->bv_val ) {
407                                         memfree( nbv.bv_val, memctx );
408                                 }
409
410                                 if ( rc != LDAP_SUCCESS ) break;
411         
412                                 if ( ret == 0 ) {
413                                         rc = LDAP_COMPARE_TRUE;
414                                         break;
415                                 }
416                         }
417                         memfree( value.bv_val, memctx );
418                         if ( rc != LDAP_SUCCESS ) return rc;
419                 }
420         }
421
422         /* check attrs in DN AVAs if required */
423         if ( mra->ma_dnattrs && !BER_BVISEMPTY( &e->e_nname ) ) {
424                 LDAPDN          dn = NULL;
425                 int             iRDN, iAVA;
426                 int             rc;
427
428                 /* parse and pretty the dn */
429                 rc = dnPrettyDN( NULL, &e->e_name, &dn, memctx );
430                 if ( rc != LDAP_SUCCESS ) {
431                         return LDAP_INVALID_SYNTAX;
432                 }
433
434                 /* for each AVA of each RDN ... */
435                 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
436                         LDAPRDN         rdn = dn[ iRDN ];
437
438                         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
439                                 LDAPAVA         *ava = rdn[ iAVA ];
440                                 struct berval   *bv = &ava->la_value,
441                                                 value = BER_BVNULL,
442                                                 nbv = BER_BVNULL;
443                                 AttributeDescription *ad =
444                                         (AttributeDescription *)ava->la_private;
445                                 int             ret;
446                                 const char      *text;
447
448                                 assert( ad != NULL );
449
450                                 if ( mra->ma_desc ) {
451                                         /* have a mra type? check for subtype */
452                                         if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
453                                                 continue;
454                                         }
455                                         value = mra->ma_value;
456
457                                 } else {
458                                         const char      *text = NULL;
459
460                                         /* check if matching is appropriate */
461                                         if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type ) ) {
462                                                 continue;
463                                         }
464
465                                         /* normalize for equality */
466                                         rc = asserted_value_validate_normalize( ad,
467                                                 mra->ma_rule,
468                                                 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
469                                                 &mra->ma_value, &value, &text, memctx );
470                                         if ( rc != LDAP_SUCCESS ) continue;
471
472                                         /* check search access */
473                                         if ( !access_allowed( op, e,
474                                                 ad, &value, ACL_SEARCH, NULL ) )
475                                         {
476                                                 memfree( value.bv_val, memctx );
477                                                 continue;
478                                         }
479                                 }
480
481                                 if ( mra->ma_rule->smr_normalize ) {
482                                         /* see comment above */
483                                         if ( mra->ma_rule->smr_normalize(
484                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
485                                                         mra->ma_rule->smr_syntax,
486                                                         mra->ma_rule,
487                                                         bv, &nbv, memctx ) != LDAP_SUCCESS )
488                                         {
489                                                 /* FIXME: stop processing? */
490                                                 rc = LDAP_SUCCESS;
491                                                 ret = -1;
492                                                 goto cleanup;
493                                         }
494
495                                 } else {
496                                         nbv = *bv;
497                                 }
498
499                                 /* check match */
500                                 rc = value_match( &ret, ad, mra->ma_rule, SLAP_MR_EXT,
501                                         &nbv, &value, &text );
502
503 cleanup:;
504                                 if ( !BER_BVISNULL( &value ) && value.bv_val != mra->ma_value.bv_val ) {
505                                         memfree( value.bv_val, memctx );
506                                 }
507
508                                 if ( !BER_BVISNULL( &nbv ) && nbv.bv_val != bv->bv_val ) {
509                                         memfree( nbv.bv_val, memctx );
510                                 }
511
512                                 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
513
514                                 if ( rc != LDAP_SUCCESS ) {
515                                         ldap_dnfree_x( dn, memctx );
516                                         return rc;
517                                 }
518                         }
519                 }
520                 ldap_dnfree_x( dn, memctx );
521         }
522
523         return LDAP_COMPARE_FALSE;
524 }
525
526 static int
527 test_ava_filter(
528         Operation       *op,
529         Entry           *e,
530         AttributeAssertion *ava,
531         int             type )
532 {
533         int rc;
534         Attribute       *a;
535 #ifdef LDAP_COMP_MATCH
536         int i, num_attr_vals = 0;
537         AttributeAliasing *a_alias = NULL;
538 #endif
539
540         if ( !access_allowed( op, e,
541                 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
542         {
543                 return LDAP_INSUFFICIENT_ACCESS;
544         }
545
546         if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates 
547                 && op && op->o_bd && op->o_bd->be_has_subordinates )
548         {
549                 int     hasSubordinates;
550                 struct berval hs;
551
552                 if( type != LDAP_FILTER_EQUALITY &&
553                         type != LDAP_FILTER_APPROX )
554                 {
555                         /* No other match is allowed */
556                         return LDAP_INAPPROPRIATE_MATCHING;
557                 }
558                 
559                 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
560                         LDAP_SUCCESS )
561                 {
562                         return LDAP_OTHER;
563                 }
564
565                 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
566                         hs = slap_true_bv;
567
568                 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
569                         hs = slap_false_bv;
570
571                 } else {
572                         return LDAP_OTHER;
573                 }
574
575                 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
576                 return LDAP_COMPARE_FALSE;
577         }
578
579         if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
580                 MatchingRule *mr;
581                 int match;
582                 const char *text;
583
584                 if( type != LDAP_FILTER_EQUALITY &&
585                         type != LDAP_FILTER_APPROX )
586                 {
587                         /* No other match is allowed */
588                         return LDAP_INAPPROPRIATE_MATCHING;
589                 }
590
591                 mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
592                 assert( mr != NULL );
593
594                 rc = value_match( &match, slap_schema.si_ad_entryDN, mr,
595                         SLAP_MR_EXT, &e->e_nname, &ava->aa_value, &text );
596
597                 if( rc != LDAP_SUCCESS ) return rc;
598                 if( match == 0 ) return LDAP_COMPARE_TRUE;
599                 return LDAP_COMPARE_FALSE;
600         }
601
602         rc = LDAP_COMPARE_FALSE;
603
604 #ifdef LDAP_COMP_MATCH
605         if ( is_aliased_attribute && ava->aa_cf )
606         {
607                 a_alias = is_aliased_attribute ( ava->aa_desc );
608                 if ( a_alias )
609                         ava->aa_desc = a_alias->aa_aliased_ad;
610                 else
611                         ava->aa_cf = NULL;
612         }
613 #endif
614
615         for(a = attrs_find( e->e_attrs, ava->aa_desc );
616                 a != NULL;
617                 a = attrs_find( a->a_next, ava->aa_desc ) )
618         {
619                 int use;
620                 MatchingRule *mr;
621                 struct berval *bv;
622
623                 if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
624                         e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
625                 {
626                         rc = LDAP_INSUFFICIENT_ACCESS;
627                         continue;
628                 }
629
630                 use = SLAP_MR_EQUALITY;
631
632                 switch ( type ) {
633                 case LDAP_FILTER_APPROX:
634                         use = SLAP_MR_EQUALITY_APPROX;
635                         mr = a->a_desc->ad_type->sat_approx;
636                         if( mr != NULL ) break;
637
638                         /* fallthru: use EQUALITY matching rule if no APPROX rule */
639
640                 case LDAP_FILTER_EQUALITY:
641                         /* use variable set above so fall thru use is not clobbered */
642                         mr = a->a_desc->ad_type->sat_equality;
643                         break;
644
645                 case LDAP_FILTER_GE:
646                 case LDAP_FILTER_LE:
647                         use = SLAP_MR_ORDERING;
648                         mr = a->a_desc->ad_type->sat_ordering;
649                         break;
650
651                 default:
652                         mr = NULL;
653                 }
654
655                 if( mr == NULL ) {
656                         rc = LDAP_INAPPROPRIATE_MATCHING;
657                         continue;
658                 }
659
660                 if ( a->a_flags & SLAP_ATTR_SORTED_VALS ) {
661                         unsigned slot;
662                         rc = attr_valfind( a, use | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
663                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, 
664                                 &ava->aa_value, &slot, NULL );
665                         if ( rc == LDAP_SUCCESS )
666                                 return LDAP_COMPARE_TRUE;
667                         if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) {
668                                 /* If insertion point is not the end of the list, there was
669                                  * at least one value greater than the assertion.
670                                  */
671                                 if ( type == LDAP_FILTER_GE && slot < a->a_numvals )
672                                         return LDAP_COMPARE_TRUE;
673                                 /* Likewise, if insertion point is not the head of the list,
674                                  * there was at least one value less than the assertion.
675                                  */
676                                 if ( type == LDAP_FILTER_LE && slot > 0 )
677                                         return LDAP_COMPARE_TRUE;
678                                 return LDAP_COMPARE_FALSE;
679                         }
680                         return rc;
681                 }
682
683 #ifdef LDAP_COMP_MATCH
684                 if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
685                         /* Component Matching */
686                         for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
687                         if ( num_attr_vals <= 0 )/* no attribute value */
688                                 return LDAP_INAPPROPRIATE_MATCHING;
689                         num_attr_vals++;/* for NULL termination */
690
691                         /* following malloced will be freed by comp_tree_free () */
692                         a->a_comp_data = malloc( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
693
694                         if ( !a->a_comp_data ) {
695                                 return LDAP_NO_MEMORY;
696                         }
697
698                         a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
699                         i = num_attr_vals;
700                         for ( ; i ; i-- ) {
701                                 a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
702                         }
703
704                         a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
705                         if ( a->a_comp_data->cd_mem_op == NULL ) {
706                                 free ( a->a_comp_data );
707                                 a->a_comp_data = NULL;
708                                 return LDAP_OPERATIONS_ERROR;
709                         }
710                 }
711
712                 i = 0;
713 #endif
714
715                 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
716                         int ret, match;
717                         const char *text;
718
719 #ifdef LDAP_COMP_MATCH
720                         if( attr_converter && ava->aa_cf && a->a_comp_data ) {
721                                 /* Check if decoded component trees are already linked */
722                                 struct berval cf_bv = { 20, "componentFilterMatch" };
723                                 MatchingRule* cf_mr = mr_bvfind( &cf_bv );
724                                 MatchingRuleAssertion mra;
725                                 mra.ma_cf = ava->aa_cf;
726
727                                 if ( a->a_comp_data->cd_tree[i] == NULL )
728                                         a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
729                                 /* decoding error */
730                                 if ( !a->a_comp_data->cd_tree[i] ) {
731                                         free_ComponentData ( a );
732                                         return LDAP_OPERATIONS_ERROR;
733                                 }
734
735                                 ret = value_match( &match, a->a_desc, cf_mr,
736                                         SLAP_MR_COMPONENT,
737                                         (struct berval*)a->a_comp_data->cd_tree[i++],
738                                         (void*)&mra, &text );
739                                 if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
740                                         /* cached component tree is broken, just remove it */
741                                         free_ComponentData ( a );
742                                         return ret;
743                                 }
744                                 if ( a_alias )
745                                         ava->aa_desc = a_alias->aa_aliasing_ad;
746
747                         } else 
748 #endif
749                         {
750                                 ret = ordered_value_match( &match, a->a_desc, mr, use,
751                                         bv, &ava->aa_value, &text );
752                         }
753
754                         if( ret != LDAP_SUCCESS ) {
755                                 rc = ret;
756                                 break;
757                         }
758
759                         switch ( type ) {
760                         case LDAP_FILTER_EQUALITY:
761                         case LDAP_FILTER_APPROX:
762                                 if ( match == 0 ) return LDAP_COMPARE_TRUE;
763                                 break;
764
765                         case LDAP_FILTER_GE:
766                                 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
767                                 break;
768
769                         case LDAP_FILTER_LE:
770                                 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
771                                 break;
772                         }
773                 }
774         }
775
776 #ifdef LDAP_COMP_MATCH
777         if ( a_alias )
778                 ava->aa_desc = a_alias->aa_aliasing_ad;
779 #endif
780
781         return rc;
782 }
783
784
785 static int
786 test_presence_filter(
787         Operation       *op,
788         Entry           *e,
789         AttributeDescription *desc )
790 {
791         Attribute       *a;
792         int rc;
793
794         if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
795                 return LDAP_INSUFFICIENT_ACCESS;
796         }
797
798         if ( desc == slap_schema.si_ad_hasSubordinates ) {
799                 /*
800                  * XXX: fairly optimistic: if the function is defined,
801                  * then PRESENCE must succeed, because hasSubordinate
802                  * is boolean-valued; I think we may live with this 
803                  * simplification by now.
804                  */
805                 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
806                         return LDAP_COMPARE_TRUE;
807                 }
808
809                 return LDAP_COMPARE_FALSE;
810         }
811
812         if ( desc == slap_schema.si_ad_entryDN ||
813                 desc == slap_schema.si_ad_subschemaSubentry )
814         {
815                 /* entryDN and subschemaSubentry are always present */
816                 return LDAP_COMPARE_TRUE;
817         }
818
819         rc = LDAP_COMPARE_FALSE;
820
821         for(a = attrs_find( e->e_attrs, desc );
822                 a != NULL;
823                 a = attrs_find( a->a_next, desc ) )
824         {
825                 if (( desc != a->a_desc ) && !access_allowed( op,
826                         e, a->a_desc, NULL, ACL_SEARCH, NULL ))
827                 {
828                         rc = LDAP_INSUFFICIENT_ACCESS;
829                         continue;
830                 }
831
832                 rc = LDAP_COMPARE_TRUE;
833                 break;
834         }
835
836         return rc;
837 }
838
839
840 static int
841 test_filter_and(
842         Operation       *op,
843         Entry   *e,
844         Filter  *flist )
845 {
846         Filter  *f;
847         int rtn = LDAP_COMPARE_TRUE; /* True if empty */
848
849         Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
850
851         for ( f = flist; f != NULL; f = f->f_next ) {
852                 int rc = test_filter( op, e, f );
853
854                 if ( rc == LDAP_COMPARE_FALSE ) {
855                         /* filter is False */
856                         rtn = rc;
857                         break;
858                 }
859
860                 if ( rc != LDAP_COMPARE_TRUE ) {
861                         /* filter is Undefined unless later elements are False */
862                         rtn = rc;
863                 }
864         }
865
866         Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
867
868         return rtn;
869 }
870
871 static int
872 test_filter_or(
873         Operation       *op,
874         Entry   *e,
875         Filter  *flist )
876 {
877         Filter  *f;
878         int rtn = LDAP_COMPARE_FALSE; /* False if empty */
879
880         Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
881
882         for ( f = flist; f != NULL; f = f->f_next ) {
883                 int rc = test_filter( op, e, f );
884
885                 if ( rc == LDAP_COMPARE_TRUE ) {
886                         /* filter is True */
887                         rtn = rc;
888                         break;
889                 }
890
891                 if ( rc != LDAP_COMPARE_FALSE ) {
892                         /* filter is Undefined unless later elements are True */
893                         rtn = rc;
894                 }
895         }
896
897         Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
898         return rtn;
899 }
900
901
902 static int
903 test_substrings_filter(
904         Operation       *op,
905         Entry   *e,
906         Filter  *f )
907 {
908         Attribute       *a;
909         int rc;
910
911         Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
912
913         if ( !access_allowed( op, e,
914                 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
915         {
916                 return LDAP_INSUFFICIENT_ACCESS;
917         }
918
919         rc = LDAP_COMPARE_FALSE;
920
921         for(a = attrs_find( e->e_attrs, f->f_sub_desc );
922                 a != NULL;
923                 a = attrs_find( a->a_next, f->f_sub_desc ) )
924         {
925                 MatchingRule *mr;
926                 struct berval *bv;
927
928                 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
929                         e, a->a_desc, NULL, ACL_SEARCH, NULL ))
930                 {
931                         rc = LDAP_INSUFFICIENT_ACCESS;
932                         continue;
933                 }
934
935                 mr = a->a_desc->ad_type->sat_substr;
936                 if( mr == NULL ) {
937                         rc = LDAP_INAPPROPRIATE_MATCHING;
938                         continue;
939                 }
940
941                 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
942                         int ret, match;
943                         const char *text;
944
945                         ret = value_match( &match, a->a_desc, mr, SLAP_MR_SUBSTR,
946                                 bv, f->f_sub, &text );
947
948                         if( ret != LDAP_SUCCESS ) {
949                                 rc = ret;
950                                 break;
951                         }
952                         if ( match == 0 ) return LDAP_COMPARE_TRUE;
953                 }
954         }
955
956         Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",
957                 rc, 0, 0 );
958         return rc;
959 }