]> git.sur5r.net Git - openldap/blob - servers/slapd/filter.c
a068b74fd19eab8ce219ef1d17955d1ecb27d277
[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         const char **text );
22
23 static int      get_substring_filter(
24         Connection *conn,
25         BerElement *ber,
26         Filter *f,
27         const char **text );
28
29 static int filter_escape_value(
30         struct berval *in,
31         struct berval *out );
32
33 static void simple_vrFilter2bv(
34         ValuesReturnFilter *f,
35         struct berval *fstr );
36
37 static int      get_simple_vrFilter(
38         Connection *conn,
39         BerElement *ber,
40         ValuesReturnFilter **f,
41         const char **text );
42
43
44 int
45 get_filter(
46         Connection *conn,
47         BerElement *ber,
48         Filter **filt,
49         const char **text )
50 {
51         ber_tag_t       tag;
52         ber_len_t       len;
53         int             err;
54         Filter          *f;
55
56 #ifdef NEW_LOGGING
57         LDAP_LOG( FILTER, ENTRY, "get_filter: conn %d\n", conn->c_connid, 0, 0 );
58 #else
59         Debug( LDAP_DEBUG_FILTER, "begin get_filter\n", 0, 0, 0 );
60 #endif
61         /*
62          * A filter looks like this coming in:
63          *      Filter ::= CHOICE {
64          *              and             [0]     SET OF Filter,
65          *              or              [1]     SET OF Filter,
66          *              not             [2]     Filter,
67          *              equalityMatch   [3]     AttributeValueAssertion,
68          *              substrings      [4]     SubstringFilter,
69          *              greaterOrEqual  [5]     AttributeValueAssertion,
70          *              lessOrEqual     [6]     AttributeValueAssertion,
71          *              present         [7]     AttributeType,,
72          *              approxMatch     [8]     AttributeValueAssertion
73          *              extensibleMatch [9]     MatchingRuleAssertion
74          *      }
75          *
76          *      SubstringFilter ::= SEQUENCE {
77          *              type               AttributeType,
78          *              SEQUENCE OF CHOICE {
79          *                      initial          [0] IA5String,
80          *                      any              [1] IA5String,
81          *                      final            [2] IA5String
82          *              }
83          *      }
84          *
85          *      MatchingRuleAssertion ::= SEQUENCE {
86          *              matchingRule    [1] MatchingRuleId OPTIONAL,
87          *              type            [2] AttributeDescription OPTIONAL,
88          *              matchValue      [3] AssertionValue,
89          *              dnAttributes    [4] BOOLEAN DEFAULT FALSE
90          *      }
91          *
92          */
93
94         tag = ber_peek_tag( ber, &len );
95
96         if( tag == LBER_ERROR ) {
97                 *text = "error decoding filter";
98                 return SLAPD_DISCONNECT;
99         }
100
101         f = (Filter *) ch_malloc( sizeof(Filter) );
102         f->f_next = NULL;
103
104         err = LDAP_SUCCESS;
105         f->f_choice = tag; 
106
107         switch ( f->f_choice ) {
108         case LDAP_FILTER_EQUALITY:
109 #ifdef NEW_LOGGING
110                 LDAP_LOG( FILTER, DETAIL2, 
111                         "get_filter: conn %d  EQUALITY\n", conn->c_connid, 0, 0 );
112 #else
113                 Debug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 );
114 #endif
115                 err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY, text );
116                 if ( err != LDAP_SUCCESS ) {
117                         break;
118                 }
119
120                 assert( f->f_ava != NULL );
121                 break;
122
123         case LDAP_FILTER_SUBSTRINGS:
124 #ifdef NEW_LOGGING
125                 LDAP_LOG( FILTER, DETAIL1, 
126                         "get_filter: conn %d  SUBSTRINGS\n", conn->c_connid, 0, 0 );
127 #else
128                 Debug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 );
129 #endif
130                 err = get_substring_filter( conn, ber, f, text );
131                 break;
132
133         case LDAP_FILTER_GE:
134 #ifdef NEW_LOGGING
135                 LDAP_LOG( FILTER, DETAIL1, 
136                         "get_filter: conn %d  GE\n", conn->c_connid, 0, 0 );
137 #else
138                 Debug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 );
139 #endif
140                 err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text );
141                 if ( err != LDAP_SUCCESS ) {
142                         break;
143                 }
144                 break;
145
146         case LDAP_FILTER_LE:
147 #ifdef NEW_LOGGING
148                 LDAP_LOG( FILTER, DETAIL1, 
149                         "get_filter: conn %d  LE\n", conn->c_connid, 0, 0 );
150 #else
151                 Debug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 );
152 #endif
153                 err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text );
154                 if ( err != LDAP_SUCCESS ) {
155                         break;
156                 }
157                 break;
158
159         case LDAP_FILTER_PRESENT: {
160                 struct berval type;
161
162 #ifdef NEW_LOGGING
163                 LDAP_LOG( FILTER, DETAIL1, 
164                         "get_filter: conn %d PRESENT\n", conn->c_connid, 0, 0 );
165 #else
166                 Debug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 );
167 #endif
168                 if ( ber_scanf( ber, "m", &type ) == LBER_ERROR ) {
169                         err = SLAPD_DISCONNECT;
170                         *text = "error decoding filter";
171                         break;
172                 }
173
174                 f->f_desc = NULL;
175                 err = slap_bv2ad( &type, &f->f_desc, text );
176
177                 if( err != LDAP_SUCCESS ) {
178                         /* unrecognized attribute description or other error */
179                         f->f_choice = SLAPD_FILTER_COMPUTED;
180                         f->f_result = LDAP_COMPARE_FALSE;
181                         err = LDAP_SUCCESS;
182                         break;
183                 }
184                 } break;
185
186         case LDAP_FILTER_APPROX:
187 #ifdef NEW_LOGGING
188                 LDAP_LOG( FILTER, DETAIL1, 
189                         "get_filter: conn %d  APPROX\n", conn->c_connid, 0, 0 );
190 #else
191                 Debug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 );
192 #endif
193                 err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY_APPROX, text );
194                 if ( err != LDAP_SUCCESS ) {
195                         break;
196                 }
197                 break;
198
199         case LDAP_FILTER_AND:
200 #ifdef NEW_LOGGING
201                 LDAP_LOG( FILTER, DETAIL1, 
202                         "get_filter: conn %d  AND\n", conn->c_connid, 0, 0 );
203 #else
204                 Debug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 );
205 #endif
206                 err = get_filter_list( conn, ber, &f->f_and, text );
207                 if ( err != LDAP_SUCCESS ) {
208                         break;
209                 }
210                 break;
211
212         case LDAP_FILTER_OR:
213 #ifdef NEW_LOGGING
214                 LDAP_LOG( FILTER, DETAIL1, 
215                         "get_filter: conn %d  OR\n", conn->c_connid, 0, 0  );
216 #else
217                 Debug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 );
218 #endif
219                 err = get_filter_list( conn, ber, &f->f_or, text );
220                 if ( err != LDAP_SUCCESS ) {
221                         break;
222                 }
223                 break;
224
225         case LDAP_FILTER_NOT:
226 #ifdef NEW_LOGGING
227                 LDAP_LOG( FILTER, DETAIL1, 
228                         "get_filter: conn %d  NOT\n", conn->c_connid, 0, 0 );
229 #else
230                 Debug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 );
231 #endif
232                 (void) ber_skip_tag( ber, &len );
233                 err = get_filter( conn, ber, &f->f_not, text );
234                 if ( err != LDAP_SUCCESS ) {
235                         break;
236                 }
237                 break;
238
239         case LDAP_FILTER_EXT:
240 #ifdef NEW_LOGGING
241                 LDAP_LOG( FILTER, DETAIL1, 
242                         "get_filter: conn %d  EXTENSIBLE\n", conn->c_connid, 0, 0 );
243 #else
244                 Debug( LDAP_DEBUG_FILTER, "EXTENSIBLE\n", 0, 0, 0 );
245 #endif
246
247                 err = get_mra( ber, &f->f_mra, text );
248                 if ( err != LDAP_SUCCESS ) {
249                         break;
250                 }
251
252                 assert( f->f_mra != NULL );
253                 break;
254
255         default:
256                 (void) ber_scanf( ber, "x" ); /* skip the element */
257 #ifdef NEW_LOGGING
258                 LDAP_LOG( FILTER, ERR, 
259                         "get_filter: conn %d unknown filter type=%lu\n",
260                         conn->c_connid, f->f_choice, 0 );
261 #else
262                 Debug( LDAP_DEBUG_ANY, "get_filter: unknown filter type=%lu\n",
263                         f->f_choice, 0, 0 );
264 #endif
265                 f->f_choice = SLAPD_FILTER_COMPUTED;
266                 f->f_result = SLAPD_COMPARE_UNDEFINED;
267                 break;
268         }
269
270         if ( err != LDAP_SUCCESS ) {
271                 if( err != SLAPD_DISCONNECT ) {
272                         /* ignore error */
273                         f->f_choice = SLAPD_FILTER_COMPUTED;
274                         f->f_result = SLAPD_COMPARE_UNDEFINED;
275                         err = LDAP_SUCCESS;
276                         *filt = f;
277
278                 } else {
279                         free(f);
280                 }
281
282         } else {
283                 *filt = f;
284         }
285
286 #ifdef NEW_LOGGING
287         LDAP_LOG( FILTER, DETAIL2, 
288                 "get_filter: conn %d exit\n", conn->c_connid, 0, 0 );
289 #else
290         Debug( LDAP_DEBUG_FILTER, "end get_filter %d\n", err, 0, 0 );
291 #endif
292         return( err );
293 }
294
295 static int
296 get_filter_list( Connection *conn, BerElement *ber,
297         Filter **f,
298         const char **text )
299 {
300         Filter          **new;
301         int             err;
302         ber_tag_t       tag;
303         ber_len_t       len;
304         char            *last;
305
306 #ifdef NEW_LOGGING
307         LDAP_LOG( FILTER, ENTRY, 
308                 "get_filter_list: conn %d start\n", conn->c_connid, 0, 0 );
309 #else
310         Debug( LDAP_DEBUG_FILTER, "begin get_filter_list\n", 0, 0, 0 );
311 #endif
312         new = f;
313         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
314                 tag = ber_next_element( ber, &len, last ) )
315         {
316                 err = get_filter( conn, ber, new, text );
317                 if ( err != LDAP_SUCCESS )
318                         return( err );
319                 new = &(*new)->f_next;
320         }
321         *new = NULL;
322
323 #ifdef NEW_LOGGING
324         LDAP_LOG( FILTER, ENTRY, 
325                 "get_filter_list: conn %d exit\n", conn->c_connid, 0, 0 );
326 #else
327         Debug( LDAP_DEBUG_FILTER, "end get_filter_list\n", 0, 0, 0 );
328 #endif
329         return( LDAP_SUCCESS );
330 }
331
332 static int
333 get_substring_filter(
334         Connection      *conn,
335         BerElement      *ber,
336         Filter  *f,
337         const char      **text )
338 {
339         ber_tag_t       tag;
340         ber_len_t       len;
341         ber_tag_t       rc;
342         struct berval value;
343         char            *last;
344         struct berval bv;
345         *text = "error decoding filter";
346
347 #ifdef NEW_LOGGING
348         LDAP_LOG( FILTER, ENTRY, 
349                 "get_substring_filter: conn %d  begin\n", conn->c_connid, 0, 0 );
350 #else
351         Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 );
352 #endif
353         if ( ber_scanf( ber, "{m" /*}*/, &bv ) == LBER_ERROR ) {
354                 return SLAPD_DISCONNECT;
355         }
356
357         f->f_sub = ch_calloc( 1, sizeof(SubstringsAssertion) );
358         f->f_sub_desc = NULL;
359         rc = slap_bv2ad( &bv, &f->f_sub_desc, text );
360
361         if( rc != LDAP_SUCCESS ) {
362                 text = NULL;
363                 ch_free( f->f_sub );
364                 f->f_choice = SLAPD_FILTER_COMPUTED;
365                 f->f_result = SLAPD_COMPARE_UNDEFINED;
366                 return LDAP_SUCCESS;
367         }
368
369         f->f_sub_initial.bv_val = NULL;
370         f->f_sub_any = NULL;
371         f->f_sub_final.bv_val = NULL;
372
373         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
374                 tag = ber_next_element( ber, &len, last ) )
375         {
376                 unsigned usage;
377
378                 rc = ber_scanf( ber, "m", &value );
379                 if ( rc == LBER_ERROR ) {
380                         rc = SLAPD_DISCONNECT;
381                         goto return_error;
382                 }
383
384                 if ( value.bv_val == NULL || value.bv_len == 0 ) {
385                         rc = LDAP_INVALID_SYNTAX;
386                         goto return_error;
387                 } 
388
389                 switch ( tag ) {
390                 case LDAP_SUBSTRING_INITIAL:
391                         usage = SLAP_MR_SUBSTR_INITIAL;
392                         break;
393
394                 case LDAP_SUBSTRING_ANY:
395                         usage = SLAP_MR_SUBSTR_ANY;
396                         break;
397
398                 case LDAP_SUBSTRING_FINAL:
399                         usage = SLAP_MR_SUBSTR_FINAL;
400                         break;
401
402                 default:
403                         rc = LDAP_PROTOCOL_ERROR;
404
405 #ifdef NEW_LOGGING
406                         LDAP_LOG( FILTER, ERR,
407                                 "get_filter_substring: conn %d  unknown substring choice=%ld\n",
408                                 conn->c_connid, (long)tag, 0 );
409 #else
410                         Debug( LDAP_DEBUG_FILTER,
411                                 "  unknown substring choice=%ld\n",
412                                 (long) tag, 0, 0 );
413 #endif
414                         goto return_error;
415                 }
416
417                 /* valiate using equality matching rule validator! */
418                 rc = value_validate( f->f_sub_desc->ad_type->sat_equality,
419                         &value, text );
420                 if( rc != LDAP_SUCCESS ) {
421                         goto return_error;
422                 }
423
424                 rc = value_normalize( f->f_sub_desc, usage,
425                         &value, &bv, text );
426                 if( rc != LDAP_SUCCESS ) {
427                         goto return_error;
428                 }
429
430                 value = bv;
431
432                 rc = LDAP_PROTOCOL_ERROR;
433
434                 switch ( tag ) {
435                 case LDAP_SUBSTRING_INITIAL:
436 #ifdef NEW_LOGGING
437                         LDAP_LOG( FILTER, DETAIL1,
438                                 "get_substring_filter: conn %d  INITIAL\n", conn->c_connid, 0, 0 );
439 #else
440                         Debug( LDAP_DEBUG_FILTER, "  INITIAL\n", 0, 0, 0 );
441 #endif
442
443                         if ( f->f_sub_initial.bv_val != NULL
444                                 || f->f_sub_any != NULL 
445                                 || f->f_sub_final.bv_val != NULL )
446                         {
447                                 free( value.bv_val );
448                                 goto return_error;
449                         }
450
451                         f->f_sub_initial = value;
452                         break;
453
454                 case LDAP_SUBSTRING_ANY:
455 #ifdef NEW_LOGGING
456                         LDAP_LOG( FILTER, DETAIL1,
457                                 "get_substring_filter: conn %d  ANY\n", conn->c_connid, 0, 0 );
458 #else
459                         Debug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
460 #endif
461
462                         if ( f->f_sub_final.bv_val != NULL ) {
463                                 free( value.bv_val );
464                                 goto return_error;
465                         }
466
467                         ber_bvarray_add( &f->f_sub_any, &value );
468                         break;
469
470                 case LDAP_SUBSTRING_FINAL:
471 #ifdef NEW_LOGGING
472                         LDAP_LOG( FILTER, DETAIL1, 
473                                 "get_substring_filter: conn %d  FINAL\n", conn->c_connid, 0, 0 );
474 #else
475                         Debug( LDAP_DEBUG_FILTER, "  FINAL\n", 0, 0, 0 );
476 #endif
477
478                         if ( f->f_sub_final.bv_val != NULL ) {
479                                 free( value.bv_val );
480                                 goto return_error;
481                         }
482
483                         f->f_sub_final = value;
484                         break;
485
486                 default:
487 #ifdef NEW_LOGGING
488                         LDAP_LOG( FILTER, INFO, 
489                                 "get_substring_filter: conn %d  unknown substring type %ld\n",
490                                 conn->c_connid, (long)tag, 0 );
491 #else
492                         Debug( LDAP_DEBUG_FILTER,
493                                 "  unknown substring type=%ld\n",
494                                 (long) tag, 0, 0 );
495 #endif
496
497                         free( value.bv_val );
498
499 return_error:
500 #ifdef NEW_LOGGING
501                         LDAP_LOG( FILTER, INFO, 
502                                 "get_substring_filter: conn %d  error %ld\n",
503                                 conn->c_connid, (long)rc, 0 );
504 #else
505                         Debug( LDAP_DEBUG_FILTER, "  error=%ld\n",
506                                 (long) rc, 0, 0 );
507 #endif
508                         free( f->f_sub_initial.bv_val );
509                         ber_bvarray_free( f->f_sub_any );
510                         free( f->f_sub_final.bv_val );
511                         ch_free( f->f_sub );
512                         return rc;
513                 }
514         }
515
516 #ifdef NEW_LOGGING
517         LDAP_LOG( FILTER, ENTRY, 
518                 "get_substring_filter: conn %d exit\n", conn->c_connid, 0, 0 );
519 #else
520         Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
521 #endif
522         return( LDAP_SUCCESS );
523 }
524
525 void
526 filter_free( Filter *f )
527 {
528         Filter  *p, *next;
529
530         if ( f == NULL ) {
531                 return;
532         }
533
534         switch ( f->f_choice ) {
535         case LDAP_FILTER_PRESENT:
536                 break;
537
538         case LDAP_FILTER_EQUALITY:
539         case LDAP_FILTER_GE:
540         case LDAP_FILTER_LE:
541         case LDAP_FILTER_APPROX:
542                 ava_free( f->f_ava, 1 );
543                 break;
544
545         case LDAP_FILTER_SUBSTRINGS:
546                 if ( f->f_sub_initial.bv_val != NULL ) {
547                         free( f->f_sub_initial.bv_val );
548                 }
549                 ber_bvarray_free( f->f_sub_any );
550                 if ( f->f_sub_final.bv_val != NULL ) {
551                         free( f->f_sub_final.bv_val );
552                 }
553                 ch_free( f->f_sub );
554                 break;
555
556         case LDAP_FILTER_AND:
557         case LDAP_FILTER_OR:
558         case LDAP_FILTER_NOT:
559                 for ( p = f->f_list; p != NULL; p = next ) {
560                         next = p->f_next;
561                         filter_free( p );
562                 }
563                 break;
564
565         case LDAP_FILTER_EXT:
566                 mra_free( f->f_mra, 1 );
567                 break;
568
569         case SLAPD_FILTER_COMPUTED:
570                 break;
571
572         default:
573 #ifdef NEW_LOGGING
574                 LDAP_LOG( FILTER, ERR, 
575                         "filter_free: unknown filter type %lu\n", f->f_choice, 0, 0 );
576 #else
577                 Debug( LDAP_DEBUG_ANY, "filter_free: unknown filter type=%lu\n",
578                         f->f_choice, 0, 0 );
579 #endif
580                 break;
581         }
582
583         free( f );
584 }
585
586 void
587 filter2bv( Filter *f, struct berval *fstr )
588 {
589         int     i;
590         Filter  *p;
591         struct berval tmp;
592         ber_len_t len;
593
594         if ( f == NULL ) {
595                 ber_str2bv( "No filter!", sizeof("No filter!")-1, 1, fstr );
596                 return;
597         }
598
599         switch ( f->f_choice ) {
600         case LDAP_FILTER_EQUALITY:
601                 filter_escape_value( &f->f_av_value, &tmp );
602
603                 fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
604                         tmp.bv_len + ( sizeof("(=)") - 1 );
605                 fstr->bv_val = malloc( fstr->bv_len + 1 );
606
607                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
608                         f->f_av_desc->ad_cname.bv_val,
609                         tmp.bv_val );
610
611                 ber_memfree( tmp.bv_val );
612                 break;
613
614         case LDAP_FILTER_GE:
615                 filter_escape_value( &f->f_av_value, &tmp );
616
617                 fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
618                         tmp.bv_len + ( sizeof("(>=)") - 1 );
619                 fstr->bv_val = malloc( fstr->bv_len + 1 );
620
621                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
622                         f->f_av_desc->ad_cname.bv_val,
623                         tmp.bv_val );
624
625                 ber_memfree( tmp.bv_val );
626                 break;
627
628         case LDAP_FILTER_LE:
629                 filter_escape_value( &f->f_av_value, &tmp );
630
631                 fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
632                         tmp.bv_len + ( sizeof("(<=)") - 1 );
633                 fstr->bv_val = malloc( fstr->bv_len + 1 );
634
635                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
636                         f->f_av_desc->ad_cname.bv_val,
637                         tmp.bv_val );
638
639                 ber_memfree( tmp.bv_val );
640                 break;
641
642         case LDAP_FILTER_APPROX:
643                 filter_escape_value( &f->f_av_value, &tmp );
644
645                 fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
646                         tmp.bv_len + ( sizeof("(~=)") - 1 );
647                 fstr->bv_val = malloc( fstr->bv_len + 1 );
648
649                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
650                         f->f_av_desc->ad_cname.bv_val,
651                         tmp.bv_val );
652                 ber_memfree( tmp.bv_val );
653                 break;
654
655         case LDAP_FILTER_SUBSTRINGS:
656                 fstr->bv_len = f->f_sub_desc->ad_cname.bv_len +
657                         ( sizeof("(=*)") - 1 );
658                 fstr->bv_val = malloc( fstr->bv_len + 128 );
659
660                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
661                         f->f_sub_desc->ad_cname.bv_val );
662
663                 if ( f->f_sub_initial.bv_val != NULL ) {
664                         len = fstr->bv_len;
665
666                         filter_escape_value( &f->f_sub_initial, &tmp );
667
668                         fstr->bv_len += tmp.bv_len;
669                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
670
671                         snprintf( &fstr->bv_val[len-2], tmp.bv_len+3,
672                                 /* "(attr=" */ "%s*)",
673                                 tmp.bv_val );
674
675                         ber_memfree( tmp.bv_val );
676                 }
677
678                 if ( f->f_sub_any != NULL ) {
679                         for ( i = 0; f->f_sub_any[i].bv_val != NULL; i++ ) {
680                                 len = fstr->bv_len;
681                                 filter_escape_value( &f->f_sub_any[i], &tmp );
682
683                                 fstr->bv_len += tmp.bv_len + 1;
684                                 fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
685
686                                 snprintf( &fstr->bv_val[len-1], tmp.bv_len+3,
687                                         /* "(attr=[init]*[any*]" */ "%s*)",
688                                         tmp.bv_val );
689                                 ber_memfree( tmp.bv_val );
690                         }
691                 }
692
693                 if ( f->f_sub_final.bv_val != NULL ) {
694                         len = fstr->bv_len;
695
696                         filter_escape_value( &f->f_sub_final, &tmp );
697
698                         fstr->bv_len += tmp.bv_len;
699                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
700
701                         snprintf( &fstr->bv_val[len-1], tmp.bv_len+3,
702                                 /* "(attr=[init*][any*]" */ "%s)",
703                                 tmp.bv_val );
704
705                         ber_memfree( tmp.bv_val );
706                 }
707
708                 break;
709
710         case LDAP_FILTER_PRESENT:
711                 fstr->bv_len = f->f_desc->ad_cname.bv_len +
712                         ( sizeof("(=*)") - 1 );
713                 fstr->bv_val = malloc( fstr->bv_len + 1 );
714
715                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
716                         f->f_desc->ad_cname.bv_val );
717                 break;
718
719         case LDAP_FILTER_AND:
720         case LDAP_FILTER_OR:
721         case LDAP_FILTER_NOT:
722                 fstr->bv_len = sizeof("(%)") - 1;
723                 fstr->bv_val = malloc( fstr->bv_len + 128 );
724
725                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
726                         f->f_choice == LDAP_FILTER_AND ? '&' :
727                         f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
728
729                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
730                         len = fstr->bv_len;
731
732                         filter2bv( p, &tmp );
733                         
734                         fstr->bv_len += tmp.bv_len;
735                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
736
737                         snprintf( &fstr->bv_val[len-1], tmp.bv_len + 2, 
738                                 /*"("*/ "%s)", tmp.bv_val );
739
740                         ch_free( tmp.bv_val );
741                 }
742
743                 break;
744
745         case LDAP_FILTER_EXT:
746                 filter_escape_value( &f->f_mr_value, &tmp );
747 #ifndef SLAP_X_MRA_MATCH_DNATTRS
748                 fstr->bv_len = f->f_mr_desc->ad_cname.bv_len +
749                         ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
750                         ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
751                         tmp.bv_len + ( sizeof("(:=)") - 1 );
752                 fstr->bv_val = malloc( fstr->bv_len + 1 );
753
754                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
755                         f->f_mr_desc->ad_cname.bv_val,
756                         f->f_mr_dnattrs ? ":dn" : "",
757                         f->f_mr_rule_text.bv_len ? ":" : "",
758                         f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
759                         tmp.bv_val );
760 #else /* SLAP_X_MRA_MATCH_DNATTRS */
761                 {
762                 struct berval ad;
763
764                 if ( f->f_mr_desc ) {
765                         ad = f->f_mr_desc->ad_cname;
766                 } else {
767                         ad.bv_len = 0;
768                         ad.bv_val = "";
769                 }
770                         
771                 fstr->bv_len = ad.bv_len +
772                         ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
773                         ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
774                         tmp.bv_len + ( sizeof("(:=)") - 1 );
775                 fstr->bv_val = malloc( fstr->bv_len + 1 );
776
777                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
778                         ad.bv_val,
779                         f->f_mr_dnattrs ? ":dn" : "",
780                         f->f_mr_rule_text.bv_len ? ":" : "",
781                         f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
782                         tmp.bv_val );
783                 }
784 #endif /* SLAP_X_MRA_MATCH_DNATTRS */
785                 ber_memfree( tmp.bv_val );
786                 break;
787
788         case SLAPD_FILTER_COMPUTED:
789                 ber_str2bv(
790                         f->f_result == LDAP_COMPARE_FALSE ? "(?=false)" :
791                         f->f_result == LDAP_COMPARE_TRUE ? "(?=true)" :
792                         f->f_result == SLAPD_COMPARE_UNDEFINED ? "(?=undefined)" :
793                         "(?=error)",
794                         f->f_result == LDAP_COMPARE_FALSE ? sizeof("(?=false)")-1 :
795                         f->f_result == LDAP_COMPARE_TRUE ? sizeof("(?=true)")-1 :
796                         f->f_result == SLAPD_COMPARE_UNDEFINED ? sizeof("(?=undefined)")-1 :
797                         sizeof("(?=error)")-1,
798                         1, fstr );
799                 break;
800
801         default:
802                 ber_str2bv( "(?=unknown)", sizeof("(?=unknown)")-1, 1, fstr );
803                 break;
804         }
805 }
806
807 static int filter_escape_value(
808         struct berval *in,
809         struct berval *out )
810 {
811         ber_len_t i;
812         assert( in );
813         assert( out );
814
815         out->bv_val = (char *) ch_malloc( ( in->bv_len * 3 ) + 1 );
816         out->bv_len = 0;
817
818         for( i=0; i < in->bv_len ; i++ ) {
819                 if( FILTER_ESCAPE(in->bv_val[i]) ) {
820                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_CHAR;
821                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_HI( in->bv_val[i] );
822                         out->bv_val[out->bv_len++] = SLAP_ESCAPE_LO( in->bv_val[i] );
823                 } else {
824                         out->bv_val[out->bv_len++] = in->bv_val[i];
825                 }
826         }
827
828         out->bv_val[out->bv_len] = '\0';
829         return LDAP_SUCCESS;
830 }
831
832 static int
833 get_simple_vrFilter(
834         Connection *conn,
835         BerElement *ber,
836         ValuesReturnFilter **filt,
837         const char **text )
838 {
839         ber_tag_t       tag;
840         ber_len_t       len;
841         int             err;
842         ValuesReturnFilter *f;
843
844 #ifdef NEW_LOGGING
845         LDAP_LOG( FILTER, ENTRY, 
846                 "get_simple_vrFilter: conn %d\n", conn->c_connid, 0, 0 );
847 #else
848         Debug( LDAP_DEBUG_FILTER, "begin get_simple_vrFilter\n", 0, 0, 0 );
849 #endif
850
851         tag = ber_peek_tag( ber, &len );
852
853         if( tag == LBER_ERROR ) {
854                 *text = "error decoding filter";
855                 return SLAPD_DISCONNECT;
856         }
857
858         f = (ValuesReturnFilter *) ch_malloc( sizeof(ValuesReturnFilter) );
859         f->f_next = NULL;
860
861         err = LDAP_SUCCESS;
862         f->f_choice = tag; 
863
864         switch ( f->f_choice ) {
865         case LDAP_FILTER_EQUALITY:
866 #ifdef NEW_LOGGING
867                 LDAP_LOG( FILTER, DETAIL2, 
868                         "get_simple_vrFilter: conn %d  EQUALITY\n", conn->c_connid, 0, 0 );
869 #else
870                 Debug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 );
871 #endif
872                 err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY, text );
873                 if ( err != LDAP_SUCCESS ) {
874                         break;
875                 }
876
877                 assert( f->f_ava != NULL );
878                 break;
879
880         case LDAP_FILTER_SUBSTRINGS:
881 #ifdef NEW_LOGGING
882                 LDAP_LOG( FILTER, DETAIL1, 
883                         "get_simple_vrFilter: conn %d  SUBSTRINGS\n", conn->c_connid, 0, 0 );
884 #else
885                 Debug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 );
886 #endif
887                 err = get_substring_filter( conn, ber, (Filter *)f, text );
888                 break;
889
890         case LDAP_FILTER_GE:
891 #ifdef NEW_LOGGING
892                 LDAP_LOG( FILTER, DETAIL1, 
893                         "get_simple_vrFilter: conn %d  GE\n", conn->c_connid, 0, 0 );
894 #else
895                 Debug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 );
896 #endif
897                 err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text );
898                 if ( err != LDAP_SUCCESS ) {
899                         break;
900                 }
901                 break;
902
903         case LDAP_FILTER_LE:
904 #ifdef NEW_LOGGING
905                 LDAP_LOG( FILTER, DETAIL1, 
906                         "get_simple_vrFilter: conn %d  LE\n", conn->c_connid, 0, 0 );
907 #else
908                 Debug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 );
909 #endif
910                 err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text );
911                 if ( err != LDAP_SUCCESS ) {
912                         break;
913                 }
914                 break;
915
916         case LDAP_FILTER_PRESENT: {
917                 struct berval type;
918
919 #ifdef NEW_LOGGING
920                 LDAP_LOG( FILTER, DETAIL1, 
921                         "get_simple_vrFilter: conn %d PRESENT\n", conn->c_connid, 0, 0 );
922 #else
923                 Debug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 );
924 #endif
925                 if ( ber_scanf( ber, "m", &type ) == LBER_ERROR ) {
926                         err = SLAPD_DISCONNECT;
927                         *text = "error decoding filter";
928                         break;
929                 }
930
931                 f->f_desc = NULL;
932                 err = slap_bv2ad( &type, &f->f_desc, text );
933
934                 if( err != LDAP_SUCCESS ) {
935                         /* unrecognized attribute description or other error */
936                         f->f_choice = SLAPD_FILTER_COMPUTED;
937                         f->f_result = LDAP_COMPARE_FALSE;
938                         err = LDAP_SUCCESS;
939                         break;
940                 }
941                 } break;
942
943         case LDAP_FILTER_APPROX:
944 #ifdef NEW_LOGGING
945                 LDAP_LOG( FILTER, DETAIL1, 
946                         "get_simple_vrFilter: conn %d  APPROX\n", conn->c_connid, 0, 0 );
947 #else
948                 Debug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 );
949 #endif
950                 err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY_APPROX, text );
951                 if ( err != LDAP_SUCCESS ) {
952                         break;
953                 }
954                 break;
955
956         case LDAP_FILTER_EXT:
957 #ifdef NEW_LOGGING
958                 LDAP_LOG( FILTER, DETAIL1, 
959                         "get_simple_vrFilter: conn %d  EXTENSIBLE\n", conn->c_connid, 0, 0 );
960 #else
961                 Debug( LDAP_DEBUG_FILTER, "EXTENSIBLE\n", 0, 0, 0 );
962 #endif
963
964                 err = get_mra( ber, &f->f_mra, text );
965                 if ( err != LDAP_SUCCESS ) {
966                         break;
967                 }
968
969                 assert( f->f_mra != NULL );
970                 break;
971
972         default:
973                 (void) ber_scanf( ber, "x" ); /* skip the element */
974 #ifdef NEW_LOGGING
975                 LDAP_LOG( FILTER, ERR, 
976                         "get_simple_vrFilter: conn %d unknown filter type=%lu\n",
977                         conn->c_connid, f->f_choice, 0 );
978 #else
979                 Debug( LDAP_DEBUG_ANY, "get_simple_vrFilter: unknown filter type=%lu\n",
980                         f->f_choice, 0, 0 );
981 #endif
982                 f->f_choice = SLAPD_FILTER_COMPUTED;
983                 f->f_result = SLAPD_COMPARE_UNDEFINED;
984                 break;
985         }
986
987         if ( err != LDAP_SUCCESS ) {
988                 if( err != SLAPD_DISCONNECT ) {
989                         /* ignore error */
990                         f->f_choice = SLAPD_FILTER_COMPUTED;
991                         f->f_result = SLAPD_COMPARE_UNDEFINED;
992                         err = LDAP_SUCCESS;
993                         *filt = f;
994
995                 } else {
996                         free(f);
997                 }
998
999         } else {
1000                 *filt = f;
1001         }
1002
1003 #ifdef NEW_LOGGING
1004         LDAP_LOG( FILTER, DETAIL2, 
1005                 "get_simple_vrFilter: conn %d exit\n", conn->c_connid, 0, 0 );
1006 #else
1007         Debug( LDAP_DEBUG_FILTER, "end get_simple_vrFilter %d\n", err, 0, 0 );
1008 #endif
1009         return( err );
1010 }
1011
1012 int
1013 get_vrFilter( Connection *conn, BerElement *ber,
1014         ValuesReturnFilter **f,
1015         const char **text )
1016 {
1017         /*
1018          * A ValuesReturnFilter looks like this:
1019          *
1020          *      ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
1021          *      SimpleFilterItem ::= CHOICE {
1022          *              equalityMatch   [3]     AttributeValueAssertion,
1023          *              substrings      [4]     SubstringFilter,
1024          *              greaterOrEqual  [5]     AttributeValueAssertion,
1025          *              lessOrEqual     [6]     AttributeValueAssertion,
1026          *              present         [7]     AttributeType,
1027          *              approxMatch     [8]     AttributeValueAssertion,
1028          *              extensibleMatch [9]     SimpleMatchingAssertion -- LDAPv3
1029          *      }
1030          *
1031          *      SubstringFilter ::= SEQUENCE {
1032          *              type               AttributeType,
1033          *              SEQUENCE OF CHOICE {
1034          *                      initial          [0] IA5String,
1035          *                      any              [1] IA5String,
1036          *                      final            [2] IA5String
1037          *              }
1038          *      }
1039          *
1040          *      SimpleMatchingAssertion ::= SEQUENCE {  -- LDAPv3
1041          *              matchingRule    [1] MatchingRuleId OPTIONAL,
1042          *              type            [2] AttributeDescription OPTIONAL,
1043          *              matchValue      [3] AssertionValue }
1044          */
1045
1046         ValuesReturnFilter **new;
1047         ber_tag_t       tag;
1048         ber_len_t       len;
1049         char            *last;
1050
1051 #ifdef NEW_LOGGING
1052         LDAP_LOG( FILTER, ENTRY, 
1053                 "get_vrFilter: conn %d start\n", conn->c_connid, 0, 0 );
1054 #else
1055         Debug( LDAP_DEBUG_FILTER, "begin get_vrFilter\n", 0, 0, 0 );
1056 #endif
1057
1058         tag = ber_peek_tag( ber, &len );
1059
1060         if( tag == LBER_ERROR ) {
1061                 *text = "error decoding vrFilter";
1062                 return SLAPD_DISCONNECT;
1063         }
1064
1065         if( tag != LBER_SEQUENCE ) {
1066                 *text = "error decoding vrFilter, expect SEQUENCE tag";
1067                 return SLAPD_DISCONNECT;
1068         }
1069
1070         new = f;
1071         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
1072                 tag = ber_next_element( ber, &len, last ) )
1073         {
1074                 int err = get_simple_vrFilter( conn, ber, new, text );
1075                 if ( err != LDAP_SUCCESS )
1076                         return( err );
1077                 new = &(*new)->f_next;
1078         }
1079         *new = NULL;
1080
1081 #ifdef NEW_LOGGING
1082         LDAP_LOG( FILTER, ENTRY, 
1083                 "get_vrFilter: conn %d exit\n", conn->c_connid, 0, 0 );
1084 #else
1085         Debug( LDAP_DEBUG_FILTER, "end get_vrFilter\n", 0, 0, 0 );
1086 #endif
1087         return( LDAP_SUCCESS );
1088 }
1089
1090 void
1091 vrFilter_free( ValuesReturnFilter *f )
1092 {
1093         ValuesReturnFilter      *p, *next;
1094
1095         if ( f == NULL ) {
1096                 return;
1097         }
1098
1099         for ( p = f; p != NULL; p = next ) {
1100                 next = p->f_next;
1101
1102                 switch ( f->f_choice ) {
1103                 case LDAP_FILTER_PRESENT:
1104                         break;
1105
1106                 case LDAP_FILTER_EQUALITY:
1107                 case LDAP_FILTER_GE:
1108                 case LDAP_FILTER_LE:
1109                 case LDAP_FILTER_APPROX:
1110                         ava_free( f->f_ava, 1 );
1111                         break;
1112
1113                 case LDAP_FILTER_SUBSTRINGS:
1114                         if ( f->f_sub_initial.bv_val != NULL ) {
1115                                 free( f->f_sub_initial.bv_val );
1116                         }
1117                         ber_bvarray_free( f->f_sub_any );
1118                         if ( f->f_sub_final.bv_val != NULL ) {
1119                                 free( f->f_sub_final.bv_val );
1120                         }
1121                         ch_free( f->f_sub );
1122                         break;
1123
1124                 case LDAP_FILTER_EXT:
1125                         mra_free( f->f_mra, 1 );
1126                         break;
1127
1128                 case SLAPD_FILTER_COMPUTED:
1129                         break;
1130
1131                 default:
1132 #ifdef NEW_LOGGING
1133                         LDAP_LOG( FILTER, ERR, 
1134                                 "filter_free: unknown filter type %lu\n", f->f_choice, 0, 0 );
1135 #else
1136                         Debug( LDAP_DEBUG_ANY, "filter_free: unknown filter type=%lu\n",
1137                                 f->f_choice, 0, 0 );
1138 #endif
1139                         break;
1140                 }
1141
1142                 free( f );
1143         }
1144 }
1145
1146
1147 void
1148 vrFilter2bv( ValuesReturnFilter *f, struct berval *fstr )
1149 {
1150         ValuesReturnFilter      *p;
1151         struct berval tmp;
1152         ber_len_t len;
1153
1154         if ( f == NULL ) {
1155                 ber_str2bv( "No filter!", sizeof("No filter!")-1, 1, fstr );
1156                 return;
1157         }
1158
1159         fstr->bv_len = sizeof("()") - 1;
1160         fstr->bv_val = malloc( fstr->bv_len + 128 );
1161
1162         snprintf( fstr->bv_val, fstr->bv_len + 1, "()");
1163
1164         for ( p = f; p != NULL; p = p->f_next ) {
1165                 len = fstr->bv_len;
1166
1167                 simple_vrFilter2bv( p, &tmp );
1168                         
1169                 fstr->bv_len += tmp.bv_len;
1170                 fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
1171
1172                 snprintf( &fstr->bv_val[len-1], tmp.bv_len + 2, 
1173                         /*"("*/ "%s)", tmp.bv_val );
1174
1175                 ch_free( tmp.bv_val );
1176         }
1177 }
1178
1179 static void
1180 simple_vrFilter2bv( ValuesReturnFilter *f, struct berval *fstr )
1181 {
1182         struct berval tmp;
1183         ber_len_t len;
1184
1185         if ( f == NULL ) {
1186                 ber_str2bv( "No filter!", sizeof("No filter!")-1, 1, fstr );
1187                 return;
1188         }
1189
1190         switch ( f->f_choice ) {
1191         case LDAP_FILTER_EQUALITY:
1192                 filter_escape_value( &f->f_av_value, &tmp );
1193
1194                 fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
1195                         tmp.bv_len + ( sizeof("(=)") - 1 );
1196                 fstr->bv_val = malloc( fstr->bv_len + 1 );
1197
1198                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
1199                         f->f_av_desc->ad_cname.bv_val,
1200                         tmp.bv_val );
1201
1202                 ber_memfree( tmp.bv_val );
1203                 break;
1204
1205         case LDAP_FILTER_GE:
1206                 filter_escape_value( &f->f_av_value, &tmp );
1207
1208                 fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
1209                         tmp.bv_len + ( sizeof("(>=)") - 1 );
1210                 fstr->bv_val = malloc( fstr->bv_len + 1 );
1211
1212                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
1213                         f->f_av_desc->ad_cname.bv_val,
1214                         tmp.bv_val );
1215
1216                 ber_memfree( tmp.bv_val );
1217                 break;
1218
1219         case LDAP_FILTER_LE:
1220                 filter_escape_value( &f->f_av_value, &tmp );
1221
1222                 fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
1223                         tmp.bv_len + ( sizeof("(<=)") - 1 );
1224                 fstr->bv_val = malloc( fstr->bv_len + 1 );
1225
1226                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
1227                         f->f_av_desc->ad_cname.bv_val,
1228                         tmp.bv_val );
1229
1230                 ber_memfree( tmp.bv_val );
1231                 break;
1232
1233         case LDAP_FILTER_APPROX:
1234                 filter_escape_value( &f->f_av_value, &tmp );
1235
1236                 fstr->bv_len = f->f_av_desc->ad_cname.bv_len +
1237                         tmp.bv_len + ( sizeof("(~=)") - 1 );
1238                 fstr->bv_val = malloc( fstr->bv_len + 1 );
1239
1240                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
1241                         f->f_av_desc->ad_cname.bv_val,
1242                         tmp.bv_val );
1243                 ber_memfree( tmp.bv_val );
1244                 break;
1245
1246         case LDAP_FILTER_SUBSTRINGS:
1247                 fstr->bv_len = f->f_sub_desc->ad_cname.bv_len +
1248                         ( sizeof("(=*)") - 1 );
1249                 fstr->bv_val = malloc( fstr->bv_len + 128 );
1250
1251                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
1252                         f->f_sub_desc->ad_cname.bv_val );
1253
1254                 if ( f->f_sub_initial.bv_val != NULL ) {
1255                         len = fstr->bv_len;
1256
1257                         filter_escape_value( &f->f_sub_initial, &tmp );
1258
1259                         fstr->bv_len += tmp.bv_len;
1260                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
1261
1262                         snprintf( &fstr->bv_val[len-2], tmp.bv_len+3,
1263                                 /* "(attr=" */ "%s*)",
1264                                 tmp.bv_val );
1265
1266                         ber_memfree( tmp.bv_val );
1267                 }
1268
1269                 if ( f->f_sub_any != NULL ) {
1270                         int i;
1271                         for ( i = 0; f->f_sub_any[i].bv_val != NULL; i++ ) {
1272                                 len = fstr->bv_len;
1273                                 filter_escape_value( &f->f_sub_any[i], &tmp );
1274
1275                                 fstr->bv_len += tmp.bv_len + 1;
1276                                 fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
1277
1278                                 snprintf( &fstr->bv_val[len-1], tmp.bv_len+3,
1279                                         /* "(attr=[init]*[any*]" */ "%s*)",
1280                                         tmp.bv_val );
1281                                 ber_memfree( tmp.bv_val );
1282                         }
1283                 }
1284
1285                 if ( f->f_sub_final.bv_val != NULL ) {
1286                         len = fstr->bv_len;
1287
1288                         filter_escape_value( &f->f_sub_final, &tmp );
1289
1290                         fstr->bv_len += tmp.bv_len;
1291                         fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 );
1292
1293                         snprintf( &fstr->bv_val[len-1], tmp.bv_len+3,
1294                                 /* "(attr=[init*][any*]" */ "%s)",
1295                                 tmp.bv_val );
1296
1297                         ber_memfree( tmp.bv_val );
1298                 }
1299
1300                 break;
1301
1302         case LDAP_FILTER_PRESENT:
1303                 fstr->bv_len = f->f_desc->ad_cname.bv_len +
1304                         ( sizeof("(=*)") - 1 );
1305                 fstr->bv_val = malloc( fstr->bv_len + 1 );
1306
1307                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
1308                         f->f_desc->ad_cname.bv_val );
1309                 break;
1310
1311         case LDAP_FILTER_EXT:
1312                 filter_escape_value( &f->f_mr_value, &tmp );
1313
1314 #ifndef SLAP_X_MRA_MATCH_DNATTRS
1315                 fstr->bv_len = f->f_mr_desc->ad_cname.bv_len +
1316                         ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
1317                         ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
1318                         tmp.bv_len + ( sizeof("(:=)") - 1 );
1319                 fstr->bv_val = malloc( fstr->bv_len + 1 );
1320
1321                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
1322                         f->f_mr_desc->ad_cname.bv_val,
1323                         f->f_mr_dnattrs ? ":dn" : "",
1324                         f->f_mr_rule_text.bv_len ? ":" : "",
1325                         f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
1326                         tmp.bv_val );
1327 #else /* SLAP_X_MRA_MATCH_DNATTRS */
1328                 {
1329                 struct berval ad;
1330
1331                 if ( f->f_mr_desc ) {
1332                         ad = f->f_mr_desc->ad_cname;
1333                 } else {
1334                         ad.bv_len = 0;
1335                         ad.bv_val = "";
1336                 }
1337                         
1338                 fstr->bv_len = ad.bv_len +
1339                         ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
1340                         ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
1341                         tmp.bv_len + ( sizeof("(:=)") - 1 );
1342                 fstr->bv_val = malloc( fstr->bv_len + 1 );
1343
1344                 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
1345                         ad.bv_val,
1346                         f->f_mr_dnattrs ? ":dn" : "",
1347                         f->f_mr_rule_text.bv_len ? ":" : "",
1348                         f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
1349                         tmp.bv_val );
1350                 }
1351 #endif /* SLAP_X_MRA_MATCH_DNATTRS */
1352
1353                 ber_memfree( tmp.bv_val );
1354                 break;
1355
1356         case SLAPD_FILTER_COMPUTED:
1357                 ber_str2bv(
1358                         f->f_result == LDAP_COMPARE_FALSE ? "(?=false)" :
1359                         f->f_result == LDAP_COMPARE_TRUE ? "(?=true)" :
1360                         f->f_result == SLAPD_COMPARE_UNDEFINED ? "(?=undefined)" :
1361                         "(?=error)",
1362                         f->f_result == LDAP_COMPARE_FALSE ? sizeof("(?=false)")-1 :
1363                         f->f_result == LDAP_COMPARE_TRUE ? sizeof("(?=true)")-1 :
1364                         f->f_result == SLAPD_COMPARE_UNDEFINED ? sizeof("(?=undefined)")-1 :
1365                         sizeof("(?=error)")-1,
1366                         1, fstr );
1367                 break;
1368
1369         default:
1370                 ber_str2bv( "(?=unknown)", sizeof("(?=unknown)")-1, 1, fstr );
1371                 break;
1372         }
1373 }
1374
1375 static int
1376 get_substring_vrFilter(
1377         Connection      *conn,
1378         BerElement      *ber,
1379         ValuesReturnFilter      *f,
1380         const char      **text )
1381 {
1382         ber_tag_t       tag;
1383         ber_len_t       len;
1384         ber_tag_t       rc;
1385         struct berval value;
1386         char            *last;
1387         struct berval bv;
1388         *text = "error decoding filter";
1389
1390 #ifdef NEW_LOGGING
1391         LDAP_LOG( FILTER, ENTRY, 
1392                 "get_substring_filter: conn %d  begin\n", conn->c_connid, 0, 0 );
1393 #else
1394         Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 );
1395 #endif
1396         if ( ber_scanf( ber, "{m" /*}*/, &bv ) == LBER_ERROR ) {
1397                 return SLAPD_DISCONNECT;
1398         }
1399
1400         f->f_sub = ch_calloc( 1, sizeof(SubstringsAssertion) );
1401         f->f_sub_desc = NULL;
1402         rc = slap_bv2ad( &bv, &f->f_sub_desc, text );
1403
1404         if( rc != LDAP_SUCCESS ) {
1405                 text = NULL;
1406                 ch_free( f->f_sub );
1407                 f->f_choice = SLAPD_FILTER_COMPUTED;
1408                 f->f_result = SLAPD_COMPARE_UNDEFINED;
1409                 return LDAP_SUCCESS;
1410         }
1411
1412         f->f_sub_initial.bv_val = NULL;
1413         f->f_sub_any = NULL;
1414         f->f_sub_final.bv_val = NULL;
1415
1416         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
1417                 tag = ber_next_element( ber, &len, last ) )
1418         {
1419                 unsigned usage;
1420
1421                 rc = ber_scanf( ber, "m", &value );
1422                 if ( rc == LBER_ERROR ) {
1423                         rc = SLAPD_DISCONNECT;
1424                         goto return_error;
1425                 }
1426
1427                 if ( value.bv_val == NULL || value.bv_len == 0 ) {
1428                         rc = LDAP_INVALID_SYNTAX;
1429                         goto return_error;
1430                 } 
1431
1432                 switch ( tag ) {
1433                 case LDAP_SUBSTRING_INITIAL:
1434                         usage = SLAP_MR_SUBSTR_INITIAL;
1435                         break;
1436
1437                 case LDAP_SUBSTRING_ANY:
1438                         usage = SLAP_MR_SUBSTR_ANY;
1439                         break;
1440
1441                 case LDAP_SUBSTRING_FINAL:
1442                         usage = SLAP_MR_SUBSTR_FINAL;
1443                         break;
1444
1445                 default:
1446                         rc = LDAP_PROTOCOL_ERROR;
1447
1448 #ifdef NEW_LOGGING
1449                         LDAP_LOG( FILTER, ERR, 
1450                                 "get_filter_substring: conn %d  unknown substring choice=%ld\n",
1451                                 conn->c_connid, (long)tag, 0 );
1452 #else
1453                         Debug( LDAP_DEBUG_FILTER,
1454                                 "  unknown substring choice=%ld\n",
1455                                 (long) tag, 0, 0 );
1456 #endif
1457                         goto return_error;
1458                 }
1459
1460                 /* valiate using equality matching rule validator! */
1461                 rc = value_validate( f->f_sub_desc->ad_type->sat_equality,
1462                         &value, text );
1463                 if( rc != LDAP_SUCCESS ) {
1464                         goto return_error;
1465                 }
1466
1467                 rc = value_normalize( f->f_sub_desc, usage,
1468                         &value, &bv, text );
1469                 if( rc != LDAP_SUCCESS ) {
1470                         goto return_error;
1471                 }
1472
1473                 value = bv;
1474
1475                 rc = LDAP_PROTOCOL_ERROR;
1476
1477                 switch ( tag ) {
1478                 case LDAP_SUBSTRING_INITIAL:
1479 #ifdef NEW_LOGGING
1480                         LDAP_LOG( FILTER, DETAIL1, 
1481                                 "get_substring_filter: conn %d  INITIAL\n", 
1482                                 conn->c_connid, 0, 0 );
1483 #else
1484                         Debug( LDAP_DEBUG_FILTER, "  INITIAL\n", 0, 0, 0 );
1485 #endif
1486
1487                         if ( f->f_sub_initial.bv_val != NULL
1488                                 || f->f_sub_any != NULL 
1489                                 || f->f_sub_final.bv_val != NULL )
1490                         {
1491                                 free( value.bv_val );
1492                                 goto return_error;
1493                         }
1494
1495                         f->f_sub_initial = value;
1496                         break;
1497
1498                 case LDAP_SUBSTRING_ANY:
1499 #ifdef NEW_LOGGING
1500                         LDAP_LOG( FILTER, DETAIL1, 
1501                                 "get_substring_filter: conn %d  ANY\n", conn->c_connid, 0, 0 );
1502 #else
1503                         Debug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
1504 #endif
1505
1506                         if ( f->f_sub_final.bv_val != NULL ) {
1507                                 free( value.bv_val );
1508                                 goto return_error;
1509                         }
1510
1511                         ber_bvarray_add( &f->f_sub_any, &value );
1512                         break;
1513
1514                 case LDAP_SUBSTRING_FINAL:
1515 #ifdef NEW_LOGGING
1516                         LDAP_LOG( FILTER, DETAIL1, 
1517                                 "get_substring_filter: conn %d  FINAL\n", conn->c_connid, 0, 0 );
1518 #else
1519                         Debug( LDAP_DEBUG_FILTER, "  FINAL\n", 0, 0, 0 );
1520 #endif
1521
1522                         if ( f->f_sub_final.bv_val != NULL ) {
1523                                 free( value.bv_val );
1524                                 goto return_error;
1525                         }
1526
1527                         f->f_sub_final = value;
1528                         break;
1529
1530                 default:
1531 #ifdef NEW_LOGGING
1532                         LDAP_LOG( FILTER, INFO, 
1533                                 "get_substring_filter: conn %d  unknown substring type %ld\n",
1534                                 conn->c_connid, (long)tag, 0 );
1535 #else
1536                         Debug( LDAP_DEBUG_FILTER,
1537                                 "  unknown substring type=%ld\n",
1538                                 (long) tag, 0, 0 );
1539 #endif
1540
1541                         free( value.bv_val );
1542
1543 return_error:
1544 #ifdef NEW_LOGGING
1545                         LDAP_LOG( FILTER, INFO, 
1546                                 "get_substring_filter: conn %d  error %ld\n",
1547                                 conn->c_connid, (long)rc, 0 );
1548 #else
1549                         Debug( LDAP_DEBUG_FILTER, "  error=%ld\n",
1550                                 (long) rc, 0, 0 );
1551 #endif
1552                         free( f->f_sub_initial.bv_val );
1553                         ber_bvarray_free( f->f_sub_any );
1554                         free( f->f_sub_final.bv_val );
1555                         ch_free( f->f_sub );
1556                         return rc;
1557                 }
1558         }
1559
1560 #ifdef NEW_LOGGING
1561         LDAP_LOG( FILTER, ENTRY, 
1562                 "get_substring_filter: conn %d exit\n", conn->c_connid, 0, 0 );
1563 #else
1564         Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
1565 #endif
1566         return( LDAP_SUCCESS );
1567 }
1568
1569 #ifdef SLAP_X_FILTER_HASSUBORDINATES
1570 static int filter_has_subordinates_list(
1571         Filter          *filter );
1572
1573 /*
1574  * FIXME: we could detect the need to filter
1575  * for hasSubordinates when parsing the filter ...
1576  */
1577
1578 static int
1579 filter_has_subordinates_list(
1580         Filter          *fl )
1581 {
1582         Filter                  *f;
1583
1584         for ( f = fl; f != NULL; f = f->f_next ) {
1585                 int     rc;
1586
1587                 rc = filter_has_subordinates( f );
1588
1589                 if ( rc ) {
1590                         return rc;
1591                 }
1592         }
1593
1594         return 0;
1595 }
1596
1597 int
1598 filter_has_subordinates(
1599         Filter          *f )
1600 {
1601         AttributeDescription    *ad = NULL;
1602
1603         switch ( f->f_choice ) {
1604         case LDAP_FILTER_PRESENT:
1605                 ad = f->f_desc;
1606                 break;
1607
1608         case LDAP_FILTER_EQUALITY:
1609         case LDAP_FILTER_APPROX:
1610         case LDAP_FILTER_GE:
1611         case LDAP_FILTER_LE:
1612                 ad = f->f_ava->aa_desc;
1613                 break;
1614
1615         case LDAP_FILTER_SUBSTRINGS:
1616                 ad = f->f_sub_desc;
1617                 break;
1618
1619         case LDAP_FILTER_EXT:
1620                 /* could be null; however here it is harmless */
1621                 ad = f->f_mra->ma_desc;
1622                 break;
1623
1624         case LDAP_FILTER_NOT:
1625                 return filter_has_subordinates( f->f_not );
1626
1627         case LDAP_FILTER_AND:
1628                 return filter_has_subordinates_list( f->f_and );
1629
1630         case LDAP_FILTER_OR:
1631                 return filter_has_subordinates_list( f->f_or );
1632
1633         case SLAPD_FILTER_COMPUTED:
1634                 /*
1635                  * something wrong?
1636                  */
1637                 return 0;
1638
1639         default:
1640                 /*
1641                  * this means a new type of filter has been implemented,
1642                  * which is not handled yet in this function; we should
1643                  * issue a developer's warning, e.g. an assertion
1644                  */
1645                 assert( 0 );
1646                 return -1;
1647         }
1648
1649         if ( ad == slap_schema.si_ad_hasSubordinates ) {
1650                 return 1;
1651         }
1652
1653         return 0;
1654 }
1655
1656 #endif /* SLAP_X_FILTER_HASSUBORDINATES */
1657