From c6e4ad6c1216bf976b5977076d1ef72462509b42 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Wed, 7 Jun 2000 23:43:56 +0000 Subject: [PATCH] Add VLV/Sort controls (from Novell) --- libraries/libldap/sortctrl.c | 467 +++++++++++++++++++++++++++++++++++ libraries/libldap/vlvctrl.c | 280 +++++++++++++++++++++ 2 files changed, 747 insertions(+) create mode 100644 libraries/libldap/sortctrl.c create mode 100644 libraries/libldap/vlvctrl.c diff --git a/libraries/libldap/sortctrl.c b/libraries/libldap/sortctrl.c new file mode 100644 index 0000000000..3f04a20529 --- /dev/null +++ b/libraries/libldap/sortctrl.c @@ -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 +#include +#include +#include +#include + +#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); +} diff --git a/libraries/libldap/vlvctrl.c b/libraries/libldap/vlvctrl.c new file mode 100644 index 0000000000..04b5526a65 --- /dev/null +++ b/libraries/libldap/vlvctrl.c @@ -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 +#include +#include +#include +#include + +#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); +} -- 2.39.5