]> git.sur5r.net Git - openldap/blob - servers/slapd/filter.c
3e9d764ab7d94b17bb24429ea28ff9f030323959
[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                 /* valiate using equality matching rule validator! */
538                 rc = value_validate( f->f_sub_desc->ad_type->sat_equality,
539                         &value, text );
540                 if( rc != LDAP_SUCCESS ) {
541                         goto return_error;
542                 }
543
544                 rc = value_normalize( f->f_sub_desc, usage,
545                         &value, &bv, text );
546                 if( rc != LDAP_SUCCESS ) {
547                         goto return_error;
548                 }
549
550                 value = bv;
551
552                 rc = LDAP_PROTOCOL_ERROR;
553
554                 switch ( tag ) {
555                 case LDAP_SUBSTRING_INITIAL:
556 #ifdef NEW_LOGGING
557                         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
558                                    "get_substring_filter: conn %d  INITIAL\n",
559                                    conn->c_connid ));
560 #else
561                         Debug( LDAP_DEBUG_FILTER, "  INITIAL\n", 0, 0, 0 );
562 #endif
563
564                         if ( f->f_sub_initial.bv_val != NULL
565                                 || f->f_sub_any != NULL 
566                                 || f->f_sub_final.bv_val != NULL )
567                         {
568                                 free( value.bv_val );
569                                 goto return_error;
570                         }
571
572                         f->f_sub_initial = value;
573
574                         if( fstr->bv_val ) {
575                                 int i = fstr->bv_len;
576                                 filter_escape_value( &value, &escaped );
577                                 fstr->bv_len += escaped.bv_len;
578                                 fstr->bv_val = ch_realloc( fstr->bv_val,
579                                         fstr->bv_len + 1 );
580                                 strcpy( fstr->bv_val+i, escaped.bv_val );
581                                 ber_memfree( escaped.bv_val );
582                         }
583                         break;
584
585                 case LDAP_SUBSTRING_ANY:
586 #ifdef NEW_LOGGING
587                         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
588                                    "get_substring_filter: conn %d  ANY\n",
589                                    conn->c_connid ));
590 #else
591                         Debug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
592 #endif
593
594                         if ( f->f_sub_final.bv_val != NULL ) {
595                                 free( value.bv_val );
596                                 goto return_error;
597                         }
598
599                         ber_bvarray_add( &f->f_sub_any, &value );
600
601                         if( fstr->bv_val ) {
602                                 int i = fstr->bv_len;
603                                 filter_escape_value( &value, &escaped );
604                                 fstr->bv_len += escaped.bv_len + 2;
605                                 fstr->bv_val = ch_realloc( fstr->bv_val,
606                                         fstr->bv_len + 1 );
607                                 strcpy( fstr->bv_val+i, "*" );
608                                 strcpy( fstr->bv_val+i+1, escaped.bv_val );
609                                 ber_memfree( escaped.bv_val );
610                         }
611                         break;
612
613                 case LDAP_SUBSTRING_FINAL:
614 #ifdef NEW_LOGGING
615                         LDAP_LOG(( "filter", LDAP_LEVEL_DETAIL1,
616                                    "get_substring_filter: conn %d  FINAL\n",
617                                    conn->c_connid ));
618 #else
619                         Debug( LDAP_DEBUG_FILTER, "  FINAL\n", 0, 0, 0 );
620 #endif
621
622                         if ( f->f_sub_final.bv_val != NULL ) {
623                                 free( value.bv_val );
624                                 goto return_error;
625                         }
626
627                         f->f_sub_final = value;
628
629                         if( fstr->bv_val ) {
630                                 int i = fstr->bv_len;
631                                 filter_escape_value( &value, &escaped );
632                                 fstr->bv_len += escaped.bv_len + 2;
633                                 fstr->bv_val = ch_realloc( fstr->bv_val,
634                                         fstr->bv_len + 1 );
635                                 strcpy( fstr->bv_val+i, "*" );
636                                 strcpy( fstr->bv_val+i+1, escaped.bv_val );
637                                 ber_memfree( escaped.bv_val );
638                         }
639                         break;
640
641                 default:
642 #ifdef NEW_LOGGING
643                         LDAP_LOG(( "filter", LDAP_LEVEL_INFO,
644                                    "get_substring_filter: conn %d  unknown substring type %ld\n",
645                                    conn->c_connid, (long)tag ));
646 #else
647                         Debug( LDAP_DEBUG_FILTER,
648                                 "  unknown substring type=%ld\n",
649                                 (long) tag, 0, 0 );
650 #endif
651
652                         free( value.bv_val );
653
654 return_error:
655 #ifdef NEW_LOGGING
656                         LDAP_LOG(( "filter", LDAP_LEVEL_INFO,
657                                    "get_substring_filter: conn %d  error %ld\n",
658                                    conn->c_connid, (long)rc ));
659 #else
660                         Debug( LDAP_DEBUG_FILTER, "  error=%ld\n",
661                                 (long) rc, 0, 0 );
662 #endif
663                         if( fstr->bv_val ) {
664                                 free( fstr->bv_val );
665                                 fstr->bv_val = NULL;
666                                 fstr->bv_len = 0;
667                         }
668
669                         free( f->f_sub_initial.bv_val );
670                         ber_bvarray_free( f->f_sub_any );
671                         free( f->f_sub_final.bv_val );
672                         ch_free( f->f_sub );
673                         return rc;
674                 }
675         }
676
677         if( fstr->bv_val ) {
678                 int i = fstr->bv_len;
679                 fstr->bv_len += 3;
680                 fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 3 );
681                 if ( f->f_sub_final.bv_val == NULL ) {
682                         strcpy( fstr->bv_val+i, "*" );
683                         i++;
684                 }
685                 strcpy( fstr->bv_val+i, /*(*/ ")" );
686         }
687
688 #ifdef NEW_LOGGING
689         LDAP_LOG(( "filter", LDAP_LEVEL_ENTRY,
690                    "get_substring_filter: conn %d exit\n", conn->c_connid ));
691 #else
692         Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
693 #endif
694         return( LDAP_SUCCESS );
695 }
696
697 void
698 filter_free( Filter *f )
699 {
700         Filter  *p, *next;
701
702         if ( f == NULL ) {
703                 return;
704         }
705
706         switch ( f->f_choice ) {
707         case LDAP_FILTER_PRESENT:
708                 break;
709
710         case LDAP_FILTER_EQUALITY:
711         case LDAP_FILTER_GE:
712         case LDAP_FILTER_LE:
713         case LDAP_FILTER_APPROX:
714                 ava_free( f->f_ava, 1 );
715                 break;
716
717         case LDAP_FILTER_SUBSTRINGS:
718                 if ( f->f_sub_initial.bv_val != NULL ) {
719                         free( f->f_sub_initial.bv_val );
720                 }
721                 ber_bvarray_free( f->f_sub_any );
722                 if ( f->f_sub_final.bv_val != NULL ) {
723                         free( f->f_sub_final.bv_val );
724                 }
725                 ch_free( f->f_sub );
726                 break;
727
728         case LDAP_FILTER_AND:
729         case LDAP_FILTER_OR:
730         case LDAP_FILTER_NOT:
731                 for ( p = f->f_list; p != NULL; p = next ) {
732                         next = p->f_next;
733                         filter_free( p );
734                 }
735                 break;
736
737         case LDAP_FILTER_EXT:
738                 mra_free( f->f_mra, 1 );
739                 break;
740
741         case SLAPD_FILTER_COMPUTED:
742                 break;
743
744         default:
745 #ifdef NEW_LOGGING
746                 LDAP_LOG(( "filter", LDAP_LEVEL_ERR,
747                            "filter_free: unknown filter type %lu\n", f->f_choice ));
748 #else
749                 Debug( LDAP_DEBUG_ANY, "filter_free: unknown filter type=%lu\n",
750                        f->f_choice, 0, 0 );
751 #endif
752                 break;
753         }
754
755         free( f );
756 }
757
758 #ifdef LDAP_DEBUG
759 void
760 filter_print( Filter *f )
761 {
762         int     i;
763         Filter  *p;
764         struct berval escaped;
765
766         if ( f == NULL ) {
767                 fprintf( stderr, "No filter!" );
768         }
769
770         switch ( f->f_choice ) {
771         case LDAP_FILTER_EQUALITY:
772                 filter_escape_value( &f->f_av_value, &escaped );
773                 fprintf( stderr, "(%s=%s)",
774                         f->f_av_desc->ad_cname.bv_val,
775                     escaped.bv_val );
776                 ber_memfree( escaped.bv_val );
777                 break;
778
779         case LDAP_FILTER_GE:
780                 filter_escape_value( &f->f_av_value, &escaped );
781                 fprintf( stderr, "(%s>=%s)",
782                         f->f_av_desc->ad_cname.bv_val,
783                     escaped.bv_val );
784                 ber_memfree( escaped.bv_val );
785                 break;
786
787         case LDAP_FILTER_LE:
788                 filter_escape_value( &f->f_av_value, &escaped );
789                 fprintf( stderr, "(%s<=%s)",
790                         f->f_ava->aa_desc->ad_cname.bv_val,
791                     escaped.bv_val );
792                 ber_memfree( escaped.bv_val );
793                 break;
794
795         case LDAP_FILTER_APPROX:
796                 filter_escape_value( &f->f_av_value, &escaped );
797                 fprintf( stderr, "(%s~=%s)",
798                         f->f_ava->aa_desc->ad_cname.bv_val,
799                     escaped.bv_val );
800                 ber_memfree( escaped.bv_val );
801                 break;
802
803         case LDAP_FILTER_SUBSTRINGS:
804                 fprintf( stderr, "(%s=" /*)*/,
805                         f->f_sub_desc->ad_cname.bv_val );
806                 if ( f->f_sub_initial.bv_val != NULL ) {
807                         filter_escape_value( &f->f_sub_initial, &escaped );
808                         fprintf( stderr, "%s",
809                                 escaped.bv_val );
810                         ber_memfree( escaped.bv_val );
811                 }
812                 if ( f->f_sub_any != NULL ) {
813                         for ( i = 0; f->f_sub_any[i].bv_val != NULL; i++ ) {
814                                 filter_escape_value( &f->f_sub_any[i], &escaped );
815                                 fprintf( stderr, "*%s",
816                                         escaped.bv_val );
817                                 ber_memfree( escaped.bv_val );
818                         }
819                 }
820                 if ( f->f_sub_final.bv_val != NULL ) {
821                         filter_escape_value( &f->f_sub_final, &escaped );
822                         fprintf( stderr,
823                                 "*%s", escaped.bv_val );
824                         ber_memfree( escaped.bv_val );
825                 }
826                 fprintf( stderr, /*(*/ ")" );
827                 break;
828
829         case LDAP_FILTER_PRESENT:
830                 fprintf( stderr, "(%s=*)",
831                         f->f_desc->ad_cname.bv_val );
832                 break;
833
834         case LDAP_FILTER_AND:
835         case LDAP_FILTER_OR:
836         case LDAP_FILTER_NOT:
837                 fprintf( stderr, "(%c" /*)*/,
838                         f->f_choice == LDAP_FILTER_AND ? '&' :
839                     f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
840                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
841                         filter_print( p );
842                 }
843                 fprintf( stderr, /*(*/ ")" );
844                 break;
845
846         case SLAPD_FILTER_COMPUTED:
847                 fprintf( stderr, "(?=%s)",
848                         f->f_result == LDAP_COMPARE_FALSE ? "false" :
849                         f->f_result == LDAP_COMPARE_TRUE ? "true" :
850                         f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" :
851                         "error" );
852                 break;
853
854         default:
855                 fprintf( stderr, "(unknown-filter=%lu)", f->f_choice );
856                 break;
857         }
858 }
859
860 #endif /* ldap_debug */
861
862 static int filter_escape_value(
863         struct berval *in,
864         struct berval *out )
865 {
866         ber_len_t i;
867         assert( in );
868         assert( out );
869
870         out->bv_val = (char *) ch_malloc( ( in->bv_len * 3 ) + 1 );
871         out->bv_len = 0;
872
873         for( i=0; i < in->bv_len ; i++ ) {
874                 if( FILTER_ESCAPE(in->bv_val[i]) ) {
875                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_CHAR;
876                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_HI( in->bv_val[i] );
877                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_LO( in->bv_val[i] );
878                 } else {
879                         out->bv_val[out->bv_len++] = in->bv_val[i];
880                 }
881         }
882
883         out->bv_val[out->bv_len] = '\0';
884         return LDAP_SUCCESS;
885 }