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