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