2 * Copyright 1998-2002 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>
29 #define LDAP_MATCHRULE_IDENTIFIER 0x80L
30 #define LDAP_REVERSEORDER_IDENTIFIER 0x81L
31 #define LDAP_ATTRTYPES_IDENTIFIER 0x80L
35 /* ---------------------------------------------------------------------------
38 Internal function to determine the number of keys in the string.
40 keyString (IN) String of items separated by whitespace.
41 ---------------------------------------------------------------------------*/
43 static int countKeys(char *keyString)
50 while (LDAP_SPACE(*p)) /* Skip leading whitespace */
53 if (*p == '\0') /* End of string? */
56 count++; /* Found start of a key */
58 while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */
65 /* ---------------------------------------------------------------------------
68 Internal function to parse the next sort key in the string.
69 Allocate an LDAPSortKey structure and initialize it with
70 attribute name, reverse flag, and matching rule OID.
72 Each sort key in the string has the format:
73 [whitespace][-]attribute[:[OID]]
75 pNextKey (IN/OUT) Points to the next key in the sortkey string to parse.
76 The pointer is updated to point to the next character
77 after the sortkey being parsed.
79 key (OUT) Points to the address of an LDAPSortKey stucture
80 which has been allocated by this routine and
81 initialized with information from the next sortkey.
82 ---------------------------------------------------------------------------*/
84 static int readNextKey( char **pNextKey, LDAPSortKey **key)
90 char *oidStart = NULL;
93 /* Skip leading white space. */
94 while (LDAP_SPACE(*p))
97 if (*p == '-') /* Check if the reverse flag is present. */
103 /* We're now positioned at the start of the attribute. */
106 /* Get the length of the attribute until the next whitespace or ":". */
107 attrLen = strcspn(p, " \t:");
110 if (attrLen == 0) /* If no attribute name was present, quit. */
111 return LDAP_PARAM_ERROR;
115 oidStart = ++p; /* Start of the OID, after the colon */
116 oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */
120 *pNextKey = p; /* Update argument to point to next key */
122 /* Allocate an LDAPSortKey structure */
123 *key = LDAP_MALLOC(sizeof(LDAPSortKey));
124 if (*key == NULL) return LDAP_NO_MEMORY;
126 /* Allocate memory for the attribute and copy to it. */
127 (*key)->attributeType = LDAP_MALLOC(attrLen+1);
128 if ((*key)->attributeType == NULL) {
130 return LDAP_NO_MEMORY;
133 strncpy((*key)->attributeType, attrStart, attrLen);
134 (*key)->attributeType[attrLen] = 0;
136 /* If present, allocate memory for the OID and copy to it. */
138 (*key)->orderingRule = LDAP_MALLOC(oidLen+1);
139 if ((*key)->orderingRule == NULL) {
140 LDAP_FREE((*key)->attributeType);
142 return LDAP_NO_MEMORY;
144 strncpy((*key)->orderingRule, oidStart, oidLen);
145 (*key)->orderingRule[oidLen] = 0;
148 (*key)->orderingRule = NULL;
151 (*key)->reverseOrder = rev;
157 /* ---------------------------------------------------------------------------
158 ldap_create_sort_keylist
160 Create an array of pointers to LDAPSortKey structures, containing the
161 information specified by the string representation of one or more
164 sortKeyList (OUT) Points to a null-terminated array of pointers to
165 LDAPSortKey structures allocated by this routine.
166 This memory SHOULD be freed by the calling program
167 using ldap_free_sort_keylist().
169 keyString (IN) Points to a string of one or more sort keys.
171 ---------------------------------------------------------------------------*/
174 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
178 LDAPSortKey **keyList = NULL;
180 if (( sortKeyList == NULL ) || ( keyString == NULL )) {
181 return LDAP_PARAM_ERROR;
185 /* Determine the number of sort keys so we can allocate memory. */
186 if (( numKeys = countKeys(keyString)) == 0) {
187 return LDAP_PARAM_ERROR;
190 /* Allocate the array of pointers. Initialize to NULL. */
191 keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*));
192 if ( keyList == NULL) return LDAP_NO_MEMORY;
194 /* For each sort key in the string, create an LDAPSortKey structure
195 and add it to the list.
197 nextKey = keyString; /* Points to the next key in the string */
198 for (i=0; i < numKeys; i++) {
199 rc = readNextKey(&nextKey, &keyList[i]);
201 if (rc != LDAP_SUCCESS) {
202 ldap_free_sort_keylist(keyList);
207 *sortKeyList = keyList;
212 /* ---------------------------------------------------------------------------
213 ldap_free_sort_keylist
215 Frees the sort key structures created by ldap_create_sort_keylist().
216 Frees the memory referenced by the LDAPSortKey structures,
217 the LDAPSortKey structures themselves, and the array of pointers
220 keyList (IN) Points to an array of pointers to LDAPSortKey structures.
221 ---------------------------------------------------------------------------*/
224 ldap_free_sort_keylist ( LDAPSortKey **keyList )
227 LDAPSortKey *nextKeyp;
229 if (keyList == NULL) return;
232 while ( 0 != (nextKeyp = keyList[i++]) ) {
233 if (nextKeyp->attributeType) {
234 LBER_FREE(nextKeyp->attributeType);
237 if (nextKeyp->orderingRule != NULL) {
238 LBER_FREE(nextKeyp->orderingRule);
248 /* ---------------------------------------------------------------------------
249 ldap_create_sort_control
251 Create and encode the server-side sort control.
253 ld (IN) An LDAP session handle, as obtained from a call to
256 keyList (IN) Points to a null-terminated array of pointers to
257 LDAPSortKey structures, containing a description of
258 each of the sort keys to be used. The description
259 consists of an attribute name, ascending/descending flag,
260 and an optional matching rule (OID) to use.
262 isCritical (IN) 0 - Indicates the control is not critical to the operation.
263 non-zero - The control is critical to the operation.
265 ctrlp (OUT) Returns a pointer to the LDAPControl created. This control
266 SHOULD be freed by calling ldap_control_free() when done.
271 SortKeyList ::= SEQUENCE OF SEQUENCE {
272 attributeType AttributeDescription,
273 orderingRule [0] MatchingRuleId OPTIONAL,
274 reverseOrder [1] BOOLEAN DEFAULT FALSE }
276 ---------------------------------------------------------------------------*/
279 ldap_create_sort_control (
281 LDAPSortKey **keyList,
283 LDAPControl **ctrlp )
290 if ( (ld == NULL) || (keyList == NULL) || (ctrlp == NULL) ) {
291 ld->ld_errno = LDAP_PARAM_ERROR;
292 return(ld->ld_errno);
295 if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) {
296 ld->ld_errno = LDAP_NO_MEMORY;
297 return( ld->ld_errno );
300 tag = ber_printf(ber, "{" /*}*/);
301 if (tag == LBER_ERROR) goto exit;
303 for (i = 0; keyList[i] != NULL; i++) {
304 tag = ber_printf(ber, "{s" /*}*/, (keyList[i])->attributeType);
305 if (tag == LBER_ERROR) goto exit;
307 if ((keyList[i])->orderingRule != NULL) {
308 tag = ber_printf( ber, "ts",
309 LDAP_MATCHRULE_IDENTIFIER,
310 (keyList[i])->orderingRule );
312 if( tag == LBER_ERROR ) goto exit;
315 if ((keyList[i])->reverseOrder) {
316 tag = ber_printf(ber, "tb",
317 LDAP_REVERSEORDER_IDENTIFIER,
318 (keyList[i])->reverseOrder );
320 if( tag == LBER_ERROR ) goto exit;
323 tag = ber_printf(ber, /*{*/ "N}");
324 if( tag == LBER_ERROR ) goto exit;
327 tag = ber_printf(ber, /*{*/ "N}");
328 if( tag == LBER_ERROR ) goto exit;
330 ld->ld_errno = ldap_create_control( LDAP_CONTROL_SORTREQUEST,
331 ber, isCritical, ctrlp);
335 return(ld->ld_errno);
339 ld->ld_errno = LDAP_ENCODING_ERROR;
340 return(ld->ld_errno);
344 /* ---------------------------------------------------------------------------
345 ldap_parse_sort_control
347 Decode the server-side sort control return information.
349 ld (IN) An LDAP session handle, as obtained from a call to
352 ctrls (IN) The address of a NULL-terminated array of LDAPControl
353 structures, typically obtained by a call to
356 returnCode (OUT) This result parameter is filled in with the sort control
357 result code. This parameter MUST not be NULL.
359 attribute (OUT) If an error occured the server may return a string
360 indicating the first attribute in the sortkey list
361 that was in error. If a string is returned, the memory
362 should be freed with ldap_memfree. If this parameter is
363 NULL, no string is returned.
366 Ber encoding for sort control
368 SortResult ::= SEQUENCE {
369 sortResult ENUMERATED {
370 success (0), -- results are sorted
371 operationsError (1), -- server internal failure
372 timeLimitExceeded (3), -- timelimit reached before
373 -- sorting was completed
374 strongAuthRequired (8), -- refused to return sorted
375 -- results via insecure
377 adminLimitExceeded (11), -- too many matching entries
378 -- for the server to sort
379 noSuchAttribute (16), -- unrecognized attribute
381 inappropriateMatching (18), -- unrecognized or inappro-
382 -- priate matching rule in
384 insufficientAccessRights (50), -- refused to return sorted
385 -- results to this client
386 busy (51), -- too busy to process
387 unwillingToPerform (53), -- unable to sort
390 attributeType [0] AttributeDescription OPTIONAL }
391 ---------------------------------------------------------------------------*/
394 ldap_parse_sort_control(
397 unsigned long *returnCode,
401 LDAPControl *pControl;
403 ber_tag_t tag, berTag;
407 ld->ld_errno = LDAP_PARAM_ERROR;
408 return(ld->ld_errno);
412 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
413 return(ld->ld_errno);
420 /* Search the list of control responses for a sort control. */
421 for (i=0; ctrls[i]; i++) {
423 if (!strcmp(LDAP_CONTROL_SORTRESPONSE, pControl->ldctl_oid))
424 goto foundSortControl;
427 /* No sort control was found. */
428 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
429 return(ld->ld_errno);
432 /* Create a BerElement from the berval returned in the control. */
433 ber = ber_init(&pControl->ldctl_value);
436 ld->ld_errno = LDAP_NO_MEMORY;
437 return(ld->ld_errno);
440 /* Extract the result code from the control. */
441 tag = ber_scanf(ber, "{e" /*}*/, returnCode);
443 if( tag == LBER_ERROR ) {
445 ld->ld_errno = LDAP_DECODING_ERROR;
446 return(ld->ld_errno);
449 /* If caller wants the attribute name, and if it's present in the control,
450 extract the attribute name which caused the error. */
451 if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen)))
453 tag = ber_scanf(ber, "ta", &berTag, attribute);
455 if (tag == LBER_ERROR ) {
457 ld->ld_errno = LDAP_DECODING_ERROR;
458 return(ld->ld_errno);
464 ld->ld_errno = LDAP_SUCCESS;
465 return(ld->ld_errno);