From 809e623cd9d74f41e181094a9715dafa8f2c036c Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Tue, 24 Aug 2004 09:19:33 +0000 Subject: [PATCH] add paged results support to back-ldap --- servers/slapd/back-bdb/search.c | 130 ++++++++++++++++++++++++++++++- servers/slapd/back-ldap/search.c | 7 +- servers/slapd/controls.c | 11 ++- 3 files changed, 142 insertions(+), 6 deletions(-) diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 14975d9f36..fa80e81e01 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -37,6 +37,8 @@ static int search_candidates( ID *ids, ID *scopes ); +static int parse_paged_cookie( Operation *op, SlapReply *rs ); + static void send_paged_response( Operation *op, SlapReply *rs, @@ -786,7 +788,14 @@ dn2entry_retry: tentries = BDB_IDL_N(candidates); } - if ( get_pagedresults(sop) > SLAP_NO_CONTROL ) { + if ( get_pagedresults( sop ) > SLAP_NO_CONTROL ) { + /* deferred cookie parsing */ + rs->sr_err = parse_paged_cookie( sop, rs ); + if ( rs->sr_err != LDAP_SUCCESS ) { + send_ldap_result( sop, rs ); + goto done; + } + if ( (ID)( sop->o_pagedresults_state.ps_cookie ) == 0 ) { id = bdb_idl_first( candidates, &cursor ); @@ -1739,6 +1748,125 @@ static int search_candidates( return rc; } +static int +parse_paged_cookie( Operation *op, SlapReply *rs ) +{ + LDAPControl **c; + int rc = LDAP_SUCCESS; + ber_tag_t tag; + ber_int_t size; + BerElement *ber; + struct berval cookie = BER_BVNULL; + + /* this function must be invoked only if the pagedResults + * control has been detected, parsed and partially checked + * by the frontend */ + assert( get_pagedresults( op ) > SLAP_NO_CONTROL ); + + /* look for the appropriate ctrl structure */ + for ( c = op->o_ctrls; c[0] != NULL; c++ ) { + if ( strcmp( c[0]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 ) + { + break; + } + } + + if ( c[0] == NULL ) { + rs->sr_text = "missing pagedResults control"; + return LDAP_PROTOCOL_ERROR; + } + + /* Already tested by frontend */ + assert( c[0]->ldctl_value.bv_len > 0 ); +#if 0 + if ( c[0]->ldctl_value.bv_len == 0 ) { + rs->sr_text = "paged results control value is empty (or absent)"; + return LDAP_PROTOCOL_ERROR; + } +#endif + + /* Parse the control value + * realSearchControlValue ::= SEQUENCE { + * size INTEGER (0..maxInt), + * -- requested page size from client + * -- result set size estimate from server + * cookie OCTET STRING + * } + */ + ber = ber_init( &c[0]->ldctl_value ); + if ( ber == NULL ) { + rs->sr_text = "internal error"; + return LDAP_OTHER; + } + + tag = ber_scanf( ber, "{im}", &size, &cookie ); + + /* Already tested by frontend */ + assert( tag != LBER_ERROR ); +#if 0 + if ( tag == LBER_ERROR ) { + rs->sr_text = "paged results control could not be decoded"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } +#endif + + /* Already tested by frontend */ + assert( size >= 0 ); +#if 0 + if ( size < 0 ) { + rs->sr_text = "paged results control size invalid"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } +#endif + + /* cookie decoding/checks deferred to backend... */ + if ( cookie.bv_len ) { + PagedResultsCookie reqcookie; + if( cookie.bv_len != sizeof( reqcookie ) ) { + /* bad cookie */ + rs->sr_text = "paged results cookie is invalid"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } + + AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie )); + + if ( reqcookie > op->o_pagedresults_state.ps_cookie ) { + /* bad cookie */ + rs->sr_text = "paged results cookie is invalid"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + + } else if ( reqcookie < op->o_pagedresults_state.ps_cookie ) { + rs->sr_text = "paged results cookie is invalid or old"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto done; + } + + } else { + /* Initial request. Initialize state. */ +#if 0 + if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) { + /* There's another pagedResults control on the + * same connection; reject new pagedResults controls + * (allowed by RFC2696) */ + rs->sr_text = "paged results cookie unavailable; try later"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto done; + } +#endif + op->o_pagedresults_state.ps_cookie = 0; + op->o_pagedresults_state.ps_count = 0; + } + +done:; + (void)ber_free( ber, 1 ); + + return rc; +} + static void send_paged_response( Operation *op, diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 753d7fa6ab..6711fab063 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -260,7 +260,7 @@ fail:; } else { rc = ldap_parse_result( lc->ld, res, &rs->sr_err, &match.bv_val, (char **)&rs->sr_text, - NULL, NULL, 1 ); + NULL, &rs->sr_ctrls, 1 ); if (rc != LDAP_SUCCESS ) { rs->sr_err = rc; } @@ -307,6 +307,11 @@ finish:; } #endif /* LDAP_BACK_PROXY_AUTHZ */ + if ( rs->sr_ctrls ) { + ldap_controls_free( rs->sr_ctrls ); + rs->sr_ctrls = NULL; + } + if ( match.bv_val ) { if ( rs->sr_matched != match.bv_val ) { free( (char *)rs->sr_matched ); diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 097bfd4964..21818c0496 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -873,26 +873,28 @@ static int parsePagedResults ( * } */ ber = ber_init( &ctrl->ldctl_value ); - if( ber == NULL ) { + if ( ber == NULL ) { rs->sr_text = "internal error"; return LDAP_OTHER; } tag = ber_scanf( ber, "{im}", &size, &cookie ); - if( tag == LBER_ERROR ) { + if ( tag == LBER_ERROR ) { rs->sr_text = "paged results control could not be decoded"; rc = LDAP_PROTOCOL_ERROR; goto done; } - if( size < 0 ) { + if ( size < 0 ) { rs->sr_text = "paged results control size invalid"; rc = LDAP_PROTOCOL_ERROR; goto done; } - if( cookie.bv_len ) { +#if 0 + /* defer cookie decoding/checks to backend... */ + if ( cookie.bv_len ) { PagedResultsCookie reqcookie; if( cookie.bv_len != sizeof( reqcookie ) ) { /* bad cookie */ @@ -930,6 +932,7 @@ static int parsePagedResults ( op->o_pagedresults_state.ps_cookie = 0; op->o_pagedresults_state.ps_count = 0; } +#endif op->o_pagedresults_size = size; -- 2.39.5