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