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