#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,
*
* 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 );
*/
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 )
{
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 )
{
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:
Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
- gotescape = parens = 0;
+ parens = 0;
while ( *str ) {
switch ( *str ) {
case '(':
balance--;
}
if ( *next == '\\' && ! escape )
- gotescape = escape = 1;
+ escape = 1;
else
escape = 0;
if ( balance )
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--;
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;
}
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
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 ) {
} 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 )