]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/search.c
happy new year
[openldap] / libraries / libldap / search.c
index 2d2071030261cf7545a8e2f6dfd624717a169639..0ff402ea6997d9cdeafe6bb971bfc84475e16c9b 100644 (file)
@@ -1,13 +1,19 @@
 /* $OpenLDAP$ */
-/*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*  Portions
- *  Copyright (c) 1990 Regents of the University of Michigan.
- *  All rights reserved.
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2007 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
  *
- *  search.c
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
  */
 
 #include "portable.h"
 #include <ac/time.h>
 
 #include "ldap-int.h"
-
-static int ldap_is_attr_oid LDAP_P((
-       const char *attr ));
-
-static int ldap_is_attr_desc LDAP_P((
-       const char *attr ));
-
-static int hex2value LDAP_P((
-       int c ));
-
-static char *find_right_paren LDAP_P((
-       char *s ));
-
-static char *put_complex_filter LDAP_P((
-       BerElement *ber,
-       char *str,
-       ber_tag_t tag,
-       int not ));
-
-static int put_filter LDAP_P((
-       BerElement *ber,
-       char *str ));
-
-static int put_simple_filter LDAP_P((
-       BerElement *ber,
-       char *str ));
-
-static int put_substring_filter LDAP_P((
-       BerElement *ber,
-       char *type,
-       char *str ));
-
-static int put_filter_list LDAP_P((
-       BerElement *ber,
-       char *str ));
+#include "ldap_log.h"
 
 /*
  * ldap_search_ext - initiate an ldap search operation.
@@ -64,8 +36,11 @@ static int put_filter_list LDAP_P((
  *
  *     ld              LDAP descriptor
  *     base            DN of the base object
- *     scope           the search scope - one of LDAP_SCOPE_BASE,
- *                         LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
+ *     scope           the search scope - one of
+ *                             LDAP_SCOPE_BASE (baseObject),
+ *                         LDAP_SCOPE_ONELEVEL (oneLevel),
+ *                             LDAP_SCOPE_SUBTREE (subtree), or
+ *                             LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
  *     filter          a string containing the search filter
  *                     (e.g., "(|(cn=bob)(sn=bob))")
  *     attrs           list of attribute types to return for matches
@@ -73,7 +48,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, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
  *         attrs, attrsonly, sctrls, ctrls, timeout, sizelimit,
  *             &msgid );
  */
@@ -91,17 +66,23 @@ ldap_search_ext(
        int sizelimit,
        int *msgidp )
 {
+       int rc;
        BerElement      *ber;
        int timelimit;
+       ber_int_t id;
 
        Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
 
        assert( ld != NULL );
        assert( LDAP_VALID( ld ) );
 
+       /* check client controls */
+       rc = ldap_int_client_controls( ld, cctrls );
+       if( rc != LDAP_SUCCESS ) return rc;
+
        /*
         * if timeout is provided, both tv_sec and tv_usec must
-        * be non-zero
+        * not be zero
         */
        if( timeout != NULL ) {
                if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) {
@@ -117,26 +98,15 @@ ldap_search_ext(
        }
 
        ber = ldap_build_search_req( ld, base, scope, filter, attrs,
-           attrsonly, sctrls, cctrls, timelimit, sizelimit ); 
+           attrsonly, sctrls, cctrls, timelimit, sizelimit, &id ); 
 
        if ( ber == NULL ) {
                return ld->ld_errno;
        }
 
-#ifndef LDAP_NOCACHE
-       if ( ld->ld_cache != NULL ) {
-               if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
-                       ber_free( ber, 1 );
-                       ld->ld_errno = LDAP_SUCCESS;
-                       *msgidp = ld->ld_msgid;
-                       return ld->ld_errno;
-               }
-               ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
-       }
-#endif /* LDAP_NOCACHE */
 
        /* send the message */
-       *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber );
+       *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id );
 
        if( *msgidp < 0 )
                return ld->ld_errno;
