]> git.sur5r.net Git - openldap/blob - servers/slapd/filter.c
6c16a68046c464d151b886fdab3f6dd773b6a7e5
[openldap] / servers / slapd / filter.c
1 /* filter.c - routines for parsing and dealing with filters */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 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(
18         Connection *conn,
19         BerElement *ber,
20         Filter **f,
21         char **fstr,
22         const char **text );
23
24 static int      get_substring_filter(
25         Connection *conn,
26         BerElement *ber,
27         Filter *f,
28         char **fstr,
29         const char **text );
30
31 static int filter_escape_value(
32         struct berval *in,
33         struct berval *out );
34
35 int
36 get_filter(
37         Connection *conn,
38         BerElement *ber,
39         Filter **filt,
40         char **fstr,
41         const char **text )
42 {
43         ber_tag_t       tag;
44         ber_len_t       len;
45         int             err;
46         Filter          *f;
47         char            *ftmp = NULL;
48         struct berval escaped;
49
50 #ifdef NEW_LOGGING
51         LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY, "get_filter: conn %d\n",
52                    conn->c_connid ));
53 #else
54         Debug( LDAP_DEBUG_FILTER, "begin get_filter\n", 0, 0, 0 );
55 #endif
56         /*
57          * A filter looks like this coming in:
58          *      Filter ::= CHOICE {
59          *              and             [0]     SET OF Filter,
60          *              or              [1]     SET OF Filter,
61          *              not             [2]     Filter,
62          *              equalityMatch   [3]     AttributeValueAssertion,
63          *              substrings      [4]     SubstringFilter,
64          *              greaterOrEqual  [5]     AttributeValueAssertion,
65          *              lessOrEqual     [6]     AttributeValueAssertion,
66          *              present         [7]     AttributeType,,
67          *              approxMatch     [8]     AttributeValueAssertion
68          *              extensibleMatch [9] MatchingRuleAssertion
69          *      }
70          *
71          *      SubstringFilter ::= SEQUENCE {
72          *              type               AttributeType,
73          *              SEQUENCE OF CHOICE {
74          *                      initial          [0] IA5String,
75          *                      any              [1] IA5String,
76          *                      final            [2] IA5String
77          *              }
78          *      }
79          *
80      *  MatchingRuleAssertion ::= SEQUENCE {
81      *          matchingRule    [1] MatchingRuleId OPTIONAL,
82      *          type            [2] AttributeDescription OPTIONAL,
83      *          matchValue      [3] AssertionValue,
84      *          dnAttributes    [4] BOOLEAN DEFAULT FALSE
85          *      }
86          *
87          */
88
89         tag = ber_peek_tag( ber, &len );
90
91         if( tag == LBER_ERROR ) {
92                 *text = "error decoding filter";
93                 return SLAPD_DISCONNECT;
94         }
95
96         f = (Filter *) ch_malloc( sizeof(Filter) );
97         f->f_next = NULL;
98
99         err = LDAP_SUCCESS;
100         *fstr = NULL;
101         f->f_choice = tag; 
102
103         switch ( f->f_choice ) {
104         case LDAP_FILTER_EQUALITY:
105 #ifdef NEW_LOGGING
106                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL2,
107                            "get_filter: conn %d  EQUALITY\n", conn->c_connid ));
108 #else
109                 Debug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 );
110 #endif
111                 err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY, text );
112                 if ( err != LDAP_SUCCESS ) {
113                         break;
114                 }
115
116                 assert( f->f_ava != NULL );
117
118                 filter_escape_value( f->f_av_value, &escaped );
119
120                 *fstr = ch_malloc( sizeof("(=)")
121                         + f->f_av_desc->ad_cname.bv_len
122                         + escaped.bv_len );
123
124                 sprintf( *fstr, "(%s=%s)",
125                         f->f_av_desc->ad_cname.bv_val,
126                     escaped.bv_val );
127
128                 ber_memfree( escaped.bv_val );
129                 break;
130
131         case LDAP_FILTER_SUBSTRINGS:
132 #ifdef NEW_LOGGING
133                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
134                            "get_filter: conn %d  SUBSTRINGS\n", conn->c_connid ));
135 #else
136                 Debug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 );
137 #endif
138                 err = get_substring_filter( conn, ber, f, fstr, text );
139                 break;
140
141         case LDAP_FILTER_GE:
142 #ifdef NEW_LOGGING
143                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
144                            "get_filter: conn %d  GE\n", conn->c_connid ));
145 #else
146                 Debug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 );
147 #endif
148                 err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text );
149                 if ( err != LDAP_SUCCESS ) {
150                         break;
151                 }
152
153                 filter_escape_value( f->f_av_value, &escaped );
154
155                 *fstr = ch_malloc( sizeof("(>=)")
156                         + f->f_av_desc->ad_cname.bv_len
157                         + escaped.bv_len );
158
159                 sprintf( *fstr, "(%s>=%s)",
160                         f->f_av_desc->ad_cname.bv_val,
161                     escaped.bv_val );
162
163                 ber_memfree( escaped.bv_val );
164                 break;
165
166         case LDAP_FILTER_LE:
167 #ifdef NEW_LOGGING
168                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
169                            "get_filter: conn %d  LE\n", conn->c_connid ));
170 #else
171                 Debug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 );
172 #endif
173                 err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text );
174                 if ( err != LDAP_SUCCESS ) {
175                         break;
176                 }
177
178
179                 filter_escape_value( f->f_av_value, &escaped );
180
181                 *fstr = ch_malloc( sizeof("(<=)")
182                         + f->f_av_desc->ad_cname.bv_len
183                         + escaped.bv_len );
184
185                 sprintf( *fstr, "(%s<=%s)",
186                         f->f_av_desc->ad_cname.bv_val,
187                     escaped.bv_val );
188
189                 ber_memfree( escaped.bv_val );
190                 break;
191
192         case LDAP_FILTER_PRESENT: {
193                 struct berval type;
194
195 #ifdef NEW_LOGGING
196                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
197                            "get_filter: conn %d PRESENT\n", conn->c_connid ));
198 #else
199                 Debug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 );
200 #endif
201                 if ( ber_scanf( ber, "o", &type ) == LBER_ERROR ) {
202                         err = SLAPD_DISCONNECT;
203                         *text = "error decoding filter";
204                         break;
205                 }
206
207                 f->f_desc = NULL;
208                 err = slap_bv2ad( &type, &f->f_desc, text );
209
210                 if( err != LDAP_SUCCESS ) {
211                         /* unrecognized attribute description or other error */
212                         f->f_choice = SLAPD_FILTER_COMPUTED;
213                         f->f_result = LDAP_COMPARE_FALSE;
214                         *fstr = ch_strdup( "(unrecogized=*)" );
215                         ch_free( type.bv_val );
216                         err = LDAP_SUCCESS;
217                         break;
218                 }
219
220                 ch_free( type.bv_val );
221
222                 *fstr = ch_malloc( sizeof("(=*)")
223                         + f->f_desc->ad_cname.bv_len );
224                 sprintf( *fstr, "(%s=*)",
225                         f->f_desc->ad_cname.bv_val );
226
227                 } break;
228
229         case LDAP_FILTER_APPROX:
230 #ifdef NEW_LOGGING
231                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
232                            "get_filter: conn %d  APPROX\n", conn->c_connid ));
233 #else
234                 Debug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 );
235 #endif
236                 err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY_APPROX, text );
237                 if ( err != LDAP_SUCCESS ) {
238                         break;
239                 }
240
241                 filter_escape_value( f->f_av_value, &escaped );
242
243                 *fstr = ch_malloc( sizeof("(~=)")
244                         + f->f_av_desc->ad_cname.bv_len
245                         + escaped.bv_len );
246
247                 sprintf( *fstr, "(%s~=%s)",
248                         f->f_av_desc->ad_cname.bv_val,
249                     escaped.bv_val );
250
251                 ber_memfree( escaped.bv_val );
252                 break;
253
254         case LDAP_FILTER_AND:
255 #ifdef NEW_LOGGING
256                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
257                            "get_filter: conn %d  AND\n", conn->c_connid ));
258 #else
259                 Debug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 );
260 #endif
261                 err = get_filter_list( conn, ber, &f->f_and, &ftmp, text );
262                 if ( err != LDAP_SUCCESS ) {
263                         break;
264                 }
265                 *fstr = ch_malloc( sizeof("(&)")
266                         + ( ftmp == NULL ? 0 : strlen( ftmp ) ) );
267                 sprintf( *fstr, "(&%s)",
268                         ftmp == NULL ? "" : ftmp );
269                 break;
270
271         case LDAP_FILTER_OR:
272 #ifdef NEW_LOGGING
273                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
274                            "get_filter: conn %d  OR\n", conn->c_connid  ));
275 #else
276                 Debug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 );
277 #endif
278                 err = get_filter_list( conn, ber, &f->f_and, &ftmp, text );
279                 if ( err != LDAP_SUCCESS ) {
280                         break;
281                 }
282                 *fstr = ch_malloc( sizeof("(!)")
283                         + ( ftmp == NULL ? 0 : strlen( ftmp ) ) );
284                 sprintf( *fstr, "(|%s)",
285                         ftmp == NULL ? "" : ftmp );
286                 break;
287
288         case LDAP_FILTER_NOT:
289 #ifdef NEW_LOGGING
290                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
291                            "get_filter: conn %d  NOT\n", conn->c_connid ));
292 #else
293                 Debug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 );
294 #endif
295                 (void) ber_skip_tag( ber, &len );
296                 err = get_filter( conn, ber, &f->f_not, &ftmp, text );
297                 if ( err != LDAP_SUCCESS ) {
298                         break;
299                 }
300                 *fstr = ch_malloc( sizeof("(!)")
301                         + ( ftmp == NULL ? 0 : strlen( ftmp ) ) );
302                 sprintf( *fstr, "(!%s)",
303                         ftmp == NULL ? "" : ftmp );
304                 break;
305
306         case LDAP_FILTER_EXT:
307 #ifdef NEW_LOGGING
308                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
309                            "get_filter: conn %d  EXTENSIBLE\n", conn->c_connid ));
310 #else
311                 Debug( LDAP_DEBUG_FILTER, "EXTENSIBLE\n", 0, 0, 0 );
312 #endif
313
314                 err = get_mra( ber, &f->f_mra, text );
315                 if ( err != LDAP_SUCCESS ) {
316                         break;
317                 }
318
319                 assert( f->f_mra != NULL );
320
321                 filter_escape_value( f->f_mr_value, &escaped );
322
323                 *fstr = ch_malloc( sizeof("(:dn::=)")
324                         + (f->f_mr_desc ? f->f_mr_desc->ad_cname.bv_len : 0)
325                         + (f->f_mr_rule_text ? strlen(f->f_mr_rule_text) : 0)
326                         + escaped.bv_len );
327
328                 sprintf( *fstr, "(%s%s%s%s:=%s)",
329                          (f->f_mr_desc ? f->f_mr_desc->ad_cname.bv_val : ""),
330                          (f->f_mr_dnattrs ? ":dn" : ""),
331                          (f->f_mr_rule_text ? ":" : ""),
332                          (f->f_mr_rule_text ? f->f_mr_rule_text : ""),
333                          escaped.bv_val );
334
335                 ber_memfree( escaped.bv_val );
336                 break;
337
338         default:
339                 (void) ber_scanf( ber, "x" ); /* skip the element */
340 #ifdef NEW_LOGGING
341                 LDAP_LOG(( "filter", LDAP_LEVEL_ERR,
342                            "get_filter: conn %d unknown filter type=%lu\n",
343                            conn->c_connid, f->f_choice ));
344 #else
345                 Debug( LDAP_DEBUG_ANY, "get_filter: unknown filter type=%lu\n",
346                        f->f_choice, 0, 0 );
347 #endif
348                 f->f_choice = SLAPD_FILTER_COMPUTED;
349                 f->f_result = SLAPD_COMPARE_UNDEFINED;
350                 *fstr = ch_strdup( "(undefined)" );
351                 break;
352         }
353
354         free( ftmp );
355
356         if ( err != LDAP_SUCCESS ) {
357                 if ( *fstr != NULL ) {
358                         free( *fstr );
359                 }
360
361                 if( err != SLAPD_DISCONNECT ) {
362                         /* ignore error */
363                         f->f_choice = SLAPD_FILTER_COMPUTED;
364                         f->f_result = SLAPD_COMPARE_UNDEFINED;
365                         *fstr = ch_strdup( "(badfilter)" );
366                         err = LDAP_SUCCESS;
367                         *filt = f;
368
369                 } else {
370                         free(f);
371                 }
372         } else {
373                 *filt = f;
374         }
375
376 #ifdef NEW_LOGGING
377         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL2,
378                 "get_filter: conn %d exit\n", conn->c_connid ));
379 #else
380         Debug( LDAP_DEBUG_FILTER, "end get_filter %d\n", err, 0, 0 );
381 #endif
382         return( err );
383 }
384
385 static int
386 get_filter_list( Connection *conn, BerElement *ber,
387         Filter **f, char **fstr,
388         const char **text )
389 {
390         Filter          **new;
391         int             err;
392         ber_tag_t       tag;
393         ber_len_t       len;
394         char            *last, *ftmp;
395
396 #ifdef NEW_LOGGING
397         LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
398                    "get_filter_list: conn %d start\n", conn->c_connid ));
399 #else
400         Debug( LDAP_DEBUG_FILTER, "begin get_filter_list\n", 0, 0, 0 );
401 #endif
402         *fstr = NULL;
403         new = f;
404         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
405             tag = ber_next_element( ber, &len, last ) )
406         {
407                 err = get_filter( conn, ber, new, &ftmp, text );
408                 if ( err != LDAP_SUCCESS )
409                         return( err );
410
411                 if ( *fstr == NULL ) {
412                         *fstr = ftmp;
413                 } else {
414                         *fstr = ch_realloc( *fstr, strlen( *fstr ) +
415                             strlen( ftmp ) + 1 );
416                         strcat( *fstr, ftmp );
417                         free( ftmp );
418                 }
419                 new = &(*new)->f_next;
420         }
421         *new = NULL;
422
423 #ifdef NEW_LOGGING
424         LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
425                    "get_filter_list: conn %d exit\n", conn->c_connid ));
426 #else
427         Debug( LDAP_DEBUG_FILTER, "end get_filter_list\n", 0, 0, 0 );
428 #endif
429         return( LDAP_SUCCESS );
430 }
431
432 static int
433 get_substring_filter(
434     Connection  *conn,
435     BerElement  *ber,
436     Filter      *f,
437     char        **fstr,
438         const char      **text
439 )
440 {
441         ber_tag_t       tag;
442         ber_len_t       len;
443         ber_tag_t       rc;
444         struct berval *value;
445         struct berval escaped;
446         char            *last;
447         struct berval type;
448         struct berval *nvalue;
449         *text = "error decoding filter";
450
451 #ifdef NEW_LOGGING
452         LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
453                    "get_substring_filter: conn %d  begin\n", conn->c_connid ));
454 #else
455         Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 );
456 #endif
457         if ( ber_scanf( ber, "{o" /*}*/, &type ) == LBER_ERROR ) {
458                 return SLAPD_DISCONNECT;
459         }
460
461         f->f_sub = ch_calloc( 1, sizeof(SubstringsAssertion) );
462         f->f_sub_desc = NULL;
463         rc = slap_bv2ad( &type, &f->f_sub_desc, text );
464
465         ch_free( type.bv_val );
466
467         if( rc != LDAP_SUCCESS ) {
468                 text = NULL;
469                 ch_free( f->f_sub );
470                 f->f_choice = SLAPD_FILTER_COMPUTED;
471                 f->f_result = SLAPD_COMPARE_UNDEFINED;
472                 *fstr = ch_strdup( "(undefined)" );
473                 return LDAP_SUCCESS;
474         }
475
476         f->f_sub_initial = NULL;
477         f->f_sub_any = NULL;
478         f->f_sub_final = NULL;
479
480         if( fstr ) {
481                 *fstr = ch_malloc( sizeof("(=" /*)*/) +
482                         f->f_sub_desc->ad_cname.bv_len );
483                 sprintf( *fstr, "(%s=" /*)*/, f->f_sub_desc->ad_cname.bv_val );
484         }
485
486         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
487             tag = ber_next_element( ber, &len, last ) )
488         {
489                 unsigned usage;
490
491                 rc = ber_scanf( ber, "O", &value );
492                 if ( rc == LBER_ERROR ) {
493                         rc = SLAPD_DISCONNECT;
494                         goto return_error;
495                 }
496
497                 if ( value == NULL || value->bv_len == 0 ) {
498                         ber_bvfree( value );
499                         rc = LDAP_INVALID_SYNTAX;
500                         goto return_error;
501                 } 
502
503                 switch ( tag ) {
504                 case LDAP_SUBSTRING_INITIAL:
505                         usage = SLAP_MR_SUBSTR_INITIAL;
506                         break;
507
508                 case LDAP_SUBSTRING_ANY:
509                         usage = SLAP_MR_SUBSTR_ANY;
510                         break;
511
512                 case LDAP_SUBSTRING_FINAL:
513                         usage = SLAP_MR_SUBSTR_FINAL;
514                         break;
515
516                 default:
517                         rc = LDAP_PROTOCOL_ERROR;
518
519 #ifdef NEW_LOGGING
520                         LDAP_LOG(( "filter", LDAP_LEVEL_ERR,
521                                    "get_filter_substring: conn %d  unknown substring choice=%ld\n",
522                                    conn->c_connid, (long)tag ));
523 #else
524                         Debug( LDAP_DEBUG_FILTER,
525                                 "  unknown substring choice=%ld\n",
526                                 (long) tag, 0, 0 );
527 #endif
528                         ber_bvfree( value );
529                         goto return_error;
530                 }
531
532                 rc = value_normalize( f->f_sub_desc, usage, value, &nvalue, text );
533                 ber_bvfree( value );
534
535                 if( rc != LDAP_SUCCESS ) {
536                         goto return_error;
537                 }
538
539                 value = nvalue;
540
541                 rc = LDAP_PROTOCOL_ERROR;
542
543                 switch ( tag ) {
544                 case LDAP_SUBSTRING_INITIAL:
545 #ifdef NEW_LOGGING
546                         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
547                                    "get_substring_filter: conn %d  INITIAL\n",
548                                    conn->c_connid ));
549 #else
550                         Debug( LDAP_DEBUG_FILTER, "  INITIAL\n", 0, 0, 0 );
551 #endif
552
553                         if ( f->f_sub_initial != NULL
554                                 || f->f_sub_any != NULL 
555                                 || f->f_sub_final != NULL )
556                         {
557                                 ber_bvfree( value );
558                                 goto return_error;
559                         }
560
561                         f->f_sub_initial = value;
562
563                         if( fstr ) {
564                                 filter_escape_value( value, &escaped );
565                                 *fstr = ch_realloc( *fstr,
566                                         strlen( *fstr ) + escaped.bv_len + 1 );
567                                 strcat( *fstr, escaped.bv_val );
568                                 ber_memfree( escaped.bv_val );
569                         }
570                         break;
571
572                 case LDAP_SUBSTRING_ANY:
573 #ifdef NEW_LOGGING
574                         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
575                                    "get_substring_filter: conn %d  ANY\n",
576                                    conn->c_connid ));
577 #else
578                         Debug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
579 #endif
580
581                         if ( f->f_sub_final != NULL ) {
582                                 ber_bvfree( value );
583                                 goto return_error;
584                         }
585
586                         if( ber_bvecadd( &f->f_sub_any, value ) < 0 ) {
587                                 ber_bvfree( value );
588                                 goto return_error;
589                         }
590
591                         if( fstr ) {
592                                 filter_escape_value( value, &escaped );
593                                 *fstr = ch_realloc( *fstr,
594                                         strlen( *fstr ) + escaped.bv_len + 2 );
595                                 strcat( *fstr, "*" );
596                                 strcat( *fstr, escaped.bv_val );
597                                 ber_memfree( escaped.bv_val );
598                         }
599                         break;
600
601                 case LDAP_SUBSTRING_FINAL:
602 #ifdef NEW_LOGGING
603                         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
604                                    "get_substring_filter: conn %d  FINAL\n",
605                                    conn->c_connid ));
606 #else
607                         Debug( LDAP_DEBUG_FILTER, "  FINAL\n", 0, 0, 0 );
608 #endif
609
610                         if ( f->f_sub_final != NULL ) {
611                                 ber_bvfree( value );
612                                 goto return_error;
613                         }
614
615                         f->f_sub_final = value;
616
617                         if( fstr ) {
618                                 filter_escape_value( value, &escaped );
619                                 *fstr = ch_realloc( *fstr,
620                                         strlen( *fstr ) + escaped.bv_len + 2 );
621                                 strcat( *fstr, "*" );
622                                 strcat( *fstr, escaped.bv_val );
623                                 ber_memfree( escaped.bv_val );
624                         }
625                         break;
626
627                 default:
628 #ifdef NEW_LOGGING
629                         LDAP_LOG(( "filter", LDAP_LEVEL_INFO,
630                                    "get_substring_filter: conn %d  unknown substring type %ld\n",
631                                    conn->c_connid, (long)tag ));
632 #else
633                         Debug( LDAP_DEBUG_FILTER,
634                                 "  unknown substring type=%ld\n",
635                                 (long) tag, 0, 0 );
636 #endif
637
638                         ber_bvfree( value );
639
640 return_error:
641 #ifdef NEW_LOGGING
642                         LDAP_LOG(( "filter", LDAP_LEVEL_INFO,
643                                    "get_substring_filter: conn %d  error %ld\n",
644                                    conn->c_connid, (long)rc ));
645 #else
646                         Debug( LDAP_DEBUG_FILTER, "  error=%ld\n",
647                                 (long) rc, 0, 0 );
648 #endif
649                         if( fstr ) {
650                                 free( *fstr );
651                                 *fstr = NULL;
652                         }
653
654                         ber_bvfree( f->f_sub_initial );
655                         ber_bvecfree( f->f_sub_any );
656                         ber_bvfree( f->f_sub_final );
657                         ch_free( f->f_sub );
658                         return rc;
659                 }
660         }
661
662         if( fstr ) {
663                 *fstr = ch_realloc( *fstr, strlen( *fstr ) + 3 );
664                 if ( f->f_sub_final == NULL ) {
665                         strcat( *fstr, "*" );
666                 }
667                 strcat( *fstr, /*(*/ ")" );
668         }
669
670 #ifdef NEW_LOGGING
671         LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
672                    "get_substring_filter: conn %d exit\n", conn->c_connid ));
673 #else
674         Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
675 #endif
676         return( LDAP_SUCCESS );
677 }
678
679 void
680 filter_free( Filter *f )
681 {
682         Filter  *p, *next;
683
684         if ( f == NULL ) {
685                 return;
686         }
687
688         switch ( f->f_choice ) {
689         case LDAP_FILTER_PRESENT:
690                 break;
691
692         case LDAP_FILTER_EQUALITY:
693         case LDAP_FILTER_GE:
694         case LDAP_FILTER_LE:
695         case LDAP_FILTER_APPROX:
696                 ava_free( f->f_ava, 1 );
697                 break;
698
699         case LDAP_FILTER_SUBSTRINGS:
700                 if ( f->f_sub_initial != NULL ) {
701                         ber_bvfree( f->f_sub_initial );
702                 }
703                 ber_bvecfree( f->f_sub_any );
704                 if ( f->f_sub_final != NULL ) {
705                         ber_bvfree( f->f_sub_final );
706                 }
707                 ch_free( f->f_sub );
708                 break;
709
710         case LDAP_FILTER_AND:
711         case LDAP_FILTER_OR:
712         case LDAP_FILTER_NOT:
713                 for ( p = f->f_list; p != NULL; p = next ) {
714                         next = p->f_next;
715                         filter_free( p );
716                 }
717                 break;
718
719         case SLAPD_FILTER_COMPUTED:
720                 break;
721
722         default:
723 #ifdef NEW_LOGGING
724                 LDAP_LOG(( "filter", LDAP_LEVEL_ERR,
725                            "filter_free: unknown filter type %lu\n", f->f_choice ));
726 #else
727                 Debug( LDAP_DEBUG_ANY, "filter_free: unknown filter type=%lu\n",
728                        f->f_choice, 0, 0 );
729 #endif
730                 break;
731         }
732
733         free( f );
734 }
735
736 #ifdef LDAP_DEBUG
737 void
738 filter_print( Filter *f )
739 {
740         int     i;
741         Filter  *p;
742         struct berval escaped;
743
744         if ( f == NULL ) {
745                 fprintf( stderr, "No filter!" );
746         }
747
748         switch ( f->f_choice ) {
749         case LDAP_FILTER_EQUALITY:
750                 filter_escape_value( f->f_av_value, &escaped );
751                 fprintf( stderr, "(%s=%s)",
752                         f->f_av_desc->ad_cname.bv_val,
753                     escaped.bv_val );
754                 ber_memfree( escaped.bv_val );
755                 break;
756
757         case LDAP_FILTER_GE:
758                 filter_escape_value( f->f_av_value, &escaped );
759                 fprintf( stderr, "(%s>=%s)",
760                         f->f_av_desc->ad_cname.bv_val,
761                     escaped.bv_val );
762                 ber_memfree( escaped.bv_val );
763                 break;
764
765         case LDAP_FILTER_LE:
766                 filter_escape_value( f->f_av_value, &escaped );
767                 fprintf( stderr, "(%s<=%s)",
768                         f->f_ava->aa_desc->ad_cname.bv_val,
769                     escaped.bv_val );
770                 ber_memfree( escaped.bv_val );
771                 break;
772
773         case LDAP_FILTER_APPROX:
774                 filter_escape_value( f->f_av_value, &escaped );
775                 fprintf( stderr, "(%s~=%s)",
776                         f->f_ava->aa_desc->ad_cname.bv_val,
777                     escaped.bv_val );
778                 ber_memfree( escaped.bv_val );
779                 break;
780
781         case LDAP_FILTER_SUBSTRINGS:
782                 fprintf( stderr, "(%s=" /*)*/,
783                         f->f_sub_desc->ad_cname.bv_val );
784                 if ( f->f_sub_initial != NULL ) {
785                         filter_escape_value( f->f_sub_initial, &escaped );
786                         fprintf( stderr, "%s",
787                                 escaped.bv_val );
788                         ber_memfree( escaped.bv_val );
789                 }
790                 if ( f->f_sub_any != NULL ) {
791                         for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
792                                 filter_escape_value( f->f_sub_any[i], &escaped );
793                                 fprintf( stderr, "*%s",
794                                         escaped.bv_val );
795                                 ber_memfree( escaped.bv_val );
796                         }
797                 }
798                 if ( f->f_sub_final != NULL ) {
799                         filter_escape_value( f->f_sub_final, &escaped );
800                         fprintf( stderr,
801                                 "*%s", escaped.bv_val );
802                         ber_memfree( escaped.bv_val );
803                 }
804                 fprintf( stderr, /*(*/ ")" );
805                 break;
806
807         case LDAP_FILTER_PRESENT:
808                 fprintf( stderr, "(%s=*)",
809                         f->f_desc->ad_cname.bv_val );
810                 break;
811
812         case LDAP_FILTER_AND:
813         case LDAP_FILTER_OR:
814         case LDAP_FILTER_NOT:
815                 fprintf( stderr, "(%c" /*)*/,
816                         f->f_choice == LDAP_FILTER_AND ? '&' :
817                     f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
818                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
819                         filter_print( p );
820                 }
821                 fprintf( stderr, /*(*/ ")" );
822                 break;
823
824         case SLAPD_FILTER_COMPUTED:
825                 fprintf( stderr, "(?=%s)",
826                         f->f_result == LDAP_COMPARE_FALSE ? "false" :
827                         f->f_result == LDAP_COMPARE_TRUE ? "true" :
828                         f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" :
829                         "error" );
830                 break;
831
832         default:
833                 fprintf( stderr, "(unknown-filter=%lu)", f->f_choice );
834                 break;
835         }
836 }
837
838 #endif /* ldap_debug */
839
840 static int filter_escape_value(
841         struct berval *in,
842         struct berval *out )
843 {
844         ber_len_t i;
845         assert( in );
846         assert( out );
847
848         out->bv_val = (char *) ch_malloc( ( in->bv_len * 3 ) + 1 );
849         out->bv_len = 0;
850
851         for( i=0; i < in->bv_len ; i++ ) {
852                 if( FILTER_ESCAPE(in->bv_val[i]) ) {
853                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_CHAR;
854                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_HI( in->bv_val[i] );
855                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_LO( in->bv_val[i] );
856                 } else {
857                         out->bv_val[out->bv_len++] = in->bv_val[i];
858                 }
859         }
860
861         out->bv_val[out->bv_len] = '\0';
862         return LDAP_SUCCESS;
863 }