mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-01-07 15:41:24 -05:00
Fix filter escapes. ITS#247
This commit is contained in:
parent
06a895ff2c
commit
0fe5da0f9a
1 changed files with 177 additions and 56 deletions
|
|
@ -22,9 +22,24 @@
|
|||
|
||||
#include "ldap-int.h"
|
||||
|
||||
static int ldap_is_attribute LDAP_P((
|
||||
const char *attr ));
|
||||
|
||||
static int ldap_is_attribute_ext LDAP_P((
|
||||
const char *attr ));
|
||||
|
||||
static int hex2value LDAP_P((
|
||||
int c ));
|
||||
|
||||
static ber_slen_t filter_value_unescape LDAP_P((
|
||||
char *filter ));
|
||||
|
||||
static char *find_right_paren LDAP_P((
|
||||
char *s ));
|
||||
|
||||
static char *find_wildcard LDAP_P((
|
||||
char *s ));
|
||||
|
||||
static char *put_complex_filter LDAP_P((
|
||||
BerElement *ber,
|
||||
char *str,
|
||||
|
|
@ -64,7 +79,7 @@ static int put_filter_list LDAP_P((
|
|||
*
|
||||
* Example:
|
||||
* char *attrs[] = { "mail", "title", 0 };
|
||||
* ldap_search_ext( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
|
||||
* ldap_search_ext( ld, "c=us,o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
|
||||
* attrs, attrsonly, sctrls, ctrls, timeout, sizelimit,
|
||||
* &msgid );
|
||||
*/
|
||||
|
|
@ -318,6 +333,35 @@ ldap_build_search_req(
|
|||
return( ber );
|
||||
}
|
||||
|
||||
#ifndef LDAP_UNDERSCORE
|
||||
#define LDAP_UNDERSCORE ""
|
||||
#endif
|
||||
|
||||
static char *spanset =
|
||||
":-.;" LDAP_UNDERSCORE
|
||||
"ABCDEFGHIGKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789";
|
||||
|
||||
#define ATTR_SPANSET (spanset)
|
||||
#define EXT_SPANSET (&spanset[1])
|
||||
|
||||
static int ldap_is_attribute LDAP_P(( const char *attr ))
|
||||
{
|
||||
size_t len = strlen( attr );
|
||||
size_t span = strspn( attr, ATTR_SPANSET );
|
||||
|
||||
return span == len;
|
||||
}
|
||||
|
||||
static int ldap_is_attribute_ext LDAP_P(( const char *attr ))
|
||||
{
|
||||
size_t len = strlen( attr );
|
||||
size_t span = strspn( attr, EXT_SPANSET );
|
||||
|
||||
return span == len;
|
||||
}
|
||||
|
||||
static char *
|
||||
find_right_paren( char *s )
|
||||
{
|
||||
|
|
@ -343,6 +387,89 @@ find_right_paren( char *s )
|
|||
return( *s ? s : NULL );
|
||||
}
|
||||
|
||||
static int hex2value( int c )
|
||||
{
|
||||
if( c >= '0' && c <= '9' ) {
|
||||
return c - '0';
|
||||
}
|
||||
|
||||
if( c >= 'A' && c <= 'F' ) {
|
||||
return c + (10 - (int) 'A');
|
||||
}
|
||||
|
||||
if( c >= 'a' && c <= 'f' ) {
|
||||
return c + (10 - (int) 'a');
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *
|
||||
find_wildcard( char *s )
|
||||
{
|
||||
for( ; *s != '\0' ; s++ ) {
|
||||
switch( *s ) {
|
||||
case '*': /* found wildcard */
|
||||
return s;
|
||||
|
||||
case '\\':
|
||||
s++; /* skip over escape */
|
||||
if( hex2value( s[0] ) >= 0 && hex2value( s[1] ) >= 0 ) {
|
||||
/* skip over lead digit of two hex digit code */
|
||||
s++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* unescape filter value */
|
||||
/* support both LDAP v2 and v3 escapes */
|
||||
/* output can include nul characters */
|
||||
static ber_slen_t
|
||||
filter_value_unescape( char *fval )
|
||||
{
|
||||
ber_slen_t r, v;
|
||||
int v1, v2;
|
||||
|
||||
for( r=v=0; fval[v] != '\0'; v++ ) {
|
||||
switch( fval[v] ) {
|
||||
case '\\':
|
||||
/* escape */
|
||||
v++;
|
||||
|
||||
if ( fval[v] == '\0' ) {
|
||||
/* escape at end of string */
|
||||
return -1;
|
||||
|
||||
} else if (( v1 = hex2value( fval[v] )) < 0 ) {
|
||||
/* LDAPv3 escape */
|
||||
|
||||
if (( v2 = hex2value( fval[v+1] )) < 0 ) {
|
||||
/* must be two digit code */
|
||||
return -1;
|
||||
}
|
||||
|
||||
fval[r++] = v1 * 16 + v2;
|
||||
v++;
|
||||
|
||||
} else {
|
||||
/* LDAPv2 escape */
|
||||
fval[r++] = fval[v];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
fval[r++] = fval[v];
|
||||
}
|
||||
}
|
||||
|
||||
fval[r] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *
|
||||
put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
|
||||
{
|
||||
|
|
@ -378,8 +505,8 @@ put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
|
|||
static int
|
||||
put_filter( BerElement *ber, char *str )
|
||||
{
|
||||
char *next, *tmp, *s, *d;
|
||||
int parens, balance, escape, gotescape;
|
||||
char *next;
|
||||
int parens, balance, escape;
|
||||
|
||||
/*
|
||||
* A Filter looks like this:
|
||||
|
|
@ -416,7 +543,7 @@ put_filter( BerElement *ber, char *str )
|
|||
|
||||
Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
|
||||
|
||||
gotescape = parens = 0;
|
||||
parens = 0;
|
||||
while ( *str ) {
|
||||
switch ( *str ) {
|
||||
case '(':
|
||||
|
|
@ -471,7 +598,7 @@ put_filter( BerElement *ber, char *str )
|
|||
balance--;
|
||||
}
|
||||
if ( *next == '\\' && ! escape )
|
||||
gotescape = escape = 1;
|
||||
escape = 1;
|
||||
else
|
||||
escape = 0;
|
||||
if ( balance )
|
||||
|
|
@ -481,24 +608,9 @@ put_filter( BerElement *ber, char *str )
|
|||
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 );
|
||||
if ( put_simple_filter( ber, str ) == -1 ) {
|
||||
return( -1 );
|
||||
}
|
||||
LDAP_FREE( tmp );
|
||||
*next++ = ')';
|
||||
str = next;
|
||||
parens--;
|
||||
|
|
@ -523,24 +635,9 @@ put_filter( BerElement *ber, char *str )
|
|||
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 );
|
||||
if ( put_simple_filter( ber, str ) == -1 ) {
|
||||
return( -1 );
|
||||
}
|
||||
LDAP_FREE( tmp );
|
||||
str = next;
|
||||
break;
|
||||
}
|
||||
|
|
@ -589,57 +686,76 @@ put_simple_filter(
|
|||
char *str )
|
||||
{
|
||||
char *s;
|
||||
char *value, savechar;
|
||||
char *value;
|
||||
ber_tag_t ftype;
|
||||
int rc;
|
||||
int rc = -1;
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
|
||||
|
||||
if ( (s = strchr( str, '=' )) == NULL )
|
||||
return( -1 );
|
||||
str = LDAP_STRDUP( str );
|
||||
if( str == NULL ) return -1;
|
||||
|
||||
if ( (s = strchr( str, '=' )) == NULL ) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
value = s + 1;
|
||||
*s-- = '\0';
|
||||
savechar = *s;
|
||||
|
||||
switch ( *s ) {
|
||||
case '<':
|
||||
ftype = LDAP_FILTER_LE;
|
||||
*s = '\0';
|
||||
if(! ldap_is_attribute( str ) ) goto done;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
ftype = LDAP_FILTER_GE;
|
||||
*s = '\0';
|
||||
if(! ldap_is_attribute( str ) ) goto done;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
ftype = LDAP_FILTER_APPROX;
|
||||
*s = '\0';
|
||||
if(! ldap_is_attribute( str ) ) goto done;
|
||||
break;
|
||||
|
||||
case ':': /* LDAPv3 extended filter */
|
||||
ftype = LDAP_FILTER_EXTENDED;
|
||||
return -1;
|
||||
if(! ldap_is_attribute_ext( str ) ) goto done;
|
||||
goto done; /* XXX not yet implemented */
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( strchr( value, '*' ) == NULL ) {
|
||||
if ( find_wildcard( 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 );
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ftype == LDAP_FILTER_PRESENT ) {
|
||||
rc = ber_printf( ber, "ts", ftype, str );
|
||||
|
||||
} else {
|
||||
rc = ber_printf( ber, "t{ss}", ftype, str, value );
|
||||
ber_slen_t len = filter_value_unescape( value );
|
||||
|
||||
if( len >= 0 ) {
|
||||
rc = ber_printf( ber, "t{so}",
|
||||
ftype, str, value, len );
|
||||
}
|
||||
}
|
||||
|
||||
*s = savechar;
|
||||
*(value-1) = '=';
|
||||
return( rc == -1 ? rc : 0 );
|
||||
if( rc != -1 ) rc = 0;
|
||||
|
||||
done:
|
||||
LDAP_FREE( str );
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -654,8 +770,8 @@ put_substring_filter( BerElement *ber, char *type, char *val )
|
|||
if ( ber_printf( ber, "t{s{", ftype, type ) == -1 )
|
||||
return( -1 );
|
||||
|
||||
while ( val != NULL ) {
|
||||
if ( (nextstar = strchr( val, '*' )) != NULL )
|
||||
for( ; val != NULL; val=nextstar ) {
|
||||
if ( (nextstar = find_wildcard( val )) != NULL )
|
||||
*nextstar++ = '\0';
|
||||
|
||||
if ( gotstar == 0 ) {
|
||||
|
|
@ -665,15 +781,20 @@ put_substring_filter( BerElement *ber, char *type, char *val )
|
|||
} else {
|
||||
ftype = LDAP_SUBSTRING_ANY;
|
||||
}
|
||||
|
||||
if ( *val != '\0' ) {
|
||||
if ( ber_printf( ber, "ts", ftype, val ) == -1 )
|
||||
ber_slen_t len = filter_value_unescape( val );
|
||||
|
||||
if ( len < 0 ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
|
||||
gotstar = 1;
|
||||
if ( nextstar != NULL )
|
||||
*(nextstar-1) = '*';
|
||||
val = nextstar;
|
||||
}
|
||||
|
||||
if ( ber_printf( ber, /* {{ */ "}}" ) == -1 )
|
||||
|
|
|
|||
Loading…
Reference in a new issue