]> git.sur5r.net Git - openldap/blob - servers/slapd/filter.c
5e146e11f9fd0f91f194a27c9e7f106a807cd2c4
[openldap] / servers / slapd / filter.c
1 /* filter.c - routines for parsing and dealing with filters */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/socket.h>
13 #include <ac/string.h>
14
15 #include "slap.h"
16
17 static int      get_filter_list(
18         Connection *conn,
19         BerElement *ber,
20         Filter **f,
21         char **fstr,
22         char **text );
23 static int      get_substring_filter(
24         Connection *conn,
25         BerElement *ber,
26         Filter *f,
27         char **fstr,
28         char **text );
29
30 int
31 get_filter(
32         Connection *conn,
33         BerElement *ber,
34         Filter **filt,
35         char **fstr,
36         char **text )
37 {
38         ber_tag_t       tag;
39         ber_len_t       len;
40         int             err;
41         Filter          *f;
42         char            *ftmp;
43
44         Debug( LDAP_DEBUG_FILTER, "begin get_filter\n", 0, 0, 0 );
45
46         /*
47          * A filter looks like this coming in:
48          *      Filter ::= CHOICE {
49          *              and             [0]     SET OF Filter,
50          *              or              [1]     SET OF Filter,
51          *              not             [2]     Filter,
52          *              equalityMatch   [3]     AttributeValueAssertion,
53          *              substrings      [4]     SubstringFilter,
54          *              greaterOrEqual  [5]     AttributeValueAssertion,
55          *              lessOrEqual     [6]     AttributeValueAssertion,
56          *              present         [7]     AttributeType,,
57          *              approxMatch     [8]     AttributeValueAssertion
58          *              extensibleMatch [9] MatchingRuleAssertion
59          *      }
60          *
61          *      SubstringFilter ::= SEQUENCE {
62          *              type               AttributeType,
63          *              SEQUENCE OF CHOICE {
64          *                      initial          [0] IA5String,
65          *                      any              [1] IA5String,
66          *                      final            [2] IA5String
67          *              }
68          *      }
69          *
70      *  MatchingRuleAssertion ::= SEQUENCE {
71      *          matchingRule    [1] MatchingRuleId OPTIONAL,
72      *          type            [2] AttributeDescription OPTIONAL,
73      *          matchValue      [3] AssertionValue,
74      *          dnAttributes    [4] BOOLEAN DEFAULT FALSE
75          *      }
76          *
77          */
78
79         tag = ber_peek_tag( ber, &len );
80
81         if( tag == LBER_ERROR ) {
82                 *text = "error decoding filter";
83                 return SLAPD_DISCONNECT;
84         }
85
86         f = (Filter *) ch_malloc( sizeof(Filter) );
87         f->f_next = NULL;
88
89         err = LDAP_SUCCESS;
90         *fstr = NULL;
91         f->f_choice = tag; 
92
93         switch ( f->f_choice ) {
94 #ifdef SLAPD_SCHEMA_NOT_COMPAT
95         /* not yet implemented */
96 #else
97         case LDAP_FILTER_EQUALITY:
98                 Debug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 );
99                 if ( (err = get_ava( ber, &f->f_ava )) != LDAP_SUCCESS ) {
100                         *text = "error decoding filter";
101                         break;
102                 }
103                 *fstr = ch_malloc(4 + strlen( f->f_avtype ) +
104                     f->f_avvalue.bv_len);
105                 sprintf( *fstr, "(%s=%s)", f->f_avtype,
106                     f->f_avvalue.bv_val );
107                 break;
108
109         case LDAP_FILTER_SUBSTRINGS:
110                 Debug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 );
111                 err = get_substring_filter( conn, ber, f, fstr, text );
112                 break;
113
114         case LDAP_FILTER_GE:
115                 Debug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 );
116                 if ( (err = get_ava( ber, &f->f_ava )) != LDAP_SUCCESS ) {
117                         *text = "decoding filter error";
118                         break;
119                 }
120                 *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
121                     f->f_avvalue.bv_len);
122                 sprintf( *fstr, "(%s>=%s)", f->f_avtype,
123                     f->f_avvalue.bv_val );
124                 break;
125
126         case LDAP_FILTER_LE:
127                 Debug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 );
128                 if ( (err = get_ava( ber, &f->f_ava )) != LDAP_SUCCESS ) {
129                         *text = "error decoding filter";
130                         break;
131                 }
132                 *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
133                     f->f_avvalue.bv_len);
134                 sprintf( *fstr, "(%s<=%s)", f->f_avtype,
135                     f->f_avvalue.bv_val );
136                 break;
137
138         case LDAP_FILTER_PRESENT:
139                 Debug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 );
140                 if ( ber_scanf( ber, "a", &f->f_type ) == LBER_ERROR ) {
141                         err = SLAPD_DISCONNECT;
142                         *text = "error decoding filter";
143                         break;
144                 }
145
146                 err = LDAP_SUCCESS;
147                 attr_normalize( f->f_type );
148                 *fstr = ch_malloc( 5 + strlen( f->f_type ) );
149                 sprintf( *fstr, "(%s=*)", f->f_type );
150                 break;
151
152         case LDAP_FILTER_APPROX:
153                 Debug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 );
154                 if ( (err = get_ava( ber, &f->f_ava )) != LDAP_SUCCESS ) {
155                         *text = "error decoding filter";
156                         break;
157                 }
158                 *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
159                     f->f_avvalue.bv_len);
160                 sprintf( *fstr, "(%s~=%s)", f->f_avtype,
161                     f->f_avvalue.bv_val );
162                 break;
163 #endif
164
165         case LDAP_FILTER_AND:
166                 Debug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 );
167                 err = get_filter_list( conn, ber, &f->f_and, &ftmp, text );
168                 if ( err != LDAP_SUCCESS ) {
169                         break;
170                 }
171                 if (ftmp == NULL) ftmp = ch_strdup("");
172                 *fstr = ch_malloc( 4 + strlen( ftmp ) );
173                 sprintf( *fstr, "(&%s)", ftmp );
174                 free( ftmp );
175                 break;
176
177         case LDAP_FILTER_OR:
178                 Debug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 );
179                 err = get_filter_list( conn, ber, &f->f_and, &ftmp, text );
180                 if ( err != LDAP_SUCCESS ) {
181                         break;
182                 }
183                 if (ftmp == NULL) ftmp = ch_strdup("");
184                 *fstr = ch_malloc( 4 + strlen( ftmp ) );
185                 sprintf( *fstr, "(|%s)", ftmp );
186                 free( ftmp );
187                 break;
188
189         case LDAP_FILTER_NOT:
190                 Debug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 );
191                 (void) ber_skip_tag( ber, &len );
192                 err = get_filter( conn, ber, &f->f_not, &ftmp, text );
193                 if ( err != LDAP_SUCCESS ) {
194                         break;
195                 }
196                 if (ftmp == NULL) ftmp = ch_strdup("");
197                 *fstr = ch_malloc( 4 + strlen( ftmp ) );
198                 sprintf( *fstr, "(!%s)", ftmp );
199                 free( ftmp );
200                 break;
201
202         case LDAP_FILTER_EXT:
203                 /* not yet implemented */
204                 Debug( LDAP_DEBUG_ANY, "extensible match not yet implemented.\n",
205                        f->f_choice, 0, 0 );
206                 err = LDAP_PROTOCOL_ERROR;
207                 *text = "extensible match not yet implemented";
208                 break;
209
210         default:
211                 Debug( LDAP_DEBUG_ANY, "unknown filter type %lu\n",
212                        f->f_choice, 0, 0 );
213                 err = LDAP_PROTOCOL_ERROR;
214                 *text = "unknown filter type";
215                 break;
216         }
217
218         if ( err != LDAP_SUCCESS ) {
219                 free( (char *) f );
220                 if ( *fstr != NULL ) {
221                         free( *fstr );
222                 }
223         } else {
224                 *filt = f;
225         }
226
227         Debug( LDAP_DEBUG_FILTER, "end get_filter %d\n", err, 0, 0 );
228         return( err );
229 }
230
231 static int
232 get_filter_list( Connection *conn, BerElement *ber, Filter **f, char **fstr, char **text )
233 {
234         Filter          **new;
235         int             err;
236         ber_tag_t       tag;
237         ber_len_t       len;
238         char            *last, *ftmp;
239
240         Debug( LDAP_DEBUG_FILTER, "begin get_filter_list\n", 0, 0, 0 );
241
242         *fstr = NULL;
243         new = f;
244         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
245             tag = ber_next_element( ber, &len, last ) )
246         {
247                 err = get_filter( conn, ber, new, &ftmp, text );
248                 if ( err != LDAP_SUCCESS )
249                         return( err );
250
251                 if ( *fstr == NULL ) {
252                         *fstr = ftmp;
253                 } else {
254                         *fstr = ch_realloc( *fstr, strlen( *fstr ) +
255                             strlen( ftmp ) + 1 );
256                         strcat( *fstr, ftmp );
257                         free( ftmp );
258                 }
259                 new = &(*new)->f_next;
260         }
261         *new = NULL;
262
263         Debug( LDAP_DEBUG_FILTER, "end get_filter_list\n", 0, 0, 0 );
264         return( LDAP_SUCCESS );
265 }
266
267 #ifndef SLAPD_SCHEMA_NOT_COMPAT
268
269 static int
270 get_substring_filter(
271     Connection  *conn,
272     BerElement  *ber,
273     Filter      *f,
274     char        **fstr,
275         char    **text
276 )
277 {
278         ber_tag_t       tag;
279         ber_len_t       len;
280         ber_tag_t       rc;
281         struct berval *val;
282         char            *last;
283         int             syntax;
284
285         *text = "error decoding filter";
286
287         Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 );
288
289         if ( ber_scanf( ber, "{a" /*}*/, &f->f_sub_type ) == LBER_ERROR ) {
290                 return SLAPD_DISCONNECT;
291         }
292
293 #ifdef SLAPD_SCHEMA_NOT_COMPAT
294         /* not yet implemented */
295 #else
296         attr_normalize( f->f_sub_type );
297
298         /* should get real syntax and see if we have a substring matching rule */
299         syntax = attr_syntax( f->f_sub_type );
300 #endif
301
302         f->f_sub_initial = NULL;
303         f->f_sub_any = NULL;
304         f->f_sub_final = NULL;
305
306         if( fstr ) {
307                 *fstr = ch_malloc( strlen( f->f_sub_type ) + 3 );
308                 sprintf( *fstr, "(%s=" /*)*/, f->f_sub_type );
309         }
310
311         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
312             tag = ber_next_element( ber, &len, last ) )
313         {
314                 rc = ber_scanf( ber, "O", &val );
315                 if ( rc == LBER_ERROR ) {
316                         rc = SLAPD_DISCONNECT;
317                         goto return_error;
318                 }
319
320                 if ( val == NULL || val->bv_len == 0 ) {
321                         ber_bvfree( val );
322                         rc = LDAP_INVALID_SYNTAX;
323                         goto return_error;
324                 } 
325
326                 rc = LDAP_PROTOCOL_ERROR;
327
328 #ifdef SLAPD_SCHEMA_NOT_COMPAT
329                 /* not yet implemented */
330 #else
331                 /* we should call a substring syntax normalization routine */
332                 value_normalize( val->bv_val, syntax );
333                 /* this is bogus, value_normalize should take a berval */
334                 val->bv_len = strlen( val->bv_val );
335 #endif
336
337                 switch ( tag ) {
338                 case LDAP_SUBSTRING_INITIAL:
339                         Debug( LDAP_DEBUG_FILTER, "  INITIAL\n", 0, 0, 0 );
340                         if ( f->f_sub_initial != NULL ) {
341                                 ber_bvfree( val );
342                                 goto return_error;
343                         }
344                         f->f_sub_initial = val;
345
346                         if( fstr ) {
347                                 *fstr = ch_realloc( *fstr,
348                                         strlen( *fstr ) + val->bv_len + 1 );
349                                 strcat( *fstr, val->bv_val );
350                         }
351                         break;
352
353                 case LDAP_SUBSTRING_ANY:
354                         Debug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
355                         if( ber_bvecadd( &f->f_sub_any, val ) < 0 ) {
356                                 ber_bvfree( val );
357                                 goto return_error;
358                         }
359
360                         if( fstr ) {
361                                 *fstr = ch_realloc( *fstr,
362                                         strlen( *fstr ) + val->bv_len + 2 );
363                                 strcat( *fstr, "*" );
364                                 strcat( *fstr, val->bv_val );
365                         }
366                         break;
367
368                 case LDAP_SUBSTRING_FINAL:
369                         Debug( LDAP_DEBUG_FILTER, "  FINAL\n", 0, 0, 0 );
370                         if ( f->f_sub_final != NULL ) {
371                                 ber_bvfree( val );
372                                 goto return_error;
373                         }
374                         f->f_sub_final = val;
375
376                         if( fstr ) {
377                                 *fstr = ch_realloc( *fstr,
378                                         strlen( *fstr ) + val->bv_len + 2 );
379                                 strcat( *fstr, "*" );
380                                 strcat( *fstr, val->bv_val );
381                         }
382                         break;
383
384                 default:
385                         Debug( LDAP_DEBUG_FILTER, "  unknown type=%ld\n",
386                                 (long) tag, 0, 0 );
387
388                         ber_bvfree( val );
389
390 return_error:
391                         Debug( LDAP_DEBUG_FILTER, "  error=%ld\n",
392                                 (long) rc, 0, 0 );
393
394                         if( fstr ) {
395                                 free( *fstr );
396                                 *fstr = NULL;
397                         }
398
399                         ch_free( f->f_sub_type );
400                         ber_bvfree( f->f_sub_initial );
401                         ber_bvecfree( f->f_sub_any );
402                         ber_bvfree( f->f_sub_final );
403                         return rc;
404                 }
405         }
406
407         if( fstr ) {
408                 *fstr = ch_realloc( *fstr, strlen( *fstr ) + 3 );
409                 if ( f->f_sub_final == NULL ) {
410                         strcat( *fstr, "*" );
411                 }
412                 strcat( *fstr, /*(*/ ")" );
413         }
414
415         Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
416         return( LDAP_SUCCESS );
417 }
418
419 #endif /* not compat */
420
421 void
422 filter_free( Filter *f )
423 {
424         Filter  *p, *next;
425
426         if ( f == NULL ) {
427                 return;
428         }
429
430         switch ( f->f_choice ) {
431         case LDAP_FILTER_PRESENT:
432 #ifdef SLAPD_SCHEMA_NOT_COMPAT
433                 ad_free( f->f_desc, 1 );
434 #else
435                 if ( f->f_type != NULL ) {
436                         free( f->f_type );
437                 }
438 #endif
439                 break;
440
441         case LDAP_FILTER_EQUALITY:
442         case LDAP_FILTER_GE:
443         case LDAP_FILTER_LE:
444         case LDAP_FILTER_APPROX:
445 #ifdef SLAPD_SCHEMA_NOT_COMPAT
446                 ava_free( f->f_ava, 1 );
447 #else
448                 ava_free( &f->f_ava, 0 );
449 #endif
450                 break;
451
452         case LDAP_FILTER_SUBSTRINGS:
453 #ifdef SLAPD_SCHEMA_NOT_COMPAT
454                 ad_free( f->f_sub_desc, 1 );
455                 if ( f->f_sub_initial != NULL ) {
456                         ber_bvfree( f->f_sub_initial );
457                 }
458                 ber_bvecfree( f->f_sub_any );
459                 if ( f->f_sub_final != NULL ) {
460                         ber_bvfree( f->f_sub_final );
461                 }
462 #else
463                 if ( f->f_sub_type != NULL ) {
464                         free( f->f_sub_type );
465                 }
466                 if ( f->f_sub_initial != NULL ) {
467                         ber_bvfree( f->f_sub_initial );
468                 }
469                 ber_bvecfree( f->f_sub_any );
470                 if ( f->f_sub_final != NULL ) {
471                         ber_bvfree( f->f_sub_final );
472                 }
473 #endif
474                 break;
475
476         case LDAP_FILTER_AND:
477         case LDAP_FILTER_OR:
478         case LDAP_FILTER_NOT:
479                 for ( p = f->f_list; p != NULL; p = next ) {
480                         next = p->f_next;
481                         filter_free( p );
482                 }
483                 break;
484
485         case SLAPD_FILTER_COMPUTED:
486                 break;
487
488         default:
489                 Debug( LDAP_DEBUG_ANY, "unknown filter type %lu\n",
490                        f->f_choice, 0, 0 );
491                 break;
492         }
493
494         free( f );
495 }
496
497 #ifdef LDAP_DEBUG
498
499 void
500 filter_print( Filter *f )
501 {
502         int     i;
503         Filter  *p;
504
505         if ( f == NULL ) {
506                 fprintf( stderr, "No filter!" );
507         }
508
509         switch ( f->f_choice ) {
510         case LDAP_FILTER_EQUALITY:
511 #ifdef SLAPD_SCHEMA_NOT_COMPAT
512                 fprintf( stderr, "(%s=%s)",
513                         f->f_ava->aa_desc->ad_cname,
514                     f->f_ava->aa_value->bv_val );
515 #else
516                 fprintf( stderr, "(%s=%s)", f->f_ava.ava_type,
517                     f->f_ava.ava_value.bv_val );
518 #endif
519                 break;
520
521         case LDAP_FILTER_GE:
522 #ifdef SLAPD_SCHEMA_NOT_COMPAT
523                 fprintf( stderr, "(%s>=%s)",
524                         f->f_ava->aa_desc->ad_cname,
525                     f->f_ava->aa_value->bv_val );
526 #else
527                 fprintf( stderr, "(%s>=%s)", f->f_ava.ava_type,
528                     f->f_ava.ava_value.bv_val );
529 #endif
530                 break;
531
532         case LDAP_FILTER_LE:
533 #ifdef SLAPD_SCHEMA_NOT_COMPAT
534                 fprintf( stderr, "(%s<=%s)",
535                         f->f_ava->aa_desc->ad_cname,
536                     f->f_ava->aa_value->bv_val );
537 #else
538                 fprintf( stderr, "(%s<=%s)", f->f_ava.ava_type,
539                     f->f_ava.ava_value.bv_val );
540 #endif
541                 break;
542
543         case LDAP_FILTER_APPROX:
544 #ifdef SLAPD_SCHEMA_NOT_COMPAT
545                 fprintf( stderr, "(%s~=%s)",
546                         f->f_ava->aa_desc->ad_cname,
547                     f->f_ava->aa_value->bv_val );
548 #else
549                 fprintf( stderr, "(%s~=%s)", f->f_ava.ava_type,
550                     f->f_ava.ava_value.bv_val );
551 #endif
552                 break;
553
554         case LDAP_FILTER_SUBSTRINGS:
555 #ifdef SLAPD_SCHEMA_NOT_COMPAT
556                 fprintf( stderr, "(%s=" /*)*/, f->f_sub_desc->ad_cname );
557 #else
558                 fprintf( stderr, "(%s=" /*)*/, f->f_sub_type );
559 #endif
560                 if ( f->f_sub_initial != NULL ) {
561                         fprintf( stderr, "%s", f->f_sub_initial->bv_val );
562                 }
563                 if ( f->f_sub_any != NULL ) {
564                         for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
565                                 fprintf( stderr, "*%s", f->f_sub_any[i]->bv_val );
566                         }
567                 }
568                 if ( f->f_sub_final != NULL ) {
569                         fprintf( stderr, "*%s", f->f_sub_final->bv_val );
570                 }
571                 fprintf( stderr, /*(*/ ")" );
572                 break;
573
574         case LDAP_FILTER_PRESENT:
575 #ifdef SLAPD_SCHEMA_NOT_COMPAT
576                 fprintf( stderr, "(%s=*)",
577                         f->f_desc->ad_cname );
578 #else
579                 fprintf( stderr, "(%s=*)", f->f_type );
580 #endif
581                 break;
582
583         case LDAP_FILTER_AND:
584         case LDAP_FILTER_OR:
585         case LDAP_FILTER_NOT:
586                 fprintf( stderr, "(%c" /*)*/,
587                         f->f_choice == LDAP_FILTER_AND ? '&' :
588                     f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
589                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
590                         filter_print( p );
591                 }
592                 fprintf( stderr, /*(*/ ")" );
593                 break;
594
595         case SLAPD_FILTER_COMPUTED:
596                 fprintf( stderr, "(%s)",
597                         f->f_result == LDAP_COMPARE_FALSE ? "false" :
598                         f->f_result == LDAP_COMPARE_TRUE ? "true" :
599                         f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" :
600                         "error" );
601                 break;
602
603         default:
604                 fprintf( stderr, "(unknown filter %lu)", f->f_choice );
605                 break;
606         }
607 }
608
609 #endif /* ldap_debug */