]> git.sur5r.net Git - openldap/blob - servers/slapd/filterentry.c
Make slap_passwd_parse non-destructive
[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 #ifdef LDAP_COMP_MATCH
661                 if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
662                         /* Component Matching */
663                         for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
664                         if ( num_attr_vals <= 0 )/* no attribute value */
665                                 return LDAP_INAPPROPRIATE_MATCHING;
666                         num_attr_vals++;/* for NULL termination */
667
668                         /* following malloced will be freed by comp_tree_free () */
669                         a->a_comp_data = malloc( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
670
671                         if ( !a->a_comp_data ) {
672                                 return LDAP_NO_MEMORY;
673                         }
674
675                         a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
676                         i = num_attr_vals;
677                         for ( ; i ; i-- ) {
678                                 a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
679                         }
680
681                         a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
682                         if ( a->a_comp_data->cd_mem_op == NULL ) {
683                                 free ( a->a_comp_data );
684                                 a->a_comp_data = NULL;
685                                 return LDAP_OPERATIONS_ERROR;
686                         }
687                 }
688
689                 i = 0;
690 #endif
691
692                 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
693                         int ret, match;
694                         const char *text;
695
696 #ifdef LDAP_COMP_MATCH
697                         if( attr_converter && ava->aa_cf && a->a_comp_data ) {
698                                 /* Check if decoded component trees are already linked */
699                                 struct berval cf_bv = { 20, "componentFilterMatch" };
700                                 MatchingRule* cf_mr = mr_bvfind( &cf_bv );
701                                 MatchingRuleAssertion mra;
702                                 mra.ma_cf = ava->aa_cf;
703
704                                 if ( a->a_comp_data->cd_tree[i] == NULL )
705                                         a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
706                                 /* decoding error */
707                                 if ( !a->a_comp_data->cd_tree[i] ) {
708                                         free_ComponentData ( a );
709                                         return LDAP_OPERATIONS_ERROR;
710                                 }
711
712                                 ret = value_match( &match, a->a_desc, cf_mr,
713                                         SLAP_MR_COMPONENT,
714                                         (struct berval*)a->a_comp_data->cd_tree[i++],
715                                         (void*)&mra, &text );
716                                 if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
717                                         /* cached component tree is broken, just remove it */
718                                         free_ComponentData ( a );
719                                         return ret;
720                                 }
721                                 if ( a_alias )
722                                         ava->aa_desc = a_alias->aa_aliasing_ad;
723
724                         } else 
725 #endif
726                         {
727                                 ret = ordered_value_match( &match, a->a_desc, mr, use,
728                                         bv, &ava->aa_value, &text );
729                         }
730
731                         if( ret != LDAP_SUCCESS ) {
732                                 rc = ret;
733                                 break;
734                         }
735
736                         switch ( type ) {
737                         case LDAP_FILTER_EQUALITY:
738                         case LDAP_FILTER_APPROX:
739                                 if ( match == 0 ) return LDAP_COMPARE_TRUE;
740                                 break;
741
742                         case LDAP_FILTER_GE:
743                                 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
744                                 break;
745
746                         case LDAP_FILTER_LE:
747                                 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
748                                 break;
749                         }
750                 }
751         }
752
753 #ifdef LDAP_COMP_MATCH
754         if ( a_alias )
755                 ava->aa_desc = a_alias->aa_aliasing_ad;
756 #endif
757
758         return rc;
759 }
760
761
762 static int
763 test_presence_filter(
764         Operation       *op,
765         Entry           *e,
766         AttributeDescription *desc )
767 {
768         Attribute       *a;
769         int rc;
770
771         if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
772                 return LDAP_INSUFFICIENT_ACCESS;
773         }
774
775         if ( desc == slap_schema.si_ad_hasSubordinates ) {
776                 /*
777                  * XXX: fairly optimistic: if the function is defined,
778                  * then PRESENCE must succeed, because hasSubordinate
779                  * is boolean-valued; I think we may live with this 
780                  * simplification by now.
781                  */
782                 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
783                         return LDAP_COMPARE_TRUE;
784                 }
785
786                 return LDAP_COMPARE_FALSE;
787         }
788
789         if ( desc == slap_schema.si_ad_entryDN ||
790                 desc == slap_schema.si_ad_subschemaSubentry )
791         {
792                 /* entryDN and subschemaSubentry are always present */
793                 return LDAP_COMPARE_TRUE;
794         }
795
796         rc = LDAP_COMPARE_FALSE;
797
798         for(a = attrs_find( e->e_attrs, desc );
799                 a != NULL;
800                 a = attrs_find( a->a_next, desc ) )
801         {
802                 if (( desc != a->a_desc ) && !access_allowed( op,
803                         e, a->a_desc, NULL, ACL_SEARCH, NULL ))
804                 {
805                         rc = LDAP_INSUFFICIENT_ACCESS;
806                         continue;
807                 }
808
809                 rc = LDAP_COMPARE_TRUE;
810                 break;
811         }
812
813         return rc;
814 }
815
816
817 static int
818 test_filter_and(
819         Operation       *op,
820         Entry   *e,
821         Filter  *flist )
822 {
823         Filter  *f;
824         int rtn = LDAP_COMPARE_TRUE; /* True if empty */
825
826         Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
827
828         for ( f = flist; f != NULL; f = f->f_next ) {
829                 int rc = test_filter( op, e, f );
830
831                 if ( rc == LDAP_COMPARE_FALSE ) {
832                         /* filter is False */
833                         rtn = rc;
834                         break;
835                 }
836
837                 if ( rc != LDAP_COMPARE_TRUE ) {
838                         /* filter is Undefined unless later elements are False */
839                         rtn = rc;
840                 }
841         }
842
843         Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
844
845         return rtn;
846 }
847
848 static int
849 test_filter_or(
850         Operation       *op,
851         Entry   *e,
852         Filter  *flist )
853 {
854         Filter  *f;
855         int rtn = LDAP_COMPARE_FALSE; /* False if empty */
856
857         Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
858
859         for ( f = flist; f != NULL; f = f->f_next ) {
860                 int rc = test_filter( op, e, f );
861
862                 if ( rc == LDAP_COMPARE_TRUE ) {
863                         /* filter is True */
864                         rtn = rc;
865                         break;
866                 }
867
868                 if ( rc != LDAP_COMPARE_FALSE ) {
869                         /* filter is Undefined unless later elements are True */
870                         rtn = rc;
871                 }
872         }
873
874         Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
875         return rtn;
876 }
877
878
879 static int
880 test_substrings_filter(
881         Operation       *op,
882         Entry   *e,
883         Filter  *f )
884 {
885         Attribute       *a;
886         int rc;
887
888         Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
889
890         if ( !access_allowed( op, e,
891                 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
892         {
893                 return LDAP_INSUFFICIENT_ACCESS;
894         }
895
896         rc = LDAP_COMPARE_FALSE;
897
898         for(a = attrs_find( e->e_attrs, f->f_sub_desc );
899                 a != NULL;
900                 a = attrs_find( a->a_next, f->f_sub_desc ) )
901         {
902                 MatchingRule *mr;
903                 struct berval *bv;
904
905                 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
906                         e, a->a_desc, NULL, ACL_SEARCH, NULL ))
907                 {
908                         rc = LDAP_INSUFFICIENT_ACCESS;
909                         continue;
910                 }
911
912                 mr = a->a_desc->ad_type->sat_substr;
913                 if( mr == NULL ) {
914                         rc = LDAP_INAPPROPRIATE_MATCHING;
915                         continue;
916                 }
917
918                 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
919                         int ret, match;
920                         const char *text;
921
922                         ret = value_match( &match, a->a_desc, mr, SLAP_MR_SUBSTR,
923                                 bv, f->f_sub, &text );
924
925                         if( ret != LDAP_SUCCESS ) {
926                                 rc = ret;
927                                 break;
928                         }
929                         if ( match == 0 ) return LDAP_COMPARE_TRUE;
930                 }
931         }
932
933         Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",
934                 rc, 0, 0 );
935         return rc;
936 }