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