Support for RFC 2696:

LDAP Control Extension for Simple Paged Results Manipulation

contributed by Lynn Moss <lynnmoss@us.ibm.com> (ITS#2189)

applied with changes.
This commit is contained in:
Pierangelo Masarati 2002-11-21 02:16:53 +00:00
parent 0f17b4f852
commit c354bb23bf
6 changed files with 368 additions and 9 deletions

View File

@ -56,6 +56,9 @@ usage( const char *s )
" -b basedn base dn for search\n"
" -E [!]<ctrl>[=<ctrlparam>] search controls (! indicates criticality)\n"
" [!]mv=<filter> (matched values filter)\n"
#ifdef LDAP_CONTROL_PAGEDRESULTS
" [!]pr=<size> (paged results)\n"
#endif /* LDAP_CONTROL_PAGEDRESULTS */
#ifdef LDAP_CONTROL_SUBENTRIES
" [!]subentries[=true|false] (subentries)\n"
#endif
@ -150,6 +153,13 @@ static int dosearch LDAP_P((
struct timeval *timeout,
int sizelimit ));
#ifdef LDAP_CONTROL_PAGEDRESULTS
static int parse_page_control(
LDAP *ld,
LDAPMessage *result,
struct berval *cookie );
#endif /* LDAP_CONTROL_PAGEDRESULTS */
static char *tmpdir = NULL;
static char *urlpre = NULL;
static char *prog = NULL;
@ -170,6 +180,17 @@ static char *sasl_secprops = NULL;
static int use_tls = 0;
static char *sortattr = NULL;
static int verbose, not, includeufn, vals2tmp, ldif;
#ifdef LDAP_CONTROL_PAGEDRESULTS
static int pageSize;
static ber_int_t searchControlSize = 0;
static ber_int_t morePagedResults = 1;
static struct berval cookie = { 0, NULL };
static int npagedresponses;
static int npagedentries;
static int npagedreferences;
static int npagedextended;
static int npagedpartial;
#endif /* LDAP_CONTROL_PAGEDRESULTS */
static void
urlize(char *url)
@ -198,6 +219,11 @@ main( int argc, char **argv )
struct berval *bvalp = NULL;
char *vrFilter = NULL, *control = NULL, *cvalue;
char *pw_file = NULL;
#ifdef LDAP_CONTROL_PAGEDRESULTS
BerElement *pageber = NULL;
struct berval *bvalptr = NULL;
int num = 0, moreEntries, searchControlCrit = 0;
#endif /* LDAP_CONTROL_PAGEDRESULTS */
infile = NULL;
@ -205,6 +231,11 @@ main( int argc, char **argv )
subentries = valuesReturnFilter =
attrsonly = manageDSAit = noop = ldif = want_bindpw = 0;
#ifdef LDAP_CONTROL_PAGEDRESULTS
npagedresponses = npagedentries = npagedreferences =
npagedextended = npagedpartial = 0;
#endif /* LDAP_CONTROL_PAGEDRESULTS */
prog = lutil_progname( "ldapsearch", argc, argv );
lutil_log_initialize(argc, argv);
@ -302,6 +333,25 @@ main( int argc, char **argv )
version = LDAP_VERSION3;
break;
#ifdef LDAP_CONTROL_PAGEDRESULTS
} else if ( strcasecmp( control, "pr" ) == 0 ) {
/* PagedResults control */
if ( searchControlSize !=0 ) {
fprintf( stderr, "PagedResultsControl previously specified" );
return EXIT_FAILURE;
}
num = sscanf( cvalue, "%d", &pageSize );
if ( num != 1 ) {
fprintf( stderr, "Invalid value for PagedResultsControl, %s.\n", cvalue);
return EXIT_FAILURE;
}
searchControlSize = (ber_int_t)pageSize;
searchControlCrit = crit;
break;
#endif /* LDAP_CONTROL_PAGEDRESULTS */
#ifdef LDAP_CONTROL_SUBENTRIES
} else if ( strcasecmp( control, "subentries" ) == 0 ) {
if( subentries ) {
@ -973,11 +1023,17 @@ main( int argc, char **argv )
}
}
#ifdef LDAP_CONTROL_PAGEDRESULTS
getNextPage:
if ( manageDSAit || noop || valuesReturnFilter || searchControlSize ) {
int critical = 0;
#else /* !LDAP_CONTROL_PAGEDRESULTS */
if ( manageDSAit || noop || valuesReturnFilter ) {
#endif /* !LDAP_CONTROL_PAGEDRESULTS */
int err;
int i=0;
LDAPControl c1,c2,c3,c4;
LDAPControl *ctrls[5];
LDAPControl c1,c2,c3,c4,c5;
LDAPControl *ctrls[6];
if ( manageDSAit ) {
ctrls[i++]=&c1;
@ -987,6 +1043,9 @@ main( int argc, char **argv )
c1.ldctl_value.bv_val = NULL;
c1.ldctl_value.bv_len = 0;
c1.ldctl_iscritical = manageDSAit > 1;
#ifdef LDAP_CONTROL_PAGEDRESULTS
if ( c1.ldctl_iscritical ) critical = 1;
#endif /* LDAP_CONTROL_PAGEDRESULTS */
}
if ( noop ) {
@ -997,6 +1056,9 @@ main( int argc, char **argv )
c2.ldctl_value.bv_val = NULL;
c2.ldctl_value.bv_len = 0;
c2.ldctl_iscritical = noop > 1;
#ifdef LDAP_CONTROL_PAGEDRESULTS
if ( c2.ldctl_iscritical ) critical = 1;
#endif /* LDAP_CONTROL_PAGEDRESULTS */
}
#ifdef LDAP_CONTROL_SUBENTRIES
@ -1006,6 +1068,9 @@ main( int argc, char **argv )
c3.ldctl_oid = LDAP_CONTROL_SUBENTRIES;
c3.ldctl_iscritical = subentries < 1;
#ifdef LDAP_CONTROL_PAGEDRESULTS
if ( c3.ldctl_iscritical ) critical = 1;
#endif /* LDAP_CONTROL_PAGEDRESULTS */
if (( ber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
return EXIT_FAILURE;
@ -1032,6 +1097,9 @@ main( int argc, char **argv )
c4.ldctl_oid = LDAP_CONTROL_VALUESRETURNFILTER;
c4.ldctl_iscritical = valuesReturnFilter > 1;
#ifdef LDAP_CONTROL_PAGEDRESULTS
if ( c4.ldctl_iscritical ) critical = 1;
#endif /* LDAP_CONTROL_PAGEDRESULTS */
if (( ber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
return EXIT_FAILURE;
@ -1050,11 +1118,46 @@ main( int argc, char **argv )
c4.ldctl_value=(*bvalp);
}
#ifdef LDAP_CONTROL_PAGEDRESULTS
if ( searchControlSize ) {
if (( pageber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
return EXIT_FAILURE;
}
ber_printf( pageber, "{iO}", searchControlSize, &cookie );
if ( ber_flatten( pageber, &bvalptr ) == LBER_ERROR) {
return EXIT_FAILURE;
}
ctrls[i++]=&c5;
ctrls[i] = NULL;
c5.ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
c5.ldctl_value = ( *bvalptr );
c5.ldctl_iscritical = searchControlCrit;
if ( c5.ldctl_iscritical ) critical = 1;
}
#endif /* LDAP_CONTROL_PAGEDRESULTS */
err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
ber_bvfree(bvalp);
ber_free( ber, 1 );
#ifdef LDAP_CONTROL_PAGEDRESULTS
ber_free( pageber, 1 );
ber_bvfree( bvalptr );
#endif /* LDAP_CONTROL_PAGEDRESULTS */
#ifdef LDAP_CONTROL_PAGEDRESULTS
if( err != LDAP_OPT_SUCCESS ) {
if ( critical ) {
fprintf( stderr, "Could not set controls\n");
return EXIT_FAILURE;
} else {
fprintf( stderr, "Could not set critical controls\n" );
}
}
#else /* !LDAP_CONTROL_PAGEDRESULTS */
if( err != LDAP_OPT_SUCCESS ) {
fprintf( stderr, "Could not set %scontrols\n",
(c1.ldctl_iscritical || c2.ldctl_iscritical)
@ -1063,6 +1166,7 @@ main( int argc, char **argv )
return EXIT_FAILURE;
}
}
#endif /* !LDAP_CONTROL_PAGEDRESULTS */
}
if ( verbose ) {
@ -1149,6 +1253,22 @@ main( int argc, char **argv )
}
}
#ifdef LDAP_CONTROL_PAGEDRESULTS
if ( ( searchControlSize != 0 ) && ( morePagedResults != 0 ) ) {
/* Loop to get the next pages when
* enter is pressed on the terminal.
*/
printf( "Press Enter for the next %d entries.\n",
(int)searchControlSize );
moreEntries = getchar();
while ( moreEntries != EOF && moreEntries != '\n' ) {
moreEntries = getchar();
}
goto getNextPage;
}
#endif /* LDAP_CONTROL_PAGEDRESULTS */
ldap_unbind( ld );
return( rc );
}
@ -1262,6 +1382,11 @@ static int dosearch(
case LDAP_RES_SEARCH_RESULT:
rc = print_result( ld, msg, 1 );
#ifdef LDAP_CONTROL_PAGEDRESULTS
if ( searchControlSize != 0 ) {
rc = parse_page_control( ld, msg, &cookie );
}
#endif /* LDAP_CONTROL_PAGEDRESULTS */
goto done;
}
}
@ -1275,6 +1400,30 @@ static int dosearch(
}
done:
#ifdef LDAP_CONTROL_PAGEDRESULTS
if ( searchControlSize == 0 ) {
if ( ldif < 2 ) {
printf( "\n# numResponses: %d\n", nresponses );
if( nentries ) printf( "# numEntries: %d\n", nentries );
if( nextended ) printf( "# numExtended: %d\n", nextended );
if( npartial ) printf( "# numPartial: %d\n", npartial );
if( nreferences ) printf( "# numReferences: %d\n", nreferences );
}
} else {
npagedresponses = npagedresponses + nresponses;
npagedentries = npagedentries + nentries;
npagedreferences = npagedreferences + nreferences;
npagedextended = npagedextended + nextended;
npagedpartial = npagedpartial + npartial;
if ( ( morePagedResults == 0 ) && ( ldif < 2 ) ) {
printf( "\n# numResponses: %d\n", npagedresponses );
if( nentries ) printf( "# numEntries: %d\n", npagedentries );
if( nextended ) printf( "# numExtended: %d\n", npagedextended );
if( npartial ) printf( "# numPartial: %d\n", npagedpartial );
if( nreferences ) printf( "# numReferences: %d\n", npagedreferences );
}
}
#else /* !LDAP_CONTROL_PAGEDRESULTS */
if ( ldif < 2 ) {
printf( "\n# numResponses: %d\n", nresponses );
if( nentries ) printf( "# numEntries: %d\n", nentries );
@ -1282,6 +1431,7 @@ done:
if( npartial ) printf( "# numPartial: %d\n", npartial );
if( nreferences ) printf( "# numReferences: %d\n", nreferences );
}
#endif /* LDAP_CONTROL_PAGEDRESULTS */
return( rc );
}
@ -1759,3 +1909,72 @@ write_ldif( int type, char *name, char *value, ber_len_t vallen )
return( 0 );
}
#ifdef LDAP_CONTROL_PAGEDRESULTS
static int
parse_page_control(
LDAP *ld,
LDAPMessage *result,
struct berval *cookie )
{
int rc;
int err;
LDAPControl **ctrl = NULL;
LDAPControl *ctrlp = NULL;
BerElement *ber;
ber_tag_t tag;
ber_int_t entriesLeft;
struct berval servercookie = { 0, NULL };
rc = ldap_parse_result( ld, result,
&err, NULL, NULL, NULL, &ctrl, 0 );
if( rc != LDAP_SUCCESS ) {
ldap_perror(ld, "ldap_parse_result");
exit( EXIT_FAILURE );
}
if ( err != LDAP_SUCCESS ) {
fprintf( stderr, "%s (%d)\n", ldap_err2string(err), err );
}
if( ctrl ) {
/* Parse the control value
* searchResult ::= SEQUENCE {
* size INTEGER (0..maxInt),
* -- result set size estimate from server - unused
* cookie OCTET STRING
*/
ctrlp = *ctrl;
ber = ber_init( &ctrlp->ldctl_value );
if ( ber == NULL ) {
fprintf( stderr, "Internal error.\n" );
return EXIT_FAILURE;
}
tag = ber_scanf( ber, "{im}", &entriesLeft, &servercookie );
ber_dupbv( cookie, &servercookie );
(void) ber_free( ber, 1 );
if( tag == LBER_ERROR ) {
fprintf( stderr, "Paged results response control could not be decoded.\n" );
return EXIT_FAILURE;
}
if( entriesLeft < 0 ) {
fprintf( stderr, "Invalid entries estimate in paged results response.\n" );
return EXIT_FAILURE;
}
ldap_controls_free( ctrl );
} else {
morePagedResults = 0;
}
return err;
}
#endif /* LDAP_CONTROL_PAGEDRESULTS */

