]> git.sur5r.net Git - openldap/blob - servers/slapd/filter.c
9f10361528ac8111b7ee3ea532902ec2cc1e605e
[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(Connection *conn, BerElement *ber, Filter **f, char **fstr);
18 static int      get_substring_filter(Connection *conn, BerElement *ber, Filter *f, char **fstr);
19
20 int
21 get_filter( Connection *conn, BerElement *ber, Filter **filt, char **fstr )
22 {
23         ber_len_t       len;
24         int             err;
25         Filter          *f;
26         char            *ftmp;
27
28         Debug( LDAP_DEBUG_FILTER, "begin get_filter\n", 0, 0, 0 );
29
30         /*
31          * A filter looks like this coming in:
32          *      Filter ::= CHOICE {
33          *              and             [0]     SET OF Filter,
34          *              or              [1]     SET OF Filter,
35          *              not             [2]     Filter,
36          *              equalityMatch   [3]     AttributeValueAssertion,
37          *              substrings      [4]     SubstringFilter,
38          *              greaterOrEqual  [5]     AttributeValueAssertion,
39          *              lessOrEqual     [6]     AttributeValueAssertion,
40          *              present         [7]     AttributeType,,
41          *              approxMatch     [8]     AttributeValueAssertion
42          *              extensibleMatch [9] MatchingRuleAssertion
43          *      }
44          *
45          *      SubstringFilter ::= SEQUENCE {
46          *              type               AttributeType,
47          *              SEQUENCE OF CHOICE {
48          *                      initial          [0] IA5String,
49          *                      any              [1] IA5String,
50          *                      final            [2] IA5String
51          *              }
52          *      }
53          *
54      *  MatchingRuleAssertion ::= SEQUENCE {
55      *          matchingRule    [1] MatchingRuleId OPTIONAL,
56      *          type            [2] AttributeDescription OPTIONAL,
57      *          matchValue      [3] AssertionValue,
58      *          dnAttributes    [4] BOOLEAN DEFAULT FALSE
59          *      }
60          *
61          */
62
63         f = (Filter *) ch_malloc( sizeof(Filter) );
64         f->f_next = NULL;
65
66         err = LDAP_SUCCESS;
67         *fstr = NULL;
68         f->f_choice = ber_peek_tag( ber, &len );
69
70         switch ( f->f_choice ) {
71         case LDAP_FILTER_EQUALITY:
72                 Debug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 );
73                 if ( (err = get_ava( ber, &f->f_ava )) == LDAP_SUCCESS ) {
74                         *fstr = ch_malloc(4 + strlen( f->f_avtype ) +
75                             f->f_avvalue.bv_len);
76                         sprintf( *fstr, "(%s=%s)", f->f_avtype,
77                             f->f_avvalue.bv_val );
78                 }
79                 break;
80
81         case LDAP_FILTER_SUBSTRINGS:
82                 Debug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 );
83                 err = get_substring_filter( conn, ber, f, fstr );
84                 break;
85
86         case LDAP_FILTER_GE:
87                 Debug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 );
88                 if ( (err = get_ava( ber, &f->f_ava )) == LDAP_SUCCESS ) {
89                         *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
90                             f->f_avvalue.bv_len);
91                         sprintf( *fstr, "(%s>=%s)", f->f_avtype,
92                             f->f_avvalue.bv_val );
93                 }
94                 break;
95
96         case LDAP_FILTER_LE:
97                 Debug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 );
98                 if ( (err = get_ava( ber, &f->f_ava )) == LDAP_SUCCESS ) {
99                         *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
100                             f->f_avvalue.bv_len);
101                         sprintf( *fstr, "(%s<=%s)", f->f_avtype,
102                             f->f_avvalue.bv_val );
103                 }
104                 break;
105
106         case LDAP_FILTER_PRESENT:
107                 Debug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 );
108                 if ( ber_scanf( ber, "a", &f->f_type ) == LBER_ERROR ) {
109                         err = -1;
110                 } else {
111                         err = LDAP_SUCCESS;
112                         attr_normalize( f->f_type );
113                         *fstr = ch_malloc( 5 + strlen( f->f_type ) );
114                         sprintf( *fstr, "(%s=*)", f->f_type );
115                 }
116                 break;
117
118         case LDAP_FILTER_APPROX:
119                 Debug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 );
120                 if ( (err = get_ava( ber, &f->f_ava )) == LDAP_SUCCESS ) {
121                         *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
122                             f->f_avvalue.bv_len);
123                         sprintf( *fstr, "(%s~=%s)", f->f_avtype,
124                             f->f_avvalue.bv_val );
125                 }
126                 break;
127
128         case LDAP_FILTER_AND:
129                 Debug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 );
130                 if ( (err = get_filter_list( conn, ber, &f->f_and, &ftmp ))
131                     == LDAP_SUCCESS ) {
132                         if (ftmp == NULL) ftmp = ch_strdup("");
133                         *fstr = ch_malloc( 4 + strlen( ftmp ) );
134                         sprintf( *fstr, "(&%s)", ftmp );
135                         free( ftmp );
136                 }
137                 break;
138
139         case LDAP_FILTER_OR:
140                 Debug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 );
141                 if ( (err = get_filter_list( conn, ber, &f->f_or, &ftmp ))
142                     == LDAP_SUCCESS ) {
143                         if (ftmp == NULL) ftmp = ch_strdup("");
144                         *fstr = ch_malloc( 4 + strlen( ftmp ) );
145                         sprintf( *fstr, "(|%s)", ftmp );
146                         free( ftmp );
147                 }
148                 break;
149
150         case LDAP_FILTER_NOT:
151                 Debug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 );
152                 (void) ber_skip_tag( ber, &len );
153                 if ( (err = get_filter( conn, ber, &f->f_not, &ftmp )) == LDAP_SUCCESS ) {
154                         if (ftmp == NULL) ftmp = ch_strdup("");
155                         *fstr = ch_malloc( 4 + strlen( ftmp ) );
156                         sprintf( *fstr, "(!%s)", ftmp );
157                         free( ftmp );
158                 }
159                 break;
160
161         case LBER_DEFAULT:
162                 Debug( LDAP_DEBUG_ANY, "decoding filter error\n",
163                        0, 0, 0 );
164                 err = -1;
165                 break;
166
167         default:
168                 Debug( LDAP_DEBUG_ANY, "unknown filter type %lu\n",
169                        f->f_choice, 0, 0 );
170                 err = LDAP_PROTOCOL_ERROR;
171                 break;
172         }
173
174         if ( err != LDAP_SUCCESS ) {
175                 free( (char *) f );
176                 if ( *fstr != NULL ) {
177                         free( *fstr );
178                 }
179         } else {
180                 *filt = f;
181         }
182
183         Debug( LDAP_DEBUG_FILTER, "end get_filter %d\n", err, 0, 0 );
184         return( err );
185 }
186
187 static int
188 get_filter_list( Connection *conn, BerElement *ber, Filter **f, char **fstr )
189 {
190         Filter          **new;
191         int             err;
192         ber_tag_t       tag;
193         ber_len_t       len;
194         char            *last, *ftmp;
195
196         Debug( LDAP_DEBUG_FILTER, "begin get_filter_list\n", 0, 0, 0 );
197
198         *fstr = NULL;
199         new = f;
200         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
201             tag = ber_next_element( ber, &len, last ) )
202         {
203                 if ( (err = get_filter( conn, ber, new, &ftmp )) != LDAP_SUCCESS )
204                         return( err );
205                 if ( *fstr == NULL ) {
206                         *fstr = ftmp;
207                 } else {
208                         *fstr = ch_realloc( *fstr, strlen( *fstr ) +
209                             strlen( ftmp ) + 1 );
210                         strcat( *fstr, ftmp );
211                         free( ftmp );
212                 }
213                 new = &(*new)->f_next;
214         }
215         *new = NULL;
216
217         Debug( LDAP_DEBUG_FILTER, "end get_filter_list\n", 0, 0, 0 );
218         return( LDAP_SUCCESS );
219 }
220
221 static int
222 get_substring_filter(
223     Connection  *conn,
224     BerElement  *ber,
225     Filter      *f,
226     char        **fstr
227 )
228 {
229         ber_tag_t       tag;
230         ber_len_t       len;
231         ber_tag_t       rc;
232         struct berval *val;
233         char            *last;
234         int             syntax;
235
236         Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 );
237
238         if ( ber_scanf( ber, "{a" /*}*/, &f->f_sub_type ) == LBER_ERROR ) {
239                 return( -1 );
240         }
241
242         attr_normalize( f->f_sub_type );
243
244 #ifdef SLAPD_SCHEMA_COMPAT
245         /* should get real syntax and see if we have a substring matching rule */
246         syntax = attr_syntax( f->f_sub_type );
247 #endif
248
249         f->f_sub_initial = NULL;
250         f->f_sub_any = NULL;
251         f->f_sub_final = NULL;
252
253         if( fstr ) {
254                 *fstr = ch_malloc( strlen( f->f_sub_type ) + 3 );
255                 sprintf( *fstr, "(%s=", f->f_sub_type );
256         }
257
258         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
259             tag = ber_next_element( ber, &len, last ) )
260         {
261                 rc = ber_scanf( ber, "O", &val );
262                 if ( rc == LBER_ERROR ) {
263                         rc = -1;
264                         goto return_error;
265                 }
266
267                 if ( val == NULL || val->bv_len == 0 ) {
268                         ber_bvfree( val );
269                         rc = LDAP_INVALID_SYNTAX;
270                         goto return_error;
271                 } 
272
273                 rc = LDAP_PROTOCOL_ERROR;
274
275 #ifdef SLAPD_SCHEMA_COMPAT
276                 /* we should call a substring syntax normalization routine */
277                 value_normalize( val->bv_val, syntax );
278 #endif
279
280                 /* this is bogus, value_normalize should take a berval */
281                 val->bv_len = strlen( val->bv_val );
282
283                 switch ( tag ) {
284                 case LDAP_SUBSTRING_INITIAL:
285                         Debug( LDAP_DEBUG_FILTER, "  INITIAL\n", 0, 0, 0 );
286                         if ( f->f_sub_initial != NULL ) {
287                                 ber_bvfree( val );
288                                 goto return_error;
289                         }
290                         f->f_sub_initial = val;
291
292                         if( fstr ) {
293                                 *fstr = ch_realloc( *fstr,
294                                         strlen( *fstr ) + val->bv_len + 1 );
295                                 strcat( *fstr, val->bv_val );
296                         }
297                         break;
298
299                 case LDAP_SUBSTRING_ANY:
300                         Debug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
301                         charray_add( (char ***) &f->f_sub_any, (char *) val );
302
303                         if( fstr ) {
304                                 *fstr = ch_realloc( *fstr,
305                                         strlen( *fstr ) + val->bv_len + 2 );
306                                 strcat( *fstr, "*" );
307                                 strcat( *fstr, val->bv_val );
308                         }
309                         break;
310
311                 case LDAP_SUBSTRING_FINAL:
312                         Debug( LDAP_DEBUG_FILTER, "  FINAL\n", 0, 0, 0 );
313                         if ( f->f_sub_final != NULL ) {
314                                 ber_bvfree( val );
315                                 goto return_error;
316                         }
317                         f->f_sub_final = val;
318
319                         if( fstr ) {
320                                 *fstr = ch_realloc( *fstr,
321                                         strlen( *fstr ) + val->bv_len + 2 );
322                                 strcat( *fstr, "*" );
323                                 strcat( *fstr, val->bv_val );
324                         }
325                         break;
326
327                 default:
328                         Debug( LDAP_DEBUG_FILTER, "  unknown type\n", tag, 0,
329                             0 );
330
331                         ber_bvfree( val );
332
333 return_error:
334                         Debug( LDAP_DEBUG_FILTER, "  error=%d\n", rc, 0, 0 );
335
336                         if( fstr ) {
337                                 free( *fstr );
338                                 *fstr = NULL;
339                         }
340
341                         ch_free( f->f_sub_type );
342                         ber_bvfree( f->f_sub_initial );
343                         ber_bvecfree( f->f_sub_any );
344                         ber_bvfree( f->f_sub_final );
345                         return rc;
346                 }
347         }
348
349         if( fstr ) {
350                 *fstr = ch_realloc( *fstr, strlen( *fstr ) + 3 );
351                 if ( f->f_sub_final == NULL ) {
352                         strcat( *fstr, "*" );
353                 }
354                 strcat( *fstr, ")" );
355         }
356
357         Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
358         return( LDAP_SUCCESS );
359 }
360
361 void
362 filter_free( Filter *f )
363 {
364         Filter  *p, *next;
365
366         if ( f == NULL ) {
367                 return;
368         }
369
370         switch ( f->f_choice ) {
371         case LDAP_FILTER_EQUALITY:
372         case LDAP_FILTER_GE:
373         case LDAP_FILTER_LE:
374         case LDAP_FILTER_APPROX:
375                 ava_free( &f->f_ava, 0 );
376                 break;
377
378         case LDAP_FILTER_SUBSTRINGS:
379                 if ( f->f_sub_type != NULL ) {
380                         free( f->f_sub_type );
381                 }
382                 if ( f->f_sub_initial != NULL ) {
383                         ber_bvfree( f->f_sub_initial );
384                 }
385                 ber_bvecfree( f->f_sub_any );
386                 if ( f->f_sub_final != NULL ) {
387                         ber_bvfree( f->f_sub_final );
388                 }
389                 break;
390
391         case LDAP_FILTER_PRESENT:
392                 if ( f->f_type != NULL ) {
393                         free( f->f_type );
394                 }
395                 break;
396
397         case LDAP_FILTER_AND:
398         case LDAP_FILTER_OR:
399         case LDAP_FILTER_NOT:
400                 for ( p = f->f_list; p != NULL; p = next ) {
401                         next = p->f_next;
402                         filter_free( p );
403                 }
404                 break;
405
406         default:
407                 Debug( LDAP_DEBUG_ANY, "unknown filter type %lu\n",
408                        f->f_choice, 0, 0 );
409                 break;
410         }
411         free( f );
412 }
413
414 #ifdef LDAP_DEBUG
415
416 void
417 filter_print( Filter *f )
418 {
419         int     i;
420         Filter  *p;
421
422         if ( f == NULL ) {
423                 fprintf( stderr, "NULL" );
424         }
425
426         switch ( f->f_choice ) {
427         case LDAP_FILTER_EQUALITY:
428                 fprintf( stderr, "(%s=%s)", f->f_ava.ava_type,
429                     f->f_ava.ava_value.bv_val );
430                 break;
431
432         case LDAP_FILTER_GE:
433                 fprintf( stderr, "(%s>=%s)", f->f_ava.ava_type,
434                     f->f_ava.ava_value.bv_val );
435                 break;
436
437         case LDAP_FILTER_LE:
438                 fprintf( stderr, "(%s<=%s)", f->f_ava.ava_type,
439                     f->f_ava.ava_value.bv_val );
440                 break;
441
442         case LDAP_FILTER_APPROX:
443                 fprintf( stderr, "(%s~=%s)", f->f_ava.ava_type,
444                     f->f_ava.ava_value.bv_val );
445                 break;
446
447         case LDAP_FILTER_SUBSTRINGS:
448                 fprintf( stderr, "(%s=", f->f_sub_type );
449                 if ( f->f_sub_initial != NULL ) {
450                         fprintf( stderr, "%s", f->f_sub_initial->bv_val );
451                 }
452                 if ( f->f_sub_any != NULL ) {
453                         for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
454                                 fprintf( stderr, "*%s", f->f_sub_any[i]->bv_val );
455                         }
456                 }
457                 if ( f->f_sub_final != NULL ) {
458                         fprintf( stderr, "*%s", f->f_sub_final->bv_val );
459                 }
460                 break;
461
462         case LDAP_FILTER_PRESENT:
463                 fprintf( stderr, "%s=*", f->f_type );
464                 break;
465
466         case LDAP_FILTER_AND:
467         case LDAP_FILTER_OR:
468         case LDAP_FILTER_NOT:
469                 fprintf( stderr, "(%c", f->f_choice == LDAP_FILTER_AND ? '&' :
470                     f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
471                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
472                         filter_print( p );
473                 }
474                 fprintf( stderr, ")" );
475                 break;
476
477         default:
478                 fprintf( stderr, "unknown type %lu", f->f_choice );
479                 break;
480         }
481 }
482
483 #endif /* ldap_debug */