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