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