@@ -168,14 +138,14 @@ ldap_search_ext_s(
                return( rc );
        }
 
-       rc = ldap_result( ld, msgid, 1, timeout, res );
+       rc = ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res );
 
        if( rc <= 0 ) {
                /* error(-1) or timeout(0) */
                return( ld->ld_errno );
        }
 
-       if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_EXTENDED_PARTIAL ) {
+       if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) {
                return( ld->ld_errno );
        }
 
@@ -189,8 +159,11 @@ ldap_search_ext_s(
  *
  *     ld              LDAP descriptor
  *     base            DN of the base object
- *     scope           the search scope - one of LDAP_SCOPE_BASE,
- *                         LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
+ *     scope           the search scope - one of
+ *                             LDAP_SCOPE_BASE (baseObject),
+ *                         LDAP_SCOPE_ONELEVEL (oneLevel),
+ *                             LDAP_SCOPE_SUBTREE (subtree), or
+ *                             LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
  *     filter          a string containing the search filter
  *                     (e.g., "(|(cn=bob)(sn=bob))")
  *     attrs           list of attribute types to return for matches
@@ -198,7 +171,7 @@ ldap_search_ext_s(
  *
  * Example:
  *     char    *attrs[] = { "mail", "title", 0 };
- *     msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
+ *     msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
  *         attrs, attrsonly );
  */
 int
@@ -207,6 +180,7 @@ ldap_search(
        char **attrs, int attrsonly )
 {
        BerElement      *ber;
+       ber_int_t       id;
 
        Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
 
@@ -214,25 +188,15 @@ ldap_search(
        assert( LDAP_VALID( ld ) );
 
        ber = ldap_build_search_req( ld, base, scope, filter, attrs,
-           attrsonly, NULL, NULL, -1, -1 ); 
+           attrsonly, NULL, NULL, -1, -1, &id ); 
 
        if ( ber == NULL ) {
                return( -1 );
        }
 
-#ifndef LDAP_NOCACHE
-       if ( ld->ld_cache != NULL ) {
-               if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
-                       ber_free( ber, 1 );
-                       ld->ld_errno = LDAP_SUCCESS;
-                       return( ld->ld_msgid );
-               }
-               ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
-       }
-#endif /* LDAP_NOCACHE */
 
        /* send the message */
-       return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber ));
+       return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ));
 }
 
 
