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-2021 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
test_filter(Operation * op,Entry * e,Filter * f)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
test_mra_filter(Operation * op,Entry * e,MatchingRuleAssertion * mra)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
test_ava_filter(Operation * op,Entry * e,AttributeAssertion * ava,int type)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
test_presence_filter(Operation * op,Entry * e,AttributeDescription * desc)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
test_filter_and(Operation * op,Entry * e,Filter * flist)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
test_filter_or(Operation * op,Entry * e,Filter * flist)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
test_substrings_filter(Operation * op,Entry * e,Filter * f)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 }
987