2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2006 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
15 /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
17 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
18 * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
19 * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
20 * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
21 * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
22 * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
23 * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
24 * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
26 /* Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
27 * can be found in the file "build/LICENSE-2.0.1" in this distribution
28 * of OpenLDAP Software.
30 /* Portions Copyright (C) The Internet Society (1997)
31 * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
37 #include <ac/stdlib.h>
38 #include <ac/string.h>
43 #define LDAP_MATCHRULE_IDENTIFIER 0x80L
44 #define LDAP_REVERSEORDER_IDENTIFIER 0x81L
45 #define LDAP_ATTRTYPES_IDENTIFIER 0x80L
49 /* ---------------------------------------------------------------------------
52 Internal function to determine the number of keys in the string.
54 keyString (IN) String of items separated by whitespace.
55 ---------------------------------------------------------------------------*/
57 static int countKeys(char *keyString)
64 while (LDAP_SPACE(*p)) /* Skip leading whitespace */
67 if (*p == '\0') /* End of string? */
70 count++; /* Found start of a key */
72 while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */
79 /* ---------------------------------------------------------------------------
82 Internal function to parse the next sort key in the string.
83 Allocate an LDAPSortKey structure and initialize it with
84 attribute name, reverse flag, and matching rule OID.
86 Each sort key in the string has the format:
87 [whitespace][-]attribute[:[OID]]
89 pNextKey (IN/OUT) Points to the next key in the sortkey string to parse.
90 The pointer is updated to point to the next character
91 after the sortkey being parsed.
93 key (OUT) Points to the address of an LDAPSortKey stucture
94 which has been allocated by this routine and
95 initialized with information from the next sortkey.
96 ---------------------------------------------------------------------------*/
98 static int readNextKey( char **pNextKey, LDAPSortKey **key)
104 char *oidStart = NULL;
107 /* Skip leading white space. */
108 while (LDAP_SPACE(*p))
111 if (*p == '-') /* Check if the reverse flag is present. */
117 /* We're now positioned at the start of the attribute. */
120 /* Get the length of the attribute until the next whitespace or ":". */
121 attrLen = strcspn(p, " \t:");
124 if (attrLen == 0) /* If no attribute name was present, quit. */
125 return LDAP_PARAM_ERROR;
129 oidStart = ++p; /* Start of the OID, after the colon */
130 oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */
134 *pNextKey = p; /* Update argument to point to next key */
136 /* Allocate an LDAPSortKey structure */
137 *key = LDAP_MALLOC(sizeof(LDAPSortKey));
138 if (*key == NULL) return LDAP_NO_MEMORY;
140 /* Allocate memory for the attribute and copy to it. */
141 (*key)->attributeType = LDAP_MALLOC(attrLen+1);
142 if ((*key)->attributeType == NULL) {
144 return LDAP_NO_MEMORY;
147 strncpy((*key)->attributeType, attrStart, attrLen);
148 (*key)->attributeType[attrLen] = 0;
150 /* If present, allocate memory for the OID and copy to it. */
152 (*key)->orderingRule = LDAP_MALLOC(oidLen+1);
153 if ((*key)->orderingRule == NULL) {
154 LDAP_FREE((*key)->attributeType);
156 return LDAP_NO_MEMORY;
158 strncpy((*key)->orderingRule, oidStart, oidLen);
159 (*key)->orderingRule[oidLen] = 0;
162 (*key)->orderingRule = NULL;
165 (*key)->reverseOrder = rev;
171 /* ---------------------------------------------------------------------------
172 ldap_create_sort_keylist
174 Create an array of pointers to LDAPSortKey structures, containing the
175 information specified by the string representation of one or more
178 sortKeyList (OUT) Points to a null-terminated array of pointers to
179 LDAPSortKey structures allocated by this routine.
180 This memory SHOULD be freed by the calling program
181 using ldap_free_sort_keylist().
183 keyString (IN) Points to a string of one or more sort keys.
185 ---------------------------------------------------------------------------*/
188 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
192 LDAPSortKey **keyList = NULL;
194 assert( sortKeyList != NULL );
195 assert( keyString != NULL );
199 /* Determine the number of sort keys so we can allocate memory. */
200 if (( numKeys = countKeys(keyString)) == 0) {
201 return LDAP_PARAM_ERROR;
204 /* Allocate the array of pointers. Initialize to NULL. */
205 keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*));
206 if ( keyList == NULL) return LDAP_NO_MEMORY;
208 /* For each sort key in the string, create an LDAPSortKey structure
209 and add it to the list.
211 nextKey = keyString; /* Points to the next key in the string */
212 for (i=0; i < numKeys; i++) {
213 rc = readNextKey(&nextKey, &keyList[i]);
215 if (rc != LDAP_SUCCESS) {
216 ldap_free_sort_keylist(keyList);
221 *sortKeyList = keyList;
226 /* ---------------------------------------------------------------------------
227 ldap_free_sort_keylist
229 Frees the sort key structures created by ldap_create_sort_keylist().
230 Frees the memory referenced by the LDAPSortKey structures,
231 the LDAPSortKey structures themselves, and the array of pointers
234 keyList (IN) Points to an array of pointers to LDAPSortKey structures.
235 ---------------------------------------------------------------------------*/
238 ldap_free_sort_keylist ( LDAPSortKey **keyList )
241 LDAPSortKey *nextKeyp;
243 if (keyList == NULL) return;
246 while ( 0 != (nextKeyp = keyList[i++]) ) {
247 if (nextKeyp->attributeType) {
248 LBER_FREE(nextKeyp->attributeType);
251 if (nextKeyp->orderingRule != NULL) {
252 LBER_FREE(nextKeyp->orderingRule);
262 /* ---------------------------------------------------------------------------
263 ldap_create_sort_control_value
265 Create and encode the value of the server-side sort control.
267 ld (IN) An LDAP session handle, as obtained from a call to
270 keyList (IN) Points to a null-terminated array of pointers to
271 LDAPSortKey structures, containing a description of
272 each of the sort keys to be used. The description
273 consists of an attribute name, ascending/descending flag,
274 and an optional matching rule (OID) to use.
276 value (OUT) Contains the control value; the bv_val member of the berval structure
277 SHOULD be freed by calling ldap_memfree() when done.
282 SortKeyList ::= SEQUENCE OF SEQUENCE {
283 attributeType AttributeDescription,
284 orderingRule [0] MatchingRuleId OPTIONAL,
285 reverseOrder [1] BOOLEAN DEFAULT FALSE }
287 ---------------------------------------------------------------------------*/
290 ldap_create_sort_control_value(
292 LDAPSortKey **keyList,
293 struct berval *value )
296 BerElement *ber = NULL;
299 assert( ld != NULL );
300 assert( LDAP_VALID( ld ) );
302 if ( ld == NULL ) return LDAP_PARAM_ERROR;
303 if ( keyList == NULL || value == NULL ) {
304 ld->ld_errno = LDAP_PARAM_ERROR;
305 return LDAP_PARAM_ERROR;
308 value->bv_val = NULL;
311 ber = ldap_alloc_ber_with_options( ld );
313 ld->ld_errno = LDAP_NO_MEMORY;
317 tag = ber_printf( ber, "{" /*}*/ );
318 if ( tag == LBER_ERROR ) {
322 for ( i = 0; keyList[i] != NULL; i++ ) {
323 tag = ber_printf( ber, "{s" /*}*/, keyList[i]->attributeType );
324 if ( tag == LBER_ERROR ) {
328 if ( keyList[i]->orderingRule != NULL ) {
329 tag = ber_printf( ber, "ts",
330 LDAP_MATCHRULE_IDENTIFIER,
331 keyList[i]->orderingRule );
333 if ( tag == LBER_ERROR ) {
338 if ( keyList[i]->reverseOrder ) {
339 tag = ber_printf( ber, "tb",
340 LDAP_REVERSEORDER_IDENTIFIER,
341 keyList[i]->reverseOrder );
343 if ( tag == LBER_ERROR ) {
348 tag = ber_printf( ber, /*{*/ "N}" );
349 if ( tag == LBER_ERROR ) {
354 tag = ber_printf( ber, /*{*/ "N}" );
355 if ( tag == LBER_ERROR ) {
359 if ( ber_flatten2( ber, value, 1 ) == -1 ) {
360 ld->ld_errno = LDAP_NO_MEMORY;
365 ld->ld_errno = LDAP_ENCODING_ERROR;
376 /* ---------------------------------------------------------------------------
377 ldap_create_sort_control
379 Create and encode the server-side sort control.
381 ld (IN) An LDAP session handle, as obtained from a call to
384 keyList (IN) Points to a null-terminated array of pointers to
385 LDAPSortKey structures, containing a description of
386 each of the sort keys to be used. The description
387 consists of an attribute name, ascending/descending flag,
388 and an optional matching rule (OID) to use.
390 isCritical (IN) 0 - Indicates the control is not critical to the operation.
391 non-zero - The control is critical to the operation.
393 ctrlp (OUT) Returns a pointer to the LDAPControl created. This control
394 SHOULD be freed by calling ldap_control_free() when done.
399 SortKeyList ::= SEQUENCE OF SEQUENCE {
400 attributeType AttributeDescription,
401 orderingRule [0] MatchingRuleId OPTIONAL,
402 reverseOrder [1] BOOLEAN DEFAULT FALSE }
404 ---------------------------------------------------------------------------*/
407 ldap_create_sort_control(
409 LDAPSortKey **keyList,
411 LDAPControl **ctrlp )
416 assert( ld != NULL );
417 assert( LDAP_VALID( ld ) );
419 if ( ld == NULL ) return LDAP_PARAM_ERROR;
420 if ( ctrlp == NULL ) {
421 ld->ld_errno = LDAP_PARAM_ERROR;
425 ld->ld_errno = ldap_create_sort_control_value( ld, keyList, &value );
426 if ( ld->ld_errno == LDAP_SUCCESS ) {
427 if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) {
428 ld->ld_errno = LDAP_NO_MEMORY;
429 return LDAP_NO_MEMORY;
432 ld->ld_errno = ldap_create_control( LDAP_CONTROL_SORTREQUEST,
433 ber, isCritical, ctrlp );
434 if ( ld->ld_errno == LDAP_SUCCESS ) {
435 (*ctrlp)->ldctl_value = value;
437 LDAP_FREE( value.bv_val );
446 /* ---------------------------------------------------------------------------
447 ldap_parse_sortedresult_control
449 Decode the server-side sort control return information.
451 ld (IN) An LDAP session handle, as obtained from a call to
454 ctrl (IN) The address of the LDAP Control Structure.
456 returnCode (OUT) This result parameter is filled in with the sort control
457 result code. This parameter MUST not be NULL.
459 attribute (OUT) If an error occured the server may return a string
460 indicating the first attribute in the sortkey list
461 that was in error. If a string is returned, the memory
462 should be freed with ldap_memfree. If this parameter is
463 NULL, no string is returned.
466 Ber encoding for sort control
468 SortResult ::= SEQUENCE {
469 sortResult ENUMERATED {
470 success (0), -- results are sorted
471 operationsError (1), -- server internal failure
472 timeLimitExceeded (3), -- timelimit reached before
473 -- sorting was completed
474 strongAuthRequired (8), -- refused to return sorted
475 -- results via insecure
477 adminLimitExceeded (11), -- too many matching entries
478 -- for the server to sort
479 noSuchAttribute (16), -- unrecognized attribute
481 inappropriateMatching (18), -- unrecognized or inappro-
482 -- priate matching rule in
484 insufficientAccessRights (50), -- refused to return sorted
485 -- results to this client
486 busy (51), -- too busy to process
487 unwillingToPerform (53), -- unable to sort
490 attributeType [0] AttributeDescription OPTIONAL }
491 ---------------------------------------------------------------------------*/
494 ldap_parse_sortresponse_control(
497 ber_int_t *returnCode,
501 ber_tag_t tag, berTag;
504 assert( ld != NULL );
505 assert( LDAP_VALID( ld ) );
508 return LDAP_PARAM_ERROR;
512 ld->ld_errno = LDAP_PARAM_ERROR;
513 return(ld->ld_errno);
520 if ( strcmp(LDAP_CONTROL_SORTRESPONSE, ctrl->ldctl_oid) != 0 ) {
521 /* Not sort result control */
522 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
523 return(ld->ld_errno);
526 /* Create a BerElement from the berval returned in the control. */
527 ber = ber_init(&ctrl->ldctl_value);
530 ld->ld_errno = LDAP_NO_MEMORY;
531 return(ld->ld_errno);
534 /* Extract the result code from the control. */
535 tag = ber_scanf(ber, "{e" /*}*/, returnCode);
537 if( tag == LBER_ERROR ) {
539 ld->ld_errno = LDAP_DECODING_ERROR;
540 return(ld->ld_errno);
543 /* If caller wants the attribute name, and if it's present in the control,
544 extract the attribute name which caused the error. */
545 if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen)))
547 tag = ber_scanf(ber, "ta", &berTag, attribute);
549 if (tag == LBER_ERROR ) {
551 ld->ld_errno = LDAP_DECODING_ERROR;
552 return(ld->ld_errno);
558 ld->ld_errno = LDAP_SUCCESS;
559 return(ld->ld_errno);