@@ -241,17 +205,17 @@ ldap_build_search_req(
        LDAP *ld,
        LDAP_CONST char *base,
        ber_int_t scope,
-       LDAP_CONST char *filter_in,
+       LDAP_CONST char *filter,
        char **attrs,
        ber_int_t attrsonly,
        LDAPControl **sctrls,
        LDAPControl **cctrls,
        ber_int_t timelimit,
-       ber_int_t sizelimit )
+       ber_int_t sizelimit,
+       ber_int_t *idp)
 {
        BerElement      *ber;
        int             err;
-       char    *filter;
 
        /*
         * Create the search request.  It looks like this:
@@ -292,11 +256,29 @@ ldap_build_search_req(
                }
        }
 
-       err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid,
+       LDAP_NEXT_MSGID( ld, *idp );
+#ifdef LDAP_CONNECTIONLESS
+       if ( LDAP_IS_UDP(ld) ) {
+           err = ber_write( ber, ld->ld_options.ldo_peer,
+                   sizeof(struct sockaddr), 0);
+       }
+       if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
+           char *dn = ld->ld_options.ldo_cldapdn;
+           if (!dn) dn = "";
+           err = ber_printf( ber, "{ist{seeiib", *idp, dn,
                LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
                (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
                (timelimit < 0) ? ld->ld_timelimit : timelimit,
                attrsonly );
+       } else
+#endif
+       {
+           err = ber_printf( ber, "{it{seeiib", *idp,
+               LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
+               (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
+               (timelimit < 0) ? ld->ld_timelimit : timelimit,
+               attrsonly );
+       }
 
        if ( err == -1 ) {
                ld->ld_errno = LDAP_ENCODING_ERROR;
@@ -304,13 +286,11 @@ ldap_build_search_req(
                return( NULL );
        }
 
-       if( filter_in != NULL ) {
-               filter = LDAP_STRDUP( filter_in );
-       } else {
-               filter = LDAP_STRDUP( "(objectclass=*)" );
+       if( filter == NULL ) {
+               filter = "(objectclass=*)";
        }
-       err = put_filter( ber, filter );
-       LDAP_FREE( filter );
+
+       err = ldap_pvt_put_filter( ber, filter );
 
        if ( err  == -1 ) {
                ld->ld_errno = LDAP_FILTER_ERROR;
@@ -318,6 +298,32 @@ ldap_build_search_req(
                return( NULL );
        }
 
+#ifdef LDAP_DEBUG
+       if ( ldap_debug & LDAP_DEBUG_ARGS ) {
+               char    buf[ BUFSIZ ] = { ' ', '*', '\0' };
+
+               if ( attrs != NULL ) {
+                       char    *ptr;
+                       int     i;
+
+                       for ( ptr = buf, i = 0;
+                               attrs[ i ] != NULL && ptr < &buf[ sizeof( buf ) ];
+                               i++ )
+                       {
+                               ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
+                                       " %s", attrs[ i ] );
+                       }
+
+                       if ( ptr >= &buf[ sizeof( buf ) ] ) {
+                               AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
+                                       "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
+                       } 
+               }
+
+               Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", buf, 0, 0 );
+       }
+#endif /* LDAP_DEBUG */
+
        if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
                ld->ld_errno = LDAP_ENCODING_ERROR;
                ber_free( ber, 1 );
@@ -339,613 +345,150 @@ ldap_build_search_req(
        return( ber );
 }
 
-static int ldap_is_attr_oid ( const char *attr )
+int
+ldap_search_st(
+       LDAP *ld, LDAP_CONST char *base, int scope,
+       LDAP_CONST char *filter, char **attrs,
+       int attrsonly, struct timeval *timeout, LDAPMessage **res )
 {
-       int i, c, digit=0;
-
-       for( i = 0; (c = attr[i]) != 0; i++ ) {
-               if( c >= '0' && c <= '9' ) {
-                       digit=1;
+       int     msgid;
 
-               } else if ( c != '.' ) {
-                       /* not digit nor '.' */
-                       return 0;
+       if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
+           == -1 )
+               return( ld->ld_errno );
 
-               } else if ( !digit ) {
-                       /* '.' but prev not digit */
-                       return 0;
+       if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 )
+               return( ld->ld_errno );
 
-               } else {
-                       /* '.' */
-                       digit = 0;
-               }
+       if ( ld->ld_errno == LDAP_TIMEOUT ) {
+               (void) ldap_abandon( ld, msgid );
+               ld->ld_errno = LDAP_TIMEOUT;
+               return( ld->ld_errno );
        }
 
-       return digit;
+       return( ldap_result2error( ld, *res, 0 ) );
 }
 
-static int ldap_is_attr_desc ( const char *attr )
+int
+ldap_search_s(
+       LDAP *ld,
+       LDAP_CONST char *base,
+       int scope,
+       LDAP_CONST char *filter,
+       char **attrs,
+       int attrsonly,
+       LDAPMessage **res )
 {
-       /* cheap attribute description check */
-       int i, c;
+       int     msgid;
 
-       for( i = 0; (c = attr[i]) != 0; i++ ) {
-               if (( c >= '0' && c <= '9' )
-                       || ( c >= 'A' && c <= 'Z' )
-                       || ( c >= 'a' && c <= 'z' )
-                       || ( c == '.' || c == '-' )
-                       || ( c == ';' )) continue;
+       if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
+           == -1 )
+               return( ld->ld_errno );
 
-               return 0;
-       }
+       if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 )
+               return( ld->ld_errno );
 
