]> git.sur5r.net Git - openldap/blob - servers/slapd/filter.c
7ea18509163c1e2bfbdc28b19a14a67db2f46d4a
[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   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
56         switch ( f->f_choice ) {
57         case LDAP_FILTER_EQUALITY:
58                 Debug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 );
59                 if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
60                         *fstr = ch_malloc(4 + strlen( f->f_avtype ) +
61                             f->f_avvalue.bv_len);
62                         sprintf( *fstr, "(%s=%s)", f->f_avtype,
63                             f->f_avvalue.bv_val );
64                 }
65                 break;
66
67         case LDAP_FILTER_SUBSTRINGS:
68                 Debug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 );
69                 err = get_substring_filter( conn, ber, f, fstr );
70                 break;
71
72         case LDAP_FILTER_GE:
73                 Debug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 );
74                 if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
75                         *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
76                             f->f_avvalue.bv_len);
77                         sprintf( *fstr, "(%s>=%s)", f->f_avtype,
78                             f->f_avvalue.bv_val );
79                 }
80                 break;
81
82         case LDAP_FILTER_LE:
83                 Debug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 );
84                 if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
85                         *fstr = ch_malloc(5 + strlen( f->f_avtype ) +
86                             f->f_avvalue.bv_len);
87                         sprintf( *fstr, "(%s<=%s)", f->f_avtype,
88                             f->f_avvalue.bv_val );
89                 }
90                 break;
91
92         case LDAP_FILTER_PRESENT:
93                 Debug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 );
94                 if ( ber_scanf( ber, "a", &f->f_type ) == LBER_ERROR ) {
95                         err = LDAP_PROTOCOL_ERROR;
96                 } else {
97                         err = LDAP_SUCCESS;
98                         attr_normalize( f->f_type );
99                         *fstr = ch_malloc( 5 + strlen( f->f_type ) );
100                         sprintf( *fstr, "(%s=*)", f->f_type );
101                 }
102                 break;
103
104         case LDAP_FILTER_APPROX:
105                 Debug( LDAP_DEBUG_FILTER, "APPROX\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_AND:
115                 Debug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 );
116                 if ( (err = get_filter_list( conn, ber, &f->f_and, &ftmp ))
117                     == 0 ) {
118                         if (ftmp == NULL) ftmp = ch_strdup("");
119                         *fstr = ch_malloc( 4 + strlen( ftmp ) );
120                         sprintf( *fstr, "(&%s)", ftmp );
121                         free( ftmp );
122                 }
123                 break;
124
125         case LDAP_FILTER_OR:
126                 Debug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 );
127                 if ( (err = get_filter_list( conn, ber, &f->f_or, &ftmp ))
128                     == 0 ) {
129                         if (ftmp == NULL) ftmp = ch_strdup("");
130                         *fstr = ch_malloc( 4 + strlen( ftmp ) );
131                         sprintf( *fstr, "(|%s)", ftmp );
132                         free( ftmp );
133                 }
134                 break;
135
136         case LDAP_FILTER_NOT:
137                 Debug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 );
138                 (void) ber_skip_tag( ber, &len );
139                 if ( (err = get_filter( conn, ber, &f->f_not, &ftmp )) == 0 ) {
140                         if (ftmp == NULL) ftmp = ch_strdup("");
141                         *fstr = ch_malloc( 4 + strlen( ftmp ) );
142                         sprintf( *fstr, "(!%s)", ftmp );
143                         free( ftmp );
144                 }
145                 break;
146
147         default:
148                 Debug( LDAP_DEBUG_ANY, "unknown filter type %lu\n",
149                        f->f_choice, 0, 0 );
150                 err = LDAP_PROTOCOL_ERROR;
151                 break;
152         }
153
154         if ( err != 0 ) {
155                 free( (char *) f );
156                 if ( *fstr != NULL ) {
157                         free( *fstr );
158                 }
159         } else {
160                 *filt = f;
161         }
162
163         Debug( LDAP_DEBUG_FILTER, "end get_filter %d\n", err, 0, 0 );
164         return( err );
165 }
166
167 static int
168 get_filter_list( Connection *conn, BerElement *ber, Filter **f, char **fstr )
169 {
170         Filter          **new;
171         int             err;
172         ber_tag_t       tag;
173         ber_len_t       len;
174         char            *last, *ftmp;
175
176         Debug( LDAP_DEBUG_FILTER, "begin get_filter_list\n", 0, 0, 0 );
177
178         *fstr = NULL;
179         new = f;
180         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
181             tag = ber_next_element( ber, &len, last ) ) {
182                 if ( (err = get_filter( conn, ber, new, &ftmp )) != 0 )
183                         return( err );
184                 if ( *fstr == NULL ) {
185                         *fstr = ftmp;
186                 } else {
187                         *fstr = ch_realloc( *fstr, strlen( *fstr ) +
188                             strlen( ftmp ) + 1 );
189                         strcat( *fstr, ftmp );
190                         free( ftmp );
191                 }
192                 new = &(*new)->f_next;
193         }
194         *new = NULL;
195
196         Debug( LDAP_DEBUG_FILTER, "end get_filter_list\n", 0, 0, 0 );
197         return( 0 );
198 }
199
200 static int
201 get_substring_filter(
202     Connection  *conn,
203     BerElement  *ber,
204     Filter      *f,
205     char        **fstr
206 )
207 {
208         ber_tag_t       tag;
209         ber_len_t       len;
210         ber_tag_t       rc;
211         char            *val, *last;
212         int             syntax;
213
214         Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 );
215
216         if ( ber_scanf( ber, "{a" /*}*/, &f->f_sub_type ) == LBER_ERROR ) {
217                 return( LDAP_PROTOCOL_ERROR );
218         }
219         attr_normalize( f->f_sub_type );
220         syntax = attr_syntax( f->f_sub_type );
221         f->f_sub_initial = NULL;
222         f->f_sub_any = NULL;
223         f->f_sub_final = NULL;
224
225         *fstr = ch_malloc( strlen( f->f_sub_type ) + 3 );
226         sprintf( *fstr, "(%s=", f->f_sub_type );
227         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
228             tag = ber_next_element( ber, &len, last ) ) {
229                         rc = ber_scanf( ber, "a", &val );
230                 if ( rc == LBER_ERROR ) {
231                         return( LDAP_PROTOCOL_ERROR );
232                 }
233                 if ( val == NULL || *val == '\0' ) {
234                         if ( val != NULL ) {
235                                 free( val );
236                         }
237                         return( LDAP_INVALID_SYNTAX );
238                 }
239                 value_normalize( val, syntax );
240
241                 switch ( tag ) {
242                 case LDAP_SUBSTRING_INITIAL:
243                         Debug( LDAP_DEBUG_FILTER, "  INITIAL\n", 0, 0, 0 );
244                         if ( f->f_sub_initial != NULL ) {
245                                 return( LDAP_PROTOCOL_ERROR );
246                         }
247                         f->f_sub_initial = val;
248                         *fstr = ch_realloc( *fstr, strlen( *fstr ) +
249                             strlen( val ) + 1 );
250                         strcat( *fstr, val );
251                         break;
252
253                 case LDAP_SUBSTRING_ANY:
254                         Debug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
255                         charray_add( &f->f_sub_any, val );
256                         *fstr = ch_realloc( *fstr, strlen( *fstr ) +
257                             strlen( val ) + 2 );
258                         strcat( *fstr, "*" );
259                         strcat( *fstr, val );
260                         break;
261
262                 case LDAP_SUBSTRING_FINAL:
263                         Debug( LDAP_DEBUG_FILTER, "  FINAL\n", 0, 0, 0 );
264                         if ( f->f_sub_final != NULL ) {
265                                 return( LDAP_PROTOCOL_ERROR );
266                         }
267                         f->f_sub_final = val;
268                         *fstr = ch_realloc( *fstr, strlen( *fstr ) +
269                             strlen( val ) + 2 );
270                         strcat( *fstr, "*" );
271                         strcat( *fstr, val );
272                         break;
273
274                 default:
275                         Debug( LDAP_DEBUG_FILTER, "  unknown type\n", tag, 0,
276                             0 );
277                         return( LDAP_PROTOCOL_ERROR );
278                 }
279         }
280         *fstr = ch_realloc( *fstr, strlen( *fstr ) + 3 );
281         if ( f->f_sub_final == NULL ) {
282                 strcat( *fstr, "*" );
283         }
284         strcat( *fstr, ")" );
285
286         Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
287         return( 0 );
288 }
289
290 void
291 filter_free( Filter *f )
292 {
293         Filter  *p, *next;
294
295         if ( f == NULL ) {
296                 return;
297         }
298
299         switch ( f->f_choice ) {
300         case LDAP_FILTER_EQUALITY:
301         case LDAP_FILTER_GE:
302         case LDAP_FILTER_LE:
303         case LDAP_FILTER_APPROX:
304                 ava_free( &f->f_ava, 0 );
305                 break;
306
307         case LDAP_FILTER_SUBSTRINGS:
308                 if ( f->f_sub_type != NULL ) {
309                         free( f->f_sub_type );
310                 }
311                 if ( f->f_sub_initial != NULL ) {
312                         free( f->f_sub_initial );
313                 }
314                 charray_free( f->f_sub_any );
315                 if ( f->f_sub_final != NULL ) {
316                         free( f->f_sub_final );
317                 }
318                 break;
319
320         case LDAP_FILTER_PRESENT:
321                 if ( f->f_type != NULL ) {
322                         free( f->f_type );
323                 }
324                 break;
325
326         case LDAP_FILTER_AND:
327         case LDAP_FILTER_OR:
328         case LDAP_FILTER_NOT:
329                 for ( p = f->f_list; p != NULL; p = next ) {
330                         next = p->f_next;
331                         filter_free( p );
332                 }
333                 break;
334
335         default:
336                 Debug( LDAP_DEBUG_ANY, "unknown filter type %lu\n",
337                        f->f_choice, 0, 0 );
338                 break;
339         }
340         free( f );
341 }
342
343 #ifdef LDAP_DEBUG
344
345 void
346 filter_print( Filter *f )
347 {
348         int     i;
349         Filter  *p;
350
351         if ( f == NULL ) {
352                 fprintf( stderr, "NULL" );
353         }
354
355         switch ( f->f_choice ) {
356         case LDAP_FILTER_EQUALITY:
357                 fprintf( stderr, "(%s=%s)", f->f_ava.ava_type,
358                     f->f_ava.ava_value.bv_val );
359                 break;
360
361         case LDAP_FILTER_GE:
362                 fprintf( stderr, "(%s>=%s)", f->f_ava.ava_type,
363                     f->f_ava.ava_value.bv_val );
364                 break;
365
366         case LDAP_FILTER_LE:
367                 fprintf( stderr, "(%s<=%s)", f->f_ava.ava_type,
368                     f->f_ava.ava_value.bv_val );
369                 break;
370
371         case LDAP_FILTER_APPROX:
372                 fprintf( stderr, "(%s~=%s)", f->f_ava.ava_type,
373                     f->f_ava.ava_value.bv_val );
374                 break;
375
376         case LDAP_FILTER_SUBSTRINGS:
377                 fprintf( stderr, "(%s=", f->f_sub_type );
378                 if ( f->f_sub_initial != NULL ) {
379                         fprintf( stderr, "%s", f->f_sub_initial );
380                 }
381                 if ( f->f_sub_any != NULL ) {
382                         for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
383                                 fprintf( stderr, "*%s", f->f_sub_any[i] );
384                         }
385                 }
386                 charray_free( f->f_sub_any );
387                 if ( f->f_sub_final != NULL ) {
388                         fprintf( stderr, "*%s", f->f_sub_final );
389                 }
390                 break;
391
392         case LDAP_FILTER_PRESENT:
393                 fprintf( stderr, "%s=*", f->f_type );
394                 break;
395
396         case LDAP_FILTER_AND:
397         case LDAP_FILTER_OR:
398         case LDAP_FILTER_NOT:
399                 fprintf( stderr, "(%c", f->f_choice == LDAP_FILTER_AND ? '&' :
400                     f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
401                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
402                         filter_print( p );
403                 }
404                 fprintf( stderr, ")" );
405                 break;
406
407         default:
408                 fprintf( stderr, "unknown type %lu", f->f_choice );
409                 break;
410         }
411 }
412
413 #endif /* ldap_debug */