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