]> git.sur5r.net Git - openldap/blob - servers/slapd/filterentry.c
fb01233a4d9232385cf223bb13f565ec252af06c
[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-2017 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_mfuncs.bmf_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 = SLAP_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 = 0;
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                 /* We have no Sort optimization for Approx matches */
661                 if (( a->a_flags & SLAP_ATTR_SORTED_VALS ) && type != LDAP_FILTER_APPROX ) {
662                         unsigned slot;
663                         int ret;
664
665                         /* For Ordering matches, we just need to do one comparison with
666                          * either the first (least) or last (greatest) value.
667                          */
668                         if ( use == SLAP_MR_ORDERING ) {
669                                 const char *text;
670                                 int match, which;
671                                 which = (type == LDAP_FILTER_LE) ? 0 : a->a_numvals-1;
672                                 ret = value_match( &match, a->a_desc, mr, use,
673                                         &a->a_nvals[which], &ava->aa_value, &text );
674                                 if ( ret != LDAP_SUCCESS ) return ret;
675                                 if (( type == LDAP_FILTER_LE && match <= 0 ) ||
676                                         ( type == LDAP_FILTER_GE && match >= 0 ))
677                                         return LDAP_COMPARE_TRUE;
678                                 continue;
679                         }
680                         /* Only Equality will get here */
681                         ret = attr_valfind( a, use | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
682                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, 
683                                 &ava->aa_value, &slot, NULL );
684                         if ( ret == LDAP_SUCCESS )
685                                 return LDAP_COMPARE_TRUE;
686                         else if ( ret != LDAP_NO_SUCH_ATTRIBUTE )
687                                 return ret;
688 #if 0
689                         /* The following is useful if we want to know which values
690                          * matched an ordering test. But here we don't care, we just
691                          * want to know if any value did, and that is checked above.
692                          */
693                         if ( ret == LDAP_NO_SUCH_ATTRIBUTE ) {
694                                 /* If insertion point is not the end of the list, there was
695                                  * at least one value greater than the assertion.
696                                  */
697                                 if ( type == LDAP_FILTER_GE && slot < a->a_numvals )
698                                         return LDAP_COMPARE_TRUE;
699                                 /* Likewise, if insertion point is not the head of the list,
700                                  * there was at least one value less than the assertion.
701                                  */
702                                 if ( type == LDAP_FILTER_LE && slot > 0 )
703                                         return LDAP_COMPARE_TRUE;
704                                 return LDAP_COMPARE_FALSE;
705                         }
706 #endif
707                         continue;
708                 }
709
710 #ifdef LDAP_COMP_MATCH
711                 if ( nibble_mem_allocator && ava->aa_cf && !a->a_comp_data ) {
712                         /* Component Matching */
713                         for ( num_attr_vals = 0; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
714                         if ( num_attr_vals <= 0 )/* no attribute value */
715                                 return LDAP_INAPPROPRIATE_MATCHING;
716                         num_attr_vals++;/* for NULL termination */
717
718                         /* following malloced will be freed by comp_tree_free () */
719                         a->a_comp_data = SLAP_MALLOC( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
720
721                         if ( !a->a_comp_data ) {
722                                 return LDAP_NO_MEMORY;
723                         }
724
725                         a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
726                         i = num_attr_vals;
727                         for ( ; i ; i-- ) {
728                                 a->a_comp_data->cd_tree[ i-1 ] = (ComponentSyntaxInfo*)NULL;
729                         }
730
731                         a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*10*(num_attr_vals-1), 1024 );
732                         if ( a->a_comp_data->cd_mem_op == NULL ) {
733                                 free ( a->a_comp_data );
734                                 a->a_comp_data = NULL;
735                                 return LDAP_OPERATIONS_ERROR;
736                         }
737                 }
738
739                 i = 0;
740 #endif
741
742                 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
743                         int ret, match;
744                         const char *text;
745
746 #ifdef LDAP_COMP_MATCH
747                         if( attr_converter && ava->aa_cf && a->a_comp_data ) {
748                                 /* Check if decoded component trees are already linked */
749                                 struct berval cf_bv = { 20, "componentFilterMatch" };
750                                 MatchingRule* cf_mr = mr_bvfind( &cf_bv );
751                                 MatchingRuleAssertion mra;
752                                 mra.ma_cf = ava->aa_cf;
753
754                                 if ( a->a_comp_data->cd_tree[i] == NULL )
755                                         a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, (a->a_vals + i));
756                                 /* decoding error */
757                                 if ( !a->a_comp_data->cd_tree[i] ) {
758                                         free_ComponentData ( a );
759                                         return LDAP_OPERATIONS_ERROR;
760                                 }
761
762                                 ret = value_match( &match, a->a_desc, cf_mr,
763                                         SLAP_MR_COMPONENT,
764                                         (struct berval*)a->a_comp_data->cd_tree[i++],
765                                         (void*)&mra, &text );
766                                 if ( ret == LDAP_INAPPROPRIATE_MATCHING ) {
767                                         /* cached component tree is broken, just remove it */
768                                         free_ComponentData ( a );
769                                         return ret;
770                                 }
771                                 if ( a_alias )
772                                         ava->aa_desc = a_alias->aa_aliasing_ad;
773
774                         } else 
775 #endif
776                         {
777                                 ret = ordered_value_match( &match, a->a_desc, mr, use,
778                                         bv, &ava->aa_value, &text );
779                         }
780
781                         if( ret != LDAP_SUCCESS ) {
782                                 rc = ret;
783                                 break;
784                         }
785
786                         switch ( type ) {
787                         case LDAP_FILTER_EQUALITY:
788                         case LDAP_FILTER_APPROX:
789                                 if ( match == 0 ) return LDAP_COMPARE_TRUE;
790                                 break;
791
792                         case LDAP_FILTER_GE:
793                                 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
794                                 break;
795
796                         case LDAP_FILTER_LE:
797                                 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
798                                 break;
799                         }
800                 }
801         }
802
803 #ifdef LDAP_COMP_MATCH
804         if ( a_alias )
805                 ava->aa_desc = a_alias->aa_aliasing_ad;
806 #endif
807
808         return rc;
809 }
810
811
812 static int
813 test_presence_filter(
814         Operation       *op,
815         Entry           *e,
816         AttributeDescription *desc )
817 {
818         Attribute       *a;
819         int rc;
820
821         if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
822                 return LDAP_INSUFFICIENT_ACCESS;
823         }
824
825         if ( desc == slap_schema.si_ad_hasSubordinates ) {
826                 /*
827                  * XXX: fairly optimistic: if the function is defined,
828                  * then PRESENCE must succeed, because hasSubordinate
829                  * is boolean-valued; I think we may live with this 
830                  * simplification by now.
831                  */
832                 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
833                         return LDAP_COMPARE_TRUE;
834                 }
835
836                 return LDAP_COMPARE_FALSE;
837         }
838
839         if ( desc == slap_schema.si_ad_entryDN ||
840                 desc == slap_schema.si_ad_subschemaSubentry )
841         {
842                 /* entryDN and subschemaSubentry are always present */
843                 return LDAP_COMPARE_TRUE;
844         }
845
846         rc = LDAP_COMPARE_FALSE;
847
848         for(a = attrs_find( e->e_attrs, desc );
849                 a != NULL;
850                 a = attrs_find( a->a_next, desc ) )
851         {
852                 if (( desc != a->a_desc ) && !access_allowed( op,
853                         e, a->a_desc, NULL, ACL_SEARCH, NULL ))
854                 {
855                         rc = LDAP_INSUFFICIENT_ACCESS;
856                         continue;
857                 }
858
859                 rc = LDAP_COMPARE_TRUE;
860                 break;
861         }
862
863         return rc;
864 }
865
866
867 static int
868 test_filter_and(
869         Operation       *op,
870         Entry   *e,
871         Filter  *flist )
872 {
873         Filter  *f;
874         int rtn = LDAP_COMPARE_TRUE; /* True if empty */
875
876         Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
877
878         for ( f = flist; f != NULL; f = f->f_next ) {
879                 int rc = test_filter( op, e, f );
880
881                 if ( rc == LDAP_COMPARE_FALSE ) {
882                         /* filter is False */
883                         rtn = rc;
884                         break;
885                 }
886
887                 if ( rc != LDAP_COMPARE_TRUE ) {
888                         /* filter is Undefined unless later elements are False */
889                         rtn = rc;
890                 }
891         }
892
893         Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
894
895         return rtn;
896 }
897
898 static int
899 test_filter_or(
900         Operation       *op,
901         Entry   *e,
902         Filter  *flist )
903 {
904         Filter  *f;
905         int rtn = LDAP_COMPARE_FALSE; /* False if empty */
906
907         Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
908
909         for ( f = flist; f != NULL; f = f->f_next ) {
910                 int rc = test_filter( op, e, f );
911
912                 if ( rc == LDAP_COMPARE_TRUE ) {
913                         /* filter is True */
914                         rtn = rc;
915                         break;
916                 }
917
918                 if ( rc != LDAP_COMPARE_FALSE ) {
919                         /* filter is Undefined unless later elements are True */
920                         rtn = rc;
921                 }
922         }
923
924         Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
925         return rtn;
926 }
927
928
929 static int
930 test_substrings_filter(
931         Operation       *op,
932         Entry   *e,
933         Filter  *f )
934 {
935         Attribute       *a;
936         int rc;
937
938         Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
939
940         if ( !access_allowed( op, e,
941                 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
942         {
943                 return LDAP_INSUFFICIENT_ACCESS;
944         }
945
946         rc = LDAP_COMPARE_FALSE;
947
948         for(a = attrs_find( e->e_attrs, f->f_sub_desc );
949                 a != NULL;
950                 a = attrs_find( a->a_next, f->f_sub_desc ) )
951         {
952                 MatchingRule *mr;
953                 struct berval *bv;
954
955                 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
956                         e, a->a_desc, NULL, ACL_SEARCH, NULL ))
957                 {
958                         rc = LDAP_INSUFFICIENT_ACCESS;
959                         continue;
960                 }
961
962                 mr = a->a_desc->ad_type->sat_substr;
963                 if( mr == NULL ) {
964                         rc = LDAP_INAPPROPRIATE_MATCHING;
965                         continue;
966                 }
967
968                 for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
969                         int ret, match;
970                         const char *text;
971
972                         ret = value_match( &match, a->a_desc, mr, SLAP_MR_SUBSTR,
973                                 bv, f->f_sub, &text );
974
975                         if( ret != LDAP_SUCCESS ) {
976                                 rc = ret;
977                                 break;
978                         }
979                         if ( match == 0 ) return LDAP_COMPARE_TRUE;
980                 }
981         }
982
983         Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",
984                 rc, 0, 0 );
985         return rc;
986 }