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