3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2022 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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.
24 #include <ac/stdlib.h>
26 #include <ac/socket.h>
27 #include <ac/string.h>
32 static int put_simple_vrFilter
LDAP_P((
36 static int put_vrFilter_list
LDAP_P((
40 static char *put_complex_filter
LDAP_P((
46 static int put_simple_filter
LDAP_P((
50 static int put_substring_filter
LDAP_P((
56 static int put_filter_list
LDAP_P((
61 static int ldap_is_oid ( const char *str
)
65 if( LDAP_ALPHA( str
[0] )) {
66 for( i
=1; str
[i
]; i
++ ) {
67 if( !LDAP_LDH( str
[i
] )) {
73 } else if LDAP_DIGIT( str
[0] ) {
75 for( i
=1; str
[i
]; i
++ ) {
76 if( LDAP_DIGIT( str
[i
] )) {
79 } else if ( str
[i
] == '.' ) {
80 if( ++dot
> 1 ) return 0;
92 static int ldap_is_desc ( const char *str
)
96 if( LDAP_ALPHA( str
[0] )) {
97 for( i
=1; str
[i
]; i
++ ) {
103 if( !LDAP_LDH( str
[i
] )) {
109 } else if LDAP_DIGIT( str
[0] ) {
111 for( i
=1; str
[i
]; i
++ ) {
112 if( str
[i
] == ';' ) {
118 if( LDAP_DIGIT( str
[i
] )) {
121 } else if ( str
[i
] == '.' ) {
122 if( ++dot
> 1 ) return 0;
134 if( !LDAP_LDH( str
[0] )) {
137 for( i
=1; str
[i
]; i
++ ) {
138 if( str
[i
] == ';' ) {
142 if( !LDAP_LDH( str
[i
] )) {
150 find_right_paren( char *s
)
156 while ( *s
&& balance
) {
160 } else if ( *s
== ')' ) {
165 escape
= ( *s
== '\\' && !escape
);
170 return *s
? s
: NULL
;
173 static int hex2value( int c
)
175 if( c
>= '0' && c
<= '9' ) {
179 if( c
>= 'A' && c
<= 'F' ) {
180 return c
+ (10 - (int) 'A');
183 if( c
>= 'a' && c
<= 'f' ) {
184 return c
+ (10 - (int) 'a');
191 ldap_pvt_find_wildcard( const char *s
)
195 case '*': /* found wildcard */
203 if( s
[1] == '\0' ) return NULL
;
205 if( LDAP_HEX( s
[1] ) && LDAP_HEX( s
[2] ) ) {
208 } else switch( s
[1] ) {
212 /* allow RFC 1960 escapes */
225 /* unescape filter value */
226 /* support both LDAP v2 and v3 escapes */
227 /* output can include nul characters! */
229 ldap_pvt_filter_value_unescape( char *fval
)
234 for( r
=v
=0; fval
[v
] != '\0'; v
++ ) {
245 if ( fval
[v
] == '\0' ) {
246 /* escape at end of string */
250 if (( v1
= hex2value( fval
[v
] )) >= 0 ) {
252 if (( v2
= hex2value( fval
[v
+1] )) < 0 ) {
253 /* must be two digit code */
257 fval
[r
++] = v1
* 16 + v2
;
286 put_complex_filter( BerElement
*ber
, char *str
, ber_tag_t tag
, int not )
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 ) {
303 if ( (next
= find_right_paren( str
)) == NULL
) {
308 if ( put_filter_list( ber
, str
, tag
) == -1 ) {
315 /* flush explicit tagged thang */
316 if ( ber_printf( ber
, /*"{"*/ "N}" ) == -1 ) {
324 ldap_pvt_put_filter( BerElement
*ber
, const char *str_in
)
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,
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,
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
;
379 while( LDAP_SPACE( *str
) ) str
++;
383 Debug0( LDAP_DEBUG_TRACE
, "put_filter: AND\n" );
385 str
= put_complex_filter( ber
, str
,
386 LDAP_FILTER_AND
, 0 );
396 Debug0( LDAP_DEBUG_TRACE
, "put_filter: OR\n" );
398 str
= put_complex_filter( ber
, str
,
409 Debug0( LDAP_DEBUG_TRACE
, "put_filter: NOT\n" );
411 str
= put_complex_filter( ber
, str
,
412 LDAP_FILTER_NOT
, 0 );
426 Debug0( LDAP_DEBUG_TRACE
, "put_filter: simple\n" );
432 while ( *next
&& balance
) {
434 if ( *next
== '(' ) {
436 } else if ( *next
== ')' ) {
441 if ( *next
== '\\' && ! escape
) {
447 if ( balance
) next
++;
450 if ( balance
!= 0 ) {
457 if ( put_simple_filter( ber
, str
) == -1 ) {
462 *next
++ = /*'('*/ ')';
471 Debug0( LDAP_DEBUG_TRACE
, "put_filter: end\n" );
472 if ( ber_printf( ber
, /*"["*/ "]" ) == -1 ) {
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 ) {
498 rc
= ( parens
|| *str
) ? -1 : 0;
506 * Put a list of filters like this "(filter1)(filter2)..."
510 put_filter_list( BerElement
*ber
, char *str
, ber_tag_t tag
)
515 Debug1( LDAP_DEBUG_TRACE
, "put_filter_list \"%s\"\n",
519 while ( *str
&& LDAP_SPACE( (unsigned char) *str
) ) {
522 if ( *str
== '\0' ) break;
524 if ( (next
= find_right_paren( str
+ 1 )) == NULL
) {
529 /* now we have "(filter)" with str pointing to it */
531 if ( ldap_pvt_put_filter( ber
, str
) == -1 ) return -1;
535 if( tag
== LDAP_FILTER_NOT
) break;
538 if( tag
== LDAP_FILTER_NOT
&& ( next
== NULL
|| *str
)) {
555 Debug1( LDAP_DEBUG_TRACE
, "put_simple_filter: \"%s\"\n",
558 str
= LDAP_STRDUP( str
);
559 if( str
== NULL
) return -1;
561 if ( (s
= strchr( str
, '=' )) == NULL
) {
570 ftype
= LDAP_FILTER_LE
;
575 ftype
= LDAP_FILTER_GE
;
580 ftype
= LDAP_FILTER_APPROX
;
585 /* RFC 4515 extensible filters are off the form:
586 * type [:dn] [:rule] := value
587 * or [:dn]:rule := value
589 ftype
= LDAP_FILTER_EXT
;
593 char *dn
= strchr( str
, ':' );
598 rule
= strchr( dn
, ':' );
602 if ( strcasecmp(dn
, "dn") == 0 ) {
603 /* must have attribute */
604 if( !ldap_is_desc( str
) ) {
619 if ( strcasecmp(dn
, "dn") != 0 ) {
627 if ( *str
== '\0' && ( !rule
|| *rule
== '\0' ) ) {
628 /* must have either type or rule */
632 if ( *str
!= '\0' && !ldap_is_desc( str
) ) {
636 if ( rule
&& *rule
!= '\0' && !ldap_is_oid( rule
) ) {
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
);
651 ber_slen_t len
= ldap_pvt_filter_value_unescape( value
);
654 rc
= ber_printf( ber
, "to",
655 LDAP_FILTER_EXT_VALUE
, value
, len
);
661 if( rc
!= -1 && dn
) {
662 rc
= ber_printf( ber
, "tb",
663 LDAP_FILTER_EXT_DNATTRS
, (ber_int_t
) 1 );
667 rc
= ber_printf( ber
, /*"{"*/ "N}" );
673 if( !ldap_is_desc( str
) ) {
677 char *nextstar
= ldap_pvt_find_wildcard( value
);
679 if ( nextstar
== NULL
) {
682 } else if ( *nextstar
== '\0' ) {
683 ftype
= LDAP_FILTER_EQUALITY
;
685 } else if ( strcmp( value
, "*" ) == 0 ) {
686 ftype
= LDAP_FILTER_PRESENT
;
689 rc
= put_substring_filter( ber
, str
, value
, nextstar
);
695 if( !ldap_is_desc( str
) ) goto done
;
697 if ( ftype
== LDAP_FILTER_PRESENT
) {
698 rc
= ber_printf( ber
, "ts", ftype
, str
);
701 ber_slen_t len
= ldap_pvt_filter_value_unescape( value
);
704 rc
= ber_printf( ber
, "t{soN}",
705 ftype
, str
, value
, len
);
710 if( rc
!= -1 ) rc
= 0;
716 put_substring_filter( BerElement
*ber
, char *type
, char *val
, char *nextstar
)
719 ber_tag_t ftype
= LDAP_FILTER_SUBSTRINGS
;
721 Debug2( LDAP_DEBUG_TRACE
, "put_substring_filter \"%s=%s\"\n",
724 if ( ber_printf( ber
, "t{s{" /*"}}"*/, ftype
, type
) == -1 ) {
728 for( ; *val
; val
=nextstar
) {
730 nextstar
= ldap_pvt_find_wildcard( val
);
732 if ( nextstar
== NULL
) {
736 if ( *nextstar
== '\0' ) {
737 ftype
= LDAP_SUBSTRING_FINAL
;
740 if ( gotstar
++ == 0 ) {
741 ftype
= LDAP_SUBSTRING_INITIAL
;
743 ftype
= LDAP_SUBSTRING_ANY
;
747 if ( *val
!= '\0' || ftype
== LDAP_SUBSTRING_ANY
) {
748 ber_slen_t len
= ldap_pvt_filter_value_unescape( val
);
754 if ( ber_printf( ber
, "to", ftype
, val
, len
) == -1 ) {
760 if ( ber_printf( ber
, /*"{{"*/ "N}N}" ) == -1 ) {
768 put_vrFilter( BerElement
*ber
, const char *str_in
)
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,
795 * final [2] IA5String
799 * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
800 * matchingRule [1] MatchingRuleId OPTIONAL,
801 * type [2] AttributeDescription OPTIONAL,
802 * matchValue [3] AssertionValue }
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
;
821 while( LDAP_SPACE( *str
) ) str
++;
825 if ( (next
= find_right_paren( str
)) == NULL
) {
832 if ( put_vrFilter_list( ber
, str
) == -1 ) {
847 Debug0( LDAP_DEBUG_TRACE
, "put_vrFilter: simple\n" );
853 while ( *next
&& balance
) {
855 if ( *next
== '(' ) {
857 } else if ( *next
== ')' ) {
862 if ( *next
== '\\' && ! escape
) {
868 if ( balance
) next
++;
871 if ( balance
!= 0 ) {
878 if ( put_simple_vrFilter( ber
, str
) == -1 ) {
883 *next
++ = /*'('*/ ')';
892 Debug0( LDAP_DEBUG_TRACE
, "put_vrFilter: end\n" );
893 if ( ber_printf( ber
, /*"["*/ "]" ) == -1 ) {
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 ) {
917 rc
= parens
? -1 : 0;
925 ldap_put_vrFilter( BerElement
*ber
, const char *str_in
)
929 if ( ber_printf( ber
, "{" /*"}"*/ ) == -1 ) {
933 rc
= put_vrFilter( ber
, str_in
);
935 if ( ber_printf( ber
, /*"{"*/ "N}" ) == -1 ) {
943 put_vrFilter_list( BerElement
*ber
, char *str
)
948 Debug1( LDAP_DEBUG_TRACE
, "put_vrFilter_list \"%s\"\n",
952 while ( *str
&& LDAP_SPACE( (unsigned char) *str
) ) {
955 if ( *str
== '\0' ) break;
957 if ( (next
= find_right_paren( str
+ 1 )) == NULL
) {
962 /* now we have "(filter)" with str pointing to it */
964 if ( put_vrFilter( ber
, str
) == -1 ) return -1;
982 Debug1( LDAP_DEBUG_TRACE
, "put_simple_vrFilter: \"%s\"\n",
985 str
= LDAP_STRDUP( str
);
986 if( str
== NULL
) return -1;
988 if ( (s
= strchr( str
, '=' )) == NULL
) {
997 ftype
= LDAP_FILTER_LE
;
1002 ftype
= LDAP_FILTER_GE
;
1007 ftype
= LDAP_FILTER_APPROX
;
1012 /* According to ValuesReturnFilter control definition
1013 * extensible filters are off the form:
1014 * type [:rule] := value
1017 ftype
= LDAP_FILTER_EXT
;
1021 char *rule
= strchr( str
, ':' );
1023 if( rule
== NULL
) {
1024 /* must have attribute */
1025 if( !ldap_is_desc( str
) ) {
1033 if ( *str
== '\0' && ( !rule
|| *rule
== '\0' ) ) {
1034 /* must have either type or rule */
1038 if ( *str
!= '\0' && !ldap_is_desc( str
) ) {
1042 if ( rule
&& *rule
!= '\0' && !ldap_is_oid( rule
) ) {
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
);
1057 ber_slen_t len
= ldap_pvt_filter_value_unescape( value
);
1060 rc
= ber_printf( ber
, "to",
1061 LDAP_FILTER_EXT_VALUE
, value
, len
);
1068 rc
= ber_printf( ber
, /*"{"*/ "N}" );
1074 if( !ldap_is_desc( str
) ) {
1078 char *nextstar
= ldap_pvt_find_wildcard( value
);
1080 if ( nextstar
== NULL
) {
1083 } else if ( *nextstar
== '\0' ) {
1084 ftype
= LDAP_FILTER_EQUALITY
;
1086 } else if ( strcmp( value
, "*" ) == 0 ) {
1087 ftype
= LDAP_FILTER_PRESENT
;
1090 rc
= put_substring_filter( ber
, str
, value
, nextstar
);
1096 if( !ldap_is_desc( str
) ) goto done
;
1098 if ( ftype
== LDAP_FILTER_PRESENT
) {
1099 rc
= ber_printf( ber
, "ts", ftype
, str
);
1102 ber_slen_t len
= ldap_pvt_filter_value_unescape( value
);
1105 rc
= ber_printf( ber
, "t{soN}",
1106 ftype
, str
, value
, len
);
1111 if( rc
!= -1 ) rc
= 0;