]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/filter.c
fix non-printable flag detection; improve dn test (passes all but last in http:/...
[openldap] / libraries / libldap / filter.c
index 960327de282f4950b933d42ae155c150b22cdd3e..60fd907975a4d6ef06dd290029ae03301cd29dd4 100644 (file)
@@ -1,6 +1,6 @@
 /* $OpenLDAP$ */
 /*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 /*  Portions
@@ -117,7 +117,7 @@ static int ldap_is_desc ( const char *str )
        return 0;
 
 options:
-       if( !LDAP_LDH( str[i] )) {
+       if( !LDAP_LDH( str[0] )) {
                return 0;
        }
        for( i=1; str[i]; i++ ) {
@@ -153,7 +153,7 @@ find_right_paren( char *s )
                if ( balance ) s++;
        }
 
-       return( *s ? s : NULL );
+       return *s ? s : NULL;
 }
 
 static int hex2value( int c )
@@ -181,27 +181,31 @@ ldap_pvt_find_wildcard( const char *s )
                case '*':       /* found wildcard */
                        return (char *) s;
 
+               case '(':
+               case ')':
+                       return NULL;
+
                case '\\':
                        if( s[1] == '\0' ) return NULL;
+
                        if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
                                s+=2;
-                       }
 
-                       switch( s[1] ) {
+                       } else switch( s[1] ) {
                        default:
                                return NULL;
 
                        /* allow RFC 1960 escapes */
-                       case '\\':
                        case '*':
                        case '(':
                        case ')':
+                       case '\\':
                                s++;
                        }
                }
        }
 
-       return s;
+       return (char *) s;
 }
 
 /* unescape filter value */
@@ -215,6 +219,11 @@ ldap_pvt_filter_value_unescape( char *fval )
 
        for( r=v=0; fval[v] != '\0'; v++ ) {
                switch( fval[v] ) {
+               case '(':
+               case ')':
+               case '*':
+                       return -1;
+
                case '\\':
                        /* escape */
                        v++;
@@ -272,30 +281,37 @@ put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
         */
 
        /* put explicit tag */
-       if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 )
-               return( NULL );
+       if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
+               return NULL;
+       }
 
        str++;
-       if ( (next = find_right_paren( str )) == NULL )
-               return( NULL );
+       if ( (next = find_right_paren( str )) == NULL ) {
+               return NULL;
+       }
 
        *next = '\0';
-       if ( put_filter_list( ber, str, tag ) == -1 )
-               return( NULL );
+       if ( put_filter_list( ber, str, tag ) == -1 ) {
+               return NULL;
+       }
 
        /* close the '(' */
        *next++ = ')';
 
        /* flush explicit tagged thang */
-       if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 )
-               return( NULL );
+       if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
+               return NULL;
+       }
 
-       return( next );
+       return next;
 }
 
 int
-ldap_int_put_filter( BerElement *ber, char *str )
+ldap_int_put_filter( BerElement *ber, const char *str_in )
 {
+       int rc;
+       char    *freeme;
+       char    *str;
        char    *next;
        int     parens, balance, escape;
 
@@ -332,7 +348,11 @@ ldap_int_put_filter( BerElement *ber, char *str )
         * Note: tags in a choice are always explicit
         */
 
-       Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
+       Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
+
+       freeme = LDAP_STRDUP( str_in );
+       if( freeme == NULL ) return LDAP_NO_MEMORY;
+       str = freeme;
 
        parens = 0;
        while ( *str ) {
@@ -351,7 +371,10 @@ ldap_int_put_filter( BerElement *ber, char *str )
 
                                str = put_complex_filter( ber, str,
                                    LDAP_FILTER_AND, 0 );
-                               if( str == NULL ) return( -1 );
+                               if( str == NULL ) {
+                                       rc = -1;
+                                       goto done;
+                               }
 
                                parens--;
                                break;
@@ -362,7 +385,10 @@ ldap_int_put_filter( BerElement *ber, char *str )
 
                                str = put_complex_filter( ber, str,
                                    LDAP_FILTER_OR, 0 );
-                               if( str == NULL ) return( -1 );
+                               if( str == NULL ) {
+                                       rc = -1;
+                                       goto done;
+                               }
 
                                parens--;
                                break;
@@ -373,7 +399,10 @@ ldap_int_put_filter( BerElement *ber, char *str )
 
                                str = put_complex_filter( ber, str,
                                    LDAP_FILTER_NOT, 0 );
-                               if( str == NULL ) return( -1 );
+                               if( str == NULL ) {
+                                       rc = -1;
+                                       goto done;
+                               }
 
                                parens--;
                                break;
@@ -385,28 +414,39 @@ ldap_int_put_filter( BerElement *ber, char *str )
                                balance = 1;
                                escape = 0;
                                next = str;
+
                                while ( *next && balance ) {
                                        if ( escape == 0 ) {
-                                               if ( *next == '(' )
+                                               if ( *next == '(' ) {
                                                        balance++;
-                                               else if ( *next == ')' )
+                                               } else if ( *next == ')' ) {
                                                        balance--;
+                                               }
                                        }
-                                       if ( *next == '\\' && ! escape )
+
+                                       if ( *next == '\\' && ! escape ) {
                                                escape = 1;
-                                       else
+                                       } else {
                                                escape = 0;
-                                       if ( balance )
-                                               next++;
+                                       }
+
+                                       if ( balance ) next++;
+                               }
+
+                               if ( balance != 0 ) {
+                                       rc = -1;
+                                       goto done;
                                }
-                               if ( balance != 0 )
-                                       return( -1 );
 
                                *next = '\0';
+
                                if ( put_simple_filter( ber, str ) == -1 ) {
-                                       return( -1 );
+                                       rc = -1;
+                                       goto done;
                                }
-                               *next++ = ')';
+
+                               *next++ = /*'('*/ ')';
+
                                str = next;
                                parens--;
                                break;
@@ -416,8 +456,10 @@ ldap_int_put_filter( BerElement *ber, char *str )
                case /*'('*/ ')':
                        Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
                                0, 0, 0 );
-                       if ( ber_printf( ber, /*"["*/ "]" ) == -1 )
-                               return( -1 );
+                       if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
+                               rc = -1;
+                               goto done;
+                       }
                        str++;
                        parens--;
                        break;
