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