-static char *
-find_right_paren( char *s )
-{
- int balance, escape;
-
- balance = 1;
- escape = 0;
- while ( *s && balance ) {
- if ( escape == 0 ) {
- if ( *s == '(' )
- balance++;
- else if ( *s == ')' )
- balance--;
- }
- if ( *s == '\\' && ! escape )
- escape = 1;
- else
- escape = 0;
- if ( balance )
- s++;
- }
-
- return( *s ? s : NULL );
-}
-
-static char *
-put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
-{
- char *next;
-
- /*
- * We have (x(filter)...) with str sitting on
- * the x. We have to find the paren matching
- * the one before the x and put the intervening
- * filters by calling put_filter_list().
- */
-
- /* put explicit tag */
- if ( ber_printf( ber, "t{" /*}*/, tag ) == -1 )
- return( NULL );
-
- str++;
- if ( (next = find_right_paren( str )) == NULL )
- return( NULL );
-
- *next = '\0';
- if ( put_filter_list( ber, str ) == -1 )
- return( NULL );
- *next++ = ')';
-
- /* flush explicit tagged thang */
- if ( ber_printf( ber, /*{*/ "}" ) == -1 )
- return( NULL );
-
- return( next );
-}
-
-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,
- * extensibleMatch [9] MatchingRuleAssertion -- LDAPv3
- * }
- *
- * SubstringFilter ::= SEQUENCE {
- * type AttributeType,
- * SEQUENCE OF CHOICE {
- * initial [0] IA5String,
- * any [1] IA5String,
- * final [2] IA5String
- * }
- * }
- *
- * MatchingRuleAssertion ::= SEQUENCE { -- LDAPv3
- * 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, 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 = LDAP_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 ) {
- LDAP_FREE( tmp );
- return( -1 );
- }
- LDAP_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 = LDAP_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 ) {
- LDAP_FREE( tmp );
- return( -1 );
- }
- LDAP_FREE( tmp );
- str = next;
- break;
- }
- }
-
- return( parens ? -1 : 0 );
-}
-
-/*
- * Put a list of filters like this "(filter1)(filter2)..."
- */
-
-static int
-put_filter_list( BerElement *ber, char *str )
-{
- char *next;
- char save;
-
- Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
-
- while ( *str ) {
- while ( *str && isspace( (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_filter( ber, str ) == -1 )
- return( -1 );
- *next = save;
-
- str = next;
- }
-
- return( 0 );
-}
-
-static int
-put_simple_filter(
- BerElement *ber,
- char *str )
-{
- char *s;
- char *value, savechar;
- ber_tag_t ftype;
- int rc;
-
- Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
-
- if ( (s = strchr( str, '=' )) == NULL )
- return( -1 );
- value = s + 1;
- *s-- = '\0';
- savechar = *s;
-
- 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 ':': /* LDAPv3 extended filter */
- ftype = LDAP_FILTER_EXTENDED;
- return -1;
- break;
- default:
- if ( strchr( value, '*' ) == NULL ) {
- ftype = LDAP_FILTER_EQUALITY;
- } else if ( strcmp( value, "*" ) == 0 ) {
- ftype = LDAP_FILTER_PRESENT;
- } else {
- rc = put_substring_filter( ber, str, value );
- *(value-1) = '=';
- return( rc );
- }
- break;
- }
-
- if ( ftype == LDAP_FILTER_PRESENT ) {
- rc = ber_printf( ber, "ts", ftype, str );
- } else {
- rc = ber_printf( ber, "t{ss}", ftype, str, value );
- }
-
- *s = savechar;
- *(value-1) = '=';
- return( rc == -1 ? rc : 0 );
-}
-
-static int
-put_substring_filter( BerElement *ber, char *type, char *val )
-{
- char *nextstar, gotstar = 0;
- ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
-
- Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
- val, 0 );
-
- if ( ber_printf( ber, "t{s{", ftype, type ) == -1 )
- return( -1 );
-
- while ( val != NULL ) {
- if ( (nextstar = strchr( val, '*' )) != NULL )
- *nextstar++ = '\0';
-
- if ( gotstar == 0 ) {
- ftype = LDAP_SUBSTRING_INITIAL;
- } else if ( nextstar == NULL ) {
- ftype = LDAP_SUBSTRING_FINAL;
- } else {
- ftype = LDAP_SUBSTRING_ANY;
- }
- if ( *val != '\0' ) {
- if ( ber_printf( ber, "ts", ftype, val ) == -1 )
- return( -1 );
- }
-
- gotstar = 1;
- if ( nextstar != NULL )
- *(nextstar-1) = '*';
- val = nextstar;
- }
-
- if ( ber_printf( ber, /* {{ */ "}}" ) == -1 )
- return( -1 );
-
- return( 0 );
-}
-