int ldap_pvt_put_filter( BerElement *ber, const char *str_in ) { int rc; char *freeme; char *str; char *next; int parens, balance, escape; /* * A Filter looks like this (RFC 4511 as extended by RFC 4526): * Filter ::= CHOICE { * and [0] SET SIZE (0..MAX) OF filter Filter, * or [1] SET SIZE (0..MAX) OF filter Filter, * not [2] Filter, * equalityMatch [3] AttributeValueAssertion, * substrings [4] SubstringFilter, * greaterOrEqual [5] AttributeValueAssertion, * lessOrEqual [6] AttributeValueAssertion, * present [7] AttributeDescription, * approxMatch [8] AttributeValueAssertion, * extensibleMatch [9] MatchingRuleAssertion, * ... } * * SubstringFilter ::= SEQUENCE { * type AttributeDescription, * substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE { * initial [0] AssertionValue, -- only once * any [1] AssertionValue, * final [2] AssertionValue -- only once * } * } * * MatchingRuleAssertion ::= SEQUENCE { * matchingRule [1] MatchingRuleId OPTIONAL, * type [2] AttributeDescription OPTIONAL, * matchValue [3] AssertionValue, * dnAttributes [4] BOOLEAN DEFAULT FALSE } * * Note: tags in a CHOICE are always explicit */ Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 ); 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 '&': Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n", 0, 0, 0 ); str = put_complex_filter( ber, str, LDAP_FILTER_AND, 0 ); if( str == NULL ) { rc = -1; goto done; } parens--; break; case '|': Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n", 0, 0, 0 ); str = put_complex_filter( ber, str, LDAP_FILTER_OR, 0 ); if( str == NULL ) { rc = -1; goto done; } parens--; break; case '!': Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n", 0, 0, 0 ); str = put_complex_filter( ber, str, LDAP_FILTER_NOT, 0 ); if( str == NULL ) { rc = -1; goto done; } parens--; break; case '(': rc = -1; goto done; default: Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n", 0, 0, 0 ); 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_filter( ber, str ) == -1 ) { rc = -1; goto done; } *next++ = /*'('*/ ')'; str = next; parens--; break; } break; case /*'('*/ ')': Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0, 0 ); if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) { rc = -1; goto done; } str++; parens--; break; case ' ': str++; break; default: /* assume it's a simple type=value filter */ Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0, 0 ); next = strchr( str, '\0' ); if ( put_simple_filter( ber, str ) == -1 ) { rc = -1; goto done; } str = next; break; } if ( !parens ) break; } rc = ( parens || *str ) ? -1 : 0; done: LDAP_FREE( freeme ); return rc; }
static int put_filter( BerElement *ber, char *str ) { char *next, *tmp, *s, *d; int parens, balance, escape, gotescape; /* * A Filter looks like this: * Filter ::= CHOICE { * and [0] SET OF Filter, * or [1] SET OF Filter, * not [2] Filter, * equalityMatch [3] AttributeValueAssertion, * substrings [4] SubstringFilter, * greaterOrEqual [5] AttributeValueAssertion, * lessOrEqual [6] AttributeValueAssertion, * present [7] AttributeType,, * approxMatch [8] AttributeValueAssertion * } * * SubstringFilter ::= SEQUENCE { * type AttributeType, * SEQUENCE OF CHOICE { * initial [0] IA5String, * any [1] IA5String, * final [2] IA5String * } * } * Note: tags in a choice are always explicit */ Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 ); gotescape = parens = 0; while ( *str ) { switch ( *str ) { case '(': str++; parens++; switch ( *str ) { case '&': Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n", 0, 0, 0 ); if ( (str = put_complex_filter( ber, str, LDAP_FILTER_AND, 0 )) == NULL ) return( -1 ); parens--; break; case '|': Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n", 0, 0, 0 ); if ( (str = put_complex_filter( ber, str, LDAP_FILTER_OR, 0 )) == NULL ) return( -1 ); parens--; break; case '!': Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n", 0, 0, 0 ); if ( (str = put_complex_filter( ber, str, LDAP_FILTER_NOT, 1 )) == NULL ) return( -1 ); parens--; break; default: Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n", 0, 0, 0 ); balance = 1; escape = 0; next = str; while ( *next && balance ) { if ( escape == 0 ) { if ( *next == '(' ) balance++; else if ( *next == ')' ) balance--; } if ( *next == '\\' && ! escape ) gotescape = escape = 1; else escape = 0; if ( balance ) next++; } if ( balance != 0 ) return( -1 ); *next = '\0'; tmp = strdup( str ); if ( gotescape ) { escape = 0; for ( s = d = tmp; *s; s++ ) { if ( *s != '\\' || escape ) { *d++ = *s; escape = 0; } else { escape = 1; } } *d = '\0'; } if ( put_simple_filter( ber, tmp ) == -1 ) { free( tmp ); return( -1 ); } free( tmp ); *next++ = ')'; str = next; parens--; break; } break; case ')': Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0, 0 ); if ( ber_printf( ber, "]" ) == -1 ) return( -1 ); str++; parens--; break; case ' ': str++; break; default: /* assume it's a simple type=value filter */ Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0, 0 ); next = strchr( str, '\0' ); tmp = strdup( str ); if ( strchr( tmp, '\\' ) != NULL ) { escape = 0; for ( s = d = tmp; *s; s++ ) { if ( *s != '\\' || escape ) { *d++ = *s; escape = 0; } else { escape = 1; } } *d = '\0'; } if ( put_simple_filter( ber, tmp ) == -1 ) { free( tmp ); return( -1 ); } free( tmp ); str = next; break; } } return( parens ? -1 : 0 ); }