]> git.sur5r.net Git - openldap/blob - servers/slapd/filter.c
Do not log attribute value
[openldap] / servers / slapd / filter.c
1 /* filter.c - routines for parsing and dealing with filters */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/socket.h>
13 #include <ac/string.h>
14
15 #include "slap.h"
16
17 static int      get_filter_list(
18         Connection *conn,
19         BerElement *ber,
20         Filter **f,
21         char **fstr,
22         const char **text );
23
24 static int      get_substring_filter(
25         Connection *conn,
26         BerElement *ber,
27         Filter *f,
28         char **fstr,
29         const char **text );
30
31 static int filter_escape_value(
32         struct berval *in,
33         struct berval *out );
34
35 int
36 get_filter(
37         Connection *conn,
38         BerElement *ber,
39         Filter **filt,
40         char **fstr,
41         const char **text )
42 {
43         ber_tag_t       tag;
44         ber_len_t       len;
45         int             err;
46         Filter          *f;
47         char            *ftmp = NULL;
48         struct berval escaped;
49
50         Debug( LDAP_DEBUG_FILTER, "begin get_filter\n", 0, 0, 0 );
51
52         /*
53          * A filter looks like this coming in:
54          *      Filter ::= CHOICE {
55          *              and             [0]     SET OF Filter,
56          *              or              [1]     SET OF Filter,
57          *              not             [2]     Filter,
58          *              equalityMatch   [3]     AttributeValueAssertion,
59          *              substrings      [4]     SubstringFilter,
60          *              greaterOrEqual  [5]     AttributeValueAssertion,
61          *              lessOrEqual     [6]     AttributeValueAssertion,
62          *              present         [7]     AttributeType,,
63          *              approxMatch     [8]     AttributeValueAssertion
64          *              extensibleMatch [9] MatchingRuleAssertion
65          *      }
66          *
67          *      SubstringFilter ::= SEQUENCE {
68          *              type               AttributeType,
69          *              SEQUENCE OF CHOICE {
70          *                      initial          [0] IA5String,
71          *                      any              [1] IA5String,
72          *                      final            [2] IA5String
73          *              }
74          *      }
75          *
76      *  MatchingRuleAssertion ::= SEQUENCE {
77      *          matchingRule    [1] MatchingRuleId OPTIONAL,
78      *          type            [2] AttributeDescription OPTIONAL,
79      *          matchValue      [3] AssertionValue,
80      *          dnAttributes    [4] BOOLEAN DEFAULT FALSE
81          *      }
82          *
83          */
84
85         tag = ber_peek_tag( ber, &len );
86
87         if( tag == LBER_ERROR ) {
88                 *text = "error decoding filter";
89                 return SLAPD_DISCONNECT;
90         }
91
92         f = (Filter *) ch_malloc( sizeof(Filter) );
93         f->f_next = NULL;
94
95         err = LDAP_SUCCESS;
96         *fstr = NULL;
97         f->f_choice = tag; 
98
99         switch ( f->f_choice ) {
100         case LDAP_FILTER_EQUALITY:
101                 Debug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 );
102
103                 err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY, text );
104                 if ( err != LDAP_SUCCESS ) {
105                         break;
106                 }
107
108                 assert( f->f_ava != NULL );
109
110                 filter_escape_value( f->f_av_value, &escaped );
111
112                 *fstr = ch_malloc( sizeof("(=)")
113                         + f->f_av_desc->ad_cname->bv_len
114                         + escaped.bv_len );
115
116                 sprintf( *fstr, "(%s=%s)",
117                         f->f_av_desc->ad_cname->bv_val,
118                     escaped.bv_val );
119
120                 ber_memfree( escaped.bv_val );
121                 break;
122
123         case LDAP_FILTER_SUBSTRINGS:
124                 Debug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 );
125                 err = get_substring_filter( conn, ber, f, fstr, text );
126                 break;
127
128         case LDAP_FILTER_GE:
129                 Debug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 );
130
131                 err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text );
132                 if ( err != LDAP_SUCCESS ) {
133                         break;
134                 }
135
136                 filter_escape_value( f->f_av_value, &escaped );
137
138                 *fstr = ch_malloc( sizeof("(>=)")
139                         + f->f_av_desc->ad_cname->bv_len
140                         + escaped.bv_len );
141
142                 sprintf( *fstr, "(%s>=%s)",
143                         f->f_av_desc->ad_cname->bv_val,
144                     escaped.bv_val );
145
146                 ber_memfree( escaped.bv_val );
147                 break;
148
149         case LDAP_FILTER_LE:
150                 Debug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 );
151
152                 err = get_ava( ber, &f->f_ava, SLAP_MR_ORDERING, text );
153                 if ( err != LDAP_SUCCESS ) {
154                         break;
155                 }
156
157
158                 filter_escape_value( f->f_av_value, &escaped );
159
160                 *fstr = ch_malloc( sizeof("(<=)")
161                         + f->f_av_desc->ad_cname->bv_len
162                         + escaped.bv_len );
163
164                 sprintf( *fstr, "(%s<=%s)",
165                         f->f_av_desc->ad_cname->bv_val,
166                     escaped.bv_val );
167
168                 ber_memfree( escaped.bv_val );
169                 break;
170
171         case LDAP_FILTER_PRESENT: {
172                 struct berval type;
173
174                 Debug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 );
175
176                 if ( ber_scanf( ber, "o", &type ) == LBER_ERROR ) {
177                         err = SLAPD_DISCONNECT;
178                         *text = "error decoding filter";
179                         break;
180                 }
181
182                 f->f_desc = NULL;
183                 err = slap_bv2ad( &type, &f->f_desc, text );
184
185                 if( err != LDAP_SUCCESS ) {
186                         ch_free( type.bv_val );
187                         break;
188                 }
189
190                 ch_free( type.bv_val );
191
192                 *fstr = ch_malloc( sizeof("(=*)")
193                         + f->f_desc->ad_cname->bv_len );
194                 sprintf( *fstr, "(%s=*)",
195                         f->f_desc->ad_cname->bv_val );
196
197                 } break;
198
199         case LDAP_FILTER_APPROX:
200                 Debug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 );
201
202                 err = get_ava( ber, &f->f_ava, SLAP_MR_EQUALITY_APPROX, text );
203                 if ( err != LDAP_SUCCESS ) {
204                         break;
205                 }
206
207                 filter_escape_value( f->f_av_value, &escaped );
208
209                 *fstr = ch_malloc( sizeof("(~=)")
210                         + f->f_av_desc->ad_cname->bv_len
211                         + escaped.bv_len );
212
213                 sprintf( *fstr, "(%s~=%s)",
214                         f->f_av_desc->ad_cname->bv_val,
215                     escaped.bv_val );
216
217                 ber_memfree( escaped.bv_val );
218                 break;
219
220         case LDAP_FILTER_AND:
221                 Debug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 );
222                 err = get_filter_list( conn, ber, &f->f_and, &ftmp, text );
223                 if ( err != LDAP_SUCCESS ) {
224                         break;
225                 }
226                 *fstr = ch_malloc( sizeof("(&)")
227                         + ( ftmp == NULL ? 0 : strlen( ftmp ) ) );
228                 sprintf( *fstr, "(&%s)",
229                         ftmp == NULL ? "" : ftmp );
230                 break;
231
232         case LDAP_FILTER_OR:
233                 Debug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 );
234                 err = get_filter_list( conn, ber, &f->f_and, &ftmp, text );
235                 if ( err != LDAP_SUCCESS ) {
236                         break;
237                 }
238                 *fstr = ch_malloc( sizeof("(!)")
239                         + ( ftmp == NULL ? 0 : strlen( ftmp ) ) );
240                 sprintf( *fstr, "(|%s)",
241                         ftmp == NULL ? "" : ftmp );
242                 break;
243
244         case LDAP_FILTER_NOT:
245                 Debug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 );
246                 (void) ber_skip_tag( ber, &len );
247                 err = get_filter( conn, ber, &f->f_not, &ftmp, text );
248                 if ( err != LDAP_SUCCESS ) {
249                         break;
250                 }
251                 *fstr = ch_malloc( sizeof("(!)")
252                         + ( ftmp == NULL ? 0 : strlen( ftmp ) ) );
253                 sprintf( *fstr, "(!%s)",
254                         ftmp == NULL ? "" : ftmp );
255                 break;
256
257         case LDAP_FILTER_EXT:
258                 /* not yet implemented */
259                 Debug( LDAP_DEBUG_ANY, "extensible match not yet implemented.\n",
260                        f->f_choice, 0, 0 );
261                 (void) ber_skip_tag( ber, &len );
262                 f->f_choice = SLAPD_FILTER_COMPUTED;
263                 f->f_result = SLAPD_COMPARE_UNDEFINED;
264                 *fstr = ch_strdup( "(extended)" );
265                 break;
266
267         default:
268                 (void) ber_skip_tag( ber, &len );
269                 Debug( LDAP_DEBUG_ANY, "get_filter: unknown filter type=%lu\n",
270                        f->f_choice, 0, 0 );
271                 f->f_choice = SLAPD_FILTER_COMPUTED;
272                 f->f_result = SLAPD_COMPARE_UNDEFINED;
273                 *fstr = ch_strdup( "(undefined)" );
274                 break;
275         }
276
277         free( ftmp );
278
279         if ( err != LDAP_SUCCESS ) {
280                 if ( *fstr != NULL ) {
281                         free( *fstr );
282                 }
283
284                 if( err != SLAPD_DISCONNECT ) {
285                         /* ignore error */
286                         f->f_choice = SLAPD_FILTER_COMPUTED;
287                         f->f_result = SLAPD_COMPARE_UNDEFINED;
288                         *fstr = ch_strdup( "(badfilter)" );
289                         err = LDAP_SUCCESS;
290                         *filt = f;
291
292                 } else {
293                         free(f);
294                 }
295         } else {
296                 *filt = f;
297         }
298
299         Debug( LDAP_DEBUG_FILTER, "end get_filter %d\n", err, 0, 0 );
300         return( err );
301 }
302
303 static int
304 get_filter_list( Connection *conn, BerElement *ber,
305         Filter **f, char **fstr,
306         const char **text )
307 {
308         Filter          **new;
309         int             err;
310         ber_tag_t       tag;
311         ber_len_t       len;
312         char            *last, *ftmp;
313
314         Debug( LDAP_DEBUG_FILTER, "begin get_filter_list\n", 0, 0, 0 );
315
316         *fstr = NULL;
317         new = f;
318         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
319             tag = ber_next_element( ber, &len, last ) )
320         {
321                 err = get_filter( conn, ber, new, &ftmp, text );
322                 if ( err != LDAP_SUCCESS )
323                         return( err );
324
325                 if ( *fstr == NULL ) {
326                         *fstr = ftmp;
327                 } else {
328                         *fstr = ch_realloc( *fstr, strlen( *fstr ) +
329                             strlen( ftmp ) + 1 );
330                         strcat( *fstr, ftmp );
331                         free( ftmp );
332                 }
333                 new = &(*new)->f_next;
334         }
335         *new = NULL;
336
337         Debug( LDAP_DEBUG_FILTER, "end get_filter_list\n", 0, 0, 0 );
338         return( LDAP_SUCCESS );
339 }
340
341 static int
342 get_substring_filter(
343     Connection  *conn,
344     BerElement  *ber,
345     Filter      *f,
346     char        **fstr,
347         const char      **text
348 )
349 {
350         ber_tag_t       tag;
351         ber_len_t       len;
352         ber_tag_t       rc;
353         struct berval *value;
354         struct berval escaped;
355         char            *last;
356         struct berval type;
357         struct berval *nvalue;
358         *text = "error decoding filter";
359
360         Debug( LDAP_DEBUG_FILTER, "begin get_substring_filter\n", 0, 0, 0 );
361
362         if ( ber_scanf( ber, "{o" /*}*/, &type ) == LBER_ERROR ) {
363                 return SLAPD_DISCONNECT;
364         }
365
366         f->f_sub = ch_calloc( 1, sizeof(SubstringsAssertion) );
367         f->f_sub_desc = NULL;
368         rc = slap_bv2ad( &type, &f->f_sub_desc, text );
369
370         ch_free( type.bv_val );
371
372         if( rc != LDAP_SUCCESS ) {
373                 text = NULL;
374                 ch_free( f->f_sub );
375                 f->f_choice = SLAPD_FILTER_COMPUTED;
376                 f->f_result = SLAPD_COMPARE_UNDEFINED;
377                 *fstr = ch_strdup( "(undefined)" );
378                 return LDAP_SUCCESS;
379         }
380
381         f->f_sub_initial = NULL;
382         f->f_sub_any = NULL;
383         f->f_sub_final = NULL;
384
385         if( fstr ) {
386                 *fstr = ch_malloc( sizeof("(=" /*)*/) +
387                         f->f_sub_desc->ad_cname->bv_len );
388                 sprintf( *fstr, "(%s=" /*)*/, f->f_sub_desc->ad_cname->bv_val );
389         }
390
391         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
392             tag = ber_next_element( ber, &len, last ) )
393         {
394                 unsigned usage;
395
396                 rc = ber_scanf( ber, "O", &value );
397                 if ( rc == LBER_ERROR ) {
398                         rc = SLAPD_DISCONNECT;
399                         goto return_error;
400                 }
401
402                 if ( value == NULL || value->bv_len == 0 ) {
403                         ber_bvfree( value );
404                         rc = LDAP_INVALID_SYNTAX;
405                         goto return_error;
406                 } 
407
408                 switch ( tag ) {
409                 case LDAP_SUBSTRING_INITIAL:
410                         usage = SLAP_MR_SUBSTR_INITIAL;
411                         break;
412
413                 case LDAP_SUBSTRING_ANY:
414                         usage = SLAP_MR_SUBSTR_ANY;
415                         break;
416
417                 case LDAP_SUBSTRING_FINAL:
418                         usage = SLAP_MR_SUBSTR_FINAL;
419                         break;
420
421                 default:
422                         rc = LDAP_PROTOCOL_ERROR;
423
424                         Debug( LDAP_DEBUG_FILTER,
425                                 "  unknown substring choice=%ld\n",
426                                 (long) tag, 0, 0 );
427
428                         ber_bvfree( value );
429                         goto return_error;
430                 }
431
432                 rc = value_normalize( f->f_sub_desc, usage, value, &nvalue, text );
433                 ber_bvfree( value );
434
435                 if( rc != LDAP_SUCCESS ) {
436                         goto return_error;
437                 }
438
439                 value = nvalue;
440
441                 rc = LDAP_PROTOCOL_ERROR;
442
443                 switch ( tag ) {
444                 case LDAP_SUBSTRING_INITIAL:
445                         Debug( LDAP_DEBUG_FILTER, "  INITIAL\n", 0, 0, 0 );
446                         if ( f->f_sub_initial != NULL ) {
447                                 ber_bvfree( value );
448                                 goto return_error;
449                         }
450
451                         f->f_sub_initial = value;
452
453                         if( fstr ) {
454                                 filter_escape_value( value, &escaped );
455                                 *fstr = ch_realloc( *fstr,
456                                         strlen( *fstr ) + escaped.bv_len + 1 );
457                                 strcat( *fstr, escaped.bv_val );
458                                 ber_memfree( escaped.bv_val );
459                         }
460                         break;
461
462                 case LDAP_SUBSTRING_ANY:
463                         Debug( LDAP_DEBUG_FILTER, "  ANY\n", 0, 0, 0 );
464                         if( ber_bvecadd( &f->f_sub_any, value ) < 0 ) {
465                                 ber_bvfree( value );
466                                 goto return_error;
467                         }
468
469                         if( fstr ) {
470                                 filter_escape_value( value, &escaped );
471                                 *fstr = ch_realloc( *fstr,
472                                         strlen( *fstr ) + escaped.bv_len + 2 );
473                                 strcat( *fstr, "*" );
474                                 strcat( *fstr, escaped.bv_val );
475                                 ber_memfree( escaped.bv_val );
476                         }
477                         break;
478
479                 case LDAP_SUBSTRING_FINAL:
480                         Debug( LDAP_DEBUG_FILTER, "  FINAL\n", 0, 0, 0 );
481                         if ( f->f_sub_final != NULL ) {
482                                 ber_bvfree( value );
483                                 goto return_error;
484                         }
485                         f->f_sub_final = value;
486
487                         if( fstr ) {
488                                 filter_escape_value( value, &escaped );
489                                 *fstr = ch_realloc( *fstr,
490                                         strlen( *fstr ) + escaped.bv_len + 2 );
491                                 strcat( *fstr, "*" );
492                                 strcat( *fstr, escaped.bv_val );
493                                 ber_memfree( escaped.bv_val );
494                         }
495                         break;
496
497                 default:
498                         Debug( LDAP_DEBUG_FILTER,
499                                 "  unknown substring type=%ld\n",
500                                 (long) tag, 0, 0 );
501
502                         ber_bvfree( value );
503
504 return_error:
505                         Debug( LDAP_DEBUG_FILTER, "  error=%ld\n",
506                                 (long) rc, 0, 0 );
507
508                         if( fstr ) {
509                                 free( *fstr );
510                                 *fstr = NULL;
511                         }
512
513                         ad_free( f->f_sub_desc, 1 );
514                         ber_bvfree( f->f_sub_initial );
515                         ber_bvecfree( f->f_sub_any );
516                         ber_bvfree( f->f_sub_final );
517                         ch_free( f->f_sub );
518                         return rc;
519                 }
520         }
521
522         if( fstr ) {
523                 *fstr = ch_realloc( *fstr, strlen( *fstr ) + 3 );
524                 if ( f->f_sub_final == NULL ) {
525                         strcat( *fstr, "*" );
526                 }
527                 strcat( *fstr, /*(*/ ")" );
528         }
529
530         Debug( LDAP_DEBUG_FILTER, "end get_substring_filter\n", 0, 0, 0 );
531         return( LDAP_SUCCESS );
532 }
533
534 void
535 filter_free( Filter *f )
536 {
537         Filter  *p, *next;
538
539         if ( f == NULL ) {
540                 return;
541         }
542
543         switch ( f->f_choice ) {
544         case LDAP_FILTER_PRESENT:
545                 ad_free( f->f_desc, 1 );
546                 break;
547
548         case LDAP_FILTER_EQUALITY:
549         case LDAP_FILTER_GE:
550         case LDAP_FILTER_LE:
551         case LDAP_FILTER_APPROX:
552                 ava_free( f->f_ava, 1 );
553                 break;
554
555         case LDAP_FILTER_SUBSTRINGS:
556                 ad_free( f->f_sub_desc, 1 );
557                 if ( f->f_sub_initial != NULL ) {
558                         ber_bvfree( f->f_sub_initial );
559                 }
560                 ber_bvecfree( f->f_sub_any );
561                 if ( f->f_sub_final != NULL ) {
562                         ber_bvfree( f->f_sub_final );
563                 }
564                 break;
565
566         case LDAP_FILTER_AND:
567         case LDAP_FILTER_OR:
568         case LDAP_FILTER_NOT:
569                 for ( p = f->f_list; p != NULL; p = next ) {
570                         next = p->f_next;
571                         filter_free( p );
572                 }
573                 break;
574
575         case SLAPD_FILTER_COMPUTED:
576                 break;
577
578         default:
579                 Debug( LDAP_DEBUG_ANY, "filter_free: unknown filter type=%lu\n",
580                        f->f_choice, 0, 0 );
581                 break;
582         }
583
584         free( f );
585 }
586
587 #ifdef LDAP_DEBUG
588 void
589 filter_print( Filter *f )
590 {
591         int     i;
592         Filter  *p;
593         struct berval escaped;
594
595         if ( f == NULL ) {
596                 fprintf( stderr, "No filter!" );
597         }
598
599         switch ( f->f_choice ) {
600         case LDAP_FILTER_EQUALITY:
601                 filter_escape_value( f->f_av_value, &escaped );
602                 fprintf( stderr, "(%s=%s)",
603                         f->f_av_desc->ad_cname->bv_val,
604                     escaped.bv_val );
605                 ber_memfree( escaped.bv_val );
606                 break;
607
608         case LDAP_FILTER_GE:
609                 filter_escape_value( f->f_av_value, &escaped );
610                 fprintf( stderr, "(%s>=%s)",
611                         f->f_av_desc->ad_cname->bv_val,
612                     escaped.bv_val );
613                 ber_memfree( escaped.bv_val );
614                 break;
615
616         case LDAP_FILTER_LE:
617                 filter_escape_value( f->f_av_value, &escaped );
618                 fprintf( stderr, "(%s<=%s)",
619                         f->f_ava->aa_desc->ad_cname->bv_val,
620                     escaped.bv_val );
621                 ber_memfree( escaped.bv_val );
622                 break;
623
624         case LDAP_FILTER_APPROX:
625                 filter_escape_value( f->f_av_value, &escaped );
626                 fprintf( stderr, "(%s~=%s)",
627                         f->f_ava->aa_desc->ad_cname->bv_val,
628                     escaped.bv_val );
629                 ber_memfree( escaped.bv_val );
630                 break;
631
632         case LDAP_FILTER_SUBSTRINGS:
633                 fprintf( stderr, "(%s=" /*)*/,
634                         f->f_sub_desc->ad_cname->bv_val );
635                 if ( f->f_sub_initial != NULL ) {
636                         filter_escape_value( f->f_sub_initial, &escaped );
637                         fprintf( stderr, "%s",
638                                 escaped.bv_val );
639                         ber_memfree( escaped.bv_val );
640                 }
641                 if ( f->f_sub_any != NULL ) {
642                         for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
643                                 filter_escape_value( f->f_sub_any[i], &escaped );
644                                 fprintf( stderr, "*%s",
645                                         escaped.bv_val );
646                                 ber_memfree( escaped.bv_val );
647                         }
648                 }
649                 if ( f->f_sub_final != NULL ) {
650                         filter_escape_value( f->f_sub_final, &escaped );
651                         fprintf( stderr,
652                                 "*%s", escaped.bv_val );
653                         ber_memfree( escaped.bv_val );
654                 }
655                 fprintf( stderr, /*(*/ ")" );
656                 break;
657
658         case LDAP_FILTER_PRESENT:
659                 fprintf( stderr, "(%s=*)",
660                         f->f_desc->ad_cname->bv_val );
661                 break;
662
663         case LDAP_FILTER_AND:
664         case LDAP_FILTER_OR:
665         case LDAP_FILTER_NOT:
666                 fprintf( stderr, "(%c" /*)*/,
667                         f->f_choice == LDAP_FILTER_AND ? '&' :
668                     f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
669                 for ( p = f->f_list; p != NULL; p = p->f_next ) {
670                         filter_print( p );
671                 }
672                 fprintf( stderr, /*(*/ ")" );
673                 break;
674
675         case SLAPD_FILTER_COMPUTED:
676                 fprintf( stderr, "(?=%s)",
677                         f->f_result == LDAP_COMPARE_FALSE ? "false" :
678                         f->f_result == LDAP_COMPARE_TRUE ? "true" :
679                         f->f_result == SLAPD_COMPARE_UNDEFINED ? "undefined" :
680                         "error" );
681                 break;
682
683         default:
684                 fprintf( stderr, "(unknown-filter=%lu)", f->f_choice );
685                 break;
686         }
687 }
688
689 #endif /* ldap_debug */
690
691 int filter_escape_value(
692         struct berval *in,
693         struct berval *out )
694 {
695         ber_len_t i;
696         assert( in );
697         assert( out );
698
699         out->bv_val = (char *) ch_malloc( ( in->bv_len * 3 ) + 1 );
700         out->bv_len = 0;
701
702 #undef NIBBLE
703 #undef ESCAPE_LO
704 #undef ESCAPE_HI
705 #define NIBBLE(c) ((c)&0x0f)
706 #define ESCAPE_LO(c) ( NIBBLE(c) + ( NIBBLE(c) < 10 ? '0' : 'A' - 10 ) )
707 #define ESCAPE_HI(c) ( ESCAPE_LO((c)>>4) )
708
709         for( i=0; i < in->bv_len ; i++ ) {
710                 if( FILTER_ESCAPE(in->bv_val[i]) ) {
711                         out->bv_val[out->bv_len++] = '\\';
712                         out->bv_val[out->bv_len++] = ESCAPE_HI( in->bv_val[i] );
713                         out->bv_val[out->bv_len++] = ESCAPE_LO( in->bv_val[i] );
714                 } else {
715                         out->bv_val[out->bv_len++] = in->bv_val[i];
716                 }
717         }
718
719         out->bv_val[out->bv_len] = '\0';
720         return LDAP_SUCCESS;
721 }
722
723