Back to index

openldap  2.4.31
sortctrl.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
00016  *
00017  * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
00018  * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
00019  * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
00020  * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
00021  * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
00022  * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
00023  * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
00024  * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
00025  */
00026 /* Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License 
00027  * can be found in the file "build/LICENSE-2.0.1" in this distribution
00028  * of OpenLDAP Software.
00029  */
00030 
00031 #include "portable.h"
00032 
00033 #include <stdio.h>
00034 #include <ac/stdlib.h>
00035 #include <ac/string.h>
00036 #include <ac/time.h>
00037 
00038 #include "ldap-int.h"
00039 
00040 #define LDAP_MATCHRULE_IDENTIFIER      0x80L
00041 #define LDAP_REVERSEORDER_IDENTIFIER   0x81L
00042 #define LDAP_ATTRTYPES_IDENTIFIER      0x80L
00043 
00044 
00045 
00046 /* ---------------------------------------------------------------------------
00047    countKeys
00048    
00049    Internal function to determine the number of keys in the string.
00050    
00051    keyString  (IN) String of items separated by whitespace.
00052    ---------------------------------------------------------------------------*/
00053 
00054 static int countKeys(char *keyString)
00055 {
00056        char *p = keyString;
00057        int count = 0;
00058 
00059        for (;;)
00060        {
00061               while (LDAP_SPACE(*p))              /* Skip leading whitespace */
00062                      p++;
00063 
00064               if (*p == '\0')                    /* End of string? */
00065                      return count;
00066 
00067               count++;                           /* Found start of a key */
00068 
00069               while (!LDAP_SPACE(*p))     /* Skip till next space or end of string. */
00070                      if (*p++ == '\0')
00071                             return count;
00072        }
00073 }
00074 
00075 
00076 /* ---------------------------------------------------------------------------
00077    readNextKey
00078    
00079    Internal function to parse the next sort key in the string.
00080    Allocate an LDAPSortKey structure and initialize it with
00081    attribute name, reverse flag, and matching rule OID.
00082 
00083    Each sort key in the string has the format:
00084          [whitespace][-]attribute[:[OID]]
00085 
00086    pNextKey    (IN/OUT) Points to the next key in the sortkey string to parse.
00087                                           The pointer is updated to point to the next character
00088                                           after the sortkey being parsed.
00089                                           
00090    key         (OUT)    Points to the address of an LDAPSortKey stucture
00091                                           which has been allocated by this routine and
00092                                           initialized with information from the next sortkey.                        
00093    ---------------------------------------------------------------------------*/
00094 
00095 static int readNextKey( char **pNextKey, LDAPSortKey **key)
00096 {
00097        char *p = *pNextKey;
00098        int rev = 0;
00099        char *attrStart;
00100        int attrLen;
00101        char *oidStart = NULL;
00102        int oidLen = 0;
00103 
00104        /* Skip leading white space. */
00105        while (LDAP_SPACE(*p))
00106               p++;
00107 
00108        if (*p == '-')               /* Check if the reverse flag is present. */
00109        {
00110               rev=1;
00111               p++;
00112        }
00113 
00114        /* We're now positioned at the start of the attribute. */
00115        attrStart = p;
00116 
00117        /* Get the length of the attribute until the next whitespace or ":". */
00118        attrLen = strcspn(p, " \t:");
00119        p += attrLen;
00120 
00121        if (attrLen == 0)     /* If no attribute name was present, quit. */
00122               return LDAP_PARAM_ERROR;
00123 
00124        if (*p == ':')
00125        {
00126               oidStart = ++p;                            /* Start of the OID, after the colon */
00127               oidLen = strcspn(p, " \t");  /* Get length of OID till next whitespace */
00128               p += oidLen;
00129        }
00130 
00131        *pNextKey = p;               /* Update argument to point to next key */
00132 
00133        /* Allocate an LDAPSortKey structure */
00134        *key = LDAP_MALLOC(sizeof(LDAPSortKey));
00135        if (*key == NULL) return LDAP_NO_MEMORY;
00136 
00137        /* Allocate memory for the attribute and copy to it. */
00138        (*key)->attributeType = LDAP_MALLOC(attrLen+1);
00139        if ((*key)->attributeType == NULL) {
00140               LDAP_FREE(*key);
00141               return LDAP_NO_MEMORY;
00142        }
00143 
00144        strncpy((*key)->attributeType, attrStart, attrLen);
00145        (*key)->attributeType[attrLen] = 0;
00146 
00147        /* If present, allocate memory for the OID and copy to it. */
00148        if (oidLen) {
00149               (*key)->orderingRule = LDAP_MALLOC(oidLen+1);
00150               if ((*key)->orderingRule == NULL) {
00151                      LDAP_FREE((*key)->attributeType);
00152                      LDAP_FREE(*key);
00153                      return LDAP_NO_MEMORY;
00154               }
00155               strncpy((*key)->orderingRule, oidStart, oidLen);
00156               (*key)->orderingRule[oidLen] = 0;
00157 
00158        } else {
00159               (*key)->orderingRule = NULL;
00160        }
00161 
00162        (*key)->reverseOrder = rev;
00163 
00164        return LDAP_SUCCESS;
00165 }
00166 
00167 
00168 /* ---------------------------------------------------------------------------
00169    ldap_create_sort_keylist
00170    
00171    Create an array of pointers to LDAPSortKey structures, containing the
00172    information specified by the string representation of one or more
00173    sort keys.
00174    
00175    sortKeyList    (OUT) Points to a null-terminated array of pointers to
00176                                           LDAPSortKey structures allocated by this routine.
00177                                           This memory SHOULD be freed by the calling program
00178                                           using ldap_free_sort_keylist().
00179                                           
00180    keyString      (IN)  Points to a string of one or more sort keys.                      
00181    
00182    ---------------------------------------------------------------------------*/
00183 
00184 int
00185 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
00186 {
00187        int         numKeys, rc, i;
00188        char        *nextKey;
00189        LDAPSortKey **keyList = NULL;
00190 
00191        assert( sortKeyList != NULL );
00192        assert( keyString != NULL );
00193 
00194        *sortKeyList = NULL;
00195 
00196        /* Determine the number of sort keys so we can allocate memory. */
00197        if (( numKeys = countKeys(keyString)) == 0) {
00198               return LDAP_PARAM_ERROR;
00199        }
00200 
00201        /* Allocate the array of pointers.  Initialize to NULL. */
00202        keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*));
00203        if ( keyList == NULL) return LDAP_NO_MEMORY;
00204 
00205        /* For each sort key in the string, create an LDAPSortKey structure
00206           and add it to the list.
00207        */
00208        nextKey = keyString;          /* Points to the next key in the string */
00209        for (i=0; i < numKeys; i++) {
00210               rc = readNextKey(&nextKey, &keyList[i]);
00211 
00212               if (rc != LDAP_SUCCESS) {
00213                      ldap_free_sort_keylist(keyList);
00214                      return rc;
00215               }
00216        }
00217 
00218        *sortKeyList = keyList;
00219        return LDAP_SUCCESS;
00220 }
00221 
00222 
00223 /* ---------------------------------------------------------------------------
00224    ldap_free_sort_keylist
00225    
00226    Frees the sort key structures created by ldap_create_sort_keylist().
00227    Frees the memory referenced by the LDAPSortKey structures,
00228    the LDAPSortKey structures themselves, and the array of pointers
00229    to the structures.
00230    
00231    keyList     (IN) Points to an array of pointers to LDAPSortKey structures.
00232    ---------------------------------------------------------------------------*/
00233 
00234 void
00235 ldap_free_sort_keylist ( LDAPSortKey **keyList )
00236 {
00237        int i;
00238        LDAPSortKey *nextKeyp;
00239 
00240        if (keyList == NULL) return;
00241 
00242        i=0;
00243        while ( 0 != (nextKeyp = keyList[i++]) ) {
00244               if (nextKeyp->attributeType) {
00245                      LBER_FREE(nextKeyp->attributeType);
00246               }
00247 
00248               if (nextKeyp->orderingRule != NULL) {
00249                      LBER_FREE(nextKeyp->orderingRule);
00250               }
00251 
00252               LBER_FREE(nextKeyp);
00253        }
00254 
00255        LBER_FREE(keyList);
00256 }
00257 
00258 
00259 /* ---------------------------------------------------------------------------
00260    ldap_create_sort_control_value
00261    
00262    Create and encode the value of the server-side sort control.
00263    
00264    ld          (IN) An LDAP session handle, as obtained from a call to
00265                                    ldap_init().
00266 
00267    keyList     (IN) Points to a null-terminated array of pointers to
00268                                    LDAPSortKey structures, containing a description of
00269                                    each of the sort keys to be used.  The description
00270                                    consists of an attribute name, ascending/descending flag,
00271                                    and an optional matching rule (OID) to use.
00272                         
00273    value      (OUT) Contains the control value; the bv_val member of the berval structure
00274                                    SHOULD be freed by calling ldap_memfree() when done.
00275    
00276    
00277    Ber encoding
00278    
00279    SortKeyList ::= SEQUENCE OF SEQUENCE {
00280                  attributeType   AttributeDescription,
00281                  orderingRule    [0] MatchingRuleId OPTIONAL,
00282                  reverseOrder    [1] BOOLEAN DEFAULT FALSE }
00283    
00284    ---------------------------------------------------------------------------*/
00285 
00286 int
00287 ldap_create_sort_control_value(
00288        LDAP *ld,
00289        LDAPSortKey **keyList,
00290        struct berval *value )
00291 {
00292        int           i;
00293        BerElement    *ber = NULL;
00294        ber_tag_t     tag;
00295 
00296        assert( ld != NULL );
00297        assert( LDAP_VALID( ld ) );
00298 
00299        if ( ld == NULL ) return LDAP_PARAM_ERROR;
00300        if ( keyList == NULL || value == NULL ) {
00301               ld->ld_errno = LDAP_PARAM_ERROR;
00302               return LDAP_PARAM_ERROR;
00303        }
00304 
00305        value->bv_val = NULL;
00306        value->bv_len = 0;
00307        ld->ld_errno = LDAP_SUCCESS;
00308 
00309        ber = ldap_alloc_ber_with_options( ld );
00310        if ( ber == NULL) {
00311               ld->ld_errno = LDAP_NO_MEMORY;
00312               return ld->ld_errno;
00313        }
00314 
00315        tag = ber_printf( ber, "{" /*}*/ );
00316        if ( tag == LBER_ERROR ) {
00317               goto error_return;
00318        }
00319 
00320        for ( i = 0; keyList[i] != NULL; i++ ) {
00321               tag = ber_printf( ber, "{s" /*}*/, keyList[i]->attributeType );
00322               if ( tag == LBER_ERROR ) {
00323                      goto error_return;
00324               }
00325 
00326               if ( keyList[i]->orderingRule != NULL ) {
00327                      tag = ber_printf( ber, "ts",
00328                             LDAP_MATCHRULE_IDENTIFIER,
00329                             keyList[i]->orderingRule );
00330 
00331                      if ( tag == LBER_ERROR ) {
00332                             goto error_return;
00333                      }
00334               }
00335 
00336               if ( keyList[i]->reverseOrder ) {
00337                      tag = ber_printf( ber, "tb",
00338                             LDAP_REVERSEORDER_IDENTIFIER,
00339                             keyList[i]->reverseOrder );
00340 
00341                      if ( tag == LBER_ERROR ) {
00342                             goto error_return;
00343                      }
00344               }
00345 
00346               tag = ber_printf( ber, /*{*/ "N}" );
00347               if ( tag == LBER_ERROR ) {
00348                      goto error_return;
00349               }
00350        }
00351 
00352        tag = ber_printf( ber, /*{*/ "N}" );
00353        if ( tag == LBER_ERROR ) {
00354               goto error_return;
00355        }
00356 
00357        if ( ber_flatten2( ber, value, 1 ) == -1 ) {
00358               ld->ld_errno = LDAP_NO_MEMORY;
00359        }
00360 
00361        if ( 0 ) {
00362 error_return:;
00363               ld->ld_errno =  LDAP_ENCODING_ERROR;
00364        }
00365 
00366        if ( ber != NULL ) {
00367               ber_free( ber, 1 );
00368        }
00369 
00370        return ld->ld_errno;
00371 }
00372 
00373 
00374 /* ---------------------------------------------------------------------------
00375    ldap_create_sort_control
00376    
00377    Create and encode the server-side sort control.
00378    
00379    ld          (IN) An LDAP session handle, as obtained from a call to
00380                                    ldap_init().
00381 
00382    keyList     (IN) Points to a null-terminated array of pointers to
00383                                    LDAPSortKey structures, containing a description of
00384                                    each of the sort keys to be used.  The description
00385                                    consists of an attribute name, ascending/descending flag,
00386                                    and an optional matching rule (OID) to use.
00387                         
00388    isCritical  (IN) 0 - Indicates the control is not critical to the operation.
00389                                    non-zero - The control is critical to the operation.
00390                                     
00391    ctrlp      (OUT) Returns a pointer to the LDAPControl created.  This control
00392                                    SHOULD be freed by calling ldap_control_free() when done.
00393    
00394    
00395    Ber encoding
00396    
00397    SortKeyList ::= SEQUENCE OF SEQUENCE {
00398                  attributeType   AttributeDescription,
00399                  orderingRule    [0] MatchingRuleId OPTIONAL,
00400                  reverseOrder    [1] BOOLEAN DEFAULT FALSE }
00401    
00402    ---------------------------------------------------------------------------*/
00403 
00404 int
00405 ldap_create_sort_control(
00406        LDAP *ld,
00407        LDAPSortKey **keyList,
00408        int isCritical,
00409        LDAPControl **ctrlp )
00410 {
00411        struct berval value;
00412 
00413        assert( ld != NULL );
00414        assert( LDAP_VALID( ld ) );
00415 
00416        if ( ld == NULL ) {
00417               return LDAP_PARAM_ERROR;
00418        }
00419 
00420        if ( ctrlp == NULL ) {
00421               ld->ld_errno = LDAP_PARAM_ERROR;
00422               return ld->ld_errno;
00423        }
00424 
00425        ld->ld_errno = ldap_create_sort_control_value( ld, keyList, &value );
00426        if ( ld->ld_errno == LDAP_SUCCESS ) {
00427               ld->ld_errno = ldap_control_create( LDAP_CONTROL_SORTREQUEST,
00428                      isCritical, &value, 0, ctrlp );
00429               if ( ld->ld_errno != LDAP_SUCCESS ) {
00430                      LDAP_FREE( value.bv_val );
00431               }
00432        }
00433 
00434        return ld->ld_errno;
00435 }
00436 
00437 
00438 /* ---------------------------------------------------------------------------
00439    ldap_parse_sortedresult_control
00440    
00441    Decode the server-side sort control return information.
00442 
00443    ld          (IN) An LDAP session handle, as obtained from a call to
00444                                    ldap_init().
00445 
00446    ctrl        (IN) The address of the LDAP Control Structure.
00447                               
00448    returnCode (OUT) This result parameter is filled in with the sort control
00449                                    result code.  This parameter MUST not be NULL.
00450                               
00451    attribute  (OUT) If an error occured the server may return a string
00452                                    indicating the first attribute in the sortkey list
00453                                    that was in error.  If a string is returned, the memory
00454                                    should be freed with ldap_memfree.  If this parameter is
00455                                    NULL, no string is returned.
00456    
00457                         
00458    Ber encoding for sort control
00459         
00460         SortResult ::= SEQUENCE {
00461               sortResult  ENUMERATED {
00462                      success                   (0), -- results are sorted
00463                      operationsError           (1), -- server internal failure
00464                      timeLimitExceeded         (3), -- timelimit reached before
00465                                                                          -- sorting was completed
00466                      strongAuthRequired        (8), -- refused to return sorted
00467                                                                          -- results via insecure
00468                                                                          -- protocol
00469                      adminLimitExceeded       (11), -- too many matching entries
00470                                                                          -- for the server to sort
00471                      noSuchAttribute          (16), -- unrecognized attribute
00472                                                                          -- type in sort key
00473                      inappropriateMatching    (18), -- unrecognized or inappro-
00474                                                                          -- priate matching rule in
00475                                                                          -- sort key
00476                      insufficientAccessRights (50), -- refused to return sorted
00477                                                                          -- results to this client
00478                      busy                     (51), -- too busy to process
00479                      unwillingToPerform       (53), -- unable to sort
00480                      other                    (80)
00481                      },
00482          attributeType [0] AttributeDescription OPTIONAL }
00483    ---------------------------------------------------------------------------*/
00484 
00485 int
00486 ldap_parse_sortresponse_control(
00487        LDAP *ld,
00488        LDAPControl *ctrl,
00489        ber_int_t *returnCode,
00490        char **attribute )
00491 {
00492        BerElement *ber;
00493        ber_tag_t tag, berTag;
00494        ber_len_t berLen;
00495 
00496        assert( ld != NULL );
00497        assert( LDAP_VALID( ld ) );
00498 
00499        if (ld == NULL) {
00500               return LDAP_PARAM_ERROR;
00501        }
00502 
00503        if (ctrl == NULL) {
00504               ld->ld_errno =  LDAP_PARAM_ERROR;
00505               return(ld->ld_errno);
00506        }
00507 
00508        if (attribute) {
00509               *attribute = NULL;
00510        }
00511 
00512        if ( strcmp(LDAP_CONTROL_SORTRESPONSE, ctrl->ldctl_oid) != 0 ) {
00513               /* Not sort result control */
00514               ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
00515               return(ld->ld_errno);
00516        }
00517 
00518        /* Create a BerElement from the berval returned in the control. */
00519        ber = ber_init(&ctrl->ldctl_value);
00520 
00521        if (ber == NULL) {
00522               ld->ld_errno = LDAP_NO_MEMORY;
00523               return(ld->ld_errno);
00524        }
00525 
00526        /* Extract the result code from the control. */
00527        tag = ber_scanf(ber, "{e" /*}*/, returnCode);
00528 
00529        if( tag == LBER_ERROR ) {
00530               ber_free(ber, 1);
00531               ld->ld_errno = LDAP_DECODING_ERROR;
00532               return(ld->ld_errno);
00533        }
00534 
00535        /* If caller wants the attribute name, and if it's present in the control,
00536           extract the attribute name which caused the error. */
00537        if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen)))
00538        {
00539               tag = ber_scanf(ber, "ta", &berTag, attribute);
00540 
00541               if (tag == LBER_ERROR ) {
00542                      ber_free(ber, 1);
00543                      ld->ld_errno = LDAP_DECODING_ERROR;
00544                      return(ld->ld_errno);
00545               }
00546        }
00547 
00548        ber_free(ber,1);
00549 
00550        ld->ld_errno = LDAP_SUCCESS;
00551        return(ld->ld_errno);
00552 }