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