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