libs: Import code from upstream openldap 2.5.13.
[wine.git] / libs / ldap / libldap / sortctrl.c
blobfee693d01bc8afa0fba0fb81b37d84d6436eb201
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2022 The OpenLDAP Foundation.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
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.
31 #include "portable.h"
33 #include <stdio.h>
34 #include <ac/stdlib.h>
35 #include <ac/string.h>
36 #include <ac/time.h>
38 #include "ldap-int.h"
40 #define LDAP_MATCHRULE_IDENTIFIER 0x80L
41 #define LDAP_REVERSEORDER_IDENTIFIER 0x81L
42 #define LDAP_ATTRTYPES_IDENTIFIER 0x80L
46 /* ---------------------------------------------------------------------------
47 countKeys
49 Internal function to determine the number of keys in the string.
51 keyString (IN) String of items separated by whitespace.
52 ---------------------------------------------------------------------------*/
54 static int countKeys(char *keyString)
56 char *p = keyString;
57 int count = 0;
59 for (;;)
61 while (LDAP_SPACE(*p)) /* Skip leading whitespace */
62 p++;
64 if (*p == '\0') /* End of string? */
65 return count;
67 count++; /* Found start of a key */
69 while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */
70 if (*p++ == '\0')
71 return count;
76 /* ---------------------------------------------------------------------------
77 readNextKey
79 Internal function to parse the next sort key in the string.
80 Allocate an LDAPSortKey structure and initialize it with
81 attribute name, reverse flag, and matching rule OID.
83 Each sort key in the string has the format:
84 [whitespace][-]attribute[:[OID]]
86 pNextKey (IN/OUT) Points to the next key in the sortkey string to parse.
87 The pointer is updated to point to the next character
88 after the sortkey being parsed.
90 key (OUT) Points to the address of an LDAPSortKey structure
91 which has been allocated by this routine and
92 initialized with information from the next sortkey.
93 ---------------------------------------------------------------------------*/
95 static int readNextKey( char **pNextKey, LDAPSortKey **key)
97 char *p = *pNextKey;
98 int rev = 0;
99 char *attrStart;
100 int attrLen;
101 char *oidStart = NULL;
102 int oidLen = 0;
104 /* Skip leading white space. */
105 while (LDAP_SPACE(*p))
106 p++;
108 if (*p == '-') /* Check if the reverse flag is present. */
110 rev=1;
111 p++;
114 /* We're now positioned at the start of the attribute. */
115 attrStart = p;
117 /* Get the length of the attribute until the next whitespace or ":". */
118 attrLen = strcspn(p, " \t:");
119 p += attrLen;
121 if (attrLen == 0) /* If no attribute name was present, quit. */
122 return LDAP_PARAM_ERROR;
124 if (*p == ':')
126 oidStart = ++p; /* Start of the OID, after the colon */
127 oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */
128 p += oidLen;
131 *pNextKey = p; /* Update argument to point to next key */
133 /* Allocate an LDAPSortKey structure */
134 *key = LDAP_MALLOC(sizeof(LDAPSortKey));
135 if (*key == NULL) return LDAP_NO_MEMORY;
137 /* Allocate memory for the attribute and copy to it. */
138 (*key)->attributeType = LDAP_MALLOC(attrLen+1);
139 if ((*key)->attributeType == NULL) {
140 LDAP_FREE(*key);
141 return LDAP_NO_MEMORY;
144 strncpy((*key)->attributeType, attrStart, attrLen);
145 (*key)->attributeType[attrLen] = 0;
147 /* If present, allocate memory for the OID and copy to it. */
148 if (oidLen) {
149 (*key)->orderingRule = LDAP_MALLOC(oidLen+1);
150 if ((*key)->orderingRule == NULL) {
151 LDAP_FREE((*key)->attributeType);
152 LDAP_FREE(*key);
153 return LDAP_NO_MEMORY;
155 strncpy((*key)->orderingRule, oidStart, oidLen);
156 (*key)->orderingRule[oidLen] = 0;
158 } else {
159 (*key)->orderingRule = NULL;
162 (*key)->reverseOrder = rev;
164 return LDAP_SUCCESS;
168 /* ---------------------------------------------------------------------------
169 ldap_create_sort_keylist
171 Create an array of pointers to LDAPSortKey structures, containing the
172 information specified by the string representation of one or more
173 sort keys.
175 sortKeyList (OUT) Points to a null-terminated array of pointers to
176 LDAPSortKey structures allocated by this routine.
177 This memory SHOULD be freed by the calling program
178 using ldap_free_sort_keylist().
180 keyString (IN) Points to a string of one or more sort keys.
182 ---------------------------------------------------------------------------*/
185 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
187 int numKeys, rc, i;
188 char *nextKey;
189 LDAPSortKey **keyList = NULL;
191 assert( sortKeyList != NULL );
192 assert( keyString != NULL );
194 *sortKeyList = NULL;
196 /* Determine the number of sort keys so we can allocate memory. */
197 if (( numKeys = countKeys(keyString)) == 0) {
198 return LDAP_PARAM_ERROR;
201 /* Allocate the array of pointers. Initialize to NULL. */
202 keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*));
203 if ( keyList == NULL) return LDAP_NO_MEMORY;
205 /* For each sort key in the string, create an LDAPSortKey structure
206 and add it to the list.
208 nextKey = keyString; /* Points to the next key in the string */
209 for (i=0; i < numKeys; i++) {
210 rc = readNextKey(&nextKey, &keyList[i]);
212 if (rc != LDAP_SUCCESS) {
213 ldap_free_sort_keylist(keyList);
214 return rc;
218 *sortKeyList = keyList;
219 return LDAP_SUCCESS;
223 /* ---------------------------------------------------------------------------
224 ldap_free_sort_keylist
226 Frees the sort key structures created by ldap_create_sort_keylist().
227 Frees the memory referenced by the LDAPSortKey structures,
228 the LDAPSortKey structures themselves, and the array of pointers
229 to the structures.
231 keyList (IN) Points to an array of pointers to LDAPSortKey structures.
232 ---------------------------------------------------------------------------*/
234 void
235 ldap_free_sort_keylist ( LDAPSortKey **keyList )
237 int i;
238 LDAPSortKey *nextKeyp;
240 if (keyList == NULL) return;
242 i=0;
243 while ( 0 != (nextKeyp = keyList[i++]) ) {
244 if (nextKeyp->attributeType) {
245 LBER_FREE(nextKeyp->attributeType);
248 if (nextKeyp->orderingRule != NULL) {
249 LBER_FREE(nextKeyp->orderingRule);
252 LBER_FREE(nextKeyp);
255 LBER_FREE(keyList);
259 /* ---------------------------------------------------------------------------
260 ldap_create_sort_control_value
262 Create and encode the value of the server-side sort control.
264 ld (IN) An LDAP session handle, as obtained from a call to
265 ldap_init().
267 keyList (IN) Points to a null-terminated array of pointers to
268 LDAPSortKey structures, containing a description of
269 each of the sort keys to be used. The description
270 consists of an attribute name, ascending/descending flag,
271 and an optional matching rule (OID) to use.
273 value (OUT) Contains the control value; the bv_val member of the berval structure
274 SHOULD be freed by calling ldap_memfree() when done.
277 Ber encoding
279 SortKeyList ::= SEQUENCE OF SEQUENCE {
280 attributeType AttributeDescription,
281 orderingRule [0] MatchingRuleId OPTIONAL,
282 reverseOrder [1] BOOLEAN DEFAULT FALSE }
284 ---------------------------------------------------------------------------*/
287 ldap_create_sort_control_value(
288 LDAP *ld,
289 LDAPSortKey **keyList,
290 struct berval *value )
292 int i;
293 BerElement *ber = NULL;
294 ber_tag_t tag;
296 assert( ld != NULL );
297 assert( LDAP_VALID( ld ) );
299 if ( ld == NULL ) return LDAP_PARAM_ERROR;
300 if ( keyList == NULL || value == NULL ) {
301 ld->ld_errno = LDAP_PARAM_ERROR;
302 return LDAP_PARAM_ERROR;
305 value->bv_val = NULL;
306 value->bv_len = 0;
307 ld->ld_errno = LDAP_SUCCESS;
309 ber = ldap_alloc_ber_with_options( ld );
310 if ( ber == NULL) {
311 ld->ld_errno = LDAP_NO_MEMORY;
312 return ld->ld_errno;
315 tag = ber_printf( ber, "{" /*}*/ );
316 if ( tag == LBER_ERROR ) {
317 goto error_return;
320 for ( i = 0; keyList[i] != NULL; i++ ) {
321 tag = ber_printf( ber, "{s" /*}*/, keyList[i]->attributeType );
322 if ( tag == LBER_ERROR ) {
323 goto error_return;
326 if ( keyList[i]->orderingRule != NULL ) {
327 tag = ber_printf( ber, "ts",
328 LDAP_MATCHRULE_IDENTIFIER,
329 keyList[i]->orderingRule );
331 if ( tag == LBER_ERROR ) {
332 goto error_return;
336 if ( keyList[i]->reverseOrder ) {
337 tag = ber_printf( ber, "tb",
338 LDAP_REVERSEORDER_IDENTIFIER,
339 keyList[i]->reverseOrder );
341 if ( tag == LBER_ERROR ) {
342 goto error_return;
346 tag = ber_printf( ber, /*{*/ "N}" );
347 if ( tag == LBER_ERROR ) {
348 goto error_return;
352 tag = ber_printf( ber, /*{*/ "N}" );
353 if ( tag == LBER_ERROR ) {
354 goto error_return;
357 if ( ber_flatten2( ber, value, 1 ) == -1 ) {
358 ld->ld_errno = LDAP_NO_MEMORY;
361 if ( 0 ) {
362 error_return:;
363 ld->ld_errno = LDAP_ENCODING_ERROR;
366 if ( ber != NULL ) {
367 ber_free( ber, 1 );
370 return ld->ld_errno;
374 /* ---------------------------------------------------------------------------
375 ldap_create_sort_control
377 Create and encode the server-side sort control.
379 ld (IN) An LDAP session handle, as obtained from a call to
380 ldap_init().
382 keyList (IN) Points to a null-terminated array of pointers to
383 LDAPSortKey structures, containing a description of
384 each of the sort keys to be used. The description
385 consists of an attribute name, ascending/descending flag,
386 and an optional matching rule (OID) to use.
388 isCritical (IN) 0 - Indicates the control is not critical to the operation.
389 non-zero - The control is critical to the operation.
391 ctrlp (OUT) Returns a pointer to the LDAPControl created. This control
392 SHOULD be freed by calling ldap_control_free() when done.
395 Ber encoding
397 SortKeyList ::= SEQUENCE OF SEQUENCE {
398 attributeType AttributeDescription,
399 orderingRule [0] MatchingRuleId OPTIONAL,
400 reverseOrder [1] BOOLEAN DEFAULT FALSE }
402 ---------------------------------------------------------------------------*/
405 ldap_create_sort_control(
406 LDAP *ld,
407 LDAPSortKey **keyList,
408 int isCritical,
409 LDAPControl **ctrlp )
411 struct berval value;
413 assert( ld != NULL );
414 assert( LDAP_VALID( ld ) );
416 if ( ld == NULL ) {
417 return LDAP_PARAM_ERROR;
420 if ( ctrlp == NULL ) {
421 ld->ld_errno = LDAP_PARAM_ERROR;
422 return ld->ld_errno;
425 ld->ld_errno = ldap_create_sort_control_value( ld, keyList, &value );
426 if ( ld->ld_errno == LDAP_SUCCESS ) {
427 ld->ld_errno = ldap_control_create( LDAP_CONTROL_SORTREQUEST,
428 isCritical, &value, 0, ctrlp );
429 if ( ld->ld_errno != LDAP_SUCCESS ) {
430 LDAP_FREE( value.bv_val );
434 return ld->ld_errno;
438 /* ---------------------------------------------------------------------------
439 ldap_parse_sortedresult_control
441 Decode the server-side sort control return information.
443 ld (IN) An LDAP session handle, as obtained from a call to
444 ldap_init().
446 ctrl (IN) The address of the LDAP Control Structure.
448 returnCode (OUT) This result parameter is filled in with the sort control
449 result code. This parameter MUST not be NULL.
451 attribute (OUT) If an error occurred the server may return a string
452 indicating the first attribute in the sortkey list
453 that was in error. If a string is returned, the memory
454 should be freed with ldap_memfree. If this parameter is
455 NULL, no string is returned.
458 Ber encoding for sort control
460 SortResult ::= SEQUENCE {
461 sortResult ENUMERATED {
462 success (0), -- results are sorted
463 operationsError (1), -- server internal failure
464 timeLimitExceeded (3), -- timelimit reached before
465 -- sorting was completed
466 strongAuthRequired (8), -- refused to return sorted
467 -- results via insecure
468 -- protocol
469 adminLimitExceeded (11), -- too many matching entries
470 -- for the server to sort
471 noSuchAttribute (16), -- unrecognized attribute
472 -- type in sort key
473 inappropriateMatching (18), -- unrecognized or inappro-
474 -- priate matching rule in
475 -- sort key
476 insufficientAccessRights (50), -- refused to return sorted
477 -- results to this client
478 busy (51), -- too busy to process
479 unwillingToPerform (53), -- unable to sort
480 other (80)
482 attributeType [0] AttributeDescription OPTIONAL }
483 ---------------------------------------------------------------------------*/
486 ldap_parse_sortresponse_control(
487 LDAP *ld,
488 LDAPControl *ctrl,
489 ber_int_t *returnCode,
490 char **attribute )
492 BerElement *ber;
493 ber_tag_t tag, berTag;
494 ber_len_t berLen;
496 assert( ld != NULL );
497 assert( LDAP_VALID( ld ) );
499 if (ld == NULL) {
500 return LDAP_PARAM_ERROR;
503 if (ctrl == NULL) {
504 ld->ld_errno = LDAP_PARAM_ERROR;
505 return(ld->ld_errno);
508 if (attribute) {
509 *attribute = NULL;
512 if ( strcmp(LDAP_CONTROL_SORTRESPONSE, ctrl->ldctl_oid) != 0 ) {
513 /* Not sort result control */
514 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
515 return(ld->ld_errno);
518 /* Create a BerElement from the berval returned in the control. */
519 ber = ber_init(&ctrl->ldctl_value);
521 if (ber == NULL) {
522 ld->ld_errno = LDAP_NO_MEMORY;
523 return(ld->ld_errno);
526 /* Extract the result code from the control. */
527 tag = ber_scanf(ber, "{e" /*}*/, returnCode);
529 if( tag == LBER_ERROR ) {
530 ber_free(ber, 1);
531 ld->ld_errno = LDAP_DECODING_ERROR;
532 return(ld->ld_errno);
535 /* If caller wants the attribute name, and if it's present in the control,
536 extract the attribute name which caused the error. */
537 if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen)))
539 tag = ber_scanf(ber, "ta", &berTag, attribute);
541 if (tag == LBER_ERROR ) {
542 ber_free(ber, 1);
543 ld->ld_errno = LDAP_DECODING_ERROR;
544 return(ld->ld_errno);
548 ber_free(ber,1);
550 ld->ld_errno = LDAP_SUCCESS;
551 return(ld->ld_errno);