Hello,

Active Directory (and ADAM) limits the maximum number of objects that
are returned in a single search result. This limit is controlled using
AD server parameter MaxPageSize. Default value is 1000. To perform a
search where the result might exceed this number of objects, the
client must specify the paged search control.

Mozilla LDAP C SDK doesn't support the paged search control (RFC2696)
and I added it for my needs (bulk load of public certificates from
AD). I use the patched version for a while: since Sep'2009 for
testing; since Oct'2009 in 3 production systems. Didn't see any
problems so far.

So, I'd like to contribute the patch that adds the paged search
control, under suitable license (i assume, that means MPL 1.1/GPL 2.0/
LGPL 2.1)

Please, let me know, if there is any interest in it: if yes, i will
double-check it to ensure that it builds cleanly against head version
in CVS at least on the following platforms:
 - Win32 (VC7.1, VC8 and VC9);
 - Linux x86 (gcc 3.4.6 on RHEL4 and 4.1.2 on RHEL5);
 - Linux x86-64 (gcc 4.1.2 on RHEL5).


--- a/ldap/include/ldap-extension.h
+++ b/ldap/include/ldap-extension.h
@@ -103,6 +103,7 @@ extern "C" {
 */
 #define LDAP_CONTROL_PROXIEDAUTH        "2.16.840.1.113730.3.4.18" /*
version 2
 */
+#define LDAP_CONTROL_PAGEDRESULT        "1.2.840.113556.1.4.319"

 /* Authorization Identity Request and Response Controls */
 #define LDAP_CONTROL_AUTHZID_REQ        "2.16.840.1.113730.3.4.16"
@@ -235,6 +236,14 @@ LDAP_API(int) LDAP_CALL
ldap_create_geteffectiveRights_control( LDAP *ld,
         const char *authzid, const char **attrlist,  const char
ctl_iscritical,
                LDAPControl **ctrlp );

+LDAP_API(int) LDAP_CALL ldap_create_page_control( LDAP *ld,
+        unsigned long pagesize, struct berval *cookiep, const char
ctl_iscritical,
+               LDAPControl **ctrlp );
+
+LDAP_API(int) LDAP_CALL ldap_parse_page_control( LDAP *ld,
+        LDAPControl **ctrls, unsigned long *list_countp, struct
berval **cookiep );
+
+
 /*
  * Virtual list view (an LDAPv3 extension --
LDAP_API_FEATURE_VIRTUAL_LIST_VIEW)
  */
--- /dev/null
+++ b/ldap/libraries/libldap/pagectrl.c
@@ -0,0 +1,221 @@
+/* pagectrl.c - paged results control implementation. */
+#include "ldap-int.h"
+
+/*
+ * function to create a Simple Paged Results control that can be
passed
+ * to ldap_search_ext() or ldap_search_ext_s().  *ctrlp will be set
to a
+ * freshly allocated LDAPControl structure.  Returns an LDAP error
code
+ * (LDAP_SUCCESS if all goes well).
+ *
+ *  Parameters:
+ *
+ *   ld              LDAP pointer to the desired connection
+ *
+ *   pagesize        The number of entries to return in each page
+ *
+ *   cookiep         Pointer to a berVal structure that the server
uses
+ *                   to determine the current location in the result
set.
+ *                   Set to NULL the first time.
+ *
+ *   iscritical      Is this control critical to the search?
+ *
+ *   ctrlp           the address of a place to put the constructed
control
+
+ The controlValue is an OCTET STRING wrapping the BER-encoded version
+ of the following SEQUENCE:
+
+   PageResult ::= SEQUENCE {
+               pageSize     INTEGER (0..maxInt),
+                                -- requested page size from client
+                                -- result set size estimate from
server
+               cookie       OCTET STRING }
+
+
+   Note:  The first time the Page control is created, the cookie
+                 should be set to a zero-length string. The cookie obtained
+                 from calling ldap_parse_page_control() should be used as
+                 the cookie in the next ldap_create_page_control call.
+
+ */
+
+int
+LDAP_CALL
+ldap_create_page_control(
+    LDAP *ld,
+    unsigned long pagesize,
+    struct berval *cookiep,
+    const char iscritical,
+    LDAPControl **ctrlp
+)
+{
+    BerElement *ber;
+    int rc;
+
+    if (!NSLDAPI_VALID_LDAP_POINTER( ld )) {
+        return( LDAP_PARAM_ERROR );
+    }
+
+    if ( NULL == ctrlp ) {
+        LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
+        return( LDAP_PARAM_ERROR );
+    }
+
+    /* create a ber package to hold the controlValue */
+    if ( LDAP_SUCCESS != nsldapi_alloc_ber_with_options( ld,
&ber )  )
+    {
+        LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+        return( LDAP_NO_MEMORY );
+    }
+
+    if ( LBER_ERROR == ber_printf( ber,
+                                   "{i",
+                                   pagesize ))
+    {
+        LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+        ber_free( ber, 1 );
+        return( LDAP_ENCODING_ERROR );
+    }
+
+    if ( NULL == cookiep )
+    {
+        if ( LBER_ERROR == ber_printf( ber,
+                                       "o",
+                                       "",
+                                       0 ))
+        {
+            LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+            ber_free( ber, 1 );
+            return( LDAP_ENCODING_ERROR );
+        }
+    }
+    else
+    {
+        if ( LBER_ERROR == ber_printf( ber,
+                                       "O",
+                                       cookiep ))
+        {
+            LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+            ber_free( ber, 1 );
+            return( LDAP_ENCODING_ERROR );
+        }
+    }
+
+    if ( LBER_ERROR == ber_printf( ber,
+                                   "}" ))
+    {
+        LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
+        ber_free( ber, 1 );
+        return( LDAP_ENCODING_ERROR );
+    }
+
+    rc = nsldapi_build_control( LDAP_CONTROL_PAGEDRESULT,
+                                ber,
+                                1,
+                                iscritical,
+                                ctrlp );
+
+    LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
+    return (rc);
+
+}
+
+/*
+ * function to find and parse the page control return information.
+ * *list_countp and *cookiep are set based on its contents. Returns
+ * an LDAP error code that indicates whether the parsing itself
+ * was successful (LDAP_SUCCESS if all goes well).
+ *
+ * Parameters:
+ *
+ *   ld              LDAP pointer to the desired connection
+ *
+ *   ctrls           The address of a NULL-terminated array of
+ *                   LDAPControl structures, typically obtained
+ *                   by a call to ldap_parse_result().
+ *
+ *   list_countp     This result parameter is filled in with the
number
+ *                   of entries returned in this page
+ *
+ *   cookiep         This result parameter is filled in with the
address
+ *                   of a struct berval that contains the server-
+ *                   generated cookie.
+ *                   The returned cookie SHOULD be used in the next
call
+ *                   to create a Page sort control.  The struct
berval
+ *                   returned SHOULD be disposed of by calling
ber_bvfree()
+ *                   when it is no longer needed.
+ *
+ */
+
+int
+LDAP_CALL
+ldap_parse_page_control(
+    LDAP *ld,
+    LDAPControl **ctrls,
+    unsigned long *list_countp,
+    struct berval **cookiep
+)
+{
+    BerElement *ber;
+    LDAPControl *pControl;
+    int i, foundPageControl;
+    unsigned long count;
+
+    if (cookiep) {
+        *cookiep = NULL;    /* Make sure we return a NULL if error
occurs. */
+    }
+
+    if (!NSLDAPI_VALID_LDAP_POINTER( ld )) {
+        return( LDAP_PARAM_ERROR );
+    }
+
+    /* simple paging of search results is an LDAPv3 control extension
*/
+    if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
+        LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
+        return( LDAP_NOT_SUPPORTED );
+    }
+
+    /* find the pageControl in the list of controls if it exists */
+    if ( ctrls == NULL ) {
+        LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+        return ( LDAP_CONTROL_NOT_FOUND );
+    }
+
+    foundPageControl = 0;
+    for ( i = 0; (( ctrls[i] != NULL ) && ( !foundPageControl )); i+
+ ) {
+        foundPageControl = !strcmp( ctrls[i]->ldctl_oid,
+                                    LDAP_CONTROL_PAGEDRESULT );
+    }
+
+    if ( !foundPageControl ) {
+        LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
+        return ( LDAP_CONTROL_NOT_FOUND );
+    } else {
+        /* let local var point to the pageControl */
+        pControl = ctrls[i-1];
+    }
+
+    /* allocate a Ber element with the contents of the control's
struct berval */
+    ber = ber_init (&pControl->ldctl_value);
+    if ( ber == NULL ) {
+        LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
+        return( LDAP_NO_MEMORY );
+    }
+
+    /* decode the result from the Ber element */
+    if ( LBER_ERROR == ber_scanf( ber, "{iO", &count, cookiep ) ) {
+        LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
+        ber_free( ber, 1 );
+        return( LDAP_DECODING_ERROR );
+    }
+
+    /* Return data to the caller for items that were requested. */
+    if (list_countp) {
+        *list_countp = count;
+    }
+
+    /* the ber encoding is no longer needed */
+    ber_free(ber,1);
+
+    return(LDAP_SUCCESS);
+
+}
--- a/ldap/libraries/msdos/winsock/nsldap32.def
+++ b/ldap/libraries/msdos/winsock/nsldap32.def
@@ -266,9 +266,6 @@ EXPORTS
        ldap_parse_sasl_bind_result             @489
        ldap_sasl_interactive_bind_s            @490
        ldap_sasl_interactive_bind_ext_s                @491
-;  LDAPv3 simple paging controls are not supported by Netscape at
this time.
-;  490 ldap_create_page_control
-;  491 ldap_parse_page_control
        ldap_create_sort_control                @492
        ldap_parse_sort_control         @493
 ;  an LDAPv3 language control was proposed but then retracted.
@@ -345,6 +342,9 @@ EXPORTS
 ;
        ldap_create_authzid_control             @600
        ldap_parse_authzid_control              @601
+;
+       ldap_create_page_control        @602
+       ldap_parse_page_control         @603
 ;
        ldap_memcache_init              @1000
        ldap_memcache_set               @1001
_______________________________________________
dev-tech-ldap mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-tech-ldap

Reply via email to