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
Just submitted it to Bugzilla@Mozilla:
https://bugzilla.mozilla.org/show_bug.cgi?id=546893