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