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