]> git.sur5r.net Git - openldap/blob - servers/slapd/filterentry.c
Read config tree from back-ldif
[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-2005 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;
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                                 0, &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, 0,
268                                                 (struct berval*)a->a_comp_data->cd_tree[i++],
269                                                 (void*)mra, &text );
270                                 } else 
271 #endif
272                                 {
273                                         struct berval   nbv = BER_BVNULL;
274
275                                         if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
276                                                 /*
277                                 
278                                 Document: draft-ietf-ldapbis-protocol
279
280                                     4.5.1. Search Request 
281                                         ...
282                                     If the type field is present and the matchingRule is present, 
283                                     the matchValue is compared against entry attributes of the 
284                                     specified type. In this case, the matchingRule MUST be one 
285                                     suitable for use with the specified type (see [Syntaxes]), 
286                                     otherwise the filter item is Undefined.  
287
288
289                                 In this case, since the matchingRule requires the assertion
290                                 value to be normalized, we normalize the attribute value
291                                 according to the syntax of the matchingRule.
292
293                                 This should likely be done inside value_match(), by passing
294                                 the appropriate flags, but this is not done at present.
295                                 See ITS#3406.
296                                                  */
297                                                 if ( mra->ma_rule->smr_normalize(
298                                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
299                                                                 mra->ma_rule->smr_syntax,
300                                                                 mra->ma_rule,
301                                                                 bv, &nbv, memctx ) != LDAP_SUCCESS )
302                                                 {
303                                                         /* FIXME: stop processing? */
304                                                         continue;
305                                                 }
306
307                                         } else {
308                                                 nbv = *bv;
309                                         }
310
311                                         rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
312                                                 &nbv, &mra->ma_value, &text );
313
314                                         if ( nbv.bv_val != bv->bv_val ) {
315                                                 memfree( nbv.bv_val, memctx );
316                                         }
317                                 }
318
319                                 if ( rc != LDAP_SUCCESS ) return rc;
320                                 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
321                         }
322                 }
323
324         } else {
325                 /*
326                  * No attribute description: test all
327                  */
328                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
329                         struct berval   *bv, value;
330                         const char      *text = NULL;
331                         int             rc;
332                         int             normalize_attribute = 0;
333
334                         /* check if matching is appropriate */
335                         if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type ) ) {
336                                 continue;
337                         }
338
339                         /* normalize for equality */
340                         rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule,
341                                 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
342                                 &mra->ma_value, &value, &text, memctx );
343                         if ( rc != LDAP_SUCCESS ) continue;
344
345                         /* check search access */
346                         if ( !access_allowed( op, e,
347                                 a->a_desc, &value, ACL_SEARCH, NULL ) )
348                         {
349                                 memfree( value.bv_val, memctx );
350                                 continue;
351                         }
352 #ifdef LDAP_COMP_MATCH
353                         /* Component Matching */
354                         if ( mra->ma_cf &&
355                                 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
356                         {
357                                 int ret;
358
359                                 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
360                                         (struct berval*)a, (void*)mra, &text );
361                                 if ( rc != LDAP_SUCCESS ) break;
362         
363                                 if ( ret == 0 ) {
364                                         rc = LDAP_COMPARE_TRUE;
365                                         break;
366                                 }
367
368                         }
369 #endif
370
371                         /* check match */
372                         if ( mra->ma_rule == a->a_desc->ad_type->sat_equality ) {
373                                 bv = a->a_nvals;
374
375                         } else {
376                                 bv = a->a_vals;
377                                 normalize_attribute = 1;
378                         }
379
380                         for ( ; !BER_BVISNULL( bv ); bv++ ) {
381                                 int             ret;
382                                 struct berval   nbv = BER_BVNULL;
383
384                                 if ( normalize_attribute && mra->ma_rule->smr_normalize ) {
385                                         /* see comment above */
386                                         if ( mra->ma_rule->smr_normalize(
387                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
388                                                         mra->ma_rule->smr_syntax,
389                                                         mra->ma_rule,
390                                                         bv, &nbv, memctx ) != LDAP_SUCCESS )
391                                         {
392                                                 /* FIXME: stop processing? */
393                                                 continue;
394                                         }
395
396                                 } else {
397                                         nbv = *bv;
398                                 }
399
400                                 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
401                                         &nbv, &value, &text );
402
403                                 if ( nbv.bv_val != bv->bv_val ) {
404                                         memfree( nbv.bv_val, memctx );
405                                 }
406
407                                 if ( rc != LDAP_SUCCESS ) break;
408         
409                                 if ( ret == 0 ) {
410                                         rc = LDAP_COMPARE_TRUE;
411                                         break;
412                                 }
413                         }
414                         memfree( value.bv_val, memctx );
415                         if ( rc != LDAP_SUCCESS ) return rc;
416                 }
417         }
418
419         /* check attrs in DN AVAs if required */
420         if ( mra->ma_dnattrs && !BER_BVISEMPTY( &e->e_nname ) ) {
421                 LDAPDN          dn = NULL;
422                 int             iRDN, iAVA;
423                 int             rc;
424
425                 /* parse and pretty the dn */
426                 rc = dnPrettyDN( NULL, &e->e_name, &dn, memctx );
427                 if ( rc != LDAP_SUCCESS ) {
428                         return LDAP_INVALID_SYNTAX;
429                 }
430
431                 /* for each AVA of each RDN ... */
432                 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
433                         LDAPRDN         rdn = dn[ iRDN ];
434
435                         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
436                                 LDAPAVA         *ava = rdn[ iAVA ];
437                                 struct berval   *bv = &ava->la_value,
438                                                 value = BER_BVNULL,
439                                                 nbv = BER_BVNULL;
440                                 AttributeDescription *ad =
441                                         (AttributeDescription *)ava->la_private;
442                                 int             ret;
443                                 const char      *text;
444
445                                 assert( ad );
446
447                                 if ( mra->ma_desc ) {
448                                         /* have a mra type? check for subtype */
449                                         if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
450                                                 continue;
451                                         }
452                                         value = mra->ma_value;
453
454                                 } else {
455                                         const char      *text = NULL;
456
457                                         /* check if matching is appropriate */
458                                         if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type ) ) {
459                                                 continue;
460                                         }
461
462                                         /* normalize for equality */
463                                         rc = asserted_value_validate_normalize( ad,
464                                                 mra->ma_rule,
465                                                 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
466                                                 &mra->ma_value, &value, &text, memctx );
467                                         if ( rc != LDAP_SUCCESS ) continue;
468
469                                         /* check search access */
470                                         if ( !access_allowed( op, e,
471                                                 ad, &value, ACL_SEARCH, NULL ) )
472                                         {
473                                                 memfree( value.bv_val, memctx );
474                                                 continue;
475                                         }
476                                 }
477
478                                 if ( mra->ma_rule->smr_normalize ) {
479                                         /* see comment above */
480                                         if ( mra->ma_rule->smr_normalize(
481                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
482                                                         mra->ma_rule->smr_syntax,
483                                                         mra->ma_rule,
484                                                         bv, &nbv, memctx ) != LDAP_SUCCESS )
485                                         {
486                                                 /* FIXME: stop processing? */
487                                                 rc = LDAP_SUCCESS;
488                                                 ret = -1;
489                                                 goto cleanup;
490                                         }
491
492                                 } else {
493                                         nbv = *bv;
494                                 }
495
496                                 /* check match */
497                                 rc = value_match( &ret, ad, mra->ma_rule, 0,
498                                         &nbv, &value, &text );
499
500 cleanup:;
501                                 if ( !BER_BVISNULL( &value ) && value.bv_val != mra->ma_value.bv_val ) {
502                                         memfree( value.bv_val, memctx );
503                                 }
504
505                                 if ( !BER_BVISNULL( &nbv ) && nbv.bv_val != bv->bv_val ) {
506                                         memfree( nbv.bv_val, memctx );
507                                 }
508
509                                 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
510
511                                 if ( rc != LDAP_SUCCESS ) {
512                                         ldap_dnfree_x( dn, memctx );
513                                         return rc;
514                                 }
515                         }
516                 }
517                 ldap_dnfree_x( dn, memctx );
518         }
519
520         return LDAP_COMPARE_FALSE;
521 }
522
523 static int
524 test_ava_filter(
525         Operation       *op,
526         Entry           *e,
527         AttributeAssertion *ava,
528         int             type )
529 {
530         int rc;
531         Attribute       *a;
532 #ifdef LDAP_COMP_MATCH
533         int i, num_attr_vals = 0;
534         AttributeAliasing *a_alias = NULL;
535 #endif
536
537         if ( !access_allowed( op, e,
538                 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
539         {
540                 return LDAP_INSUFFICIENT_ACCESS;
541         }
542
543         if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates 
544                 && op && op->o_bd && op->o_bd->be_has_subordinates )
545         {
546                 int     hasSubordinates;
547                 struct berval hs;
548
549                 if( type != LDAP_FILTER_EQUALITY &&
550                         type != LDAP_FILTER_APPROX )
551                 {
552                         /* No other match is allowed */
553                         return LDAP_INAPPROPRIATE_MATCHING;
554                 }
555                 
556                 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
557                         LDAP_SUCCESS )
558                 {
559                         return LDAP_OTHER;
560                 }
561
562                 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
563                         hs = slap_true_bv;
564
565                 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
566                         hs = slap_false_bv;
567
568                 } else {
569                         return LDAP_OTHER;
570                 }
571
572                 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
573                 return LDAP_COMPARE_FALSE;
574         }
575
576         if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
577                 MatchingRule *mr;
578                 int rc, match;
579                 const char *text;
580
581                 if( type != LDAP_FILTER_EQUALITY &&
582                         type != LDAP_FILTER_APPROX )
583                 {
584                         /* No other match is allowed */
585                         return LDAP_INAPPROPRIATE_MATCHING;
586                 }
587
588                 mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
589                 assert( mr );
590
591                 rc = value_match( &match, slap_schema.si_ad_entryDN, mr, 0,
592                         &e->e_nname, &ava->aa_value, &text );
593
594                 if( rc != LDAP_SUCCESS ) return rc;
595                 if( match == 0 ) return LDAP_COMPARE_TRUE;
596                 return LDAP_COMPARE_FALSE;
597         }
598
599         rc = LDAP_COMPARE_FALSE;
600
601 #ifdef LDAP_COMP_MATCH
602         if ( is_aliased_attribute && ava->aa_cf )
603         {
604                 a_alias = is_aliased_attribute ( ava->aa_desc );
605                 if ( a_alias )
606                         ava->aa_desc = a_alias->aa_aliased_ad;
607                 else
608                         ava->aa_cf = NULL;
609         }
610 #endif
611
612         for(a = attrs_find( e->e_attrs, ava->aa_desc );
613                 a != NULL;
614                 a = attrs_find( a->a_next, ava->aa_desc ) )
615         {
616                 MatchingRule *mr;
617                 struct berval *bv;
618
619                 if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
620                         e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
621                 {
622                         rc = LDAP_INSUFFICIENT_ACCESS;
623                         continue;
624                 }
625
626                 switch ( type ) {
627                 case LDAP_FILTER_APPROX:
628                         mr = a->a_desc->ad_type->sat_approx;
629                         if( mr != NULL ) break;
630
631                         /* use EQUALITY matching rule if no APPROX rule */
632
633                 case LDAP_FILTER_EQUALITY:
634                         mr = a->a_desc->ad_type->sat_equality;
635                         break;
636
637                 case LDAP_FILTER_GE:
638                 case LDAP_FILTER_LE:
639                         mr = a->a_desc->ad_type->sat_ordering;
640                         break;
641
642                 default:
643                         mr = NULL;
644                 }
645
646                 if( mr == NULL ) {
647                         rc = LDAP_INAPPROPRIATE_MATCHING;
648                         continue;
649                 }
650
651 #ifdef LDAP_COMP_MATCH
652                 if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
653                         /* Component Matching */
654                         for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
655                         if ( num_attr_vals <= 0 )/* no attribute value */
656                                 return LDAP_INAPPROPRIATE_MATCHING;
657                         num_attr_vals++;/* for NULL termination */
658
659                         /* following malloced will be freed by comp_tree_free () */
660                         a->a_comp_data = malloc( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
661
662                         if ( !a->a_comp_data ) {
663                                 return LDAP_NO_MEMORY;
664                         }
665
666                         a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
667                         i = num_attr_vals;
668                         for ( ; i ; i-- ) {
669                                 a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
670                         }
671
672                         a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
673                         if ( a->a_comp_data->cd_mem_op == NULL ) {
674                                 free ( a->a_comp_data );
675                                 a->a_comp_data = NULL;
676                                 return LDAP_OPERATIONS_ERROR;
677                         }
678                 }
679
680                 i = 0;
681 #endif
682
683                 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
684                         int ret, match;
685                         const char *text;
686
687 #ifdef LDAP_COMP_MATCH
688                         if( attr_converter && ava->aa_cf && a->a_comp_data ) {
689                                 /* Check if decoded component trees are already linked */
690                                 struct berval cf_bv = { 20, "componentFilterMatch" };
691                                 MatchingRule* cf_mr = mr_bvfind( &cf_bv );
692                                 MatchingRuleAssertion mra;
693                                 mra.ma_cf = ava->aa_cf;
694
695                                 if ( a->a_comp_data->cd_tree[i] == NULL )
696                                         a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
697                                 /* decoding error */
698                                 if ( !a->a_comp_data->cd_tree[i] ) {
699                                         free_ComponentData ( a );
700                                         return LDAP_OPERATIONS_ERROR;
701                                 }
702
703                                 ret = value_match( &match, a->a_desc, cf_mr, 0,
704                                         (struct berval*)a->a_comp_data->cd_tree[i++], (void*)&mra, &text );
705                                 if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
706                                         /* cached component tree is broken, just remove it */
707                                         free_ComponentData ( a );
708                                         return ret;
709                                 }
710                                 if ( a_alias )
711                                         ava->aa_desc = a_alias->aa_aliasing_ad;
712                         }
713                         else 
714 #endif
715                         {
716
717                                 ret = value_match( &match, a->a_desc, mr, 0,
718                                         bv, &ava->aa_value, &text );
719                         }
720
721                         if( ret != LDAP_SUCCESS ) {
722                                 rc = ret;
723                                 break;
724                         }
725
726                         switch ( type ) {
727                         case LDAP_FILTER_EQUALITY:
728                         case LDAP_FILTER_APPROX:
729                                 if ( match == 0 ) return LDAP_COMPARE_TRUE;
730                                 break;
731
732                         case LDAP_FILTER_GE:
733                                 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
734                                 break;
735
736                         case LDAP_FILTER_LE:
737                                 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
738                                 break;
739                         }
740                 }
741         }
742
743 #ifdef LDAP_COMP_MATCH
744         if ( a_alias )
745                 ava->aa_desc = a_alias->aa_aliasing_ad;
746 #endif
747
748         return rc;
749 }
750
751
752 static int
753 test_presence_filter(
754         Operation       *op,
755         Entry           *e,
756         AttributeDescription *desc )
757 {
758         Attribute       *a;
759         int rc;
760
761         if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
762                 return LDAP_INSUFFICIENT_ACCESS;
763         }
764
765         if ( desc == slap_schema.si_ad_hasSubordinates ) {
766                 /*
767                  * XXX: fairly optimistic: if the function is defined,
768                  * then PRESENCE must succeed, because hasSubordinate
769                  * is boolean-valued; I think we may live with this 
770                  * simplification by now.
771                  */
772                 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
773                         return LDAP_COMPARE_TRUE;
774                 }
775
776                 return LDAP_COMPARE_FALSE;
777         }
778
779         if ( desc == slap_schema.si_ad_entryDN ||
780                 desc == slap_schema.si_ad_subschemaSubentry )
781         {
782                 /* entryDN and subschemaSubentry are always present */
783                 return LDAP_COMPARE_TRUE;
784         }
785
786         rc = LDAP_COMPARE_FALSE;
787
788         for(a = attrs_find( e->e_attrs, desc );
789                 a != NULL;
790                 a = attrs_find( a->a_next, desc ) )
791         {
792                 if (( desc != a->a_desc ) && !access_allowed( op,
793                         e, a->a_desc, NULL, ACL_SEARCH, NULL ))
794                 {
795                         rc = LDAP_INSUFFICIENT_ACCESS;
796                         continue;
797                 }
798
799                 rc = LDAP_COMPARE_TRUE;
800                 break;
801         }
802
803         return rc;
804 }
805
806
807 static int
808 test_filter_and(
809         Operation       *op,
810         Entry   *e,
811         Filter  *flist )
812 {
813         Filter  *f;
814         int rtn = LDAP_COMPARE_TRUE; /* True if empty */
815
816         Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
817
818         for ( f = flist; f != NULL; f = f->f_next ) {
819                 int rc = test_filter( op, e, f );
820
821                 if ( rc == LDAP_COMPARE_FALSE ) {
822                         /* filter is False */
823                         rtn = rc;
824                         break;
825                 }
826
827                 if ( rc != LDAP_COMPARE_TRUE ) {
828                         /* filter is Undefined unless later elements are False */
829                         rtn = rc;
830                 }
831         }
832
833         Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
834
835         return rtn;
836 }
837
838 static int
839 test_filter_or(
840         Operation       *op,
841         Entry   *e,
842         Filter  *flist )
843 {
844         Filter  *f;
845         int rtn = LDAP_COMPARE_FALSE; /* False if empty */
846
847         Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
848
849         for ( f = flist; f != NULL; f = f->f_next ) {
850                 int rc = test_filter( op, e, f );
851
852                 if ( rc == LDAP_COMPARE_TRUE ) {
853                         /* filter is True */
854                         rtn = rc;
855                         break;
856                 }
857
858                 if ( rc != LDAP_COMPARE_FALSE ) {
859                         /* filter is Undefined unless later elements are True */
860                         rtn = rc;
861                 }
862         }
863
864         Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
865         return rtn;
866 }
867
868
869 static int
870 test_substrings_filter(
871         Operation       *op,
872         Entry   *e,
873         Filter  *f )
874 {
875         Attribute       *a;
876         int rc;
877
878         Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
879
880         if ( !access_allowed( op, e,
881                 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
882         {
883                 return LDAP_INSUFFICIENT_ACCESS;
884         }
885
886         rc = LDAP_COMPARE_FALSE;
887
888         for(a = attrs_find( e->e_attrs, f->f_sub_desc );
889                 a != NULL;
890                 a = attrs_find( a->a_next, f->f_sub_desc ) )
891         {
892                 MatchingRule *mr;
893                 struct berval *bv;
894
895                 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
896                         e, a->a_desc, NULL, ACL_SEARCH, NULL ))
897                 {
898                         rc = LDAP_INSUFFICIENT_ACCESS;
899                         continue;
900                 }
901
902                 mr = a->a_desc->ad_type->sat_substr;
903                 if( mr == NULL ) {
904                         rc = LDAP_INAPPROPRIATE_MATCHING;
905                         continue;
906                 }
907
908                 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
909                         int ret, match;
910                         const char *text;
911
912                         ret = value_match( &match, a->a_desc, mr, 0,
913                                 bv, f->f_sub, &text );
914
915                         if( ret != LDAP_SUCCESS ) {
916                                 rc = ret;
917                                 break;
918                         }
919                         if ( match == 0 ) return LDAP_COMPARE_TRUE;
920                 }
921         }
922
923         Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",
924                 rc, 0, 0 );
925         return rc;
926 }