3 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright (c) 1990 Regents of the University of Michigan.
13 * Portions Copyright (C) The Internet Society (1997)
14 * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
21 #include <ac/stdlib.h>
23 #include <ac/socket.h>
24 #include <ac/string.h>
29 static int put_simple_vrFilter LDAP_P((
33 static int put_vrFilter_list LDAP_P((
37 static char *put_complex_filter LDAP_P((
43 static int put_simple_filter LDAP_P((
47 static int put_substring_filter LDAP_P((
52 static int put_filter_list LDAP_P((
57 static int ldap_is_oid ( const char *str )
61 if( LDAP_ALPHA( str[0] )) {
62 for( i=1; str[i]; i++ ) {
63 if( !LDAP_LDH( str[i] )) {
69 } else if LDAP_DIGIT( str[0] ) {
71 for( i=1; str[i]; i++ ) {
72 if( LDAP_DIGIT( str[i] )) {
75 } else if ( str[i] == '.' ) {
77 if( ++dot > 1 ) return 0;
89 static int ldap_is_desc ( const char *str )
93 if( LDAP_ALPHA( str[0] )) {
94 for( i=1; str[i]; i++ ) {
100 if( !LDAP_LDH( str[i] )) {
106 } else if LDAP_DIGIT( str[0] ) {
108 for( i=1; str[i]; i++ ) {
109 if( str[i] == ';' ) {
115 if( LDAP_DIGIT( str[i] )) {
118 } else if ( str[i] == '.' ) {
120 if( ++dot > 1 ) return 0;
132 if( !LDAP_LDH( str[0] )) {
135 for( i=1; str[i]; i++ ) {
136 if( str[i] == ';' ) {
140 if( !LDAP_LDH( str[i] )) {
148 find_right_paren( char *s )
154 while ( *s && balance ) {
158 } else if ( *s == ')' ) {
163 escape = ( *s == '\\' && !escape );
168 return *s ? s : NULL;
171 static int hex2value( int c )
173 if( c >= '0' && c <= '9' ) {
177 if( c >= 'A' && c <= 'F' ) {
178 return c + (10 - (int) 'A');
181 if( c >= 'a' && c <= 'f' ) {
182 return c + (10 - (int) 'a');
189 ldap_pvt_find_wildcard( const char *s )
193 case '*': /* found wildcard */
201 if( s[1] == '\0' ) return NULL;
203 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
206 } else switch( s[1] ) {
210 /* allow RFC 1960 escapes */
223 /* unescape filter value */
224 /* support both LDAP v2 and v3 escapes */
225 /* output can include nul characters! */
227 ldap_pvt_filter_value_unescape( char *fval )
232 for( r=v=0; fval[v] != '\0'; v++ ) {
243 if ( fval[v] == '\0' ) {
244 /* escape at end of string */
248 if (( v1 = hex2value( fval[v] )) >= 0 ) {
250 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
251 /* must be two digit code */
255 fval[r++] = v1 * 16 + v2;
284 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
289 * We have (x(filter)...) with str sitting on
290 * the x. We have to find the paren matching
291 * the one before the x and put the intervening
292 * filters by calling put_filter_list().
295 /* put explicit tag */
296 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
301 if ( (next = find_right_paren( str )) == NULL ) {
306 if ( put_filter_list( ber, str, tag ) == -1 ) {
313 /* flush explicit tagged thang */
314 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
322 ldap_pvt_put_filter( BerElement *ber, const char *str_in )
328 int parens, balance, escape;
331 * A Filter looks like this:
332 * Filter ::= CHOICE {
333 * and [0] SET OF Filter,
334 * or [1] SET OF Filter,
336 * equalityMatch [3] AttributeValueAssertion,
337 * substrings [4] SubstringFilter,
338 * greaterOrEqual [5] AttributeValueAssertion,
339 * lessOrEqual [6] AttributeValueAssertion,
340 * present [7] AttributeType,
341 * approxMatch [8] AttributeValueAssertion,
342 * extensibleMatch [9] MatchingRuleAssertion -- LDAPv3
345 * SubstringFilter ::= SEQUENCE {
346 * type AttributeType,
347 * SEQUENCE OF CHOICE {
348 * initial [0] IA5String,
350 * final [2] IA5String
354 * MatchingRuleAssertion ::= SEQUENCE { -- LDAPv3
355 * matchingRule [1] MatchingRuleId OPTIONAL,
356 * type [2] AttributeDescription OPTIONAL,
357 * matchValue [3] AssertionValue,
358 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
360 * Note: tags in a choice are always explicit
364 LDAP_LOG ( FILTER, ARGS, "ldap_pvt_put_filter: \"%s\"\n", str_in,0,0 );
366 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
369 freeme = LDAP_STRDUP( str_in );
370 if( freeme == NULL ) return LDAP_NO_MEMORY;
381 while( LDAP_SPACE( *str ) ) str++;
386 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: AND\n", 0,0,0 );
388 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
392 str = put_complex_filter( ber, str,
393 LDAP_FILTER_AND, 0 );
404 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: OR\n", 0,0,0 );
406 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
410 str = put_complex_filter( ber, str,
422 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: NOT\n", 0,0,0 );
424 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
428 str = put_complex_filter( ber, str,
429 LDAP_FILTER_NOT, 0 );
440 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: simple\n", 0,0,0);
442 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
450 while ( *next && balance ) {
452 if ( *next == '(' ) {
454 } else if ( *next == ')' ) {
459 if ( *next == '\\' && ! escape ) {
465 if ( balance ) next++;
468 if ( balance != 0 ) {
475 if ( put_simple_filter( ber, str ) == -1 ) {
480 *next++ = /*'('*/ ')';
490 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: end\n", 0,0,0 );
492 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
495 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
507 default: /* assume it's a simple type=value filter */
509 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: default\n", 0,0,0 );
511 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
514 next = strchr( str, '\0' );
515 if ( put_simple_filter( ber, str ) == -1 ) {
524 rc = parens ? -1 : 0;
532 * Put a list of filters like this "(filter1)(filter2)..."
536 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
542 LDAP_LOG ( FILTER, ARGS, "put_filter_list \"%s\"\n", str,0,0 );
544 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
549 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
552 if ( *str == '\0' ) break;
554 if ( (next = find_right_paren( str + 1 )) == NULL ) {
559 /* now we have "(filter)" with str pointing to it */
561 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1;
565 if( tag == LDAP_FILTER_NOT ) break;
568 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
586 LDAP_LOG ( FILTER, ARGS, "put_simple_filter: \"%s\"\n", str,0,0 );
588 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
592 str = LDAP_STRDUP( str );
593 if( str == NULL ) return -1;
595 if ( (s = strchr( str, '=' )) == NULL ) {
604 ftype = LDAP_FILTER_LE;
609 ftype = LDAP_FILTER_GE;
614 ftype = LDAP_FILTER_APPROX;
619 /* RFC2254 extensible filters are off the form:
620 * type [:dn] [:rule] := value
621 * or [:dn]:rule := value
623 ftype = LDAP_FILTER_EXT;
627 char *dn = strchr( str, ':' );
632 rule = strchr( dn, ':' );
636 if ( strcmp(dn, "dn") == 0 ) {
637 /* must have attribute */
638 if( !ldap_is_desc( str ) ) {
653 if ( strcmp(dn, "dn") != 0 ) {
661 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
662 /* must have either type or rule */
666 if ( *str != '\0' && !ldap_is_desc( str ) ) {
670 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
674 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
676 if( rc != -1 && rule && *rule != '\0' ) {
677 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
680 if( rc != -1 && *str != '\0' ) {
681 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
685 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
688 rc = ber_printf( ber, "to",
689 LDAP_FILTER_EXT_VALUE, value, len );
695 if( rc != -1 && dn ) {
696 rc = ber_printf( ber, "tb",
697 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
701 rc = ber_printf( ber, /*"{"*/ "N}" );
707 if( !ldap_is_desc( str ) ) {
711 char *nextstar = ldap_pvt_find_wildcard( value );
713 if ( nextstar == NULL ) {
716 } else if ( *nextstar == '\0' ) {
717 ftype = LDAP_FILTER_EQUALITY;
719 } else if ( strcmp( value, "*" ) == 0 ) {
720 ftype = LDAP_FILTER_PRESENT;
723 rc = put_substring_filter( ber, str, value );
729 if( !ldap_is_desc( str ) ) goto done;
731 if ( ftype == LDAP_FILTER_PRESENT ) {
732 rc = ber_printf( ber, "ts", ftype, str );
735 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
738 rc = ber_printf( ber, "t{soN}",
739 ftype, str, value, len );
744 if( rc != -1 ) rc = 0;
750 put_substring_filter( BerElement *ber, char *type, char *val )
754 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
757 LDAP_LOG ( FILTER, ARGS, "put_substring_filter \"%s=%s\"\n", type, val, 0 );
759 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
763 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
767 for( ; *val; val=nextstar ) {
768 nextstar = ldap_pvt_find_wildcard( val );
770 if ( nextstar == NULL ) {
774 if ( *nextstar == '\0' ) {
775 ftype = LDAP_SUBSTRING_FINAL;
778 if ( gotstar++ == 0 ) {
779 ftype = LDAP_SUBSTRING_INITIAL;
781 ftype = LDAP_SUBSTRING_ANY;
785 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
786 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
792 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
798 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {
806 put_vrFilter( BerElement *ber, const char *str_in )
812 int parens, balance, escape;
815 * A ValuesReturnFilter looks like this:
817 * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
818 * SimpleFilterItem ::= CHOICE {
819 * equalityMatch [3] AttributeValueAssertion,
820 * substrings [4] SubstringFilter,
821 * greaterOrEqual [5] AttributeValueAssertion,
822 * lessOrEqual [6] AttributeValueAssertion,
823 * present [7] AttributeType,
824 * approxMatch [8] AttributeValueAssertion,
825 * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3
828 * SubstringFilter ::= SEQUENCE {
829 * type AttributeType,
830 * SEQUENCE OF CHOICE {
831 * initial [0] IA5String,
833 * final [2] IA5String
837 * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
838 * matchingRule [1] MatchingRuleId OPTIONAL,
839 * type [2] AttributeDescription OPTIONAL,
840 * matchValue [3] AssertionValue }
844 LDAP_LOG ( FILTER, ARGS, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
846 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
849 freeme = LDAP_STRDUP( str_in );
850 if( freeme == NULL ) return LDAP_NO_MEMORY;
861 while( LDAP_SPACE( *str ) ) str++;
865 if ( (next = find_right_paren( str )) == NULL ) {
872 if ( put_vrFilter_list( ber, str ) == -1 ) {
888 LDAP_LOG ( FILTER, DETAIL1,
889 "put_vrFilter: simple\n", 0, 0, 0 );
891 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n",
899 while ( *next && balance ) {
901 if ( *next == '(' ) {
903 } else if ( *next == ')' ) {
908 if ( *next == '\\' && ! escape ) {
914 if ( balance ) next++;
917 if ( balance != 0 ) {
924 if ( put_simple_vrFilter( ber, str ) == -1 ) {
929 *next++ = /*'('*/ ')';
939 LDAP_LOG ( FILTER, DETAIL1, "put_vrFilter: end\n", 0, 0, 0 );
941 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: end\n",
944 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
956 default: /* assume it's a simple type=value filter */
958 LDAP_LOG ( FILTER, DETAIL1, "put_vrFilter: default\n",
961 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: default\n",
964 next = strchr( str, '\0' );
965 if ( put_simple_filter( ber, str ) == -1 ) {
974 rc = parens ? -1 : 0;
982 ldap_put_vrFilter( BerElement *ber, const char *str_in )
986 if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) {
990 rc = put_vrFilter( ber, str_in );
992 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
1000 put_vrFilter_list( BerElement *ber, char *str )
1006 LDAP_LOG ( FILTER, ARGS, "put_vrFilter_list \"%s\"\n", str, 0, 0 );
1008 Debug( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n",
1013 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
1016 if ( *str == '\0' ) break;
1018 if ( (next = find_right_paren( str + 1 )) == NULL ) {
1023 /* now we have "(filter)" with str pointing to it */
1025 if ( put_vrFilter( ber, str ) == -1 ) return -1;
1034 put_simple_vrFilter(
1044 LDAP_LOG ( FILTER, ARGS, "put_simple_vrFilter: \"%s\"\n", str, 0, 0 );
1046 Debug( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n",
1050 str = LDAP_STRDUP( str );
1051 if( str == NULL ) return -1;
1053 if ( (s = strchr( str, '=' )) == NULL ) {
1062 ftype = LDAP_FILTER_LE;
1067 ftype = LDAP_FILTER_GE;
1072 ftype = LDAP_FILTER_APPROX;
1077 /* According to ValuesReturnFilter control definition
1078 * extensible filters are off the form:
1079 * type [:rule] := value
1082 ftype = LDAP_FILTER_EXT;
1086 char *rule = strchr( str, ':' );
1089 if( rule == NULL ) {
1090 /* must have attribute */
1091 if( !ldap_is_desc( str ) ) {
1101 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
1102 /* must have either type or rule */
1106 if ( *str != '\0' && !ldap_is_desc( str ) ) {
1110 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
1114 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
1116 if( rc != -1 && rule && *rule != '\0' ) {
1117 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
1120 if( rc != -1 && *str != '\0' ) {
1121 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
1125 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1128 rc = ber_printf( ber, "to",
1129 LDAP_FILTER_EXT_VALUE, value, len );
1136 rc = ber_printf( ber, /*"{"*/ "N}" );
1142 if( !ldap_is_desc( str ) ) {
1146 char *nextstar = ldap_pvt_find_wildcard( value );
1148 if ( nextstar == NULL ) {
1151 } else if ( *nextstar == '\0' ) {
1152 ftype = LDAP_FILTER_EQUALITY;
1154 } else if ( strcmp( value, "*" ) == 0 ) {
1155 ftype = LDAP_FILTER_PRESENT;
1158 rc = put_substring_filter( ber, str, value );
1164 if( !ldap_is_desc( str ) ) goto done;
1166 if ( ftype == LDAP_FILTER_PRESENT ) {
1167 rc = ber_printf( ber, "ts", ftype, str );
1170 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1173 rc = ber_printf( ber, "t{soN}",
1174 ftype, str, value, len );
1179 if( rc != -1 ) rc = 0;