]> git.sur5r.net Git - openldap/blob - servers/slapd/filterentry.c
fix messages
[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
35 #include "slap.h"
36
37 static int      test_filter_and( Operation *op, Entry *e, Filter *flist );
38 static int      test_filter_or( Operation *op, Entry *e, Filter *flist );
39 static int      test_substrings_filter( Operation *op, Entry *e, Filter *f);
40 static int      test_ava_filter( Operation *op,
41         Entry *e, AttributeAssertion *ava, int type );
42 static int      test_mra_filter( Operation *op,
43         Entry *e, MatchingRuleAssertion *mra );
44 static int      test_presence_filter( Operation *op,
45         Entry *e, AttributeDescription *desc );
46
47
48 /*
49  * test_filter - test a filter against a single entry.
50  * returns:
51  *              LDAP_COMPARE_TRUE               filter matched
52  *              LDAP_COMPARE_FALSE              filter did not match
53  *              SLAPD_COMPARE_UNDEFINED filter is undefined
54  *      or an ldap result code indicating error
55  */
56
57 int
58 test_filter(
59     Operation   *op,
60     Entry       *e,
61     Filter      *f )
62 {
63         int     rc;
64         Debug( LDAP_DEBUG_FILTER, "=> test_filter\n", 0, 0, 0 );
65
66         switch ( f->f_choice ) {
67         case SLAPD_FILTER_COMPUTED:
68                 Debug( LDAP_DEBUG_FILTER, "    COMPUTED %s (%d)\n",
69                         f->f_result == LDAP_COMPARE_FALSE ? "false" :
70                         f->f_result == LDAP_COMPARE_TRUE ? "true" :
71                         f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" : "error",
72                         f->f_result, 0 );
73
74                 rc = f->f_result;
75                 break;
76
77         case LDAP_FILTER_EQUALITY:
78                 Debug( LDAP_DEBUG_FILTER, "    EQUALITY\n", 0, 0, 0 );
79                 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_EQUALITY );
80                 break;
81
82         case LDAP_FILTER_SUBSTRINGS:
83                 Debug( LDAP_DEBUG_FILTER, "    SUBSTRINGS\n", 0, 0, 0 );
84                 rc = test_substrings_filter( op, e, f );
85                 break;
86
87         case LDAP_FILTER_GE:
88                 Debug( LDAP_DEBUG_FILTER, "    GE\n", 0, 0, 0 );
89                 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_GE );
90                 break;
91
92         case LDAP_FILTER_LE:
93                 Debug( LDAP_DEBUG_FILTER, "    LE\n", 0, 0, 0 );
94                 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_LE );
95                 break;
96
97         case LDAP_FILTER_PRESENT:
98                 Debug( LDAP_DEBUG_FILTER, "    PRESENT\n", 0, 0, 0 );
99                 rc = test_presence_filter( op, e, f->f_desc );
100                 break;
101
102         case LDAP_FILTER_APPROX:
103                 Debug( LDAP_DEBUG_FILTER, "    APPROX\n", 0, 0, 0 );
104                 rc = test_ava_filter( op, e, f->f_ava, LDAP_FILTER_APPROX );
105                 break;
106
107         case LDAP_FILTER_AND:
108                 Debug( LDAP_DEBUG_FILTER, "    AND\n", 0, 0, 0 );
109                 rc = test_filter_and( op, e, f->f_and );
110                 break;
111
112         case LDAP_FILTER_OR:
113                 Debug( LDAP_DEBUG_FILTER, "    OR\n", 0, 0, 0 );
114                 rc = test_filter_or( op, e, f->f_or );
115                 break;
116
117         case LDAP_FILTER_NOT:
118                 Debug( LDAP_DEBUG_FILTER, "    NOT\n", 0, 0, 0 );
119                 rc = test_filter( op, e, f->f_not );
120
121                 /* Flip true to false and false to true
122                  * but leave Undefined alone.
123                  */
124                 switch( rc ) {
125                 case LDAP_COMPARE_TRUE:
126                         rc = LDAP_COMPARE_FALSE;
127                         break;
128                 case LDAP_COMPARE_FALSE:
129                         rc = LDAP_COMPARE_TRUE;
130                         break;
131                 }
132                 break;
133
134         case LDAP_FILTER_EXT:
135                 Debug( LDAP_DEBUG_FILTER, "    EXT\n", 0, 0, 0 );
136                 rc = test_mra_filter( op, e, f->f_mra );
137                 break;
138
139         default:
140                 Debug( LDAP_DEBUG_ANY, "    unknown filter type %lu\n",
141                     f->f_choice, 0, 0 );
142                 rc = LDAP_PROTOCOL_ERROR;
143         }
144
145         Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
146         return( rc );
147 }
148
149 static int test_mra_filter(
150         Operation *op,
151         Entry *e,
152         MatchingRuleAssertion *mra )
153 {
154         Attribute       *a;
155         void            *memctx;
156         BER_MEMFREE_FN  *memfree;
157 #ifdef LDAP_COMP_MATCH
158         int i, num_attr_vals;
159 #endif
160
161         if ( op == NULL ) {
162                 memctx = NULL;
163                 memfree = slap_sl_free;
164         } else {
165                 memctx = op->o_tmpmemctx;
166                 memfree = op->o_tmpfree;
167         }
168
169         if ( mra->ma_desc ) {
170                 /*
171                  * if ma_desc is available, then we're filtering for
172                  * one attribute, and SEARCH permissions can be checked
173                  * directly.
174                  */
175                 if( !access_allowed( op, e,
176                         mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
177                 {
178                         return LDAP_INSUFFICIENT_ACCESS;
179                 }
180
181                 if ( mra->ma_desc == slap_schema.si_ad_entryDN ) {
182                         int ret, rc;
183                         const char *text;
184
185                         rc = value_match( &ret, slap_schema.si_ad_entryDN, mra->ma_rule,
186                                 0, &e->e_nname, &mra->ma_value, &text );
187         
188         
189                         if( rc != LDAP_SUCCESS ) return rc;
190                         if ( ret == 0 ) return LDAP_COMPARE_TRUE;
191                         return LDAP_COMPARE_FALSE;
192                 }
193
194                 for(a = attrs_find( e->e_attrs, mra->ma_desc );
195                         a != NULL;
196                         a = attrs_find( a->a_next, mra->ma_desc ) )
197                 {
198                         struct berval *bv;
199 #ifdef LDAP_COMP_MATCH
200                         /* Component Matching */
201                         if( mra->ma_cf &&
202                                 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT )
203                         {
204
205                                 num_attr_vals = 0;
206                                 if ( !a->a_comp_data ) {
207                                         for ( ; a->a_vals[num_attr_vals].bv_val != NULL; num_attr_vals++ );
208                                         if ( num_attr_vals <= 0 )/* no attribute value */
209                                                 return LDAP_INAPPROPRIATE_MATCHING;
210                                         num_attr_vals++;
211
212                                         /* following malloced will be freed by comp_tree_free () */
213                                         a->a_comp_data = malloc( sizeof( ComponentData ) + sizeof( ComponentSyntaxInfo* )*num_attr_vals );
214
215                                         if ( !a->a_comp_data )
216                                                 return LDAP_NO_MEMORY;
217                                         a->a_comp_data->cd_tree = (ComponentSyntaxInfo**)((char*)a->a_comp_data + sizeof(ComponentData));
218                                         a->a_comp_data->cd_tree[ num_attr_vals - 1] = (ComponentSyntaxInfo*)NULL;
219                                         a->a_comp_data->cd_mem_op = nibble_mem_allocator ( 1024*16, 1024 );
220                                 }
221                         }
222 #endif
223
224                         /* If ma_rule is not the same as the attribute's
225                          * normal rule, then we can't use the a_nvals.
226                          */
227                         if (mra->ma_rule == a->a_desc->ad_type->sat_equality) {
228                                 bv = a->a_nvals;
229                         } else {
230                                 bv = a->a_vals;
231                         }
232 #ifdef LDAP_COMP_MATCH
233                         i = 0;
234 #endif
235                         for ( ; bv->bv_val != NULL; bv++ ) {
236                                 int ret;
237                                 int rc;
238                                 const char *text;
239         
240 #ifdef LDAP_COMP_MATCH
241                                 if( mra->ma_cf &&
242                                         mra->ma_rule->smr_usage & SLAP_MR_COMPONENT ) {
243                                         /* Check if decoded component trees are already linked */
244                                         if ( num_attr_vals )
245                                                 a->a_comp_data->cd_tree[i] = attr_converter (a, a->a_desc->ad_type->sat_syntax, bv);
246                                         /* decoding error */
247                                         if ( !a->a_comp_data->cd_tree[i] )
248                                                 return LDAP_OPERATIONS_ERROR;
249                                         rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
250                                                 (struct berval*)a->a_comp_data->cd_tree[i++], (void*)mra, &text );
251                                 } else 
252 #endif
253                                 {
254                                         rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
255                                                 bv, &mra->ma_value, &text );
256                                 }
257
258                                 if( rc != LDAP_SUCCESS ) return rc;
259                                 if ( ret == 0 ) return LDAP_COMPARE_TRUE;
260                         }
261                 }
262
263         } else {
264                 /*
265                  * No attribute description: test all
266                  */
267                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
268                         struct berval   *bv, value;
269                         const char      *text = NULL;
270                         int             rc;
271
272                         /* check if matching is appropriate */
273                         if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type )) {
274                                 continue;
275                         }
276
277                         /* normalize for equality */
278                         rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule,
279                                 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
280                                 &mra->ma_value, &value, &text, memctx );
281                         if ( rc != LDAP_SUCCESS ) continue;
282
283                         /* check search access */
284                         if ( !access_allowed( op, e,
285                                 a->a_desc, &value, ACL_SEARCH, NULL ) ) {
286                                 memfree( value.bv_val, memctx );
287                                 continue;
288                         }
289 #ifdef LDAP_COMP_MATCH
290                         /* Component Matching */
291                         if( mra->ma_cf &&
292                                 mra->ma_rule->smr_usage & SLAP_MR_COMPONENT)
293                         {
294                                 int ret;
295
296                                 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
297                                         (struct berval*)a, (void*)mra, &text );
298                                 if( rc != LDAP_SUCCESS ) break;
299         
300                                 if ( ret == 0 ) {
301                                         rc = LDAP_COMPARE_TRUE;
302                                         break;
303                                 }
304
305                         }
306 #endif
307
308                         /* check match */
309                         if (mra->ma_rule == a->a_desc->ad_type->sat_equality) {
310                                 bv = a->a_nvals;
311                         } else {
312                                 bv = a->a_vals;
313                         }
314
315                         for ( ; bv->bv_val != NULL; bv++ ) {
316                                 int ret;
317         
318                                 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
319                                         bv, &value, &text );
320
321                                 if( rc != LDAP_SUCCESS ) break;
322         
323                                 if ( ret == 0 ) {
324                                         rc = LDAP_COMPARE_TRUE;
325                                         break;
326                                 }
327                         }
328                         memfree( value.bv_val, memctx );
329                         if ( rc != LDAP_SUCCESS ) return rc;
330                 }
331         }
332
333         /* check attrs in DN AVAs if required */
334         if ( mra->ma_dnattrs ) {
335                 LDAPDN          dn = NULL;
336                 int             iRDN, iAVA;
337                 int             rc;
338
339                 /* parse and pretty the dn */
340                 rc = dnPrettyDN( NULL, &e->e_name, &dn, memctx );
341                 if ( rc != LDAP_SUCCESS ) {
342                         return LDAP_INVALID_SYNTAX;
343                 }
344
345                 /* for each AVA of each RDN ... */
346                 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
347                         LDAPRDN         rdn = dn[ iRDN ];
348
349                         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
350                                 LDAPAVA         *ava = rdn[ iAVA ];
351                                 struct berval   *bv = &ava->la_value, value;
352                                 AttributeDescription *ad =
353                                         (AttributeDescription *)ava->la_private;
354                                 int ret;
355                                 const char *text;
356
357                                 assert( ad );
358
359                                 if ( mra->ma_desc ) {
360                                         /* have a mra type? check for subtype */
361                                         if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
362                                                 continue;
363                                         }
364                                         value = mra->ma_value;
365
366                                 } else {
367                                         const char      *text = NULL;
368
369                                         /* check if matching is appropriate */
370                                         if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type )) {
371                                                 continue;
372                                         }
373
374                                         /* normalize for equality */
375                                         rc = asserted_value_validate_normalize( ad,
376                                                 mra->ma_rule,
377                                                 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
378                                                 &mra->ma_value, &value, &text, memctx );
379                                         if ( rc != LDAP_SUCCESS ) continue;
380
381                                         /* check search access */
382                                         if ( !access_allowed( op, e,
383                                                 ad, &value, ACL_SEARCH, NULL ) )
384                                         {
385                                                 memfree( value.bv_val, memctx );
386                                                 continue;
387                                         }
388                                 }
389
390                                 /* check match */
391                                 rc = value_match( &ret, ad, mra->ma_rule, 0,
392                                         bv, &value, &text );
393                                 if ( value.bv_val != mra->ma_value.bv_val ) {
394                                         memfree( value.bv_val, memctx );
395                                 }
396
397                                 if ( rc == LDAP_SUCCESS && ret == 0 ) rc = LDAP_COMPARE_TRUE;
398
399                                 if( rc != LDAP_SUCCESS ) {
400                                         ldap_dnfree_x( dn, memctx );
401                                         return rc;
402                                 }
403                         }
404                 }
405                 ldap_dnfree_x( dn, memctx );
406         }
407
408         return LDAP_COMPARE_FALSE;
409 }
410
411 static int
412 test_ava_filter(
413         Operation       *op,
414         Entry           *e,
415         AttributeAssertion *ava,
416         int             type )
417 {
418         int rc;
419         Attribute       *a;
420
421         if ( !access_allowed( op, e,
422                 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
423         {
424                 return LDAP_INSUFFICIENT_ACCESS;
425         }
426
427         if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates 
428                 && op && op->o_bd && op->o_bd->be_has_subordinates )
429         {
430                 int     hasSubordinates;
431                 struct berval hs;
432
433                 if( type != LDAP_FILTER_EQUALITY &&
434                         type != LDAP_FILTER_APPROX )
435                 {
436                         /* No other match is allowed */
437                         return LDAP_INAPPROPRIATE_MATCHING;
438                 }
439                 
440                 if ( op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) !=
441                         LDAP_SUCCESS )
442                 {
443                         return LDAP_OTHER;
444                 }
445
446                 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
447                         hs = slap_true_bv;
448
449                 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
450                         hs = slap_false_bv;
451
452                 } else {
453                         return LDAP_OTHER;
454                 }
455
456                 if ( bvmatch( &ava->aa_value, &hs ) ) return LDAP_COMPARE_TRUE;
457                 return LDAP_COMPARE_FALSE;
458         }
459
460         if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
461                 MatchingRule *mr;
462                 int rc, match;
463                 const char *text;
464
465                 if( type != LDAP_FILTER_EQUALITY &&
466                         type != LDAP_FILTER_APPROX )
467                 {
468                         /* No other match is allowed */
469                         return LDAP_INAPPROPRIATE_MATCHING;
470                 }
471
472                 mr = slap_schema.si_ad_entryDN->ad_type->sat_equality;
473                 assert( mr );
474
475                 rc = value_match( &match, slap_schema.si_ad_entryDN, mr, 0,
476                         &e->e_nname, &ava->aa_value, &text );
477
478                 if( rc != LDAP_SUCCESS ) return rc;
479                 if( match == 0 ) return LDAP_COMPARE_TRUE;
480                 return LDAP_COMPARE_FALSE;
481         }
482
483         rc = LDAP_COMPARE_FALSE;
484
485         for(a = attrs_find( e->e_attrs, ava->aa_desc );
486                 a != NULL;
487                 a = attrs_find( a->a_next, ava->aa_desc ) )
488         {
489                 MatchingRule *mr;
490                 struct berval *bv;
491
492                 if (( ava->aa_desc != a->a_desc ) && !access_allowed( op,
493                         e, a->a_desc, &ava->aa_value, ACL_SEARCH, NULL ))
494                 {
495                         rc = LDAP_INSUFFICIENT_ACCESS;
496                         continue;
497                 }
498
499                 switch ( type ) {
500                 case LDAP_FILTER_APPROX:
501                         mr = a->a_desc->ad_type->sat_approx;
502                         if( mr != NULL ) break;
503
504                         /* use EQUALITY matching rule if no APPROX rule */
505
506                 case LDAP_FILTER_EQUALITY:
507                         mr = a->a_desc->ad_type->sat_equality;
508                         break;
509
510                 case LDAP_FILTER_GE:
511                 case LDAP_FILTER_LE:
512                         mr = a->a_desc->ad_type->sat_ordering;
513                         break;
514
515                 default:
516                         mr = NULL;
517                 }
518
519                 if( mr == NULL ) {
520                         rc = LDAP_INAPPROPRIATE_MATCHING;
521                         continue;
522                 }
523
524                 for ( bv = a->a_nvals; bv->bv_val != NULL; bv++ ) {
525                         int ret, match;
526                         const char *text;
527
528                         ret = value_match( &match, a->a_desc, mr, 0,
529                                 bv, &ava->aa_value, &text );
530
531                         if( ret != LDAP_SUCCESS ) {
532                                 rc = ret;
533                                 break;
534                         }
535
536                         switch ( type ) {
537                         case LDAP_FILTER_EQUALITY:
538                         case LDAP_FILTER_APPROX:
539                                 if ( match == 0 ) return LDAP_COMPARE_TRUE;
540                                 break;
541
542                         case LDAP_FILTER_GE:
543                                 if ( match >= 0 ) return LDAP_COMPARE_TRUE;
544                                 break;
545
546                         case LDAP_FILTER_LE:
547                                 if ( match <= 0 ) return LDAP_COMPARE_TRUE;
548                                 break;
549                         }
550                 }
551         }
552
553         return rc;
554 }
555
556
557 static int
558 test_presence_filter(
559         Operation       *op,
560         Entry           *e,
561         AttributeDescription *desc )
562 {
563         Attribute       *a;
564         int rc;
565
566         if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) ) {
567                 return LDAP_INSUFFICIENT_ACCESS;
568         }
569
570         if ( desc == slap_schema.si_ad_hasSubordinates ) {
571                 /*
572                  * XXX: fairly optimistic: if the function is defined,
573                  * then PRESENCE must succeed, because hasSubordinate
574                  * is boolean-valued; I think we may live with this 
575                  * simplification by now
576                  */
577                 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
578                         return LDAP_COMPARE_TRUE;
579                 }
580
581                 return LDAP_COMPARE_FALSE;
582         }
583
584         if ( desc == slap_schema.si_ad_entryDN ||
585                 desc == slap_schema.si_ad_subschemaSubentry )
586         {
587                 /* entryDN and subschemaSubentry are always present */
588                 return LDAP_COMPARE_TRUE;
589         }
590
591         rc = LDAP_COMPARE_FALSE;
592
593         for(a = attrs_find( e->e_attrs, desc );
594                 a != NULL;
595                 a = attrs_find( a->a_next, desc ) )
596         {
597                 if (( desc != a->a_desc ) && !access_allowed( op,
598                         e, a->a_desc, NULL, ACL_SEARCH, NULL ))
599                 {
600                         rc = LDAP_INSUFFICIENT_ACCESS;
601                         continue;
602                 }
603
604                 rc = LDAP_COMPARE_TRUE;
605                 break;
606         }
607
608         return rc;
609 }
610
611
612 static int
613 test_filter_and(
614         Operation       *op,
615         Entry   *e,
616         Filter  *flist )
617 {
618         Filter  *f;
619         int rtn = LDAP_COMPARE_TRUE; /* True if empty */
620
621         Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
622
623         for ( f = flist; f != NULL; f = f->f_next ) {
624                 int rc = test_filter( op, e, f );
625
626                 if ( rc == LDAP_COMPARE_FALSE ) {
627                         /* filter is False */
628                         rtn = rc;
629                         break;
630                 }
631
632                 if ( rc != LDAP_COMPARE_TRUE ) {
633                         /* filter is Undefined unless later elements are False */
634                         rtn = rc;
635                 }
636         }
637
638         Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
639
640         return rtn;
641 }
642
643 static int
644 test_filter_or(
645         Operation       *op,
646         Entry   *e,
647         Filter  *flist )
648 {
649         Filter  *f;
650         int rtn = LDAP_COMPARE_FALSE; /* False if empty */
651
652         Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
653
654         for ( f = flist; f != NULL; f = f->f_next ) {
655                 int rc = test_filter( op, e, f );
656
657                 if ( rc == LDAP_COMPARE_TRUE ) {
658                         /* filter is True */
659                         rtn = rc;
660                         break;
661                 }
662
663                 if ( rc != LDAP_COMPARE_FALSE ) {
664                         /* filter is Undefined unless later elements are True */
665                         rtn = rc;
666                 }
667         }
668
669         Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
670         return rtn;
671 }
672
673
674 static int
675 test_substrings_filter(
676         Operation       *op,
677         Entry   *e,
678         Filter  *f )
679 {
680         Attribute       *a;
681         int rc;
682
683         Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
684
685         if ( !access_allowed( op, e,
686                 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
687         {
688                 return LDAP_INSUFFICIENT_ACCESS;
689         }
690
691         rc = LDAP_COMPARE_FALSE;
692
693         for(a = attrs_find( e->e_attrs, f->f_sub_desc );
694                 a != NULL;
695                 a = attrs_find( a->a_next, f->f_sub_desc ) )
696         {
697                 MatchingRule *mr;
698                 struct berval *bv;
699
700                 if (( f->f_sub_desc != a->a_desc ) && !access_allowed( op,
701                         e, a->a_desc, NULL, ACL_SEARCH, NULL ))
702                 {
703                         rc = LDAP_INSUFFICIENT_ACCESS;
704                         continue;
705                 }
706
707                 mr = a->a_desc->ad_type->sat_substr;
708                 if( mr == NULL ) {
709                         rc = LDAP_INAPPROPRIATE_MATCHING;
710                         continue;
711                 }
712
713                 for ( bv = a->a_nvals; bv->bv_val != NULL; bv++ ) {
714                         int ret, match;
715                         const char *text;
716
717                         ret = value_match( &match, a->a_desc, mr, 0,
718                                 bv, f->f_sub, &text );
719
720                         if( ret != LDAP_SUCCESS ) {
721                                 rc = ret;
722                                 break;
723                         }
724                         if ( match == 0 ) return LDAP_COMPARE_TRUE;
725                 }
726         }
727
728         Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter %d\n",
729                 rc, 0, 0 );
730         return rc;
731 }