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