]> git.sur5r.net Git - openldap/blob - servers/slapd/filter.c
Fixed exit code processing. passwd.c never committed its password change
[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                         ch_free( type.bv_val );
212                         break;
213                 }
214
215                 ch_free( type.bv_val );
216
217                 *fstr = ch_malloc( sizeof("(=*)")
218                         + f->f_desc->ad_cname.bv_len );
219                 sprintf( *fstr, "(%s=*)",
220                         f->f_desc->ad_cname.bv_val );
221
222                 } break;
223
224         case LDAP_FILTER_APPROX:
225 #ifdef NEW_LOGGING
226                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
227                            "get_filter: conn %d  APPROX\n", conn->c_connid ));
228 #else
229                 Debug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 );
230 #endif
231                 err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY_APPROX, text );
232                 if ( err != LDAP_SUCCESS ) {
233                         break;
234                 }
235
236                 filter_escape_value( f->f_av_value, &escaped );
237
238                 *fstr = ch_malloc( sizeof("(~=)")
239                         + f->f_av_desc->ad_cname.bv_len
240                         + escaped.bv_len );
241
242                 sprintf( *fstr, "(%s~=%s)",
243                         f->f_av_desc->ad_cname.bv_val,
244                     escaped.bv_val );
245
246                 ber_memfree( escaped.bv_val );
247                 break;
248
249         case LDAP_FILTER_AND:
250 #ifdef NEW_LOGGING
251                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
252                            "get_filter: conn %d  AND\n", conn->c_connid ));
253 #else
254                 Debug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 );
255 #endif
256                 err = get_filter_list( conn, ber, &f->f_and, &ftmp, text );
257                 if ( err != LDAP_SUCCESS ) {
258                         break;
259                 }
260                 *fstr = ch_malloc( sizeof("(&)")
261                         + ( ftmp == NULL ? 0 : strlen( ftmp ) ) );
262                 sprintf( *fstr, "(&%s)",
263                         ftmp == NULL ? "" : ftmp );
264                 break;
265
266         case LDAP_FILTER_OR:
267 #ifdef NEW_LOGGING
268                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
269                            "get_filter: conn %d  OR\n", conn->c_connid  ));
270 #else
271                 Debug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 );
272 #endif
273                 err = get_filter_list( conn, ber, &f->f_and, &ftmp, text );
274                 if ( err != LDAP_SUCCESS ) {
275                         break;
276                 }
277                 *fstr = ch_malloc( sizeof("(!)")
278                         + ( ftmp == NULL ? 0 : strlen( ftmp ) ) );
279                 sprintf( *fstr, "(|%s)",
280                         ftmp == NULL ? "" : ftmp );
281                 break;
282
283         case LDAP_FILTER_NOT:
284 #ifdef NEW_LOGGING
285                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
286                            "get_filter: conn %d  NOT\n", conn->c_connid ));
287 #else
288                 Debug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 );
289 #endif
290                 (void) ber_skip_tag( ber, &len );
291                 err = get_filter( conn, ber, &f->f_not, &ftmp, text );
292                 if ( err != LDAP_SUCCESS ) {
293                         break;
294                 }
295                 *fstr = ch_malloc( sizeof("(!)")
296                         + ( ftmp == NULL ? 0 : strlen( ftmp ) ) );
297                 sprintf( *fstr, "(!%s)",
298                         ftmp == NULL ? "" : ftmp );
299                 break;
300
301         case LDAP_FILTER_EXT:
302 #ifdef NEW_LOGGING
303                 LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
304                            "get_filter: conn %d  EXTENSIBLE\n", conn->c_connid ));
305 #else
306                 Debug( LDAP_DEBUG_FILTER, "EXTENSIBLE\n", 0, 0, 0 );
307 #endif
308
309                 err = get_mra( ber, &f->f_mra, text );
310                 if ( err != LDAP_SUCCESS ) {
311                         break;
312                 }
313
314                 assert( f->f_mra != NULL );
315
316                 filter_escape_value( f->f_mr_value, &escaped );
317
318                 *fstr = ch_malloc( sizeof("(:dn::=)")
319                         + (f->f_mr_desc ? f->f_mr_desc->ad_cname.bv_len : 0)
320                         + (f->f_mr_rule_text ? strlen(f->f_mr_rule_text) : 0)
321                         + escaped.bv_len );
322
323                 sprintf( *fstr, "(%s%s%s%s:=%s)",
324                          (f->f_mr_desc ? f->f_mr_desc->ad_cname.bv_val : ""),
325                          (f->f_mr_dnattrs ? ":dn" : ""),
326                          (f->f_mr_rule_text ? ":" : ""),
327                          (f->f_mr_rule_text ? f->f_mr_rule_text : ""),
328                          escaped.bv_val );
329
330                 ber_memfree( escaped.bv_val );
331                 break;
332
333         default:
334                 (void) ber_scanf( ber, "x" ); /* skip the element */
335 #ifdef NEW_LOGGING
336                 LDAP_LOG(( "filter", LDAP_LEVEL_ERR,
337                            "get_filter: conn %d unknown filter type=%lu\n",
338                            conn->c_connid, f->f_choice ));
339 #else
340                 Debug( LDAP_DEBUG_ANY, "get_filter: unknown filter type=%lu\n",
341                        f->f_choice, 0, 0 );
342 #endif
343                 f->f_choice = SLAPD_FILTER_COMPUTED;
344                 f->f_result = SLAPD_COMPARE_UNDEFINED;
345                 *fstr = ch_strdup( "(undefined)" );
346                 break;
347         }
348
349         free( ftmp );
350
351         if ( err != LDAP_SUCCESS ) {
352                 if ( *fstr != NULL ) {
353                         free( *fstr );
354                 }
355
356                 if( err != SLAPD_DISCONNECT ) {
357                         /* ignore error */
358                         f->f_choice = SLAPD_FILTER_COMPUTED;
359                         f->f_result = SLAPD_COMPARE_UNDEFINED;
360                         *fstr = ch_strdup( "(badfilter)" );
361                         err = LDAP_SUCCESS;
362                         *filt = f;
363
364                 } else {
365                         free(f);
366                 }
367         } else {
368                 *filt = f;
369         }
370
371 #ifdef NEW_LOGGING
372         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL2,
373                    "get_filter: conn %d  exit\n", conn->c_connid ));
374 #else
375         Debug( LDAP_DEBUG_FILTER, "end get_filter %d\n", err, 0, 0 );
376 #endif
377         return( err );
378 }
379
380 static int
381 get_filter_list( Connection *conn, BerElement *ber,
382         Filter **f, char **fstr,
383         const char **text )
384 {
385         Filter          **new;
386         int             err;
387         ber_tag_t       tag;
388         ber_len_t       len;
389         char            *last, *ftmp;
390
391 #ifdef NEW_LOGGING
392         LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
393                    "get_filter_list: conn %d start\n", conn->c_connid ));
394 #else
395         Debug( LDAP_DEBUG_FILTER, "begin get_filter_list\n", 0, 0, 0 );
396 #endif
397         *fstr = NULL;
398         new = f;
399         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
400             tag = ber_next_element( ber, &len, last ) )
401         {
402                 err = get_filter( conn, ber, new, &ftmp, text );
403                 if ( err != LDAP_SUCCESS )
404                         return( err );
405
406                 if ( *fstr == NULL ) {
407                         *fstr = ftmp;
408                 } else {
409                         *fstr = ch_realloc( *fstr, strlen( *fstr ) +
410                             strlen( ftmp ) + 1 );
411                         strcat( *fstr, ftmp );
412                         free( ftmp );
413                 }
414                 new = &(*new)->f_next;
415         }
416         *new = NULL;
417
418 #ifdef NEW_LOGGING
419         LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
420                    "get_filter_list: conn %d exit\n", conn->c_connid ));
421 #else
422         Debug( LDAP_DEBUG_FILTER, "end get_filter_list\n", 0, 0, 0 );
423 #endif
424         return( LDAP_SUCCESS );
425 }
426
427 static int
428 get_substring_filter(
429     Connection  *conn,
430     BerElement  *ber,
431     Filter      *f,
432     char        **fstr,
433         const char      **text
434 )
435 {
436         ber_tag_t       tag;
437         ber_len_t       len;
438         ber_tag_t       rc;
439         struct berval *value;
440         struct berval escaped;
441         char            *last;
442         struct berval type;
443         struct berval *nvalue;
444         *text = "error decoding filter";
445
446 #ifdef NEW_LOGGING
447         LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
448                    "get_substring_filter: conn %d  begin\n", conn->c_connid ));
449 #else
450         Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 );
451 #endif
452         if ( ber_scanf( ber, "{o" /*}*/, &type ) == LBER_ERROR ) {
453                 return SLAPD_DISCONNECT;
454         }
455
456         f->f_sub = ch_calloc( 1, sizeof(SubstringsAssertion) );
457         f->f_sub_desc = NULL;
458         rc = slap_bv2ad( &type, &f->f_sub_desc, text );
459
460         ch_free( type.bv_val );
461
462         if( rc != LDAP_SUCCESS ) {
463                 text = NULL;
464                 ch_free( f->f_sub );
465                 f->f_choice = SLAPD_FILTER_COMPUTED;
466                 f->f_result = SLAPD_COMPARE_UNDEFINED;
467                 *fstr = ch_strdup( "(undefined)" );
468                 return LDAP_SUCCESS;
469         }
470
471         f->f_sub_initial = NULL;
472         f->f_sub_any = NULL;
473         f->f_sub_final = NULL;
474
475         if( fstr ) {
476                 *fstr = ch_malloc( sizeof("(=" /*)*/) +
477                         f->f_sub_desc->ad_cname.bv_len );
478                 sprintf( *fstr, "(%s=" /*)*/, f->f_sub_desc->ad_cname.bv_val );
479         }
480
481         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
482             tag = ber_next_element( ber, &len, last ) )
483         {
484                 unsigned usage;
485
486                 rc = ber_scanf( ber, "O", &value );
487                 if ( rc == LBER_ERROR ) {
488                         rc = SLAPD_DISCONNECT;
489                         goto return_error;
490                 }
491
492                 if ( value == NULL || value->bv_len == 0 ) {
493                         ber_bvfree( value );
494                         rc = LDAP_INVALID_SYNTAX;
495                         goto return_error;
496                 } 
497
498                 switch ( tag ) {
499                 case LDAP_SUBSTRING_INITIAL:
500                         usage = SLAP_MR_SUBSTR_INITIAL;
501                         break;
502
503                 case LDAP_SUBSTRING_ANY:
504                         usage = SLAP_MR_SUBSTR_ANY;
505                         break;
506
507                 case LDAP_SUBSTRING_FINAL:
508                         usage = SLAP_MR_SUBSTR_FINAL;
509                         break;
510
511                 default:
512                         rc = LDAP_PROTOCOL_ERROR;
513
514 #ifdef NEW_LOGGING
515                         LDAP_LOG(( "filter", LDAP_LEVEL_ERR,
516                                    "get_filter_substring: conn %d  unknown substring choice=%ld\n",
517                                    conn->c_connid, (long)tag ));
518 #else
519                         Debug( LDAP_DEBUG_FILTER,
520                                 "  unknown substring choice=%ld\n",
521                                 (long) tag, 0, 0 );
522 #endif
523                         ber_bvfree( value );
524                         goto return_error;
525                 }
526
527                 rc = value_normalize( f->f_sub_desc, usage, value, &nvalue, text );
528                 ber_bvfree( value );
529
530                 if( rc != LDAP_SUCCESS ) {
531                         goto return_error;
532                 }
533
534                 value = nvalue;
535
536                 rc = LDAP_PROTOCOL_ERROR;
537
538                 switch ( tag ) {
539                 case LDAP_SUBSTRING_INITIAL:
540 #ifdef NEW_LOGGING
541                         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
542                                    "get_substring_filter: conn %d  INITIAL\n",
543                                    conn->c_connid ));
544 #else
545                         Debug( LDAP_DEBUG_FILTER, "  INITIAL\n", 0, 0, 0 );
546 #endif
547
548                         if ( f->f_sub_initial != NULL
549                                 || f->f_sub_any != NULL 
550                                 || f->f_sub_final != NULL )
551                         {
552                                 ber_bvfree( value );
553                                 goto return_error;
554                         }
555
556                         f->f_sub_initial = value;
557
558                         if( fstr ) {
559                                 filter_escape_value( value, &escaped );
560                                 *fstr = ch_realloc( *fstr,
561                                         strlen( *fstr ) + escaped.bv_len + 1 );
562                                 strcat( *fstr, escaped.bv_val );
563                                 ber_memfree( escaped.bv_val );
564                         }
565                         break;
566
567                 case LDAP_SUBSTRING_ANY:
568 #ifdef NEW_LOGGING
569                         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
570                                    "get_substring_filter: conn %d  ANY\n",
571                                    conn->c_connid ));
572 #else
573                         Debug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
574 #endif
575
576                         if ( f->f_sub_final != NULL ) {
577                                 ber_bvfree( value );
578                                 goto return_error;
579                         }
580
581                         if( ber_bvecadd( &f->f_sub_any, value ) < 0 ) {
582                                 ber_bvfree( value );
583                                 goto return_error;
584                         }
585
586                         if( fstr ) {
587                                 filter_escape_value( value, &escaped );
588                                 *fstr = ch_realloc( *fstr,
589                                         strlen( *fstr ) + escaped.bv_len + 2 );
590                                 strcat( *fstr, "*" );
591                                 strcat( *fstr, escaped.bv_val );
592                                 ber_memfree( escaped.bv_val );
593                         }
594                         break;
595
596                 case LDAP_SUBSTRING_FINAL:
597 #ifdef NEW_LOGGING
598                         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
599                                    "get_substring_filter: conn %d  FINAL\n",
600                                    conn->c_connid ));
601 #else
602                         Debug( LDAP_DEBUG_FILTER, "  FINAL\n", 0, 0, 0 );
603 #endif
604
605                         if ( f->f_sub_final != NULL ) {
606                                 ber_bvfree( value );
607                                 goto return_error;
608                         }
609
610                         f->f_sub_final = value;
611
612                         if( fstr ) {
613                                 filter_escape_value( value, &escaped );
614                                 *fstr = ch_realloc( *fstr,
615                                         strlen( *fstr ) + escaped.bv_len + 2 );
616                                 strcat( *fstr, "*" );
617                                 strcat( *fstr, escaped.bv_val );
618                                 ber_memfree( escaped.bv_val );
619                         }
620                         break;
621
622                 default:
623 #ifdef NEW_LOGGING
624                         LDAP_LOG(( "filter", LDAP_LEVEL_INFO,
625                                    "get_substring_filter: conn %d  unknown substring type %ld\n",
626                                    conn->c_connid, (long)tag ));
627 #else
628                         Debug( LDAP_DEBUG_FILTER,
629                                 "  unknown substring type=%ld\n",
630                                 (long) tag, 0, 0 );
631 #endif
632
633                         ber_bvfree( value );
634
635 return_error:
636 #ifdef NEW_LOGGING
637                         LDAP_LOG(( "filter", LDAP_LEVEL_INFO,
638                                    "get_substring_filter: conn %d  error %ld\n",
639                                    conn->c_connid, (long)rc ));
640 #else
641                         Debug( LDAP_DEBUG_FILTER, "  error=%ld\n",
642                                 (long) rc, 0, 0 );
643 #endif
644                         if( fstr ) {
645                                 free( *fstr );
646                                 *fstr = NULL;
647                         }
648
649                         ber_bvfree( f->f_sub_initial );
650                         ber_bvecfree( f->f_sub_any );
651                         ber_bvfree( f->f_sub_final );
652                         ch_free( f->f_sub );
653                         return rc;
654                 }
655         }
656
657         if( fstr ) {
658                 *fstr = ch_realloc( *fstr, strlen( *fstr ) + 3 );
659                 if ( f->f_sub_final == NULL ) {
660                         strcat( *fstr, "*" );
661                 }
662                 strcat( *fstr, /*(*/ ")" );
663         }
664
665 #ifdef NEW_LOGGING
666         LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
667                    "get_substring_filter: conn %d exit\n", conn->c_connid ));
668 #else
669         Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
670 #endif
671         return( LDAP_SUCCESS );
672 }
673
674 void
675 filter_free( Filter *f )
676 {
677         Filter  *p, *next;
678
679         if ( f == NULL ) {
680                 return;
681         }
682
683         switch ( f->f_choice ) {
684         case LDAP_FILTER_PRESENT:
685                 break;
686
687         case LDAP_FILTER_EQUALITY:
688         case LDAP_FILTER_GE:
689         case LDAP_FILTER_LE:
690         case LDAP_FILTER_APPROX:
691                 ava_free( f->f_ava, 1 );
692                 break;
693
694         case LDAP_FILTER_SUBSTRINGS:
695                 if ( f->f_sub_initial != NULL ) {
696                         ber_bvfree( f->f_sub_initial );
697                 }
698                 ber_bvecfree( f->f_sub_any );
699                 if ( f->f_sub_final != NULL ) {
700                         ber_bvfree( f->f_sub_final );
701                 }
702                 ch_free( f->f_sub );
703                 break;
704
705         case LDAP_FILTER_AND:
706         case LDAP_FILTER_OR:
707         case LDAP_FILTER_NOT:
708                 for ( p = f->f_list; p != NULL; p = next ) {
709                         next = p->f_next;
710                         filter_free( p );
711                 }
712                 break;
713
714         case SLAPD_FILTER_COMPUTED:
715                 break;
716
717         default:
718 #ifdef NEW_LOGGING
719                 LDAP_LOG(( "filter", LDAP_LEVEL_ERR,
720                            "filter_free: unknown filter type %lu\n", f->f_choice ));
721 #else
722                 Debug( LDAP_DEBUG_ANY, "filter_free: unknown filter type=%lu\n",
723                        f->f_choice, 0, 0 );
724 #endif
725                 break;
726         }
727
728         free( f );
729 }
730
731 #ifdef LDAP_DEBUG
732 void
733 filter_print( Filter *f )
734 {
735         int     i;
736         Filter  *p;
737         struct berval escaped;
738
739         if ( f == NULL ) {
740                 fprintf( stderr, "No filter!" );
741         }
742
743         switch ( f->f_choice ) {
744         case LDAP_FILTER_EQUALITY:
745                 filter_escape_value( f->f_av_value, &escaped );
746                 fprintf( stderr, "(%s=%s)",
747                         f->f_av_desc->ad_cname.bv_val,
748                     escaped.bv_val );
749                 ber_memfree( escaped.bv_val );
750                 break;
751
752         case LDAP_FILTER_GE:
753                 filter_escape_value( f->f_av_value, &escaped );
754                 fprintf( stderr, "(%s>=%s)",
755                         f->f_av_desc->ad_cname.bv_val,
756                     escaped.bv_val );
757                 ber_memfree( escaped.bv_val );
758                 break;
759
760         case LDAP_FILTER_LE:
761                 filter_escape_value( f->f_av_value, &escaped );
762                 fprintf( stderr, "(%s<=%s)",
763                         f->f_ava->aa_desc->ad_cname.bv_val,
764                     escaped.bv_val );
765                 ber_memfree( escaped.bv_val );
766                 break;
767
768         case LDAP_FILTER_APPROX:
769                 filter_escape_value( f->f_av_value, &escaped );
770                 fprintf( stderr, "(%s~=%s)",
771                         f->f_ava->aa_desc->ad_cname.bv_val,
772                     escaped.bv_val );
773                 ber_memfree( escaped.bv_val );
774                 break;
775
776         case LDAP_FILTER_SUBSTRINGS:
777                 fprintf( stderr, "(%s=" /*)*/,
778                         f->f_sub_desc->ad_cname.bv_val );
779                 if ( f->f_sub_initial != NULL ) {
780                         filter_escape_value( f->f_sub_initial, &escaped );
781                         fprintf( stderr, "%s",
782                                 escaped.bv_val );
783                         ber_memfree( escaped.bv_val );
784                 }
785                 if ( f->f_sub_any != NULL ) {
786                         for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
787                                 filter_escape_value( f->f_sub_any[i], &escaped );
788                                 fprintf( stderr, "*%s",
789                                         escaped.bv_val );
790                                 ber_memfree( escaped.bv_val );
791                         }
792                 }
793                 if ( f->f_sub_final != NULL ) {
794                         filter_escape_value( f->f_sub_final, &escaped );
795                         fprintf( stderr,
796                                 "*%s", escaped.bv_val );
797                         ber_memfree( escaped.bv_val );
798                 }
799                 fprintf( stderr, /*(*/ ")" );
800                 break;
801
802         case LDAP_FILTER_PRESENT:
803                 fprintf( stderr, "(%s=*)",
804                         f->f_desc->ad_cname.bv_val );
805                 break;
806
807         case LDAP_FILTER_AND:
808         case LDAP_FILTER_OR:
809         case LDAP_FILTER_NOT:
810                 fprintf( stderr, "(%c" /*)*/,
811                         f->f_choice == LDAP_FILTER_AND ? '&' :
812                     f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
813                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
814                         filter_print( p );
815                 }
816                 fprintf( stderr, /*(*/ ")" );
817                 break;
818
819         case SLAPD_FILTER_COMPUTED:
820                 fprintf( stderr, "(?=%s)",
821                         f->f_result == LDAP_COMPARE_FALSE ? "false" :
822                         f->f_result == LDAP_COMPARE_TRUE ? "true" :
823                         f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" :
824                         "error" );
825                 break;
826
827         default:
828                 fprintf( stderr, "(unknown-filter=%lu)", f->f_choice );
829                 break;
830         }
831 }
832
833 #endif /* ldap_debug */
834
835 int filter_escape_value(
836         struct berval *in,
837         struct berval *out )
838 {
839         ber_len_t i;
840         assert( in );
841         assert( out );
842
843         out->bv_val = (char *) ch_malloc( ( in->bv_len * 3 ) + 1 );
844         out->bv_len = 0;
845
846         for( i=0; i < in->bv_len ; i++ ) {
847                 if( FILTER_ESCAPE(in->bv_val[i]) ) {
848                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_CHAR;
849                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_HI( in->bv_val[i] );
850                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_LO( in->bv_val[i] );
851                 } else {
852                         out->bv_val[out->bv_len++] = in->bv_val[i];
853                 }
854         }
855
856         out->bv_val[out->bv_len] = '\0';
857         return LDAP_SUCCESS;
858 }