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