Add VLV/Sort controls (from Novell)

This commit is contained in:
Kurt Zeilenga 2000-06-07 23:43:56 +00:00
parent 22b8b60e49
commit c6e4ad6c12
2 changed files with 747 additions and 0 deletions

View file

@ -0,0 +1,467 @@
/*
* Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
/* Adapted for inclusion into OpenLDAP by Kurt D. Zeilenga */
/*---
* Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
* TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
* AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
* IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
* OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
* PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
* THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
*
*---*/
#include "portable.h"
#include <stdio.h>
#include <ac/stdlib.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/ctype.h>
#include "ldap-int.h"
#define LDAP_MATCHRULE_IDENTIFIER 0x80L
#define LDAP_REVERSEORDER_IDENTIFIER 0x81L
#define LDAP_ATTRTYPES_IDENTIFIER 0x80L
/* ---------------------------------------------------------------------------
countKeys
Internal function to determine the number of keys in the string.
keyString (IN) String of items separated by whitespace.
---------------------------------------------------------------------------*/
static int countKeys(char *keyString)
{
char *p = keyString;
int count = 0;
for (;;)
{
while (isspace(*p)) /* Skip leading whitespace */
p++;
if (*p == '\0') /* End of string? */
return count;
count++; /* Found start of a key */
while (!isspace(*p)) /* Skip till next space or end of string. */
if (*p++ == '\0')
return count;
}
}
/* ---------------------------------------------------------------------------
readNextKey
Internal function to parse the next sort key in the string.
Allocate an LDAPSortKey structure and initialize it with
attribute name, reverse flag, and matching rule OID.
Each sort key in the string has the format:
[whitespace][-]attribute[:[OID]]
pNextKey (IN/OUT) Points to the next key in the sortkey string to parse.
The pointer is updated to point to the next character
after the sortkey being parsed.
key (OUT) Points to the address of an LDAPSortKey stucture
which has been allocated by this routine and
initialized with information from the next sortkey.
---------------------------------------------------------------------------*/
static int readNextKey( char **pNextKey, LDAPSortKey **key)
{
char *p = *pNextKey;
int rev = 0;
char *attrStart;
int attrLen;
char *oidStart = NULL;
int oidLen = 0;
/* Skip leading white space. */
while (isspace(*p))
p++;
if (*p == '-') /* Check if the reverse flag is present. */
{
rev=1;
p++;
}
/* We're now positioned at the start of the attribute. */
attrStart = p;
/* Get the length of the attribute until the next whitespace or ":". */
attrLen = strcspn(p, " \t:");
p += attrLen;
if (attrLen == 0) /* If no attribute name was present, quit. */
return LDAP_PARAM_ERROR;
if (*p == ':')
{
oidStart = ++p; /* Start of the OID, after the colon */
oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */
p += oidLen;
}
*pNextKey = p; /* Update argument to point to next key */
/* Allocate an LDAPSortKey structure */
*key = LDAP_MALLOC(sizeof(LDAPSortKey));
if (*key == NULL) return LDAP_NO_MEMORY;
/* Allocate memory for the attribute and copy to it. */
(*key)->attributeType = LDAP_MALLOC(attrLen+1);
if ((*key)->attributeType == NULL) {
LDAP_FREE(*key);
return LDAP_NO_MEMORY;
}
strncpy((*key)->attributeType, attrStart, attrLen);
(*key)->attributeType[attrLen] = 0;
/* If present, allocate memory for the OID and copy to it. */
if (oidLen) {
(*key)->orderingRule = LDAP_MALLOC(oidLen+1);
if ((*key)->orderingRule == NULL) {
LDAP_FREE((*key)->attributeType);
LDAP_FREE(*key);
return LDAP_NO_MEMORY;
}
strncpy((*key)->orderingRule, oidStart, oidLen);
(*key)->orderingRule[oidLen] = 0;
} else {
(*key)->orderingRule = NULL;
}
(*key)->reverseOrder = rev;
return LDAP_SUCCESS;
}
/* ---------------------------------------------------------------------------
ldap_create_sort_keylist
Create an array of pointers to LDAPSortKey structures, containing the
information specified by the string representation of one or more
sort keys.
sortKeyList (OUT) Points to a null-terminated array of pointers to
LDAPSortKey structures allocated by this routine.
This memory SHOULD be freed by the calling program
using ldap_free_sort_keylist().
keyString (IN) Points to a string of one or more sort keys.
---------------------------------------------------------------------------*/
LIBLDAP_F(int)
ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
{
int numKeys, rc, i;
char *nextKey;
LDAPSortKey **keyList = NULL;
if (( sortKeyList == NULL ) || ( keyString == NULL )) {
return LDAP_PARAM_ERROR;
}
*sortKeyList = NULL;
/* Determine the number of sort keys so we can allocate memory. */
if (( numKeys = countKeys(keyString)) == 0) {
return LDAP_PARAM_ERROR;
}
/* Allocate the array of pointers. Initialize to NULL. */
keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*));
if ( keyList == NULL) return LDAP_NO_MEMORY;
/* For each sort key in the string, create an LDAPSortKey structure
and add it to the list.
*/
nextKey = keyString; /* Points to the next key in the string */
for (i=0; i < numKeys; i++) {
rc = readNextKey(&nextKey, &keyList[i]);
if (rc != LDAP_SUCCESS) {
ldap_free_sort_keylist(keyList);
return rc;
}
}
*sortKeyList = keyList;
return LDAP_SUCCESS;
}
/* ---------------------------------------------------------------------------
ldap_free_sort_keylist
Frees the sort key structures created by ldap_create_sort_keylist().
Frees the memory referenced by the LDAPSortKey structures,
the LDAPSortKey structures themselves, and the array of pointers
to the structures.
keyList (IN) Points to an array of pointers to LDAPSortKey structures.
---------------------------------------------------------------------------*/
LIBLDAP_F(void)
ldap_free_sort_keylist ( LDAPSortKey **keyList )
{
int i;
LDAPSortKey *nextKeyp;
if (keyList == NULL) return;
i=0;
while ( 0 != (nextKeyp = keyList[i++]) ) {
if (nextKeyp->attributeType) {
LBER_FREE(nextKeyp->attributeType);
}
if (nextKeyp->orderingRule != NULL) {
LBER_FREE(nextKeyp->orderingRule);
}
LBER_FREE(nextKeyp);
}
LBER_FREE(keyList);
}
/* ---------------------------------------------------------------------------
ldap_create_sort_control
Create and encode the server-side sort control.
ld (IN) An LDAP session handle, as obtained from a call to
ldap_init().
keyList (IN) Points to a null-terminated array of pointers to
LDAPSortKey structures, containing a description of
each of the sort keys to be used. The description
consists of an attribute name, ascending/descending flag,
and an optional matching rule (OID) to use.
isCritical (IN) 0 - Indicates the control is not critical to the operation.
non-zero - The control is critical to the operation.
ctrlp (OUT) Returns a pointer to the LDAPControl created. This control
SHOULD be freed by calling ldap_control_free() when done.
Ber encoding
SortKeyList ::= SEQUENCE OF SEQUENCE {
attributeType AttributeDescription,
orderingRule [0] MatchingRuleId OPTIONAL,
reverseOrder [1] BOOLEAN DEFAULT FALSE }
---------------------------------------------------------------------------*/
LIBLDAP_F( int )
ldap_create_sort_control (
LDAP *ld,
LDAPSortKey **keyList,
int isCritical,
LDAPControl **ctrlp )
{
int i;
BerElement *ber;
ber_tag_t tag;
if ( (ld == NULL) || (keyList == NULL) || (ctrlp == NULL) ) {
ld->ld_errno = LDAP_PARAM_ERROR;
return(ld->ld_errno);
}
if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) {
ld->ld_errno = LDAP_NO_MEMORY;
return( ld->ld_errno );
}
tag = ber_printf(ber, "{" /*}*/);
if (tag == LBER_ERROR) goto exit;
for (i = 0; keyList[i] != NULL; i++) {
tag = ber_printf(ber, "{s" /*}*/, (keyList[i])->attributeType);
if (tag == LBER_ERROR) goto exit;
if ((keyList[i])->orderingRule != NULL) {
tag = ber_printf( ber, "ts",
LDAP_MATCHRULE_IDENTIFIER,
(keyList[i])->orderingRule );
if( tag == LBER_ERROR ) goto exit;
}
if ((keyList[i])->reverseOrder) {
tag = ber_printf(ber, "tb",
LDAP_REVERSEORDER_IDENTIFIER,
(keyList[i])->reverseOrder );
if( tag == LBER_ERROR ) goto exit;
}
tag = ber_printf(ber, /*{*/ "}");
if( tag == LBER_ERROR ) goto exit;
}
tag = ber_printf(ber, /*{*/ "}");
if( tag == LBER_ERROR ) goto exit;
ld->ld_errno = ldap_int_create_control( LDAP_CONTROL_SORTREQUEST,
ber, isCritical, ctrlp);
ber_free(ber, 1);
return(ld->ld_errno);
exit:
ber_free(ber, 1);
ld->ld_errno = LDAP_ENCODING_ERROR;
return(ld->ld_errno);
}
/* ---------------------------------------------------------------------------
ldap_parse_sort_control
Decode the server-side sort control return information.
ld (IN) An LDAP session handle, as obtained from a call to
ldap_init().
ctrls (IN) The address of a NULL-terminated array of LDAPControl
structures, typically obtained by a call to
ldap_parse_result().
returnCode (OUT) This result parameter is filled in with the sort control
result code. This parameter MUST not be NULL.
attribute (OUT) If an error occured the server may return a string
indicating the first attribute in the sortkey list
that was in error. If a string is returned, the memory
should be freed with ldap_memfree. If this parameter is
NULL, no string is returned.
Ber encoding for sort control
SortResult ::= SEQUENCE {
sortResult ENUMERATED {
success (0), -- results are sorted
operationsError (1), -- server internal failure
timeLimitExceeded (3), -- timelimit reached before
-- sorting was completed
strongAuthRequired (8), -- refused to return sorted
-- results via insecure
-- protocol
adminLimitExceeded (11), -- too many matching entries
-- for the server to sort
noSuchAttribute (16), -- unrecognized attribute
-- type in sort key
inappropriateMatching (18), -- unrecognized or inappro-
-- priate matching rule in
-- sort key
insufficientAccessRights (50), -- refused to return sorted
-- results to this client
busy (51), -- too busy to process
unwillingToPerform (53), -- unable to sort
other (80)
},
attributeType [0] AttributeDescription OPTIONAL }
---------------------------------------------------------------------------*/
LIBLDAP_F( int )
ldap_parse_sort_control(
LDAP *ld,
LDAPControl **ctrls,
unsigned long *returnCode,
char **attribute )
{
BerElement *ber;
LDAPControl *pControl;
int i;
ber_tag_t tag, berTag;
ber_len_t berLen;
if (ld == NULL) {
ld->ld_errno = LDAP_PARAM_ERROR;
return(ld->ld_errno);
}
if (ctrls == NULL) {
ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
return(ld->ld_errno);
}
if (attribute) {
*attribute = NULL;
}
/* Search the list of control responses for a sort control. */
for (i=0; ctrls[i]; i++) {
pControl = ctrls[i];
if (!strcmp(LDAP_CONTROL_SORTRESPONSE, pControl->ldctl_oid))
goto foundSortControl;
}
/* No sort control was found. */
ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
return(ld->ld_errno);
foundSortControl:
/* Create a BerElement from the berval returned in the control. */
ber = ber_init(&pControl->ldctl_value);
if (ber == NULL) {
ld->ld_errno = LDAP_NO_MEMORY;
return(ld->ld_errno);
}
/* Extract the result code from the control. */
tag = ber_scanf(ber, "{e" /*}*/, returnCode);
if( tag == LBER_ERROR ) {
ber_free(ber, 1);
ld->ld_errno = LDAP_DECODING_ERROR;
return(ld->ld_errno);
}
/* If caller wants the attribute name, and if it's present in the control,
extract the attribute name which caused the error. */
if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen)))
{
tag = ber_scanf(ber, "ta", &berTag, attribute);
if (tag == LBER_ERROR ) {
ber_free(ber, 1);
ld->ld_errno = LDAP_DECODING_ERROR;
return(ld->ld_errno);
}
}
ber_free(ber,1);
ld->ld_errno = LDAP_SUCCESS;
return(ld->ld_errno);
}

