]> git.sur5r.net Git - openldap/blob - servers/slapd/filterentry.c
Last(?) set of changes before 2.2beta
[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         void *memctx = op ? op->o_tmpmemctx : NULL;
200
201         if ( mra->ma_desc ) {
202                 /*
203                  * if ma_desc is available, then we're filtering for
204                  * one attribute, and SEARCH permissions can be checked
205                  * directly.
206                  */
207                 if( !access_allowed( op, e,
208                         mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
209                 {
210                         return LDAP_INSUFFICIENT_ACCESS;
211                 }
212
213                 for(a = attrs_find( e->e_attrs, mra->ma_desc );
214                         a != NULL;
215                         a = attrs_find( a->a_next, mra->ma_desc ) )
216                 {
217                         struct berval *bv;
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                                 bv = a->a_vals;
225                         for ( ; bv->bv_val != NULL; bv++ )
226                         {
227                                 int ret;
228                                 int rc;
229                                 const char *text;
230         
231                                 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
232                                         bv, &mra->ma_value, &text );
233         
234                                 if( rc != LDAP_SUCCESS ) {
235                                         return rc;
236                                 }
237         
238                                 if ( ret == 0 ) {
239                                         return LDAP_COMPARE_TRUE;
240                                 }
241                         }
242                 }
243         } else {
244
245                 /*
246                  * No attribute description: test all
247                  */
248                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
249                         struct berval   *bv, value;
250                         const char      *text = NULL;
251                         int             rc;
252
253                         /* check if matching is appropriate */
254                         if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type )) {
255                                 continue;
256                         }
257
258                         /* normalize for equality */
259                         rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule,
260                                 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
261                                 &mra->ma_value, &value, &text, memctx );
262                         if ( rc != LDAP_SUCCESS ) {
263                                 continue;
264                         }
265
266                         /* check search access */
267                         if ( !access_allowed( op, e,
268                                 a->a_desc, &value, ACL_SEARCH, NULL ) ) {
269                                 continue;
270                         }
271
272                         /* check match */
273                         if (mra->ma_rule == a->a_desc->ad_type->sat_equality)
274                                 bv = a->a_nvals;
275                         else
276                                 bv = a->a_vals;
277                         for ( ; bv->bv_val != NULL; bv++ )
278                         {
279                                 int ret;
280                                 int rc;
281         
282                                 rc = value_match( &ret, a->a_desc, mra->ma_rule, 0,
283                                         bv, &value, &text );
284         
285                                 if( rc != LDAP_SUCCESS ) {
286                                         return rc;
287                                 }
288         
289                                 if ( ret == 0 ) {
290                                         return LDAP_COMPARE_TRUE;
291                                 }
292                         }
293                 }
294         }
295
296         /* check attrs in DN AVAs if required */
297         if ( mra->ma_dnattrs ) {
298                 LDAPDN          dn = NULL;
299                 int             iRDN, iAVA;
300                 int             rc;
301
302                 /* parse and pretty the dn */
303                 rc = dnPrettyDN( NULL, &e->e_name, &dn, memctx );
304                 if ( rc != LDAP_SUCCESS ) {
305                         return LDAP_INVALID_SYNTAX;
306                 }
307
308                 /* for each AVA of each RDN ... */
309                 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
310                         LDAPRDN         rdn = dn[ iRDN ];
311
312                         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
313                                 LDAPAVA         *ava = rdn[ iAVA ];
314                                 struct berval   *bv = &ava->la_value, value;
315                                 AttributeDescription *ad = (AttributeDescription *)ava->la_private;
316                                 int ret;
317                                 int rc;
318                                 const char *text;
319
320                                 assert( ad );
321
322                                 if ( mra->ma_desc ) {
323                                         /* have a mra type? check for subtype */
324                                         if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
325                                                 continue;
326                                         }
327                                         value = mra->ma_value;
328
329                                 } else {
330                                         const char      *text = NULL;
331
332                                         /* check if matching is appropriate */
333                                         if ( !mr_usable_with_at( mra->ma_rule, ad->ad_type )) {
334                                                 continue;
335                                         }
336
337                                         /* normalize for equality */
338                                         rc = asserted_value_validate_normalize( ad,
339                                                 mra->ma_rule,
340                                                 SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
341                                                 &mra->ma_value, &value, &text, memctx );
342                                         if ( rc != LDAP_SUCCESS ) {
343                                                 continue;
344                                         }
345
346                                         /* check search access */
347                                         if ( !access_allowed( op, e,
348                                                 ad, &value, ACL_SEARCH, NULL ) ) {
349                                                 continue;
350                                         }
351                                 }
352
353                                 /* check match */
354                                 rc = value_match( &ret, ad, mra->ma_rule, 0,
355                                         bv, &value, &text );
356
357                                 if( rc != LDAP_SUCCESS ) {
358                                         ldap_dnfree_x( dn, memctx );
359                                         return rc;
360                                 }
361
362                                 if ( ret == 0 ) {
363                                         ldap_dnfree_x( dn, memctx );
364                                         return LDAP_COMPARE_TRUE;
365                                 }
366                         }
367                 }
368         }
369
370         return LDAP_COMPARE_FALSE;
371 }
372
373 static int
374 test_ava_filter(
375         Operation       *op,
376         Entry           *e,
377         AttributeAssertion *ava,
378         int             type
379 )
380 {
381         Attribute       *a;
382
383         if ( !access_allowed( op, e,
384                 ava->aa_desc, &ava->aa_value, ACL_SEARCH, NULL ) )
385         {
386                 return LDAP_INSUFFICIENT_ACCESS;
387         }
388
389         for(a = attrs_find( e->e_attrs, ava->aa_desc );
390                 a != NULL;
391                 a = attrs_find( a->a_next, ava->aa_desc ) )
392         {
393                 MatchingRule *mr;
394                 struct berval *bv;
395
396                 switch ( type ) {
397                 case LDAP_FILTER_APPROX:
398                         mr = a->a_desc->ad_type->sat_approx;
399                         if( mr != NULL ) break;
400
401                         /* use EQUALITY matching rule if no APPROX rule */
402
403                 case LDAP_FILTER_EQUALITY:
404                         mr = a->a_desc->ad_type->sat_equality;
405                         break;
406
407                 case LDAP_FILTER_GE:
408                 case LDAP_FILTER_LE:
409                         mr = a->a_desc->ad_type->sat_ordering;
410                         break;
411
412                 default:
413                         mr = NULL;
414                 }
415
416                 if( mr == NULL ) {
417                         continue;
418                 }
419
420                 for ( bv = a->a_nvals; bv->bv_val != NULL; bv++ )
421                 {
422                         int ret;
423                         int rc;
424                         const char *text;
425
426                         rc = value_match( &ret, a->a_desc, mr, 0,
427                                 bv, &ava->aa_value, &text );
428
429                         if( rc != LDAP_SUCCESS ) {
430                                 return rc;
431                         }
432
433                         switch ( type ) {
434                         case LDAP_FILTER_EQUALITY:
435                         case LDAP_FILTER_APPROX:
436                                 if ( ret == 0 ) {
437                                         return LDAP_COMPARE_TRUE;
438                                 }
439                                 break;
440
441                         case LDAP_FILTER_GE:
442                                 if ( ret >= 0 ) {
443                                         return LDAP_COMPARE_TRUE;
444                                 }
445                                 break;
446
447                         case LDAP_FILTER_LE:
448                                 if ( ret <= 0 ) {
449                                         return LDAP_COMPARE_TRUE;
450                                 }
451                                 break;
452                         }
453                 }
454         }
455
456         if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates 
457                         && op && op->o_bd && op->o_bd->be_has_subordinates ) {
458                 int             hasSubordinates;
459                 struct berval   hs;
460
461                 /*
462                  * No other match should be allowed ...
463                  */
464                 assert( type == LDAP_FILTER_EQUALITY );
465                 
466                 if (op->o_bd->be_has_subordinates( op, e, &hasSubordinates ) != LDAP_SUCCESS) {
467                         return LDAP_OTHER;
468                 }
469
470                 if ( hasSubordinates == LDAP_COMPARE_TRUE ) {
471                         hs = slap_true_bv;
472
473                 } else if ( hasSubordinates == LDAP_COMPARE_FALSE ) {
474                         hs = slap_false_bv;
475
476                 } else {
477                         return LDAP_OTHER;
478                 }
479
480                 if ( bvmatch( &ava->aa_value, &hs ) ) {
481                         return LDAP_COMPARE_TRUE;
482                 }
483
484                 return LDAP_COMPARE_FALSE;
485         }
486
487         return( LDAP_COMPARE_FALSE );
488 }
489
490
491 static int
492 test_presence_filter(
493         Operation       *op,
494         Entry           *e,
495         AttributeDescription *desc
496 )
497 {
498         Attribute       *a;
499
500         if ( !access_allowed( op, e, desc, NULL, ACL_SEARCH, NULL ) )
501         {
502                 return LDAP_INSUFFICIENT_ACCESS;
503         }
504
505         a = attrs_find( e->e_attrs, desc );
506
507         if ( a == NULL && desc == slap_schema.si_ad_hasSubordinates ) {
508
509                 /*
510                  * XXX: fairly optimistic: if the function is defined,
511                  * then PRESENCE must succeed, because hasSubordinate
512                  * is boolean-valued; I think we may live with this 
513                  * simplification by now
514                  */
515                 if ( op && op->o_bd && op->o_bd->be_has_subordinates ) {
516                         return LDAP_COMPARE_TRUE;
517                 }
518
519                 return LDAP_COMPARE_FALSE;
520         }
521
522         return a != NULL ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
523 }
524
525
526 static int
527 test_filter_and(
528         Operation       *op,
529         Entry   *e,
530         Filter  *flist
531 )
532 {
533         Filter  *f;
534         int rtn = LDAP_COMPARE_TRUE; /* True if empty */
535
536 #ifdef NEW_LOGGING
537         LDAP_LOG( FILTER, ENTRY, "test_filter_and: begin\n", 0, 0, 0 );
538 #else
539         Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
540 #endif
541
542
543         for ( f = flist; f != NULL; f = f->f_next ) {
544                 int rc = test_filter( op, e, f );
545
546                 if ( rc == LDAP_COMPARE_FALSE ) {
547                         /* filter is False */
548                         rtn = rc;
549                         break;
550                 }
551
552                 if ( rc != LDAP_COMPARE_TRUE ) {
553                         /* filter is Undefined unless later elements are False */
554                         rtn = rc;
555                 }
556         }
557
558 #ifdef NEW_LOGGING
559         LDAP_LOG( FILTER, RESULTS, "test_filter_and:  rc=%d\n", rtn, 0, 0 );
560 #else
561         Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
562 #endif
563
564         return rtn;
565 }
566
567 static int
568 test_filter_or(
569         Operation       *op,
570         Entry   *e,
571         Filter  *flist
572 )
573 {
574         Filter  *f;
575         int rtn = LDAP_COMPARE_FALSE; /* False if empty */
576
577 #ifdef NEW_LOGGING
578         LDAP_LOG( FILTER, ENTRY, "test_filter_or: begin\n", 0, 0, 0 );
579 #else
580         Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
581 #endif
582
583
584         for ( f = flist; f != NULL; f = f->f_next ) {
585                 int rc = test_filter( op, e, f );
586
587                 if ( rc == LDAP_COMPARE_TRUE ) {
588                         /* filter is True */
589                         rtn = rc;
590                         break;
591                 }
592
593                 if ( rc != LDAP_COMPARE_FALSE ) {
594                         /* filter is Undefined unless later elements are True */
595                         rtn = rc;
596                 }
597         }
598
599 #ifdef NEW_LOGGING
600         LDAP_LOG( FILTER, ENTRY, "test_filter_or: result=%d\n", rtn, 0, 0 );
601 #else
602         Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
603 #endif
604
605         return rtn;
606 }
607
608
609 static int
610 test_substrings_filter(
611         Operation       *op,
612         Entry   *e,
613         Filter  *f
614 )
615 {
616         Attribute       *a;
617
618 #ifdef NEW_LOGGING
619         LDAP_LOG( FILTER, ENTRY, "test_substrings_filter: begin\n", 0, 0, 0 );
620 #else
621         Debug( LDAP_DEBUG_FILTER, "begin test_substrings_filter\n", 0, 0, 0 );
622 #endif
623
624
625         if ( !access_allowed( op, e,
626                 f->f_sub_desc, NULL, ACL_SEARCH, NULL ) )
627         {
628                 return LDAP_INSUFFICIENT_ACCESS;
629         }
630
631         for(a = attrs_find( e->e_attrs, f->f_sub_desc );
632                 a != NULL;
633                 a = attrs_find( a->a_next, f->f_sub_desc ) )
634         {
635                 MatchingRule *mr = a->a_desc->ad_type->sat_substr;
636                 struct berval *bv;
637
638                 if( mr == NULL ) {
639                         continue;
640                 }
641
642                 for ( bv = a->a_nvals; bv->bv_val != NULL; bv++ )
643                 {
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 ) {
652                                 return rc;
653                         }
654
655                         if ( ret == 0 ) {
656                                 return LDAP_COMPARE_TRUE;
657                         }
658                 }
659         }
660
661 #ifdef NEW_LOGGING
662         LDAP_LOG( FILTER, ENTRY, "test_substrings_filter: return FALSE\n", 0, 0, 0 );
663 #else
664         Debug( LDAP_DEBUG_FILTER, "end test_substrings_filter 1\n", 0, 0, 0 );
665 #endif
666
667         return LDAP_COMPARE_FALSE;
668 }