-       return i > 0;
+       return( ldap_result2error( ld, *res, 0 ) );
 }
 
-static char *
-find_right_paren( char *s )
-{
-       int     balance, escape;
-
-       balance = 1;
-       escape = 0;
-       while ( *s && balance ) {
-               if ( escape == 0 ) {
-                       if ( *s == '(' )
-                               balance++;
-                       else if ( *s == ')' )
-                               balance--;
-               }
-               if ( *s == '\\' && ! escape )
-                       escape = 1;
-               else
-                       escape = 0;
-               if ( balance )
-                       s++;
-       }
+static char escape[128] = {
+       1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1,
+
+       0, 0, 0, 0, 0, 0, 0, 0,
+       1, 1, 1, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 1, 0, 0, 0,
+
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 1
+};
+#define        NEEDFLTESCAPE(c)        ((c) & 0x80 || escape[ (unsigned)(c) ])
 
-       return( *s ? s : NULL );
-}
-
-static int hex2value( int c )
+/*
+ * compute the length of the escaped value
+ */
+ber_len_t
+ldap_bv2escaped_filter_value_len( struct berval *in )
 {
-       if( c >= '0' && c <= '9' ) {
-               return c - '0';
-       }
-
-       if( c >= 'A' && c <= 'F' ) {
-               return c + (10 - (int) 'A');
-       }
+       ber_len_t       i, l;
 
-       if( c >= 'a' && c <= 'f' ) {
-               return c + (10 - (int) 'a');
-       }
-
-       return -1;
-}
+       assert( in != NULL );
 
-char *
-ldap_pvt_find_wildcard( const char *s )
-{
-       for( ; *s != '\0' ; s++ ) {
-               switch( *s ) {
-               case '*':       /* found wildcard */
-                       return (char *) s;
-
-               case '\\':
-                       s++; /* skip over escape */
-                       if ( *s == '\0' )
-                               return NULL;    /* escape at end of string */
-               }
+       if ( in->bv_len == 0 ) {
+               return 0;
        }
 
-       return NULL;
-}
-
-/* unescape filter value */
-/* support both LDAP v2 and v3 escapes */
-/* output can include nul characters */
-ber_slen_t
-ldap_pvt_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;
-
-                       }
-
-                       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];
+       for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
+               char c = in->bv_val[ i ];
+               if ( NEEDFLTESCAPE( c ) ) {
+                       l += 2;
                }
        }
 
-       fval[r] = '\0';
-       return r;
+       return l;
 }
 