View File

@ -198,9 +198,9 @@ typedef struct ldapcontrol {
#define LDAP_CONTROL_DUPENT_RESPONSE "2.16.840.1.113719.1.27.101.2"
#define LDAP_CONTROL_DUPENT_ENTRY "2.16.840.1.113719.1.27.101.3"
#define LDAP_CONTROL_DUPENT LDAP_CONTROL_DUPENT_REQUEST
#endif
#define LDAP_CONTROL_PAGEDRESULTS "1.2.840.113556.1.4.319"
#endif
/*
#define LDAP_CLIENT_UPDATE 1

View File

@ -507,6 +507,9 @@ bdb_initialize(
#ifdef LDAP_CLIENT_UPDATE
LDAP_CONTROL_CLIENT_UPDATE,
#endif
#ifdef LDAP_CONTROL_PAGEDRESULTS
LDAP_CONTROL_PAGEDRESULTS,
#endif /* LDAP_CONTROL_PAGEDRESULTS */
NULL
};

View File

@ -26,6 +26,13 @@ static int search_candidates(
int scope,
int deref,
ID *ids );
#ifdef LDAP_CONTROL_PAGEDRESULTS
static void send_pagerequest_response(
Connection *conn,
Operation *op,
ID lastid,
int nentries );
#endif /* LDAP_CONTROL_PAGEDRESULTS */
int
bdb_search(
@ -55,6 +62,10 @@ bdb_search(
struct berval realbase = { 0, NULL };
int nentries = 0;
int manageDSAit;
#ifdef LDAP_CONTROL_PAGEDRESULTS
int pagedresults;
ID lastid = NOID;
#endif /* LDAP_CONTROL_PAGEDRESULTS */
#ifdef LDAP_CLIENT_UPDATE
Filter lcupf, csnfnot, csnfeq, csnfand, csnfge;
@ -88,6 +99,10 @@ bdb_search(
manageDSAit = get_manageDSAit( op );
#ifdef LDAP_CONTROL_PAGEDRESULTS
pagedresults = get_pagedresults( op );
#endif /* LDAP_CONTROL_PAGEDRESULTS */
rc = LOCK_ID (bdb->bi_dbenv, &locker );
switch(rc) {
case 0:
@ -338,6 +353,34 @@ dn2entry_retry:
}
}
#ifdef LDAP_CONTROL_PAGEDRESULTS
if ( pagedresults ) {
if ( op->o_pagedresults_state.ps_cookie == 0 ) {
id = 0;
} else {
for ( id = bdb_idl_first( candidates, &cursor );
id != NOID && id <= (ID)( op->o_pagedresults_state.ps_cookie );
id = bdb_idl_next( candidates, &cursor ) );
}
if ( cursor == NOID ) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, RESULTS,
"bdb_search: no paged results candidates\n",
0, 0, 0 );
#else
Debug( LDAP_DEBUG_TRACE,
"bdb_search: no paged results candidates\n",
0, 0, 0 );
#endif
send_pagerequest_response( conn, op, lastid, 0 );
rc = 1;
goto done;
}
goto loop_begin;
}
#endif /* LDAP_CONTROL_PAGEDRESULTS */
#ifdef LDAP_CLIENT_UPDATE
if ( op->o_clientupdate_type & SLAP_LCUP_SYNC ) {
lcupf.f_choice = LDAP_FILTER_AND;
@ -369,8 +412,13 @@ dn2entry_retry:
id != NOID;
id = bdb_idl_next( candidates, &cursor ) )
{
int scopeok = 0;
#ifdef LDAP_CONTROL_PAGEDRESULTS
loop_begin:
#endif /* LDAP_CONTROL_PAGEDRESULTS */
/* check for abandon */
if ( op->o_abandon ) {
rc = 0;
@ -573,6 +621,15 @@ id2entry_retry:
v2refs, NULL, nentries );
goto done;
}
#ifdef LDAP_CONTROL_PAGEDRESULTS
if ( pagedresults ) {
if ( nentries >= op->o_pagedresults_size ) {
send_pagerequest_response( conn, op, lastid, nentries );
goto done;
}
lastid = id;
}
#endif /* LDAP_CONTROL_PAGEDRESULTS */
if (e) {
int result;
@ -1023,3 +1080,71 @@ static int search_candidates(
return rc;
}
#ifdef LDAP_CONTROL_PAGEDRESULTS
static void
send_pagerequest_response(
Connection *conn,
Operation *op,
ID lastid,
int nentries )
{
LDAPControl ctrl, *ctrls[2];
BerElement *ber;
struct berval *bvalp, cookie = { 0, NULL };
PagedResultsCookie respcookie;
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ENTRY,
"send_pagerequest_response: lastid: (0x%08lx) "
"nentries: (0x%081x)\n",
lastid, nentries );
#else
Debug(LDAP_DEBUG_ARGS, "send_pagerequest_response: lastid: (0x%08lx) "
"nentries: (0x%081x)\n", lastid, nentries, NULL );
#endif
ctrl.ldctl_value.bv_val = NULL;
ctrls[0] = &ctrl;
ctrls[1] = NULL;
if (( ber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
goto done;
}
respcookie = ( PagedResultsCookie )lastid;
conn->c_pagedresults_state.ps_cookie = respcookie;
cookie.bv_len = sizeof( respcookie );
#if 0
cookie.bv_val = ber_memalloc( sizeof( respcookie ) );
AC_MEMCPY( cookie.bv_val, &respcookie, sizeof( respcookie ) );
#else
cookie.bv_val = (char *)&respcookie;
#endif
/*
conn->c_pagedresults_state.ps_cookie = cookie.bv_val;
*/
ber_printf( ber, "{iO}", 0, &cookie );
#if 0
ber_memfree( cookie.bv_val );
#endif
if ( ber_flatten( ber, &bvalp ) == LBER_ERROR ) {
goto done;
}
ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
ctrls[0]->ldctl_value = ( *bvalp );
ctrls[0]->ldctl_iscritical = 0;
send_search_result( conn, op,
LDAP_SUCCESS,
NULL, NULL, NULL, ctrls, nentries );
done:
if ( ctrls[0]->ldctl_value.bv_val ) {
ch_free( ctrls[0]->ldctl_value.bv_val );
}
}
#endif /* LDAP_CONTROL_PAGEDRESULTS */

View File

@ -76,11 +76,11 @@ static struct slap_control {
SLAP_CTRL_ACCESS, NULL,
parseNoOp },
#endif
#ifdef LDAP_CONTROL_PAGEDRESULTS_REQUEST
{ LDAP_CONTROL_PAGEDRESULTS_REQUEST,
#ifdef LDAP_CONTROL_PAGEDRESULTS
{ LDAP_CONTROL_PAGEDRESULTS,
SLAP_CTRL_SEARCH, NULL,
parsePagedResults },
#endif
#endif /* LDAP_CONTROL_PAGEDRESULTS */
#ifdef LDAP_CONTROL_VALUESRETURNFILTER
{ LDAP_CONTROL_VALUESRETURNFILTER,
SLAP_CTRL_SEARCH, NULL,
@ -155,7 +155,12 @@ int get_ctrls(
}
/* one for first control, one for termination */
#ifndef LDAP_CONTROL_PAGEDRESULTS
op->o_ctrls = ch_malloc( 2 * sizeof(LDAPControl *) );
#else /* LDAP_CONTROL_PAGEDRESULTS */
/* FIXME: are we sure we need this? */
op->o_ctrls = ch_malloc( 3 * sizeof(LDAPControl *) );
#endif /* LDAP_CONTROL_PAGEDRESULTS */
#if 0
if( op->ctrls == NULL ) {
@ -470,7 +475,7 @@ static int parseNoOp (
}
#endif
#ifdef LDAP_CONTROL_PAGEDRESULTS_REQUEST
#ifdef LDAP_CONTROL_PAGEDRESULTS
static int parsePagedResults (
Connection *conn,
Operation *op,
@ -537,9 +542,12 @@ static int parsePagedResults (
*text = "paged results cookie is invalid or old";
return LDAP_UNWILLING_TO_PERFORM;
}
} else {
/* Initial request. Initialize state. */
op->o_pagedresults_state.ps_cookie = 0;
op->o_pagedresults_state.ps_id = NOID;
}
op->o_pagedresults_state.ps_cookie = op->o_opid;
op->o_pagedresults_size = size;
op->o_pagedresults = ctrl->ldctl_iscritical
@ -548,7 +556,7 @@ static int parsePagedResults (
return LDAP_SUCCESS;
}
#endif
#endif /* LDAP_CONTROL_PAGEDRESULTS */
#ifdef LDAP_CONTROL_VALUESRETURNFILTER
int parseValuesReturnFilter (

View File

@ -1681,6 +1681,10 @@ typedef struct slap_op {
#define get_manageDSAit(op) ((int)(op)->o_managedsait)
#define get_subentries(op) ((int)(op)->o_subentries)
#define get_subentries_visibility(op) ((int)(op)->o_subentries_visibility)
#ifdef LDAP_CONTROL_PAGEDRESULTS
#define get_pagedresults(op) ((int)(op)->o_pagedresults)
#endif /* LDAP_CONTROL_PAGEDRESULTS */
/*
* Caches the result of a backend_group check for ACL evaluation