280
libraries/libldap/vlvctrl.c Normal file
View file

@ -0,0 +1,280 @@
/*
* Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
/* Adapted for inclusion into OpenLDAP by Kurt D. Zeilenga */
/*---
* Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
* TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
* AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
* IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
* OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
* PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
* THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
*---*/
#include "portable.h"
#include <stdio.h>
#include <ac/stdlib.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/ctype.h>
#include "ldap-int.h"
#define LDAP_VLVBYINDEX_IDENTIFIER 0xa0L
#define LDAP_VLVBYVALUE_IDENTIFIER 0x81L
#define LDAP_VLVCONTEXT_IDENTIFIER 0x04L
/*---
ldap_create_vlv_control
Create and encode the Virtual List View control.
ld (IN) An LDAP session handle, as obtained from a call to
ldap_init().
vlvinfop (IN) The address of an LDAPVLVInfo structure whose contents
are used to construct the value of the control
that is created.
ctrlp (OUT) A result parameter that will be assigned the address
of an LDAPControl structure that contains the
VirtualListViewRequest control created by this function.
The memory occupied by the LDAPControl structure
SHOULD be freed when it is no longer in use by
calling ldap_control_free().
Ber encoding
VirtualListViewRequest ::= SEQUENCE {
beforeCount INTEGER (0 .. maxInt),
afterCount INTEGER (0 .. maxInt),
CHOICE {
byoffset [0] SEQUENCE, {
offset INTEGER (0 .. maxInt),
contentCount INTEGER (0 .. maxInt) }
[1] greaterThanOrEqual assertionValue }
contextID OCTET STRING OPTIONAL }
Note: The first time the VLV control is created, the ldvlv_context
field of the LDAPVLVInfo structure should be set to NULL.
The context obtained from calling ldap_parse_vlv_control()
should be used as the context in the next ldap_create_vlv_control
call.
---*/
LIBLDAP_F( int )
ldap_create_vlv_control( LDAP *ld,
LDAPVLVInfo *vlvinfop,
LDAPControl **ctrlp )
{
ber_tag_t tag;
BerElement *ber;
if ( (ld==NULL) || (vlvinfop==NULL) || (ctrlp == NULL) ) {
ld->ld_errno = LDAP_PARAM_ERROR;
return(ld->ld_errno);
}
if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) {
ld->ld_errno = LDAP_NO_MEMORY;
return(LDAP_NO_MEMORY);
}
tag = ber_printf(ber, "{ii" /*}*/,
vlvinfop->ldvlv_before_count,
vlvinfop->ldvlv_after_count);
if( tag == LBER_ERROR ) goto exit;
if (vlvinfop->ldvlv_attrvalue == NULL) {
tag = ber_printf(ber, "t{ii}",
LDAP_VLVBYINDEX_IDENTIFIER,
vlvinfop->ldvlv_offset,
vlvinfop->ldvlv_count);
if( tag == LBER_ERROR ) goto exit;
} else {
tag = ber_printf(ber, "tO",
LDAP_VLVBYVALUE_IDENTIFIER,
vlvinfop->ldvlv_attrvalue);
if( tag == LBER_ERROR ) goto exit;
}
if (vlvinfop->ldvlv_context) {
tag = ber_printf(ber, "tO",
LDAP_VLVCONTEXT_IDENTIFIER,
vlvinfop->ldvlv_context);
if( tag == LBER_ERROR ) goto exit;
}
tag = ber_printf(ber, /*{*/ "}");
if( tag == LBER_ERROR ) goto exit;
ld->ld_errno = ldap_int_create_control(
LDAP_CONTROL_VLVREQUEST, ber, 1, ctrlp);
ber_free(ber, 1);
return(ld->ld_errno);
exit:
ber_free(ber, 1);
ld->ld_errno = LDAP_ENCODING_ERROR;
return(ld->ld_errno);
}
/*---
ldap_parse_vlv_control
Decode the Virtual List View control return information.
ld (IN) An LDAP session handle.
ctrls (IN) The address of a NULL-terminated array of
LDAPControl structures, typically obtained
by a call to ldap_parse_result().
target_posp (OUT) This result parameter is filled in with the list
index of the target entry. If this parameter is
NULL, the target position is not returned.
list_countp (OUT) This result parameter is filled in with the server's
estimate of the size of the list. If this parameter
is NULL, the size is not returned.
contextp (OUT) This result parameter is filled in with the address
of a struct berval that contains the server-
generated context identifier if one was returned by
the server. If the server did not return a context
identifier, this parameter will be set to NULL, even
if an error occured.
The returned context SHOULD be used in the next call
to create a VLV sort control. The struct berval
returned SHOULD be disposed of by calling ber_bvfree()
when it is no longer needed. If NULL is passed for
contextp, the context identifier is not returned.
errcodep (OUT) This result parameter is filled in with the VLV
result code. If this parameter is NULL, the result
code is not returned.
Ber encoding
VirtualListViewResponse ::= SEQUENCE {
targetPosition INTEGER (0 .. maxInt),
contentCount INTEGER (0 .. maxInt),
virtualListViewResult ENUMERATED {
success (0),
operatonsError (1),
unwillingToPerform (53),
insufficientAccessRights (50),
busy (51),
timeLimitExceeded (3),
adminLimitExceeded (11),
sortControlMissing (60),
offsetRangeError (61),
other (80) },
contextID OCTET STRING OPTIONAL }
---*/
LIBLDAP_F( int )
ldap_parse_vlv_control(
LDAP *ld,
LDAPControl **ctrls,
unsigned long *target_posp,
unsigned long *list_countp,
struct berval **contextp,
int *errcodep )
{
BerElement *ber;
LDAPControl *pControl;
int i;
unsigned long pos, count, err;
ber_tag_t tag, berTag;
ber_len_t berLen;
if (contextp) {
*contextp = NULL; /* Make sure we return a NULL if error occurs. */
}
if (ld == NULL) {
ld->ld_errno = LDAP_PARAM_ERROR;
return(ld->ld_errno);
}
if (ctrls == NULL) {
ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
return(ld->ld_errno);
}
/* Search the list of control responses for a VLV control. */
for (i=0; ctrls[i]; i++) {
pControl = ctrls[i];
if (!strcmp(LDAP_CONTROL_VLVRESPONSE, pControl->ldctl_oid))
goto foundVLVControl;
}
/* No sort control was found. */
ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
return(ld->ld_errno);
foundVLVControl:
/* Create a BerElement from the berval returned in the control. */
ber = ber_init(&pControl->ldctl_value);
if (ber == NULL) {
ld->ld_errno = LDAP_NO_MEMORY;
return(ld->ld_errno);
}
/* Extract the data returned in the control. */
tag = ber_scanf(ber, "{iie" /*}*/, &pos, &count, &err);
if( tag == LBER_ERROR) {
ber_free(ber, 1);
ld->ld_errno = LDAP_DECODING_ERROR;
return(ld->ld_errno);
}
/* Since the context is the last item encoded, if caller doesn't want
it returned, don't decode it. */
if (contextp) {
if (LDAP_VLVCONTEXT_IDENTIFIER == ber_peek_tag(ber, &berLen)) {
tag = ber_scanf(ber, "tO", &berTag, contextp);
if( tag == LBER_ERROR) {
ber_free(ber, 1);
ld->ld_errno = LDAP_DECODING_ERROR;
return(ld->ld_errno);
}
}
}
ber_free(ber, 1);
/* Return data to the caller for items that were requested. */
if (target_posp) {
*target_posp = pos;
}
if (list_countp) {
*list_countp = count;
}
if (errcodep) {
*errcodep = err;
}
ld->ld_errno = LDAP_SUCCESS;
return(ld->ld_errno);
}