]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/search.c
add support for VERSION, TIMEOUT and NETWORK_TIMEOUT in ldap.conf
[openldap] / libraries / libldap / search.c
index c8e276a6635af17e1f90e61675c094c103fb9e06..762bfd2fe7abd4999fd9365d75f72dcea8d9c7a2 100644 (file)
@@ -1,13 +1,19 @@
 /* $OpenLDAP$ */
-/*
- * Copyright 1998-2002 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-2006 The OpenLDAP Foundation.
+ * All rights reserved.
  *
- *  search.c
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * 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"
@@ -21,7 +27,7 @@
 #include <ac/time.h>
 
 #include "ldap-int.h"
-
+#include "ldap_log.h"
 
 /*
  * ldap_search_ext - initiate an ldap search operation.
  *
  *     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
@@ -60,6 +69,7 @@ ldap_search_ext(
        int rc;
        BerElement      *ber;
        int timelimit;
+       ber_int_t id;
 
        Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
 
@@ -72,7 +82,7 @@ ldap_search_ext(
 
        /*
         * 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 ) {
@@ -88,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;
@@ -139,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 );
        }
 
@@ -160,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
@@ -178,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 );
 
@@ -185,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 ));
 }
 
 
@@ -218,7 +211,8 @@ ldap_build_search_req(
        LDAPControl **sctrls,
        LDAPControl **cctrls,
        ber_int_t timelimit,
-       ber_int_t sizelimit )
+       ber_int_t sizelimit,
+       ber_int_t *idp)
 {
        BerElement      *ber;
        int             err;
@@ -262,6 +256,7 @@ ldap_build_search_req(
                }
        }
 
+       LDAP_NEXT_MSGID( ld, *idp );
 #ifdef LDAP_CONNECTIONLESS
        if ( LDAP_IS_UDP(ld) ) {
            err = ber_write( ber, ld->ld_options.ldo_peer,
@@ -270,7 +265,7 @@ ldap_build_search_req(
        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", ++ld->ld_msgid, 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,
@@ -278,7 +273,7 @@ ldap_build_search_req(
        } else
 #endif
        {
-           err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid,
+           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,
@@ -295,7 +290,7 @@ ldap_build_search_req(
                filter = "(objectclass=*)";
        }
 
-       err = ldap_int_put_filter( ber, filter );
+       err = ldap_pvt_put_filter( ber, filter );
 
        if ( err  == -1 ) {
                ld->ld_errno = LDAP_FILTER_ERROR;
@@ -303,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 );
@@ -336,7 +357,7 @@ ldap_search_st(
            == -1 )
                return( ld->ld_errno );
 
-       if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 )
+       if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 )
                return( ld->ld_errno );
 
        if ( ld->ld_errno == LDAP_TIMEOUT ) {
@@ -364,9 +385,110 @@ ldap_search_s(
            == -1 )
                return( ld->ld_errno );
 
-       if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, res ) == -1 )
+       if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 )
                return( ld->ld_errno );
 
        return( ldap_result2error( ld, *res, 0 ) );
 }
 
+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) ])
+
+/*
+ * compute the length of the escaped value
+ */
+ber_len_t
+ldap_bv2escaped_filter_value_len( struct berval *in )
+{
+       ber_len_t       i, l;
+
+       assert( in != NULL );
+
+       if ( in->bv_len == 0 ) {
+               return 0;
+       }
+
+       for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
+               char c = in->bv_val[ i ];
+               if ( NEEDFLTESCAPE( c ) ) {
+                       l += 2;
+               }
+       }
+
+       return l;
+}
+
+int
+ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
+{
+       return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
+}
+
+int
+ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
+{
+       ber_len_t       i, l;
+
+       assert( in != NULL );
+       assert( out != NULL );
+
+       BER_BVZERO( out );
+
+       if ( in->bv_len == 0 ) {
+               return 0;
+       }
+
+       /* assume we'll escape everything */
+       l = ldap_bv2escaped_filter_value_len( in );
+       if ( l == in->bv_len ) {
+               if ( inplace ) {
+                       *out = *in;
+               } else {
+                       ber_dupbv( out, in );
+               }
+               return 0;
+       }
+       out->bv_val = LDAP_MALLOCX( l + 1, ctx );
+       if ( out->bv_val == NULL ) {
+               return -1;
+       }
+
+       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];
+
+               } else {
+                       assert( out->bv_len < l );
+                       out->bv_val[out->bv_len++] = c;
+               }
+       }
+
+       out->bv_val[out->bv_len] = '\0';
+
+       return 0;
+}
+