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