/* $OpenLDAP$ */1/* This work is part of OpenLDAP Software <http://www.openldap.org/>.2*3* Copyright 1998-2024 The OpenLDAP Foundation.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted only as authorized by the OpenLDAP8* Public License.9*10* A copy of this license is available in the file LICENSE in the11* top-level directory of the distribution or, alternatively, at12* <http://www.OpenLDAP.org/license.html>.13*/14/* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.15*16* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND17* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT18* TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS19* AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"20* IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION21* OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP22* PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT23* THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.24*---25* Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License26* can be found in the file "build/LICENSE-2.0.1" in this distribution27* of OpenLDAP Software.28*/2930#include "portable.h"3132#include <stdio.h>33#include <ac/stdlib.h>34#include <ac/string.h>35#include <ac/time.h>3637#include "ldap-int.h"3839#define LDAP_VLVBYINDEX_IDENTIFIER 0xa0L40#define LDAP_VLVBYVALUE_IDENTIFIER 0x81L41#define LDAP_VLVCONTEXT_IDENTIFIER 0x04L424344/*---45ldap_create_vlv_control4647Create and encode the Virtual List View control.4849ld (IN) An LDAP session handle.5051vlvinfop (IN) The address of an LDAPVLVInfo structure whose contents52are used to construct the value of the control53that is created.5455value (OUT) A struct berval that contains the value to be assigned to the ldctl_value member56of an LDAPControl structure that contains the57VirtualListViewRequest control.58The bv_val member of the berval structure59SHOULD be freed when it is no longer in use by60calling ldap_memfree().616263Ber encoding6465VirtualListViewRequest ::= SEQUENCE {66beforeCount INTEGER (0 .. maxInt),67afterCount INTEGER (0 .. maxInt),68CHOICE {69byoffset [0] SEQUENCE, {70offset INTEGER (0 .. maxInt),71contentCount INTEGER (0 .. maxInt) }72[1] greaterThanOrEqual assertionValue }73contextID OCTET STRING OPTIONAL }747576Note: The first time the VLV control is created, the ldvlv_context77field of the LDAPVLVInfo structure should be set to NULL.78The context obtained from calling ldap_parse_vlv_control()79should be used as the context in the next ldap_create_vlv_control80call.8182---*/8384int85ldap_create_vlv_control_value(86LDAP *ld,87LDAPVLVInfo *vlvinfop,88struct berval *value )89{90ber_tag_t tag;91BerElement *ber;9293if ( ld == NULL || vlvinfop == NULL || value == NULL ) {94if ( ld )95ld->ld_errno = LDAP_PARAM_ERROR;96return LDAP_PARAM_ERROR;97}9899assert( LDAP_VALID( ld ) );100101value->bv_val = NULL;102value->bv_len = 0;103ld->ld_errno = LDAP_SUCCESS;104105ber = ldap_alloc_ber_with_options( ld );106if ( ber == NULL ) {107ld->ld_errno = LDAP_NO_MEMORY;108return ld->ld_errno;109}110111tag = ber_printf( ber, "{ii" /*}*/,112vlvinfop->ldvlv_before_count,113vlvinfop->ldvlv_after_count );114if ( tag == LBER_ERROR ) {115goto error_return;116}117118if ( vlvinfop->ldvlv_attrvalue == NULL ) {119tag = ber_printf( ber, "t{iiN}",120LDAP_VLVBYINDEX_IDENTIFIER,121vlvinfop->ldvlv_offset,122vlvinfop->ldvlv_count );123if ( tag == LBER_ERROR ) {124goto error_return;125}126127} else {128tag = ber_printf( ber, "tO",129LDAP_VLVBYVALUE_IDENTIFIER,130vlvinfop->ldvlv_attrvalue );131if ( tag == LBER_ERROR ) {132goto error_return;133}134}135136if ( vlvinfop->ldvlv_context ) {137tag = ber_printf( ber, "tO",138LDAP_VLVCONTEXT_IDENTIFIER,139vlvinfop->ldvlv_context );140if ( tag == LBER_ERROR ) {141goto error_return;142}143}144145tag = ber_printf( ber, /*{*/ "N}" );146if ( tag == LBER_ERROR ) {147goto error_return;148}149150if ( ber_flatten2( ber, value, 1 ) == -1 ) {151ld->ld_errno = LDAP_NO_MEMORY;152}153154if ( 0 ) {155error_return:;156ld->ld_errno = LDAP_ENCODING_ERROR;157}158159if ( ber != NULL ) {160ber_free( ber, 1 );161}162163return ld->ld_errno;164}165166/*---167ldap_create_vlv_control168169Create and encode the Virtual List View control.170171ld (IN) An LDAP session handle.172173vlvinfop (IN) The address of an LDAPVLVInfo structure whose contents174are used to construct the value of the control175that is created.176177ctrlp (OUT) A result parameter that will be assigned the address178of an LDAPControl structure that contains the179VirtualListViewRequest control created by this function.180The memory occupied by the LDAPControl structure181SHOULD be freed when it is no longer in use by182calling ldap_control_free().183184185Ber encoding186187VirtualListViewRequest ::= SEQUENCE {188beforeCount INTEGER (0 .. maxInt),189afterCount INTEGER (0 .. maxInt),190CHOICE {191byoffset [0] SEQUENCE, {192offset INTEGER (0 .. maxInt),193contentCount INTEGER (0 .. maxInt) }194[1] greaterThanOrEqual assertionValue }195contextID OCTET STRING OPTIONAL }196197198Note: The first time the VLV control is created, the ldvlv_context199field of the LDAPVLVInfo structure should be set to NULL.200The context obtained from calling ldap_parse_vlv_control()201should be used as the context in the next ldap_create_vlv_control202call.203204---*/205206int207ldap_create_vlv_control(208LDAP *ld,209LDAPVLVInfo *vlvinfop,210LDAPControl **ctrlp )211{212struct berval value;213214if ( ctrlp == NULL ) {215ld->ld_errno = LDAP_PARAM_ERROR;216return ld->ld_errno;217}218219ld->ld_errno = ldap_create_vlv_control_value( ld, vlvinfop, &value );220if ( ld->ld_errno == LDAP_SUCCESS ) {221222ld->ld_errno = ldap_control_create( LDAP_CONTROL_VLVREQUEST,2231, &value, 0, ctrlp );224if ( ld->ld_errno != LDAP_SUCCESS ) {225LDAP_FREE( value.bv_val );226}227}228229return ld->ld_errno;230}231232233/*---234ldap_parse_vlvresponse_control235236Decode the Virtual List View control return information.237238ld (IN) An LDAP session handle.239240ctrl (IN) The address of the LDAPControl structure.241242target_posp (OUT) This result parameter is filled in with the list243index of the target entry. If this parameter is244NULL, the target position is not returned.245246list_countp (OUT) This result parameter is filled in with the server's247estimate of the size of the list. If this parameter248is NULL, the size is not returned.249250contextp (OUT) This result parameter is filled in with the address251of a struct berval that contains the server-252generated context identifier if one was returned by253the server. If the server did not return a context254identifier, this parameter will be set to NULL, even255if an error occurred.256The returned context SHOULD be used in the next call257to create a VLV sort control. The struct berval258returned SHOULD be disposed of by calling ber_bvfree()259when it is no longer needed. If NULL is passed for260contextp, the context identifier is not returned.261262errcodep (OUT) This result parameter is filled in with the VLV263result code. If this parameter is NULL, the result264code is not returned.265266267Ber encoding268269VirtualListViewResponse ::= SEQUENCE {270targetPosition INTEGER (0 .. maxInt),271contentCount INTEGER (0 .. maxInt),272virtualListViewResult ENUMERATED {273success (0),274operationsError (1),275unwillingToPerform (53),276insufficientAccessRights (50),277busy (51),278timeLimitExceeded (3),279adminLimitExceeded (11),280sortControlMissing (60),281offsetRangeError (61),282other (80) },283contextID OCTET STRING OPTIONAL }284285---*/286287int288ldap_parse_vlvresponse_control(289LDAP *ld,290LDAPControl *ctrl,291ber_int_t *target_posp,292ber_int_t *list_countp,293struct berval **contextp,294ber_int_t *errcodep )295{296BerElement *ber;297ber_int_t pos, count, err;298ber_tag_t tag, berTag;299ber_len_t berLen;300301assert( ld != NULL );302assert( LDAP_VALID( ld ) );303304if (contextp) {305*contextp = NULL; /* Make sure we return a NULL if error occurs. */306}307308if (ctrl == NULL) {309ld->ld_errno = LDAP_PARAM_ERROR;310return(ld->ld_errno);311}312313if (strcmp(LDAP_CONTROL_VLVRESPONSE, ctrl->ldctl_oid) != 0) {314/* Not VLV Response control */315ld->ld_errno = LDAP_CONTROL_NOT_FOUND;316return(ld->ld_errno);317}318319/* Create a BerElement from the berval returned in the control. */320ber = ber_init(&ctrl->ldctl_value);321322if (ber == NULL) {323ld->ld_errno = LDAP_NO_MEMORY;324return(ld->ld_errno);325}326327/* Extract the data returned in the control. */328tag = ber_scanf(ber, "{iie" /*}*/, &pos, &count, &err);329330if( tag == LBER_ERROR) {331ber_free(ber, 1);332ld->ld_errno = LDAP_DECODING_ERROR;333return(ld->ld_errno);334}335336337/* Since the context is the last item encoded, if caller doesn't want338it returned, don't decode it. */339if (contextp) {340if (LDAP_VLVCONTEXT_IDENTIFIER == ber_peek_tag(ber, &berLen)) {341tag = ber_scanf(ber, "tO", &berTag, contextp);342343if( tag == LBER_ERROR) {344ber_free(ber, 1);345ld->ld_errno = LDAP_DECODING_ERROR;346return(ld->ld_errno);347}348}349}350351ber_free(ber, 1);352353/* Return data to the caller for items that were requested. */354if (target_posp) *target_posp = pos;355if (list_countp) *list_countp = count;356if (errcodep) *errcodep = err;357358ld->ld_errno = LDAP_SUCCESS;359return(ld->ld_errno);360}361362363