msvcirt: Fix ostream_print_char on 0 character.
[wine.git] / libs / ldap / libldap / filter.c
blob5eb54583b58cd0ab248af4e7daa54f4c492e9ef8
1 /* search.c */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2022 The OpenLDAP Foundation.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
16 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
17 * All rights reserved.
20 #include "portable.h"
22 #include <stdio.h>
24 #include <ac/stdlib.h>
26 #include <ac/socket.h>
27 #include <ac/string.h>
28 #include <ac/time.h>
30 #include "ldap-int.h"
32 static int put_simple_vrFilter LDAP_P((
33 BerElement *ber,
34 char *str ));
36 static int put_vrFilter_list LDAP_P((
37 BerElement *ber,
38 char *str ));
40 static char *put_complex_filter LDAP_P((
41 BerElement *ber,
42 char *str,
43 ber_tag_t tag,
44 int not ));
46 static int put_simple_filter LDAP_P((
47 BerElement *ber,
48 char *str ));
50 static int put_substring_filter LDAP_P((
51 BerElement *ber,
52 char *type,
53 char *str,
54 char *nextstar ));
56 static int put_filter_list LDAP_P((
57 BerElement *ber,
58 char *str,
59 ber_tag_t tag ));
61 static int ldap_is_oid ( const char *str )
63 int i;
65 if( LDAP_ALPHA( str[0] )) {
66 for( i=1; str[i]; i++ ) {
67 if( !LDAP_LDH( str[i] )) {
68 return 0;
71 return 1;
73 } else if LDAP_DIGIT( str[0] ) {
74 int dot=0;
75 for( i=1; str[i]; i++ ) {
76 if( LDAP_DIGIT( str[i] )) {
77 dot=0;
79 } else if ( str[i] == '.' ) {
80 if( ++dot > 1 ) return 0;
82 } else {
83 return 0;
86 return !dot;
89 return 0;
92 static int ldap_is_desc ( const char *str )
94 int i;
96 if( LDAP_ALPHA( str[0] )) {
97 for( i=1; str[i]; i++ ) {
98 if( str[i] == ';' ) {
99 str = &str[i+1];
100 goto options;
103 if( !LDAP_LDH( str[i] )) {
104 return 0;
107 return 1;
109 } else if LDAP_DIGIT( str[0] ) {
110 int dot=0;
111 for( i=1; str[i]; i++ ) {
112 if( str[i] == ';' ) {
113 if( dot ) return 0;
114 str = &str[i+1];
115 goto options;
118 if( LDAP_DIGIT( str[i] )) {
119 dot=0;
121 } else if ( str[i] == '.' ) {
122 if( ++dot > 1 ) return 0;
124 } else {
125 return 0;
128 return !dot;
131 return 0;
133 options:
134 if( !LDAP_LDH( str[0] )) {
135 return 0;
137 for( i=1; str[i]; i++ ) {
138 if( str[i] == ';' ) {
139 str = &str[i+1];
140 goto options;
142 if( !LDAP_LDH( str[i] )) {
143 return 0;
146 return 1;
149 static char *
150 find_right_paren( char *s )
152 int balance, escape;
154 balance = 1;
155 escape = 0;
156 while ( *s && balance ) {
157 if ( !escape ) {
158 if ( *s == '(' ) {
159 balance++;
160 } else if ( *s == ')' ) {
161 balance--;
165 escape = ( *s == '\\' && !escape );
167 if ( balance ) s++;
170 return *s ? s : NULL;
173 static int hex2value( int c )
175 if( c >= '0' && c <= '9' ) {
176 return c - '0';
179 if( c >= 'A' && c <= 'F' ) {
180 return c + (10 - (int) 'A');
183 if( c >= 'a' && c <= 'f' ) {
184 return c + (10 - (int) 'a');
187 return -1;
190 char *
191 ldap_pvt_find_wildcard( const char *s )
193 for( ; *s; s++ ) {
194 switch( *s ) {
195 case '*': /* found wildcard */
196 return (char *) s;
198 case '(':
199 case ')':
200 return NULL;
202 case '\\':
203 if( s[1] == '\0' ) return NULL;
205 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
206 s+=2;
208 } else switch( s[1] ) {
209 default:
210 return NULL;
212 /* allow RFC 1960 escapes */
213 case '*':
214 case '(':
215 case ')':
216 case '\\':
217 s++;
222 return (char *) s;
225 /* unescape filter value */
226 /* support both LDAP v2 and v3 escapes */
227 /* output can include nul characters! */
228 ber_slen_t
229 ldap_pvt_filter_value_unescape( char *fval )
231 ber_slen_t r, v;
232 int v1, v2;
234 for( r=v=0; fval[v] != '\0'; v++ ) {
235 switch( fval[v] ) {
236 case '(':
237 case ')':
238 case '*':
239 return -1;
241 case '\\':
242 /* escape */
243 v++;
245 if ( fval[v] == '\0' ) {
246 /* escape at end of string */
247 return -1;
250 if (( v1 = hex2value( fval[v] )) >= 0 ) {
251 /* LDAPv3 escape */
252 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
253 /* must be two digit code */
254 return -1;
257 fval[r++] = v1 * 16 + v2;
258 v++;
260 } else {
261 /* LDAPv2 escape */
262 switch( fval[v] ) {
263 case '(':
264 case ')':
265 case '*':
266 case '\\':
267 fval[r++] = fval[v];
268 break;
269 default:
270 /* illegal escape */
271 return -1;
274 break;
276 default:
277 fval[r++] = fval[v];
281 fval[r] = '\0';
282 return r;
285 static char *
286 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
288 char *next;
291 * We have (x(filter)...) with str sitting on
292 * the x. We have to find the paren matching
293 * the one before the x and put the intervening
294 * filters by calling put_filter_list().
297 /* put explicit tag */
298 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
299 return NULL;
302 str++;
303 if ( (next = find_right_paren( str )) == NULL ) {
304 return NULL;
307 *next = '\0';
308 if ( put_filter_list( ber, str, tag ) == -1 ) {
309 return NULL;
312 /* close the '(' */
313 *next++ = ')';
315 /* flush explicit tagged thang */
316 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
317 return NULL;
320 return next;
324 ldap_pvt_put_filter( BerElement *ber, const char *str_in )
326 int rc;
327 char *freeme;
328 char *str;
329 char *next;
330 int parens, balance, escape;
333 * A Filter looks like this (RFC 4511 as extended by RFC 4526):
334 * Filter ::= CHOICE {
335 * and [0] SET SIZE (0..MAX) OF filter Filter,
336 * or [1] SET SIZE (0..MAX) OF filter Filter,
337 * not [2] Filter,
338 * equalityMatch [3] AttributeValueAssertion,
339 * substrings [4] SubstringFilter,
340 * greaterOrEqual [5] AttributeValueAssertion,
341 * lessOrEqual [6] AttributeValueAssertion,
342 * present [7] AttributeDescription,
343 * approxMatch [8] AttributeValueAssertion,
344 * extensibleMatch [9] MatchingRuleAssertion,
345 * ... }
347 * SubstringFilter ::= SEQUENCE {
348 * type AttributeDescription,
349 * substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
350 * initial [0] AssertionValue, -- only once
351 * any [1] AssertionValue,
352 * final [2] AssertionValue -- only once
356 * MatchingRuleAssertion ::= SEQUENCE {
357 * matchingRule [1] MatchingRuleId OPTIONAL,
358 * type [2] AttributeDescription OPTIONAL,
359 * matchValue [3] AssertionValue,
360 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
362 * Note: tags in a CHOICE are always explicit
365 Debug1( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in );
367 freeme = LDAP_STRDUP( str_in );
368 if( freeme == NULL ) return LDAP_NO_MEMORY;
369 str = freeme;
371 parens = 0;
372 while ( *str ) {
373 switch ( *str ) {
374 case '(': /*')'*/
375 str++;
376 parens++;
378 /* skip spaces */
379 while( LDAP_SPACE( *str ) ) str++;
381 switch ( *str ) {
382 case '&':
383 Debug0( LDAP_DEBUG_TRACE, "put_filter: AND\n" );
385 str = put_complex_filter( ber, str,
386 LDAP_FILTER_AND, 0 );
387 if( str == NULL ) {
388 rc = -1;
389 goto done;
392 parens--;
393 break;
395 case '|':
396 Debug0( LDAP_DEBUG_TRACE, "put_filter: OR\n" );
398 str = put_complex_filter( ber, str,
399 LDAP_FILTER_OR, 0 );
400 if( str == NULL ) {
401 rc = -1;
402 goto done;
405 parens--;
406 break;
408 case '!':
409 Debug0( LDAP_DEBUG_TRACE, "put_filter: NOT\n" );
411 str = put_complex_filter( ber, str,
412 LDAP_FILTER_NOT, 0 );
413 if( str == NULL ) {
414 rc = -1;
415 goto done;
418 parens--;
419 break;
421 case '(':
422 rc = -1;
423 goto done;
425 default:
426 Debug0( LDAP_DEBUG_TRACE, "put_filter: simple\n" );
428 balance = 1;
429 escape = 0;
430 next = str;
432 while ( *next && balance ) {
433 if ( escape == 0 ) {
434 if ( *next == '(' ) {
435 balance++;
436 } else if ( *next == ')' ) {
437 balance--;
441 if ( *next == '\\' && ! escape ) {
442 escape = 1;
443 } else {
444 escape = 0;
447 if ( balance ) next++;
450 if ( balance != 0 ) {
451 rc = -1;
452 goto done;
455 *next = '\0';
457 if ( put_simple_filter( ber, str ) == -1 ) {
458 rc = -1;
459 goto done;
462 *next++ = /*'('*/ ')';
464 str = next;
465 parens--;
466 break;
468 break;
470 case /*'('*/ ')':
471 Debug0( LDAP_DEBUG_TRACE, "put_filter: end\n" );
472 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
473 rc = -1;
474 goto done;
476 str++;
477 parens--;
478 break;
480 case ' ':
481 str++;
482 break;
484 default: /* assume it's a simple type=value filter */
485 Debug0( LDAP_DEBUG_TRACE, "put_filter: default\n" );
486 next = strchr( str, '\0' );
487 if ( put_simple_filter( ber, str ) == -1 ) {
488 rc = -1;
489 goto done;
491 str = next;
492 break;
494 if ( !parens )
495 break;
498 rc = ( parens || *str ) ? -1 : 0;
500 done:
501 LDAP_FREE( freeme );
502 return rc;
506 * Put a list of filters like this "(filter1)(filter2)..."
509 static int
510 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
512 char *next = NULL;
513 char save;
515 Debug1( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
516 str );
518 while ( *str ) {
519 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
520 str++;
522 if ( *str == '\0' ) break;
524 if ( (next = find_right_paren( str + 1 )) == NULL ) {
525 return -1;
527 save = *++next;
529 /* now we have "(filter)" with str pointing to it */
530 *next = '\0';
531 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1;
532 *next = save;
533 str = next;
535 if( tag == LDAP_FILTER_NOT ) break;
538 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
539 return -1;
542 return 0;
545 static int
546 put_simple_filter(
547 BerElement *ber,
548 char *str )
550 char *s;
551 char *value;
552 ber_tag_t ftype;
553 int rc = -1;
555 Debug1( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
556 str );
558 str = LDAP_STRDUP( str );
559 if( str == NULL ) return -1;
561 if ( (s = strchr( str, '=' )) == NULL ) {
562 goto done;
565 value = s + 1;
566 *s-- = '\0';
568 switch ( *s ) {
569 case '<':
570 ftype = LDAP_FILTER_LE;
571 *s = '\0';
572 break;
574 case '>':
575 ftype = LDAP_FILTER_GE;
576 *s = '\0';
577 break;
579 case '~':
580 ftype = LDAP_FILTER_APPROX;
581 *s = '\0';
582 break;
584 case ':':
585 /* RFC 4515 extensible filters are off the form:
586 * type [:dn] [:rule] := value
587 * or [:dn]:rule := value
589 ftype = LDAP_FILTER_EXT;
590 *s = '\0';
593 char *dn = strchr( str, ':' );
594 char *rule = NULL;
596 if( dn != NULL ) {
597 *dn++ = '\0';
598 rule = strchr( dn, ':' );
600 if( rule == NULL ) {
601 /* one colon */
602 if ( strcasecmp(dn, "dn") == 0 ) {
603 /* must have attribute */
604 if( !ldap_is_desc( str ) ) {
605 goto done;
608 rule = "";
610 } else {
611 rule = dn;
612 dn = NULL;
615 } else {
616 /* two colons */
617 *rule++ = '\0';
619 if ( strcasecmp(dn, "dn") != 0 ) {
620 /* must have "dn" */
621 goto done;
627 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
628 /* must have either type or rule */
629 goto done;
632 if ( *str != '\0' && !ldap_is_desc( str ) ) {
633 goto done;
636 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
637 goto done;
640 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
642 if( rc != -1 && rule && *rule != '\0' ) {
643 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
646 if( rc != -1 && *str != '\0' ) {
647 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
650 if( rc != -1 ) {
651 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
653 if( len >= 0 ) {
654 rc = ber_printf( ber, "to",
655 LDAP_FILTER_EXT_VALUE, value, len );
656 } else {
657 rc = -1;
661 if( rc != -1 && dn ) {
662 rc = ber_printf( ber, "tb",
663 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
666 if( rc != -1 ) {
667 rc = ber_printf( ber, /*"{"*/ "N}" );
670 goto done;
672 default:
673 if( !ldap_is_desc( str ) ) {
674 goto done;
676 } else {
677 char *nextstar = ldap_pvt_find_wildcard( value );
679 if ( nextstar == NULL ) {
680 goto done;
682 } else if ( *nextstar == '\0' ) {
683 ftype = LDAP_FILTER_EQUALITY;
685 } else if ( strcmp( value, "*" ) == 0 ) {
686 ftype = LDAP_FILTER_PRESENT;
688 } else {
689 rc = put_substring_filter( ber, str, value, nextstar );
690 goto done;
692 } break;
695 if( !ldap_is_desc( str ) ) goto done;
697 if ( ftype == LDAP_FILTER_PRESENT ) {
698 rc = ber_printf( ber, "ts", ftype, str );
700 } else {
701 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
703 if( len >= 0 ) {
704 rc = ber_printf( ber, "t{soN}",
705 ftype, str, value, len );
709 done:
710 if( rc != -1 ) rc = 0;
711 LDAP_FREE( str );
712 return rc;
715 static int
716 put_substring_filter( BerElement *ber, char *type, char *val, char *nextstar )
718 int gotstar = 0;
719 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
721 Debug2( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
722 type, val );
724 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
725 return -1;
728 for( ; *val; val=nextstar ) {
729 if ( gotstar )
730 nextstar = ldap_pvt_find_wildcard( val );
732 if ( nextstar == NULL ) {
733 return -1;
736 if ( *nextstar == '\0' ) {
737 ftype = LDAP_SUBSTRING_FINAL;
738 } else {
739 *nextstar++ = '\0';
740 if ( gotstar++ == 0 ) {
741 ftype = LDAP_SUBSTRING_INITIAL;
742 } else {
743 ftype = LDAP_SUBSTRING_ANY;
747 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
748 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
750 if ( len <= 0 ) {
751 return -1;
754 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
755 return -1;
760 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {
761 return -1;
764 return 0;
767 static int
768 put_vrFilter( BerElement *ber, const char *str_in )
770 int rc;
771 char *freeme;
772 char *str;
773 char *next;
774 int parens, balance, escape;
777 * A ValuesReturnFilter looks like this:
779 * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
780 * SimpleFilterItem ::= CHOICE {
781 * equalityMatch [3] AttributeValueAssertion,
782 * substrings [4] SubstringFilter,
783 * greaterOrEqual [5] AttributeValueAssertion,
784 * lessOrEqual [6] AttributeValueAssertion,
785 * present [7] AttributeType,
786 * approxMatch [8] AttributeValueAssertion,
787 * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3
790 * SubstringFilter ::= SEQUENCE {
791 * type AttributeType,
792 * SEQUENCE OF CHOICE {
793 * initial [0] IA5String,
794 * any [1] IA5String,
795 * final [2] IA5String
799 * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
800 * matchingRule [1] MatchingRuleId OPTIONAL,
801 * type [2] AttributeDescription OPTIONAL,
802 * matchValue [3] AssertionValue }
804 * (Source: RFC 3876)
807 Debug1( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in );
809 freeme = LDAP_STRDUP( str_in );
810 if( freeme == NULL ) return LDAP_NO_MEMORY;
811 str = freeme;
813 parens = 0;
814 while ( *str ) {
815 switch ( *str ) {
816 case '(': /*')'*/
817 str++;
818 parens++;
820 /* skip spaces */
821 while( LDAP_SPACE( *str ) ) str++;
823 switch ( *str ) {
824 case '(':
825 if ( (next = find_right_paren( str )) == NULL ) {
826 rc = -1;
827 goto done;
830 *next = '\0';
832 if ( put_vrFilter_list( ber, str ) == -1 ) {
833 rc = -1;
834 goto done;
837 /* close the '(' */
838 *next++ = ')';
840 str = next;
842 parens--;
843 break;
846 default:
847 Debug0( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n" );
849 balance = 1;
850 escape = 0;
851 next = str;
853 while ( *next && balance ) {
854 if ( escape == 0 ) {
855 if ( *next == '(' ) {
856 balance++;
857 } else if ( *next == ')' ) {
858 balance--;
862 if ( *next == '\\' && ! escape ) {
863 escape = 1;
864 } else {
865 escape = 0;
868 if ( balance ) next++;
871 if ( balance != 0 ) {
872 rc = -1;
873 goto done;
876 *next = '\0';
878 if ( put_simple_vrFilter( ber, str ) == -1 ) {
879 rc = -1;
880 goto done;
883 *next++ = /*'('*/ ')';
885 str = next;
886 parens--;
887 break;
889 break;
891 case /*'('*/ ')':
892 Debug0( LDAP_DEBUG_TRACE, "put_vrFilter: end\n" );
893 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
894 rc = -1;
895 goto done;
897 str++;
898 parens--;
899 break;
901 case ' ':
902 str++;
903 break;
905 default: /* assume it's a simple type=value filter */
906 Debug0( LDAP_DEBUG_TRACE, "put_vrFilter: default\n" );
907 next = strchr( str, '\0' );
908 if ( put_simple_vrFilter( ber, str ) == -1 ) {
909 rc = -1;
910 goto done;
912 str = next;
913 break;
917 rc = parens ? -1 : 0;
919 done:
920 LDAP_FREE( freeme );
921 return rc;
925 ldap_put_vrFilter( BerElement *ber, const char *str_in )
927 int rc =0;
929 if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) {
930 return -1;
933 rc = put_vrFilter( ber, str_in );
935 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
936 rc = -1;
939 return rc;
942 static int
943 put_vrFilter_list( BerElement *ber, char *str )
945 char *next = NULL;
946 char save;
948 Debug1( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n",
949 str );
951 while ( *str ) {
952 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
953 str++;
955 if ( *str == '\0' ) break;
957 if ( (next = find_right_paren( str + 1 )) == NULL ) {
958 return -1;
960 save = *++next;
962 /* now we have "(filter)" with str pointing to it */
963 *next = '\0';
964 if ( put_vrFilter( ber, str ) == -1 ) return -1;
965 *next = save;
966 str = next;
969 return 0;
972 static int
973 put_simple_vrFilter(
974 BerElement *ber,
975 char *str )
977 char *s;
978 char *value;
979 ber_tag_t ftype;
980 int rc = -1;
982 Debug1( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n",
983 str );
985 str = LDAP_STRDUP( str );
986 if( str == NULL ) return -1;
988 if ( (s = strchr( str, '=' )) == NULL ) {
989 goto done;
992 value = s + 1;
993 *s-- = '\0';
995 switch ( *s ) {
996 case '<':
997 ftype = LDAP_FILTER_LE;
998 *s = '\0';
999 break;
1001 case '>':
1002 ftype = LDAP_FILTER_GE;
1003 *s = '\0';
1004 break;
1006 case '~':
1007 ftype = LDAP_FILTER_APPROX;
1008 *s = '\0';
1009 break;
1011 case ':':
1012 /* According to ValuesReturnFilter control definition
1013 * extensible filters are off the form:
1014 * type [:rule] := value
1015 * or :rule := value
1017 ftype = LDAP_FILTER_EXT;
1018 *s = '\0';
1021 char *rule = strchr( str, ':' );
1023 if( rule == NULL ) {
1024 /* must have attribute */
1025 if( !ldap_is_desc( str ) ) {
1026 goto done;
1028 rule = "";
1029 } else {
1030 *rule++ = '\0';
1033 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
1034 /* must have either type or rule */
1035 goto done;
1038 if ( *str != '\0' && !ldap_is_desc( str ) ) {
1039 goto done;
1042 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
1043 goto done;
1046 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
1048 if( rc != -1 && rule && *rule != '\0' ) {
1049 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
1052 if( rc != -1 && *str != '\0' ) {
1053 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
1056 if( rc != -1 ) {
1057 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1059 if( len >= 0 ) {
1060 rc = ber_printf( ber, "to",
1061 LDAP_FILTER_EXT_VALUE, value, len );
1062 } else {
1063 rc = -1;
1067 if( rc != -1 ) {
1068 rc = ber_printf( ber, /*"{"*/ "N}" );
1071 goto done;
1073 default:
1074 if( !ldap_is_desc( str ) ) {
1075 goto done;
1077 } else {
1078 char *nextstar = ldap_pvt_find_wildcard( value );
1080 if ( nextstar == NULL ) {
1081 goto done;
1083 } else if ( *nextstar == '\0' ) {
1084 ftype = LDAP_FILTER_EQUALITY;
1086 } else if ( strcmp( value, "*" ) == 0 ) {
1087 ftype = LDAP_FILTER_PRESENT;
1089 } else {
1090 rc = put_substring_filter( ber, str, value, nextstar );
1091 goto done;
1093 } break;
1096 if( !ldap_is_desc( str ) ) goto done;
1098 if ( ftype == LDAP_FILTER_PRESENT ) {
1099 rc = ber_printf( ber, "ts", ftype, str );
1101 } else {
1102 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1104 if( len >= 0 ) {
1105 rc = ber_printf( ber, "t{soN}",
1106 ftype, str, value, len );
1110 done:
1111 if( rc != -1 ) rc = 0;
1112 LDAP_FREE( str );
1113 return rc;