-static char *
-put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
-{
-       char    *next;
-
-       /*
-        * We have (x(filter)...) with str sitting on
-        * the x.  We have to find the paren matching
-        * the one before the x and put the intervening
-        * filters by calling put_filter_list().
-        */
-
-       /* put explicit tag */
-       if ( ber_printf( ber, "t{" /*}*/, tag ) == -1 )
-               return( NULL );
-
-       str++;
-       if ( (next = find_right_paren( str )) == NULL )
-               return( NULL );
-
-       *next = '\0';
-       if ( put_filter_list( ber, str ) == -1 )
-               return( NULL );
-       *next++ = ')';
-
-       /* flush explicit tagged thang */
-       if ( ber_printf( ber, /*{*/ "N}" ) == -1 )
-               return( NULL );
-
-       return( next );
-}
-
-static int
-put_filter( BerElement *ber, char *str )
-{
-       char    *next;
-       int     parens, balance, escape;
-
-       /*
-        * A Filter looks like this:
-        *      Filter ::= CHOICE {
-        *              and             [0]     SET OF Filter,
-        *              or              [1]     SET OF Filter,
-        *              not             [2]     Filter,
-        *              equalityMatch   [3]     AttributeValueAssertion,
-        *              substrings      [4]     SubstringFilter,
-        *              greaterOrEqual  [5]     AttributeValueAssertion,
-        *              lessOrEqual     [6]     AttributeValueAssertion,
-        *              present         [7]     AttributeType,
-        *              approxMatch     [8]     AttributeValueAssertion,
-        *                              extensibleMatch [9]             MatchingRuleAssertion -- LDAPv3
-        *      }
-        *
-        *      SubstringFilter ::= SEQUENCE {
-        *              type               AttributeType,
-        *              SEQUENCE OF CHOICE {
-        *                      initial          [0] IA5String,
-        *                      any              [1] IA5String,
-        *                      final            [2] IA5String
-        *              }
-        *      }
-        *
-        *              MatchingRuleAssertion ::= SEQUENCE {    -- LDAPv3
-        *                      matchingRule    [1] MatchingRuleId OPTIONAL,
-        *                      type            [2] AttributeDescription OPTIONAL,
-        *                      matchValue      [3] AssertionValue,
-        *                      dnAttributes    [4] BOOLEAN DEFAULT FALSE }
-        *
-        * Note: tags in a choice are always explicit
-        */
-
-       Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
-
-       parens = 0;
-       while ( *str ) {
-               switch ( *str ) {
-               case '(':
-                       str++;
-                       parens++;
-
-                       /* skip spaces */
-                       while( LDAP_SPACE( *str ) ) str++;
-
-                       switch ( *str ) {
-                       case '&':
-                               Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
-                                   0, 0, 0 );
-
-                               if ( (str = put_complex_filter( ber, str,
-                                   LDAP_FILTER_AND, 0 )) == NULL )
-                                       return( -1 );
-
-                               parens--;
-                               break;
-
-                       case '|':
-                               Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
-                                   0, 0, 0 );
-
-                               if ( (str = put_complex_filter( ber, str,
-                                   LDAP_FILTER_OR, 0 )) == NULL )
-                                       return( -1 );
-
-                               parens--;
-                               break;
-
-                       case '!':
-                               Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
-                                   0, 0, 0 );
-
-                               if ( (str = put_complex_filter( ber, str,
-                                   LDAP_FILTER_NOT, 1 )) == NULL )
-                                       return( -1 );
-
-                               parens--;
-                               break;
-
-                       default:
-                               Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
-                                   0, 0, 0 );
-
-                               balance = 1;
-                               escape = 0;
-                               next = str;
-                               while ( *next && balance ) {
-                                       if ( escape == 0 ) {
-                                               if ( *next == '(' )
-                                                       balance++;
-                                               else if ( *next == ')' )
-                                                       balance--;
-                                       }
-                                       if ( *next == '\\' && ! escape )
-                                               escape = 1;
-                                       else
-                                               escape = 0;
-                                       if ( balance )
-                                               next++;
-                               }
-                               if ( balance != 0 )
-                                       return( -1 );
-
-                               *next = '\0';
-                               if ( put_simple_filter( ber, str ) == -1 ) {
-                                       return( -1 );
-                               }
-                               *next++ = ')';
-                               str = next;
-                               parens--;
-                               break;
-                       }
-                       break;
-
-               case ')':
-                       Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
-                           0 );
-                       if ( ber_printf( ber, /*[*/ "]" ) == -1 )
-                               return( -1 );
-                       str++;
-                       parens--;
-                       break;
-
-               case ' ':
-                       str++;
-                       break;
-
-               default:        /* assume it's a simple type=value filter */
-                       Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0,
-                           0 );
-                       next = strchr( str, '\0' );
-                       if ( put_simple_filter( ber, str ) == -1 ) {
-                               return( -1 );
-                       }
-                       str = next;
-                       break;
-               }
-       }
-
-       return( parens ? -1 : 0 );
-}
-
-/*
- * Put a list of filters like this "(filter1)(filter2)..."
- */
-
-static int
-put_filter_list( BerElement *ber, char *str )
+int
+ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
 {
-       char    *next;
-       char    save;
-
-       Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
-
-       while ( *str ) {
-               while ( *str && LDAP_SPACE( (unsigned char) *str ) )
-                       str++;
-               if ( *str == '\0' )
-                       break;
-
-               if ( (next = find_right_paren( str + 1 )) == NULL )
-                       return( -1 );
-               save = *++next;
-
-               /* now we have "(filter)" with str pointing to it */
-               *next = '\0';
-               if ( put_filter( ber, str ) == -1 )
-                       return( -1 );
-               *next = save;
-
-               str = next;
-       }
-
-       return( 0 );
+       return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
 }
 
