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