2 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5 /* Adapted for inclusion into OpenLDAP by Kurt D. Zeilenga */
7 * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
9 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
10 * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
11 * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
12 * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
13 * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
14 * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
15 * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
16 * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
19 /* Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
20 * can be found in the file "build/LICENSE-2.0.1" in this distribution
21 * of OpenLDAP Software.
24 * Portions Copyright (C) The Internet Society (1997)
25 * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
31 #include <ac/stdlib.h>
32 #include <ac/string.h>
37 #define LDAP_MATCHRULE_IDENTIFIER 0x80L
38 #define LDAP_REVERSEORDER_IDENTIFIER 0x81L
39 #define LDAP_ATTRTYPES_IDENTIFIER 0x80L
43 /* ---------------------------------------------------------------------------
46 Internal function to determine the number of keys in the string.
48 keyString (IN) String of items separated by whitespace.
49 ---------------------------------------------------------------------------*/
51 static int countKeys(char *keyString)
58 while (LDAP_SPACE(*p)) /* Skip leading whitespace */
61 if (*p == '\0') /* End of string? */
64 count++; /* Found start of a key */
66 while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */
73 /* ---------------------------------------------------------------------------
76 Internal function to parse the next sort key in the string.
77 Allocate an LDAPSortKey structure and initialize it with
78 attribute name, reverse flag, and matching rule OID.
80 Each sort key in the string has the format:
81 [whitespace][-]attribute[:[OID]]
83 pNextKey (IN/OUT) Points to the next key in the sortkey string to parse.
84 The pointer is updated to point to the next character
85 after the sortkey being parsed.
87 key (OUT) Points to the address of an LDAPSortKey stucture
88 which has been allocated by this routine and
89 initialized with information from the next sortkey.
90 ---------------------------------------------------------------------------*/
92 static int readNextKey( char **pNextKey, LDAPSortKey **key)
98 char *oidStart = NULL;
101 /* Skip leading white space. */
102 while (LDAP_SPACE(*p))
105 if (*p == '-') /* Check if the reverse flag is present. */
111 /* We're now positioned at the start of the attribute. */
114 /* Get the length of the attribute until the next whitespace or ":". */
115 attrLen = strcspn(p, " \t:");
118 if (attrLen == 0) /* If no attribute name was present, quit. */
119 return LDAP_PARAM_ERROR;
123 oidStart = ++p; /* Start of the OID, after the colon */
124 oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */
128 *pNextKey = p; /* Update argument to point to next key */
130 /* Allocate an LDAPSortKey structure */
131 *key = LDAP_MALLOC(sizeof(LDAPSortKey));
132 if (*key == NULL) return LDAP_NO_MEMORY;
134 /* Allocate memory for the attribute and copy to it. */
135 (*key)->attributeType = LDAP_MALLOC(attrLen+1);
136 if ((*key)->attributeType == NULL) {
138 return LDAP_NO_MEMORY;
141 strncpy((*key)->attributeType, attrStart, attrLen);
142 (*key)->attributeType[attrLen] = 0;
144 /* If present, allocate memory for the OID and copy to it. */
146 (*key)->orderingRule = LDAP_MALLOC(oidLen+1);
147 if ((*key)->orderingRule == NULL) {
148 LDAP_FREE((*key)->attributeType);
150 return LDAP_NO_MEMORY;
152 strncpy((*key)->orderingRule, oidStart, oidLen);
153 (*key)->orderingRule[oidLen] = 0;
156 (*key)->orderingRule = NULL;
159 (*key)->reverseOrder = rev;
165 /* ---------------------------------------------------------------------------
166 ldap_create_sort_keylist
168 Create an array of pointers to LDAPSortKey structures, containing the
169 information specified by the string representation of one or more
172 sortKeyList (OUT) Points to a null-terminated array of pointers to
173 LDAPSortKey structures allocated by this routine.
174 This memory SHOULD be freed by the calling program
175 using ldap_free_sort_keylist().
177 keyString (IN) Points to a string of one or more sort keys.
179 ---------------------------------------------------------------------------*/
182 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
186 LDAPSortKey **keyList = NULL;
188 assert( sortKeyList != NULL );
189 assert( keyString != NULL );
193 /* Determine the number of sort keys so we can allocate memory. */
194 if (( numKeys = countKeys(keyString)) == 0) {
195 return LDAP_PARAM_ERROR;
198 /* Allocate the array of pointers. Initialize to NULL. */
199 keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*));
200 if ( keyList == NULL) return LDAP_NO_MEMORY;
202 /* For each sort key in the string, create an LDAPSortKey structure
203 and add it to the list.
205 nextKey = keyString; /* Points to the next key in the string */
206 for (i=0; i < numKeys; i++) {
207 rc = readNextKey(&nextKey, &keyList[i]);
209 if (rc != LDAP_SUCCESS) {
210 ldap_free_sort_keylist(keyList);
215 *sortKeyList = keyList;
220 /* ---------------------------------------------------------------------------
221 ldap_free_sort_keylist
223 Frees the sort key structures created by ldap_create_sort_keylist().
224 Frees the memory referenced by the LDAPSortKey structures,
225 the LDAPSortKey structures themselves, and the array of pointers
228 keyList (IN) Points to an array of pointers to LDAPSortKey structures.
229 ---------------------------------------------------------------------------*/
232 ldap_free_sort_keylist ( LDAPSortKey **keyList )
235 LDAPSortKey *nextKeyp;
237 if (keyList == NULL) return;
240 while ( 0 != (nextKeyp = keyList[i++]) ) {
241 if (nextKeyp->attributeType) {
242 LBER_FREE(nextKeyp->attributeType);
245 if (nextKeyp->orderingRule != NULL) {
246 LBER_FREE(nextKeyp->orderingRule);
256 /* ---------------------------------------------------------------------------
257 ldap_create_sort_control
259 Create and encode the server-side sort control.
261 ld (IN) An LDAP session handle, as obtained from a call to
264 keyList (IN) Points to a null-terminated array of pointers to
265 LDAPSortKey structures, containing a description of
266 each of the sort keys to be used. The description
267 consists of an attribute name, ascending/descending flag,
268 and an optional matching rule (OID) to use.
270 isCritical (IN) 0 - Indicates the control is not critical to the operation.
271 non-zero - The control is critical to the operation.
273 ctrlp (OUT) Returns a pointer to the LDAPControl created. This control
274 SHOULD be freed by calling ldap_control_free() when done.
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 (
289 LDAPSortKey **keyList,
291 LDAPControl **ctrlp )
298 if ( (ld == NULL) || (keyList == NULL) || (ctrlp == NULL) ) {
299 ld->ld_errno = LDAP_PARAM_ERROR;
300 return(ld->ld_errno);
303 if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) {
304 ld->ld_errno = LDAP_NO_MEMORY;
305 return( ld->ld_errno );
308 tag = ber_printf(ber, "{" /*}*/);
309 if (tag == LBER_ERROR) goto exit;
311 for (i = 0; keyList[i] != NULL; i++) {
312 tag = ber_printf(ber, "{s" /*}*/, (keyList[i])->attributeType);
313 if (tag == LBER_ERROR) goto exit;
315 if ((keyList[i])->orderingRule != NULL) {
316 tag = ber_printf( ber, "ts",
317 LDAP_MATCHRULE_IDENTIFIER,
318 (keyList[i])->orderingRule );
320 if( tag == LBER_ERROR ) goto exit;
323 if ((keyList[i])->reverseOrder) {
324 tag = ber_printf(ber, "tb",
325 LDAP_REVERSEORDER_IDENTIFIER,
326 (keyList[i])->reverseOrder );
328 if( tag == LBER_ERROR ) goto exit;
331 tag = ber_printf(ber, /*{*/ "N}");
332 if( tag == LBER_ERROR ) goto exit;
335 tag = ber_printf(ber, /*{*/ "N}");
336 if( tag == LBER_ERROR ) goto exit;
338 ld->ld_errno = ldap_create_control( LDAP_CONTROL_SORTREQUEST,
339 ber, isCritical, ctrlp);
343 return(ld->ld_errno);
347 ld->ld_errno = LDAP_ENCODING_ERROR;
348 return(ld->ld_errno);
352 /* ---------------------------------------------------------------------------
353 ldap_parse_sort_control
355 Decode the server-side sort control return information.
357 ld (IN) An LDAP session handle, as obtained from a call to
360 ctrls (IN) The address of a NULL-terminated array of LDAPControl
361 structures, typically obtained by a call to
364 returnCode (OUT) This result parameter is filled in with the sort control
365 result code. This parameter MUST not be NULL.
367 attribute (OUT) If an error occured the server may return a string
368 indicating the first attribute in the sortkey list
369 that was in error. If a string is returned, the memory
370 should be freed with ldap_memfree. If this parameter is
371 NULL, no string is returned.
374 Ber encoding for sort control
376 SortResult ::= SEQUENCE {
377 sortResult ENUMERATED {
378 success (0), -- results are sorted
379 operationsError (1), -- server internal failure
380 timeLimitExceeded (3), -- timelimit reached before
381 -- sorting was completed
382 strongAuthRequired (8), -- refused to return sorted
383 -- results via insecure
385 adminLimitExceeded (11), -- too many matching entries
386 -- for the server to sort
387 noSuchAttribute (16), -- unrecognized attribute
389 inappropriateMatching (18), -- unrecognized or inappro-
390 -- priate matching rule in
392 insufficientAccessRights (50), -- refused to return sorted
393 -- results to this client
394 busy (51), -- too busy to process
395 unwillingToPerform (53), -- unable to sort
398 attributeType [0] AttributeDescription OPTIONAL }
399 ---------------------------------------------------------------------------*/
402 ldap_parse_sort_control(
405 unsigned long *returnCode,
409 LDAPControl *pControl;
411 ber_tag_t tag, berTag;
415 ld->ld_errno = LDAP_PARAM_ERROR;
416 return(ld->ld_errno);
420 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
421 return(ld->ld_errno);
428 /* Search the list of control responses for a sort control. */
429 for (i=0; ctrls[i]; i++) {
431 if (!strcmp(LDAP_CONTROL_SORTRESPONSE, pControl->ldctl_oid))
432 goto foundSortControl;
435 /* No sort control was found. */
436 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
437 return(ld->ld_errno);
440 /* Create a BerElement from the berval returned in the control. */
441 ber = ber_init(&pControl->ldctl_value);
444 ld->ld_errno = LDAP_NO_MEMORY;
445 return(ld->ld_errno);
448 /* Extract the result code from the control. */
449 tag = ber_scanf(ber, "{e" /*}*/, returnCode);
451 if( tag == LBER_ERROR ) {
453 ld->ld_errno = LDAP_DECODING_ERROR;
454 return(ld->ld_errno);
457 /* If caller wants the attribute name, and if it's present in the control,
458 extract the attribute name which caused the error. */
459 if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen)))
461 tag = ber_scanf(ber, "ta", &berTag, attribute);
463 if (tag == LBER_ERROR ) {
465 ld->ld_errno = LDAP_DECODING_ERROR;
466 return(ld->ld_errno);
472 ld->ld_errno = LDAP_SUCCESS;
473 return(ld->ld_errno);