X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=libraries%2Flibldap%2Ffilter.c;h=259c9a459089dba1a482147aa463f1c82ea06ab7;hb=3b9f4a82ee478c943a66696adf9133dc9f503e16;hp=a945cd71e49b8c7bd8d5f6215c1f1c75b4f5d2eb;hpb=772b7760b81811c5458bb3c474327d62f15ba9a3;p=openldap diff --git a/libraries/libldap/filter.c b/libraries/libldap/filter.c index a945cd71e4..259c9a4590 100644 --- a/libraries/libldap/filter.c +++ b/libraries/libldap/filter.c @@ -1,6 +1,6 @@ /* $OpenLDAP$ */ /* - * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved. + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ /* Portions @@ -22,6 +22,14 @@ #include "ldap-int.h" +static int put_simple_vrFilter LDAP_P(( + BerElement *ber, + char *str )); + +static int put_vrFilter_list LDAP_P(( + BerElement *ber, + char *str )); + static char *put_complex_filter LDAP_P(( BerElement *ber, char *str, @@ -117,7 +125,7 @@ static int ldap_is_desc ( const char *str ) return 0; options: - if( !LDAP_LDH( str[i] )) { + if( !LDAP_LDH( str[0] )) { return 0; } for( i=1; str[i]; i++ ) { @@ -153,7 +161,7 @@ find_right_paren( char *s ) if ( balance ) s++; } - return( *s ? s : NULL ); + return *s ? s : NULL; } static int hex2value( int c ) @@ -181,27 +189,31 @@ ldap_pvt_find_wildcard( const char *s ) case '*': /* found wildcard */ return (char *) s; + case '(': + case ')': + return NULL; + case '\\': if( s[1] == '\0' ) return NULL; + if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) { s+=2; - } - switch( s[1] ) { + } else switch( s[1] ) { default: return NULL; /* allow RFC 1960 escapes */ - case '\\': case '*': case '(': case ')': + case '\\': s++; } } } - return NULL; + return (char *) s; } /* unescape filter value */ @@ -215,6 +227,11 @@ ldap_pvt_filter_value_unescape( char *fval ) for( r=v=0; fval[v] != '\0'; v++ ) { switch( fval[v] ) { + case '(': + case ')': + case '*': + return -1; + case '\\': /* escape */ v++; @@ -222,7 +239,6 @@ ldap_pvt_filter_value_unescape( char *fval ) if ( fval[v] == '\0' ) { /* escape at end of string */ return -1; - } if (( v1 = hex2value( fval[v] )) >= 0 ) { @@ -273,30 +289,37 @@ put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not ) */ /* put explicit tag */ - if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) - return( NULL ); + if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) { + return NULL; + } str++; - if ( (next = find_right_paren( str )) == NULL ) - return( NULL ); + if ( (next = find_right_paren( str )) == NULL ) { + return NULL; + } *next = '\0'; - if ( put_filter_list( ber, str, tag ) == -1 ) - return( NULL ); + if ( put_filter_list( ber, str, tag ) == -1 ) { + return NULL; + } /* close the '(' */ *next++ = ')'; /* flush explicit tagged thang */ - if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) - return( NULL ); + if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) { + return NULL; + } - return( next ); + return next; } int -ldap_int_put_filter( BerElement *ber, char *str ) +ldap_pvt_put_filter( BerElement *ber, const char *str_in ) { + int rc; + char *freeme; + char *str; char *next; int parens, balance, escape; @@ -333,7 +356,15 @@ ldap_int_put_filter( BerElement *ber, char *str ) * Note: tags in a choice are always explicit */ - Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 ); +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, ARGS, "ldap_pvt_put_filter: \"%s\"\n", str_in,0,0 ); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 ); +#endif + + freeme = LDAP_STRDUP( str_in ); + if( freeme == NULL ) return LDAP_NO_MEMORY; + str = freeme; parens = 0; while ( *str ) { @@ -347,67 +378,103 @@ ldap_int_put_filter( BerElement *ber, char *str ) switch ( *str ) { case '&': +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: AND\n", 0,0,0 ); +#else Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n", 0, 0, 0 ); +#endif - if ( (str = put_complex_filter( ber, str, - LDAP_FILTER_AND, 0 )) == NULL ) - return( -1 ); + str = put_complex_filter( ber, str, + LDAP_FILTER_AND, 0 ); + if( str == NULL ) { + rc = -1; + goto done; + } parens--; break; case '|': +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: OR\n", 0,0,0 ); +#else Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n", 0, 0, 0 ); +#endif - if ( (str = put_complex_filter( ber, str, - LDAP_FILTER_OR, 0 )) == NULL ) - return( -1 ); + str = put_complex_filter( ber, str, + LDAP_FILTER_OR, 0 ); + if( str == NULL ) { + rc = -1; + goto done; + } parens--; break; case '!': +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: NOT\n", 0,0,0 ); +#else Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n", 0, 0, 0 ); +#endif - if ( (str = put_complex_filter( ber, str, - LDAP_FILTER_NOT, 1 )) == NULL ) - return( -1 ); + str = put_complex_filter( ber, str, + LDAP_FILTER_NOT, 0 ); + if( str == NULL ) { + rc = -1; + goto done; + } parens--; break; default: +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: simple\n", 0,0,0); +#else Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n", 0, 0, 0 ); +#endif balance = 1; escape = 0; next = str; + while ( *next && balance ) { if ( escape == 0 ) { - if ( *next == '(' ) + if ( *next == '(' ) { balance++; - else if ( *next == ')' ) + } else if ( *next == ')' ) { balance--; + } } - if ( *next == '\\' && ! escape ) + + if ( *next == '\\' && ! escape ) { escape = 1; - else + } else { escape = 0; - if ( balance ) - next++; + } + + if ( balance ) next++; + } + + if ( balance != 0 ) { + rc = -1; + goto done; } - if ( balance != 0 ) - return( -1 ); *next = '\0'; + if ( put_simple_filter( ber, str ) == -1 ) { - return( -1 ); + rc = -1; + goto done; } - *next++ = ')'; + + *next++ = /*'('*/ ')'; + str = next; parens--; break; @@ -415,10 +482,16 @@ ldap_int_put_filter( BerElement *ber, char *str ) break; case /*'('*/ ')': +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: end\n", 0,0,0 ); +#else Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0, 0 ); - if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) - return( -1 ); +#endif + if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) { + rc = -1; + goto done; + } str++; parens--; break; @@ -428,18 +501,27 @@ ldap_int_put_filter( BerElement *ber, char *str ) break; default: /* assume it's a simple type=value filter */ +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: default\n", 0,0,0 ); +#else Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0, 0 ); +#endif next = strchr( str, '\0' ); if ( put_simple_filter( ber, str ) == -1 ) { - return( -1 ); + rc = -1; + goto done; } str = next; break; } } - return( parens ? -1 : 0 ); + rc = parens ? -1 : 0; + +done: + LDAP_FREE( freeme ); + return rc; } /* @@ -452,8 +534,12 @@ put_filter_list( BerElement *ber, char *str, ber_tag_t tag ) char *next = NULL; char save; +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, ARGS, "put_filter_list \"%s\"\n", str,0,0 ); +#else Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 ); +#endif while ( *str ) { while ( *str && LDAP_SPACE( (unsigned char) *str ) ) { @@ -462,13 +548,13 @@ put_filter_list( BerElement *ber, char *str, ber_tag_t tag ) if ( *str == '\0' ) break; if ( (next = find_right_paren( str + 1 )) == NULL ) { - return( -1 ); + return -1; } save = *++next; /* now we have "(filter)" with str pointing to it */ *next = '\0'; - if ( ldap_int_put_filter( ber, str ) == -1 ) return -1; + if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1; *next = save; str = next; @@ -492,8 +578,12 @@ put_simple_filter( ber_tag_t ftype; int rc = -1; - Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, ARGS, "put_simple_filter: \"%s\"\n", str,0,0 ); +#else + Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n", str, 0, 0 ); +#endif str = LDAP_STRDUP( str ); if( str == NULL ) return -1; @@ -509,19 +599,16 @@ put_simple_filter( case '<': ftype = LDAP_FILTER_LE; *s = '\0'; - if(! ldap_is_desc( str ) ) goto done; break; case '>': ftype = LDAP_FILTER_GE; *s = '\0'; - if(! ldap_is_desc( str ) ) goto done; break; case '~': ftype = LDAP_FILTER_APPROX; *s = '\0'; - if(! ldap_is_desc( str ) ) goto done; break; case ':': @@ -536,11 +623,7 @@ put_simple_filter( char *dn = strchr( str, ':' ); char *rule = NULL; - if( dn == NULL ) { - if(! ldap_is_desc( str ) ) goto done; - - } else { - + if( dn != NULL ) { *dn++ = '\0'; rule = strchr( dn, ':' ); @@ -589,6 +672,7 @@ put_simple_filter( if( rc != -1 && rule && *rule != '\0' ) { rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule ); } + if( rc != -1 && *str != '\0' ) { rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str ); } @@ -597,26 +681,40 @@ put_simple_filter( ber_slen_t len = ldap_pvt_filter_value_unescape( value ); if( len >= 0 ) { - rc = ber_printf( ber, "totbN}", - LDAP_FILTER_EXT_VALUE, value, len, - LDAP_FILTER_EXT_DNATTRS, dn != NULL); + rc = ber_printf( ber, "to", + LDAP_FILTER_EXT_VALUE, value, len ); } else { rc = -1; } } + + if( rc != -1 && dn ) { + rc = ber_printf( ber, "tb", + LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 ); + } + + if( rc != -1 ) { + rc = ber_printf( ber, /*"{"*/ "N}" ); + } } goto done; default: - { + if( !ldap_is_desc( str ) ) { + goto done; + + } else { char *nextstar = ldap_pvt_find_wildcard( value ); + if ( nextstar == NULL ) { - rc = -1; goto done; + } else if ( *nextstar == '\0' ) { ftype = LDAP_FILTER_EQUALITY; + } else if ( strcmp( value, "*" ) == 0 ) { ftype = LDAP_FILTER_PRESENT; + } else { rc = put_substring_filter( ber, str, value ); goto done; @@ -624,6 +722,8 @@ put_simple_filter( } break; } + if( !ldap_is_desc( str ) ) goto done; + if ( ftype == LDAP_FILTER_PRESENT ) { rc = ber_printf( ber, "ts", ftype, str ); @@ -636,9 +736,8 @@ put_simple_filter( } } - if( rc != -1 ) rc = 0; - done: + if( rc != -1 ) rc = 0; LDAP_FREE( str ); return rc; } @@ -650,11 +749,16 @@ put_substring_filter( BerElement *ber, char *type, char *val ) int gotstar = 0; ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS; +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, ARGS, "put_substring_filter \"%s=%s\"\n", type, val, 0 ); +#else Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type, val, 0 ); +#endif - if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) - return( -1 ); + if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) { + return -1; + } for( ; *val; val=nextstar ) { nextstar = ldap_pvt_find_wildcard( val ); @@ -665,15 +769,16 @@ put_substring_filter( BerElement *ber, char *type, char *val ) if ( *nextstar == '\0' ) { ftype = LDAP_SUBSTRING_FINAL; - } else if ( gotstar++ == 0 ) { - ftype = LDAP_SUBSTRING_INITIAL; } else { - ftype = LDAP_SUBSTRING_ANY; + *nextstar++ = '\0'; + if ( gotstar++ == 0 ) { + ftype = LDAP_SUBSTRING_INITIAL; + } else { + ftype = LDAP_SUBSTRING_ANY; + } } - *nextstar++ = '\0'; - - if ( *val != '\0' ) { + if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) { ber_slen_t len = ldap_pvt_filter_value_unescape( val ); if ( len < 0 ) { @@ -686,8 +791,390 @@ put_substring_filter( BerElement *ber, char *type, char *val ) } } - if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) - return( -1 ); + if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) { + return -1; + } + + return 0; +} + +static int +put_vrFilter( BerElement *ber, const char *str_in ) +{ + int rc; + char *freeme; + char *str; + char *next; + int parens, balance, escape; + + /* + * A ValuesReturnFilter looks like this: + * + * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem + * SimpleFilterItem ::= CHOICE { + * equalityMatch [3] AttributeValueAssertion, + * substrings [4] SubstringFilter, + * greaterOrEqual [5] AttributeValueAssertion, + * lessOrEqual [6] AttributeValueAssertion, + * present [7] AttributeType, + * approxMatch [8] AttributeValueAssertion, + * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3 + * } + * + * SubstringFilter ::= SEQUENCE { + * type AttributeType, + * SEQUENCE OF CHOICE { + * initial [0] IA5String, + * any [1] IA5String, + * final [2] IA5String + * } + * } + * + * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3 + * matchingRule [1] MatchingRuleId OPTIONAL, + * type [2] AttributeDescription OPTIONAL, + * matchValue [3] AssertionValue } + */ + +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, ARGS, "ldap_pvt_put_vrFilter: \"%s\"\n", + str_in, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in, 0, 0 ); +#endif + + freeme = LDAP_STRDUP( str_in ); + if( freeme == NULL ) return LDAP_NO_MEMORY; + str = freeme; + + parens = 0; + while ( *str ) { + switch ( *str ) { + case '(': /*')'*/ + str++; + parens++; + + /* skip spaces */ + while( LDAP_SPACE( *str ) ) str++; + + switch ( *str ) { + case '(': + if ( (next = find_right_paren( str )) == NULL ) { + rc = -1; + goto done; + } + + *next = '\0'; + + if ( put_vrFilter_list( ber, str ) == -1 ) { + rc = -1; + goto done; + } + + /* close the '(' */ + *next++ = ')'; + + str = next; + + parens--; + break; + + + default: +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, DETAIL1, + "put_vrFilter: simple\n", 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n", + 0, 0, 0 ); +#endif + + balance = 1; + escape = 0; + next = str; + + while ( *next && balance ) { + if ( escape == 0 ) { + if ( *next == '(' ) { + balance++; + } else if ( *next == ')' ) { + balance--; + } + } + + if ( *next == '\\' && ! escape ) { + escape = 1; + } else { + escape = 0; + } + + if ( balance ) next++; + } + + if ( balance != 0 ) { + rc = -1; + goto done; + } + + *next = '\0'; + + if ( put_simple_vrFilter( ber, str ) == -1 ) { + rc = -1; + goto done; + } + + *next++ = /*'('*/ ')'; + + str = next; + parens--; + break; + } + break; + + case /*'('*/ ')': +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: end\n", 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", + 0, 0, 0 ); +#endif + if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) { + rc = -1; + goto done; + } + str++; + parens--; + break; + + case ' ': + str++; + break; + + default: /* assume it's a simple type=value filter */ +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: default\n", + 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", + 0, 0, 0 ); +#endif + next = strchr( str, '\0' ); + if ( put_simple_filter( ber, str ) == -1 ) { + rc = -1; + goto done; + } + str = next; + break; + } + } + + rc = parens ? -1 : 0; + +done: + LDAP_FREE( freeme ); + return rc; +} + +int +ldap_put_vrFilter( BerElement *ber, const char *str_in ) +{ + int rc =0; + + if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) { + rc = -1; + } + + rc = put_vrFilter( ber, str_in ); + + if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) { + rc = -1; + } + + return rc; +} + +static int +put_vrFilter_list( BerElement *ber, char *str ) +{ + char *next = NULL; + char save; + +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, ARGS, "put_vrFilter_list \"%s\"\n", str, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n", + str, 0, 0 ); +#endif + + while ( *str ) { + while ( *str && LDAP_SPACE( (unsigned char) *str ) ) { + str++; + } + if ( *str == '\0' ) break; + + if ( (next = find_right_paren( str + 1 )) == NULL ) { + return -1; + } + save = *++next; + + /* now we have "(filter)" with str pointing to it */ + *next = '\0'; + if ( put_vrFilter( ber, str ) == -1 ) return -1; + *next = save; + str = next; + } return 0; -} \ No newline at end of file +} + +static int +put_simple_vrFilter( + BerElement *ber, + char *str ) +{ + char *s; + char *value; + ber_tag_t ftype; + int rc = -1; + +#ifdef NEW_LOGGING + LDAP_LOG ( FILTER, ARGS, "put_simple_vrFilter: \"%s\"\n", str, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n", + str, 0, 0 ); +#endif + + str = LDAP_STRDUP( str ); + if( str == NULL ) return -1; + + if ( (s = strchr( str, '=' )) == NULL ) { + goto done; + } + + value = s + 1; + *s-- = '\0'; + + switch ( *s ) { + case '<': + ftype = LDAP_FILTER_LE; + *s = '\0'; + break; + + case '>': + ftype = LDAP_FILTER_GE; + *s = '\0'; + break; + + case '~': + ftype = LDAP_FILTER_APPROX; + *s = '\0'; + break; + + case ':': + /* According to ValuesReturnFilter control definition + * extensible filters are off the form: + * type [:rule] := value + * or :rule := value + */ + ftype = LDAP_FILTER_EXT; + *s = '\0'; + + { + char *rule = strchr( str, ':' ); + *rule++ = '\0'; + + if( rule == NULL ) { + /* must have attribute */ + if( !ldap_is_desc( str ) ) { + goto done; + } + rule = ""; + + } else { + *rule++ = '\0'; + } + + + if ( *str == '\0' && ( !rule || *rule == '\0' ) ) { + /* must have either type or rule */ + goto done; + } + + if ( *str != '\0' && !ldap_is_desc( str ) ) { + goto done; + } + + if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) { + goto done; + } + + rc = ber_printf( ber, "t{" /*"}"*/, ftype ); + + if( rc != -1 && rule && *rule != '\0' ) { + rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule ); + } + + if( rc != -1 && *str != '\0' ) { + rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str ); + } + + if( rc != -1 ) { + ber_slen_t len = ldap_pvt_filter_value_unescape( value ); + + if( len >= 0 ) { + rc = ber_printf( ber, "to", + LDAP_FILTER_EXT_VALUE, value, len ); + } else { + rc = -1; + } + } + + if( rc != -1 ) { + rc = ber_printf( ber, /*"{"*/ "N}" ); + } + } + goto done; + + default: + if( !ldap_is_desc( str ) ) { + goto done; + + } else { + char *nextstar = ldap_pvt_find_wildcard( value ); + + if ( nextstar == NULL ) { + goto done; + + } else if ( *nextstar == '\0' ) { + ftype = LDAP_FILTER_EQUALITY; + + } else if ( strcmp( value, "*" ) == 0 ) { + ftype = LDAP_FILTER_PRESENT; + + } else { + rc = put_substring_filter( ber, str, value ); + goto done; + } + } break; + } + + if( !ldap_is_desc( str ) ) goto done; + + if ( ftype == LDAP_FILTER_PRESENT ) { + rc = ber_printf( ber, "ts", ftype, str ); + + } else { + ber_slen_t len = ldap_pvt_filter_value_unescape( value ); + + if( len >= 0 ) { + rc = ber_printf( ber, "t{soN}", + ftype, str, value, len ); + } + } + +done: + if( rc != -1 ) rc = 0; + LDAP_FREE( str ); + return rc; +} +