]> git.sur5r.net Git - openldap/commitdiff
ITS#247 ITS#275: fix handling of filters with '\*' (and other escapes)
authorKurt Zeilenga <kurt@openldap.org>
Mon, 30 Aug 1999 19:23:18 +0000 (19:23 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Mon, 30 Aug 1999 19:23:18 +0000 (19:23 +0000)
(based on latest devel codes).

CHANGES
libraries/libldap/search.c

diff --git a/CHANGES b/CHANGES
index 108b926aa44fdc69d34cd9bffc20b145cd6793d1..a04aee3d1b81f7d9b8309fd1f3e81b9e91a83b2c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,7 @@ Changes included in OpenLDAP 1.2 Release Engineering
        Fixed test005-modrdn to properly report failure in delete rdn case 
        Fixed ldapsearch (%s) bug (ITS#274)
        Fixed slapd (cn=*=+=*) regex bug (ITS#272)
+       Fixed -lldap (cn=*\**) filter handling (ITS#247 ITS#275)
        Build environment
                Disable config.cache to ensure consistent detection
        Documentation
index bec117c85b280f11117b994cfa9667c2b76e371b..945c0f6232960caef2a30fca2038a06e635c95f9 100644 (file)
 #include "ldap.h"
 #include "ldap-int.h"
 
+static int hex2value( int c );
+static long 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,
        unsigned long tag, int not ));
 static int put_filter LDAP_P(( BerElement *ber, char *str ));
@@ -187,6 +190,93 @@ 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 ( *s == '\0' )
+                               return NULL;    /* escape at end of string */
+                       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 long
+filter_value_unescape( char *fval )
+{
+       long 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;
+
+                       }
+
+                       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, unsigned long tag, int not )
 {
@@ -200,12 +290,8 @@ put_complex_filter( BerElement *ber, char *str, unsigned long tag, int not )
         */
 
        /* put explicit tag */
-       if ( ber_printf( ber, "t{", tag ) == -1 )
+       if ( ber_printf( ber, "t{", /*}*/ tag ) == -1 )
                return( NULL );
-/*
-       if ( !not && ber_printf( ber, "{" ) == -1 )
-               return( NULL );
-*/
 
        str++;
        if ( (next = find_right_paren( str )) == NULL )
@@ -217,12 +303,8 @@ put_complex_filter( BerElement *ber, char *str, unsigned long tag, int not )
        *next++ = ')';
 
        /* flush explicit tagged thang */
-       if ( ber_printf( ber, "}" ) == -1 )
-               return( NULL );
-/*
-       if ( !not && ber_printf( ber, "}" ) == -1 )
+       if ( ber_printf( ber, /*{*/ "}" ) == -1 )
                return( NULL );
-*/
 
        return( next );
 }
@@ -230,8 +312,8 @@ put_complex_filter( BerElement *ber, char *str, unsigned long 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:
@@ -260,7 +342,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 '(':
@@ -315,7 +397,7 @@ put_filter( BerElement *ber, char *str )
                                                        balance--;
                                        }
                                        if ( *next == '\\' && ! escape )
-                                               gotescape = escape = 1;
+                                               escape = 1;
                                        else
                                                escape = 0;
                                        if ( balance )
@@ -325,24 +407,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 ) {
-                                       free( tmp );
+                               if ( put_simple_filter( ber, str ) == -1 ) {
                                        return( -1 );
                                }
-                               free( tmp );
                                *next++ = ')';
                                str = next;
                                parens--;
@@ -353,7 +420,7 @@ put_filter( BerElement *ber, char *str )
                case ')':
                        Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
                            0 );
-                       if ( ber_printf( ber, "]" ) == -1 )
+                       if ( ber_printf( ber, /*[*/ "]" ) == -1 )
                                return( -1 );
                        str++;
                        parens--;
@@ -367,24 +434,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 ) {
-                               free( tmp );
+                       if ( put_simple_filter( ber, str ) == -1 ) {
                                return( -1 );
                        }
-                       free( tmp );
                        str = next;
                        break;
                }
@@ -431,17 +483,21 @@ static int
 put_simple_filter( BerElement *ber, char *str )
 {
        char            *s;
-       char            *value, savechar;
+       char            *value;
        unsigned long   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 '<':
@@ -457,27 +513,34 @@ put_simple_filter( BerElement *ber, char *str )
                *s = '\0';
                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 );
+               long 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:
+       free( str );
+       return rc;
 }
 
 static int
@@ -492,8 +555,8 @@ put_substring_filter( BerElement *ber, char *type, char *val )
        if ( ber_printf( ber, "t{s{", LDAP_FILTER_SUBSTRINGS, 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 ) {
@@ -503,15 +566,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 )
+                       long 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 )