2 * Copyright 1998-2000 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.
23 #include <ac/stdlib.h>
24 #include <ac/string.h>
30 #define LDAP_MATCHRULE_IDENTIFIER 0x80L
31 #define LDAP_REVERSEORDER_IDENTIFIER 0x81L
32 #define LDAP_ATTRTYPES_IDENTIFIER 0x80L
36 /* ---------------------------------------------------------------------------
39 Internal function to determine the number of keys in the string.
41 keyString (IN) String of items separated by whitespace.
42 ---------------------------------------------------------------------------*/
44 static int countKeys(char *keyString)
51 while (isspace(*p)) /* Skip leading whitespace */
54 if (*p == '\0') /* End of string? */
57 count++; /* Found start of a key */
59 while (!isspace(*p)) /* Skip till next space or end of string. */
66 /* ---------------------------------------------------------------------------
69 Internal function to parse the next sort key in the string.
70 Allocate an LDAPSortKey structure and initialize it with
71 attribute name, reverse flag, and matching rule OID.
73 Each sort key in the string has the format:
74 [whitespace][-]attribute[:[OID]]
76 pNextKey (IN/OUT) Points to the next key in the sortkey string to parse.
77 The pointer is updated to point to the next character
78 after the sortkey being parsed.
80 key (OUT) Points to the address of an LDAPSortKey stucture
81 which has been allocated by this routine and
82 initialized with information from the next sortkey.
83 ---------------------------------------------------------------------------*/
85 static int readNextKey( char **pNextKey, LDAPSortKey **key)
91 char *oidStart = NULL;
94 /* Skip leading white space. */
98 if (*p == '-') /* Check if the reverse flag is present. */
104 /* We're now positioned at the start of the attribute. */
107 /* Get the length of the attribute until the next whitespace or ":". */
108 attrLen = strcspn(p, " \t:");
111 if (attrLen == 0) /* If no attribute name was present, quit. */
112 return LDAP_PARAM_ERROR;
116 oidStart = ++p; /* Start of the OID, after the colon */
117 oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */
121 *pNextKey = p; /* Update argument to point to next key */
123 /* Allocate an LDAPSortKey structure */
124 *key = LDAP_MALLOC(sizeof(LDAPSortKey));
125 if (*key == NULL) return LDAP_NO_MEMORY;
127 /* Allocate memory for the attribute and copy to it. */
128 (*key)->attributeType = LDAP_MALLOC(attrLen+1);
129 if ((*key)->attributeType == NULL) {
131 return LDAP_NO_MEMORY;
134 strncpy((*key)->attributeType, attrStart, attrLen);
135 (*key)->attributeType[attrLen] = 0;
137 /* If present, allocate memory for the OID and copy to it. */
139 (*key)->orderingRule = LDAP_MALLOC(oidLen+1);
140 if ((*key)->orderingRule == NULL) {
141 LDAP_FREE((*key)->attributeType);
143 return LDAP_NO_MEMORY;
145 strncpy((*key)->orderingRule, oidStart, oidLen);
146 (*key)->orderingRule[oidLen] = 0;
149 (*key)->orderingRule = NULL;
152 (*key)->reverseOrder = rev;
158 /* ---------------------------------------------------------------------------
159 ldap_create_sort_keylist
161 Create an array of pointers to LDAPSortKey structures, containing the
162 information specified by the string representation of one or more
165 sortKeyList (OUT) Points to a null-terminated array of pointers to
166 LDAPSortKey structures allocated by this routine.
167 This memory SHOULD be freed by the calling program
168 using ldap_free_sort_keylist().
170 keyString (IN) Points to a string of one or more sort keys.
172 ---------------------------------------------------------------------------*/
175 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
179 LDAPSortKey **keyList = NULL;
181 if (( sortKeyList == NULL ) || ( keyString == NULL )) {
182 return LDAP_PARAM_ERROR;
186 /* Determine the number of sort keys so we can allocate memory. */
187 if (( numKeys = countKeys(keyString)) == 0) {
188 return LDAP_PARAM_ERROR;
191 /* Allocate the array of pointers. Initialize to NULL. */
192 keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*));
193 if ( keyList == NULL) return LDAP_NO_MEMORY;
195 /* For each sort key in the string, create an LDAPSortKey structure
196 and add it to the list.
198 nextKey = keyString; /* Points to the next key in the string */
199 for (i=0; i < numKeys; i++) {
200 rc = readNextKey(&nextKey, &keyList[i]);
202 if (rc != LDAP_SUCCESS) {
203 ldap_free_sort_keylist(keyList);
208 *sortKeyList = keyList;
213 /* ---------------------------------------------------------------------------
214 ldap_free_sort_keylist
216 Frees the sort key structures created by ldap_create_sort_keylist().
217 Frees the memory referenced by the LDAPSortKey structures,
218 the LDAPSortKey structures themselves, and the array of pointers
221 keyList (IN) Points to an array of pointers to LDAPSortKey structures.
222 ---------------------------------------------------------------------------*/
225 ldap_free_sort_keylist ( LDAPSortKey **keyList )
228 LDAPSortKey *nextKeyp;
230 if (keyList == NULL) return;
233 while ( 0 != (nextKeyp = keyList[i++]) ) {
234 if (nextKeyp->attributeType) {
235 LBER_FREE(nextKeyp->attributeType);
238 if (nextKeyp->orderingRule != NULL) {
239 LBER_FREE(nextKeyp->orderingRule);
249 /* ---------------------------------------------------------------------------
250 ldap_create_sort_control
252 Create and encode the server-side sort control.
254 ld (IN) An LDAP session handle, as obtained from a call to
257 keyList (IN) Points to a null-terminated array of pointers to
258 LDAPSortKey structures, containing a description of
259 each of the sort keys to be used. The description
260 consists of an attribute name, ascending/descending flag,
261 and an optional matching rule (OID) to use.
263 isCritical (IN) 0 - Indicates the control is not critical to the operation.
264 non-zero - The control is critical to the operation.
266 ctrlp (OUT) Returns a pointer to the LDAPControl created. This control
267 SHOULD be freed by calling ldap_control_free() when done.
272 SortKeyList ::= SEQUENCE OF SEQUENCE {
273 attributeType AttributeDescription,
274 orderingRule [0] MatchingRuleId OPTIONAL,
275 reverseOrder [1] BOOLEAN DEFAULT FALSE }
277 ---------------------------------------------------------------------------*/
280 ldap_create_sort_control (
282 LDAPSortKey **keyList,
284 LDAPControl **ctrlp )
291 if ( (ld == NULL) || (keyList == NULL) || (ctrlp == NULL) ) {
292 ld->ld_errno = LDAP_PARAM_ERROR;
293 return(ld->ld_errno);
296 if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) {
297 ld->ld_errno = LDAP_NO_MEMORY;
298 return( ld->ld_errno );
301 tag = ber_printf(ber, "{" /*}*/);
302 if (tag == LBER_ERROR) goto exit;
304 for (i = 0; keyList[i] != NULL; i++) {
305 tag = ber_printf(ber, "{s" /*}*/, (keyList[i])->attributeType);
306 if (tag == LBER_ERROR) goto exit;
308 if ((keyList[i])->orderingRule != NULL) {
309 tag = ber_printf( ber, "ts",
310 LDAP_MATCHRULE_IDENTIFIER,
311 (keyList[i])->orderingRule );
313 if( tag == LBER_ERROR ) goto exit;
316 if ((keyList[i])->reverseOrder) {
317 tag = ber_printf(ber, "tb",
318 LDAP_REVERSEORDER_IDENTIFIER,
319 (keyList[i])->reverseOrder );
321 if( tag == LBER_ERROR ) goto exit;
324 tag = ber_printf(ber, /*{*/ "}");
325 if( tag == LBER_ERROR ) goto exit;
328 tag = ber_printf(ber, /*{*/ "}");
329 if( tag == LBER_ERROR ) goto exit;
331 ld->ld_errno = ldap_int_create_control( LDAP_CONTROL_SORTREQUEST,
332 ber, isCritical, ctrlp);
336 return(ld->ld_errno);
340 ld->ld_errno = LDAP_ENCODING_ERROR;
341 return(ld->ld_errno);
345 /* ---------------------------------------------------------------------------
346 ldap_parse_sort_control
348 Decode the server-side sort control return information.
350 ld (IN) An LDAP session handle, as obtained from a call to
353 ctrls (IN) The address of a NULL-terminated array of LDAPControl
354 structures, typically obtained by a call to
357 returnCode (OUT) This result parameter is filled in with the sort control
358 result code. This parameter MUST not be NULL.
360 attribute (OUT) If an error occured the server may return a string
361 indicating the first attribute in the sortkey list
362 that was in error. If a string is returned, the memory
363 should be freed with ldap_memfree. If this parameter is
364 NULL, no string is returned.
367 Ber encoding for sort control
369 SortResult ::= SEQUENCE {
370 sortResult ENUMERATED {
371 success (0), -- results are sorted
372 operationsError (1), -- server internal failure
373 timeLimitExceeded (3), -- timelimit reached before
374 -- sorting was completed
375 strongAuthRequired (8), -- refused to return sorted
376 -- results via insecure
378 adminLimitExceeded (11), -- too many matching entries
379 -- for the server to sort
380 noSuchAttribute (16), -- unrecognized attribute
382 inappropriateMatching (18), -- unrecognized or inappro-
383 -- priate matching rule in
385 insufficientAccessRights (50), -- refused to return sorted
386 -- results to this client
387 busy (51), -- too busy to process
388 unwillingToPerform (53), -- unable to sort
391 attributeType [0] AttributeDescription OPTIONAL }
392 ---------------------------------------------------------------------------*/
395 ldap_parse_sort_control(
398 unsigned long *returnCode,
402 LDAPControl *pControl;
404 ber_tag_t tag, berTag;
408 ld->ld_errno = LDAP_PARAM_ERROR;
409 return(ld->ld_errno);
413 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
414 return(ld->ld_errno);
421 /* Search the list of control responses for a sort control. */
422 for (i=0; ctrls[i]; i++) {
424 if (!strcmp(LDAP_CONTROL_SORTRESPONSE, pControl->ldctl_oid))
425 goto foundSortControl;
428 /* No sort control was found. */
429 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
430 return(ld->ld_errno);
433 /* Create a BerElement from the berval returned in the control. */
434 ber = ber_init(&pControl->ldctl_value);
437 ld->ld_errno = LDAP_NO_MEMORY;
438 return(ld->ld_errno);
441 /* Extract the result code from the control. */
442 tag = ber_scanf(ber, "{e" /*}*/, returnCode);
444 if( tag == LBER_ERROR ) {
446 ld->ld_errno = LDAP_DECODING_ERROR;
447 return(ld->ld_errno);
450 /* If caller wants the attribute name, and if it's present in the control,
451 extract the attribute name which caused the error. */
452 if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen)))
454 tag = ber_scanf(ber, "ta", &berTag, attribute);
456 if (tag == LBER_ERROR ) {
458 ld->ld_errno = LDAP_DECODING_ERROR;
459 return(ld->ld_errno);
465 ld->ld_errno = LDAP_SUCCESS;
466 return(ld->ld_errno);