]> git.sur5r.net Git - openldap/commitdiff
Fix filter escapes. ITS#247
authorKurt Zeilenga <kurt@openldap.org>
Sat, 7 Aug 1999 04:48:16 +0000 (04:48 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Sat, 7 Aug 1999 04:48:16 +0000 (04:48 +0000)
libraries/libldap/search.c

index 9d27820f93fa7114993c74e5a2d4165f3e0aab69..a94f17a38c1af551c75991b396ed0c8c1a2b8188 100644 (file)
 
 #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 )