@@ -431,14 +473,19 @@ ldap_int_put_filter( BerElement *ber, char *str )
                                0, 0, 0 );
                        next = strchr( str, '\0' );
                        if ( put_simple_filter( ber, str ) == -1 ) {
-                               return( -1 );
+                               rc = -1;
+                               goto done;
                        }
                        str = next;
                        break;
                }
        }
 
-       return( parens ? -1 : 0 );
+       rc = parens ? -1 : 0;
+
+done:
+       LDAP_FREE( freeme );
+       return rc;
 }
 
 /*
@@ -461,7 +508,7 @@ put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
                if ( *str == '\0' ) break;
 
                if ( (next = find_right_paren( str + 1 )) == NULL ) {
-                       return( -1 );
+                       return -1;
                }
                save = *++next;
 
@@ -491,7 +538,7 @@ put_simple_filter(
        ber_tag_t       ftype;
        int             rc = -1;
 
-       Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n",
+       Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
                str, 0, 0 );
 
        str = LDAP_STRDUP( str );
@@ -508,19 +555,16 @@ put_simple_filter(
        case '<':
                ftype = LDAP_FILTER_LE;
                *s = '\0';
-               if(! ldap_is_desc( str ) ) goto done;
                break;
 
        case '>':
                ftype = LDAP_FILTER_GE;
                *s = '\0';
-               if(! ldap_is_desc( str ) ) goto done;
                break;
 
        case '~':
                ftype = LDAP_FILTER_APPROX;
                *s = '\0';
-               if(! ldap_is_desc( str ) ) goto done;
                break;
 
        case ':':
@@ -535,11 +579,7 @@ put_simple_filter(
                        char *dn = strchr( str, ':' );
                        char *rule = NULL;
 
-                       if( dn == NULL ) {
-                               if(! ldap_is_desc( str ) ) goto done;
-
-                       } else {
-
+                       if( dn != NULL ) {
                                *dn++ = '\0';
                                rule = strchr( dn, ':' );
 
@@ -588,6 +628,7 @@ put_simple_filter(
                        if( rc != -1 && rule && *rule != '\0' ) {
                                rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
                        }
+
                        if( rc != -1 && *str != '\0' ) {
                                rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
                        }
@@ -596,25 +637,40 @@ put_simple_filter(
                                ber_slen_t len = ldap_pvt_filter_value_unescape( value );
 
                                if( len >= 0 ) {
-                                       rc = ber_printf( ber, /*"{"*/ "totbN}",
-                                               LDAP_FILTER_EXT_VALUE, value, len,
-                                               LDAP_FILTER_EXT_DNATTRS, dn != NULL);
+                                       rc = ber_printf( ber, "to",
+                                               LDAP_FILTER_EXT_VALUE, value, len );
                                } else {
                                        rc = -1;
                                }
                        }
+
+                       if( rc != -1 && dn ) {
+                               rc = ber_printf( ber, "tb",
+                                       LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
+                       }
+
+                       if( rc != -1 ) { 
+                               rc = ber_printf( ber, /*"{"*/ "N}" );
+                       }
                }
                goto done;
 
        default:
-               {
+               if( !ldap_is_desc( str ) ) {
+                       goto done;
+
+               } else {
                        char *nextstar = ldap_pvt_find_wildcard( value );
+
                        if ( nextstar == NULL ) {
                                goto done;
+
                        } else if ( *nextstar == '\0' ) {
                                ftype = LDAP_FILTER_EQUALITY;
+
                        } else if ( strcmp( value, "*" ) == 0 ) {
                                ftype = LDAP_FILTER_PRESENT;
+
                        } else {
                                rc = put_substring_filter( ber, str, value );
                                goto done;
@@ -622,6 +678,8 @@ put_simple_filter(
                } break;
        }
 
+       if( !ldap_is_desc( str ) ) goto done;
+
        if ( ftype == LDAP_FILTER_PRESENT ) {
                rc = ber_printf( ber, "ts", ftype, str );
 
@@ -650,8 +708,9 @@ put_substring_filter( BerElement *ber, char *type, char *val )
        Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
                type, val, 0 );
 
-       if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 )
-               return( -1 );
+       if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
+               return -1;
+       }
 
        for( ; *val; val=nextstar ) {
                nextstar = ldap_pvt_find_wildcard( val );
@@ -670,7 +729,7 @@ put_substring_filter( BerElement *ber, char *type, char *val )
 
                *nextstar++ = '\0';
 
-               if ( *val != '\0' ) {
+               if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
                        ber_slen_t len = ldap_pvt_filter_value_unescape( val );
 
                        if ( len < 0  ) {
@@ -683,8 +742,9 @@ put_substring_filter( BerElement *ber, char *type, char *val )
                }
        }
 
-       if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 )
+       if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {
                return -1;
+       }
 
        return 0;
 }