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.
27 #include <ac/stdlib.h>
28 #include <ac/string.h>
33 #define LDAP_MATCHRULE_IDENTIFIER 0x80L
34 #define LDAP_REVERSEORDER_IDENTIFIER 0x81L
35 #define LDAP_ATTRTYPES_IDENTIFIER 0x80L
39 /* ---------------------------------------------------------------------------
42 Internal function to determine the number of keys in the string.
44 keyString (IN) String of items separated by whitespace.
45 ---------------------------------------------------------------------------*/
47 static int countKeys(char *keyString)
54 while (LDAP_SPACE(*p)) /* Skip leading whitespace */
57 if (*p == '\0') /* End of string? */
60 count++; /* Found start of a key */
62 while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */
69 /* ---------------------------------------------------------------------------
72 Internal function to parse the next sort key in the string.
73 Allocate an LDAPSortKey structure and initialize it with
74 attribute name, reverse flag, and matching rule OID.
76 Each sort key in the string has the format:
77 [whitespace][-]attribute[:[OID]]
79 pNextKey (IN/OUT) Points to the next key in the sortkey string to parse.
80 The pointer is updated to point to the next character
81 after the sortkey being parsed.
83 key (OUT) Points to the address of an LDAPSortKey stucture
84 which has been allocated by this routine and
85 initialized with information from the next sortkey.
86 ---------------------------------------------------------------------------*/
88 static int readNextKey( char **pNextKey, LDAPSortKey **key)
94 char *oidStart = NULL;
97 /* Skip leading white space. */
98 while (LDAP_SPACE(*p))
101 if (*p == '-') /* Check if the reverse flag is present. */
107 /* We're now positioned at the start of the attribute. */
110 /* Get the length of the attribute until the next whitespace or ":". */
111 attrLen = strcspn(p, " \t:");
114 if (attrLen == 0) /* If no attribute name was present, quit. */
115 return LDAP_PARAM_ERROR;
119 oidStart = ++p; /* Start of the OID, after the colon */
120 oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */
124 *pNextKey = p; /* Update argument to point to next key */
126 /* Allocate an LDAPSortKey structure */
127 *key = LDAP_MALLOC(sizeof(LDAPSortKey));
128 if (*key == NULL) return LDAP_NO_MEMORY;
130 /* Allocate memory for the attribute and copy to it. */
131 (*key)->attributeType = LDAP_MALLOC(attrLen+1);
132 if ((*key)->attributeType == NULL) {
134 return LDAP_NO_MEMORY;
137 strncpy((*key)->attributeType, attrStart, attrLen);
138 (*key)->attributeType[attrLen] = 0;
140 /* If present, allocate memory for the OID and copy to it. */
142 (*key)->orderingRule = LDAP_MALLOC(oidLen+1);
143 if ((*key)->orderingRule == NULL) {
144 LDAP_FREE((*key)->attributeType);
146 return LDAP_NO_MEMORY;
148 strncpy((*key)->orderingRule, oidStart, oidLen);
149 (*key)->orderingRule[oidLen] = 0;
152 (*key)->orderingRule = NULL;
155 (*key)->reverseOrder = rev;
161 /* ---------------------------------------------------------------------------
162 ldap_create_sort_keylist
164 Create an array of pointers to LDAPSortKey structures, containing the
165 information specified by the string representation of one or more
168 sortKeyList (OUT) Points to a null-terminated array of pointers to
169 LDAPSortKey structures allocated by this routine.
170 This memory SHOULD be freed by the calling program
171 using ldap_free_sort_keylist().
173 keyString (IN) Points to a string of one or more sort keys.
175 ---------------------------------------------------------------------------*/
178 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
182 LDAPSortKey **keyList = NULL;
184 assert( sortKeyList != NULL );
185 assert( keyString != NULL );
189 /* Determine the number of sort keys so we can allocate memory. */
190 if (( numKeys = countKeys(keyString)) == 0) {
191 return LDAP_PARAM_ERROR;
194 /* Allocate the array of pointers. Initialize to NULL. */
195 keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*));
196 if ( keyList == NULL) return LDAP_NO_MEMORY;
198 /* For each sort key in the string, create an LDAPSortKey structure
199 and add it to the list.
201 nextKey = keyString; /* Points to the next key in the string */
202 for (i=0; i < numKeys; i++) {
203 rc = readNextKey(&nextKey, &keyList[i]);
205 if (rc != LDAP_SUCCESS) {
206 ldap_free_sort_keylist(keyList);
211 *sortKeyList = keyList;
216 /* ---------------------------------------------------------------------------
217 ldap_free_sort_keylist
219 Frees the sort key structures created by ldap_create_sort_keylist().
220 Frees the memory referenced by the LDAPSortKey structures,
221 the LDAPSortKey structures themselves, and the array of pointers
224 keyList (IN) Points to an array of pointers to LDAPSortKey structures.
225 ---------------------------------------------------------------------------*/
228 ldap_free_sort_keylist ( LDAPSortKey **keyList )
231 LDAPSortKey *nextKeyp;
233 if (keyList == NULL) return;
236 while ( 0 != (nextKeyp = keyList[i++]) ) {
237 if (nextKeyp->attributeType) {
238 LBER_FREE(nextKeyp->attributeType);
241 if (nextKeyp->orderingRule != NULL) {
242 LBER_FREE(nextKeyp->orderingRule);
252 /* ---------------------------------------------------------------------------
253 ldap_create_sort_control
255 Create and encode the server-side sort control.
257 ld (IN) An LDAP session handle, as obtained from a call to
260 keyList (IN) Points to a null-terminated array of pointers to
261 LDAPSortKey structures, containing a description of
262 each of the sort keys to be used. The description
263 consists of an attribute name, ascending/descending flag,
264 and an optional matching rule (OID) to use.
266 isCritical (IN) 0 - Indicates the control is not critical to the operation.
267 non-zero - The control is critical to the operation.
269 ctrlp (OUT) Returns a pointer to the LDAPControl created. This control
270 SHOULD be freed by calling ldap_control_free() when done.
275 SortKeyList ::= SEQUENCE OF SEQUENCE {
276 attributeType AttributeDescription,
277 orderingRule [0] MatchingRuleId OPTIONAL,
278 reverseOrder [1] BOOLEAN DEFAULT FALSE }
280 ---------------------------------------------------------------------------*/
283 ldap_create_sort_control (
285 LDAPSortKey **keyList,
287 LDAPControl **ctrlp )
294 if ( (ld == NULL) || (keyList == NULL) || (ctrlp == NULL) ) {
295 ld->ld_errno = LDAP_PARAM_ERROR;
296 return(ld->ld_errno);
299 if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) {
300 ld->ld_errno = LDAP_NO_MEMORY;
301 return( ld->ld_errno );
304 tag = ber_printf(ber, "{" /*}*/);
305 if (tag == LBER_ERROR) goto exit;
307 for (i = 0; keyList[i] != NULL; i++) {
308 tag = ber_printf(ber, "{s" /*}*/, (keyList[i])->attributeType);
309 if (tag == LBER_ERROR) goto exit;
311 if ((keyList[i])->orderingRule != NULL) {
312 tag = ber_printf( ber, "ts",
313 LDAP_MATCHRULE_IDENTIFIER,
314 (keyList[i])->orderingRule );
316 if( tag == LBER_ERROR ) goto exit;
319 if ((keyList[i])->reverseOrder) {
320 tag = ber_printf(ber, "tb",
321 LDAP_REVERSEORDER_IDENTIFIER,
322 (keyList[i])->reverseOrder );
324 if( tag == LBER_ERROR ) goto exit;
327 tag = ber_printf(ber, /*{*/ "N}");
328 if( tag == LBER_ERROR ) goto exit;
331 tag = ber_printf(ber, /*{*/ "N}");
332 if( tag == LBER_ERROR ) goto exit;
334 ld->ld_errno = ldap_create_control( LDAP_CONTROL_SORTREQUEST,
335 ber, isCritical, ctrlp);
339 return(ld->ld_errno);
343 ld->ld_errno = LDAP_ENCODING_ERROR;
344 return(ld->ld_errno);
348 /* ---------------------------------------------------------------------------
349 ldap_parse_sort_control
351 Decode the server-side sort control return information.
353 ld (IN) An LDAP session handle, as obtained from a call to
356 ctrls (IN) The address of a NULL-terminated array of LDAPControl
357 structures, typically obtained by a call to
360 returnCode (OUT) This result parameter is filled in with the sort control
361 result code. This parameter MUST not be NULL.
363 attribute (OUT) If an error occured the server may return a string
364 indicating the first attribute in the sortkey list
365 that was in error. If a string is returned, the memory
366 should be freed with ldap_memfree. If this parameter is
367 NULL, no string is returned.
370 Ber encoding for sort control
372 SortResult ::= SEQUENCE {
373 sortResult ENUMERATED {
374 success (0), -- results are sorted
375 operationsError (1), -- server internal failure
376 timeLimitExceeded (3), -- timelimit reached before
377 -- sorting was completed
378 strongAuthRequired (8), -- refused to return sorted
379 -- results via insecure
381 adminLimitExceeded (11), -- too many matching entries
382 -- for the server to sort
383 noSuchAttribute (16), -- unrecognized attribute
385 inappropriateMatching (18), -- unrecognized or inappro-
386 -- priate matching rule in
388 insufficientAccessRights (50), -- refused to return sorted
389 -- results to this client
390 busy (51), -- too busy to process
391 unwillingToPerform (53), -- unable to sort
394 attributeType [0] AttributeDescription OPTIONAL }
395 ---------------------------------------------------------------------------*/
398 ldap_parse_sort_control(
401 unsigned long *returnCode,
405 LDAPControl *pControl;
407 ber_tag_t tag, berTag;
411 ld->ld_errno = LDAP_PARAM_ERROR;
412 return(ld->ld_errno);
416 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
417 return(ld->ld_errno);
424 /* Search the list of control responses for a sort control. */
425 for (i=0; ctrls[i]; i++) {
427 if (!strcmp(LDAP_CONTROL_SORTRESPONSE, pControl->ldctl_oid))
428 goto foundSortControl;
431 /* No sort control was found. */
432 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
433 return(ld->ld_errno);
436 /* Create a BerElement from the berval returned in the control. */
437 ber = ber_init(&pControl->ldctl_value);
440 ld->ld_errno = LDAP_NO_MEMORY;
441 return(ld->ld_errno);
444 /* Extract the result code from the control. */
445 tag = ber_scanf(ber, "{e" /*}*/, returnCode);
447 if( tag == LBER_ERROR ) {
449 ld->ld_errno = LDAP_DECODING_ERROR;
450 return(ld->ld_errno);
453 /* If caller wants the attribute name, and if it's present in the control,
454 extract the attribute name which caused the error. */
455 if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen)))
457 tag = ber_scanf(ber, "ta", &berTag, attribute);
459 if (tag == LBER_ERROR ) {
461 ld->ld_errno = LDAP_DECODING_ERROR;
462 return(ld->ld_errno);
468 ld->ld_errno = LDAP_SUCCESS;
469 return(ld->ld_errno);