-static int
-put_simple_filter(
-       BerElement *ber,
-       char *str )
+int
+ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
 {
-       char            *s;
-       char            *value;
-       ber_tag_t       ftype;
-       int             rc = -1;
+       ber_len_t       i, l;
 
-       Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
+       assert( in != NULL );
+       assert( out != NULL );
 
-       str = LDAP_STRDUP( str );
-       if( str == NULL ) return -1;
+       BER_BVZERO( out );
 
-       if ( (s = strchr( str, '=' )) == NULL ) {
-               goto done;
+       if ( in->bv_len == 0 ) {
+               return 0;
        }
 
-       value = s + 1;
-       *s-- = '\0';
-
-       switch ( *s ) {
-       case '<':
-               ftype = LDAP_FILTER_LE;
-               *s = '\0';
-               if(! ldap_is_attr_desc( str ) ) goto done;
-               break;
-
-       case '>':
-               ftype = LDAP_FILTER_GE;
-               *s = '\0';
-               if(! ldap_is_attr_desc( str ) ) goto done;
-               break;
-
-       case '~':
-               ftype = LDAP_FILTER_APPROX;
-               *s = '\0';
-               if(! ldap_is_attr_desc( str ) ) goto done;
-               break;
-
-       case ':':
-               /* RFC2254 extensible filters are off the form:
-                *              type [:dn] [:rule] := value
-                * or   [:dn]:rule := value             
-                */
-               ftype = LDAP_FILTER_EXT;
-               *s = '\0';
-
-               {
-                       char *dn = strchr( str, ':' );
-                       char *rule = NULL;
-
-                       if( dn == NULL ) {
-                               if(! ldap_is_attr_desc( str ) ) goto done;
-                       } else {
-
-                               *dn++ = '\0';
-                               rule = strchr( dn, ':' );
-
-                               if( rule == NULL ) {
-                                       /* one colon */
-                                       if ( strcmp(dn, "dn") == 0 ) {
-                                               /* must have attribute */
-                                               if( !ldap_is_attr_desc( str ) ) {
-                                                       goto done;
-                                               }
-
-                                               rule = "";
-
-                                       } else {
-                                         rule = dn;
-                                         dn = NULL;
-                                       }
-                               
-                               } else {
-                                       /* two colons */
-                                       *rule++ = '\0';
-
-                                       if ( strcmp(dn, "dn") != 0 ) {
-                                               /* must have "dn" */
-                                               goto done;
-                                       }
-                               }
-
-                       }
-
-                       if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
-                               /* must have either type or rule */
-                               goto done;
-                       }
-
-                       if ( *str != '\0' && !ldap_is_attr_desc( str ) ) {
-                               goto done;
-                       }
-
-                       if ( rule && *rule != '\0' && !ldap_is_attr_oid( rule ) ) {
-                               goto done;
-                       }
-
-                       rc = ber_printf( ber, "t{" /*}*/, ftype );
-
-                       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 );
-                       }
-
-                       if( rc != -1 ) {
-                               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);
-                               } else {
-                                       rc = -1;
-                               }
-                       }
-               }
-               goto done;
-
-       default:
-               if ( ldap_pvt_find_wildcard( value ) == NULL ) {
-                       ftype = LDAP_FILTER_EQUALITY;
-               } else if ( strcmp( value, "*" ) == 0 ) {
-                       ftype = LDAP_FILTER_PRESENT;
+       /* assume we'll escape everything */
+       l = ldap_bv2escaped_filter_value_len( in );
+       if ( l == in->bv_len ) {
+               if ( inplace ) {
+                       *out = *in;
                } else {
-                       rc = put_substring_filter( ber, str, value );
-                       goto done;
+                       ber_dupbv( out, in );
                }
-               break;
+               return 0;
        }
-
-       if ( ftype == LDAP_FILTER_PRESENT ) {
-               rc = ber_printf( ber, "ts", ftype, str );
-
-       } else {
-               ber_slen_t len = ldap_pvt_filter_value_unescape( value );
-
-               if( len >= 0 ) {
-                       rc = ber_printf( ber, "t{soN}",
-                               ftype, str, value, len );
-               }
+       out->bv_val = LDAP_MALLOCX( l + 1, ctx );
+       if ( out->bv_val == NULL ) {
+               return -1;
        }
 
-       if( rc != -1 ) rc = 0;
-
-done:
-       LDAP_FREE( str );
-       return rc;
-}
-
-static int
-put_substring_filter( BerElement *ber, char *type, char *val )
-{
-       char            *nextstar, gotstar = 0;
-       ber_tag_t       ftype = LDAP_FILTER_SUBSTRINGS;
-
-       Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
-           val, 0 );
-
-       if ( ber_printf( ber, "t{s{", ftype, type ) == -1 )
-               return( -1 );
-
-       for( ; val != NULL; val=nextstar ) {
-               if ( (nextstar = ldap_pvt_find_wildcard( val )) != NULL )
-                       *nextstar++ = '\0';
+       for ( i = 0; i < in->bv_len; i++ ) {
+               char c = in->bv_val[ i ];
+               if ( NEEDFLTESCAPE( c ) ) {
+                       assert( out->bv_len < l - 2 );
+                       out->bv_val[out->bv_len++] = '\\';
+                       out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
+                       out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
 
-               if ( gotstar == 0 ) {
-                       ftype = LDAP_SUBSTRING_INITIAL;
-               } else if ( nextstar == NULL ) {
-                       ftype = LDAP_SUBSTRING_FINAL;
                } else {
-                       ftype = LDAP_SUBSTRING_ANY;
-               }
-
-               if ( *val != '\0' ) {
-                       ber_slen_t len = ldap_pvt_filter_value_unescape( val );
-
-                       if ( len < 0  ) {
-                               return -1;
-                       }
-
-                       if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
-                               return( -1 );
-                       }
+                       assert( out->bv_len < l );
+                       out->bv_val[out->bv_len++] = c;
                }
-
-               gotstar = 1;
-       }
-
-       if ( ber_printf( ber, /* {{ */ "N}N}" ) == -1 )
-               return( -1 );
-
-       return( 0 );
-}
-
-int
-ldap_search_st(
-       LDAP *ld, LDAP_CONST char *base, int scope,
-       LDAP_CONST char *filter, char **attrs,
-       int attrsonly, struct timeval *timeout, LDAPMessage **res )
-{
-       int     msgid;
-
-       if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
-           == -1 )
-               return( ld->ld_errno );
-
-       if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 )
-               return( ld->ld_errno );
-
-       if ( ld->ld_errno == LDAP_TIMEOUT ) {
-               (void) ldap_abandon( ld, msgid );
-               ld->ld_errno = LDAP_TIMEOUT;
-               return( ld->ld_errno );
        }
 
-       return( ldap_result2error( ld, *res, 0 ) );
-}
-
-int
-ldap_search_s(
-       LDAP *ld,
-       LDAP_CONST char *base,
-       int scope,
-       LDAP_CONST char *filter,
-       char **attrs,
-       int attrsonly,
-       LDAPMessage **res )
-{
-       int     msgid;
-
-       if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
-           == -1 )
-               return( ld->ld_errno );
+       out->bv_val[out->bv_len] = '\0';
 
-       if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, res ) == -1 )
-               return( ld->ld_errno );
-
-       return( ldap_result2error( ld, *res, 0 ) );
+       return 0;
 }