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