]> git.sur5r.net Git - openldap/blob - libraries/libldap/sortctrl.c
Merge remote-tracking branch 'origin/mdb.master' into OPENLDAP_REL_ENG_2_4
[openldap] / libraries / libldap / sortctrl.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2013 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
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.
10  *
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>.
14  */
15 /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
16  *
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.
25  */
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.
29  */
30
31 #include "portable.h"
32
33 #include <stdio.h>
34 #include <ac/stdlib.h>
35 #include <ac/string.h>
36 #include <ac/time.h>
37
38 #include "ldap-int.h"
39
40 #define LDAP_MATCHRULE_IDENTIFIER      0x80L
41 #define LDAP_REVERSEORDER_IDENTIFIER   0x81L
42 #define LDAP_ATTRTYPES_IDENTIFIER      0x80L
43
44
45
46 /* ---------------------------------------------------------------------------
47    countKeys
48    
49    Internal function to determine the number of keys in the string.
50    
51    keyString  (IN) String of items separated by whitespace.
52    ---------------------------------------------------------------------------*/
53
54 static int countKeys(char *keyString)
55 {
56         char *p = keyString;
57         int count = 0;
58
59         for (;;)
60         {
61                 while (LDAP_SPACE(*p))           /* Skip leading whitespace */
62                         p++;
63
64                 if (*p == '\0')                 /* End of string? */
65                         return count;
66
67                 count++;                                /* Found start of a key */
68
69                 while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */
70                         if (*p++ == '\0')
71                                 return count;
72         }
73 }
74
75
76 /* ---------------------------------------------------------------------------
77    readNextKey
78    
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.
82
83    Each sort key in the string has the format:
84           [whitespace][-]attribute[:[OID]]
85
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.
89                                                 
90    key         (OUT)    Points to the address of an LDAPSortKey stucture
91                                                 which has been allocated by this routine and
92                                                 initialized with information from the next sortkey.                        
93    ---------------------------------------------------------------------------*/
94
95 static int readNextKey( char **pNextKey, LDAPSortKey **key)
96 {
97         char *p = *pNextKey;
98         int rev = 0;
99         char *attrStart;
100         int attrLen;
101         char *oidStart = NULL;
102         int oidLen = 0;
103
104         /* Skip leading white space. */
105         while (LDAP_SPACE(*p))
106                 p++;
107
108         if (*p == '-')           /* Check if the reverse flag is present. */
109         {
110                 rev=1;
111                 p++;
112         }
113
114         /* We're now positioned at the start of the attribute. */
115         attrStart = p;
116
117         /* Get the length of the attribute until the next whitespace or ":". */
118         attrLen = strcspn(p, " \t:");
119         p += attrLen;
120
121         if (attrLen == 0)        /* If no attribute name was present, quit. */
122                 return LDAP_PARAM_ERROR;
123
124         if (*p == ':')
125         {
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;
129         }
130
131         *pNextKey = p;           /* Update argument to point to next key */
132
133         /* Allocate an LDAPSortKey structure */
134         *key = LDAP_MALLOC(sizeof(LDAPSortKey));
135         if (*key == NULL) return LDAP_NO_MEMORY;
136
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;
142         }
143
144         strncpy((*key)->attributeType, attrStart, attrLen);
145         (*key)->attributeType[attrLen] = 0;
146
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;
154                 }
155                 strncpy((*key)->orderingRule, oidStart, oidLen);
156                 (*key)->orderingRule[oidLen] = 0;
157
158         } else {
159                 (*key)->orderingRule = NULL;
160         }
161
162         (*key)->reverseOrder = rev;
163
164         return LDAP_SUCCESS;
165 }
166
167
168 /* ---------------------------------------------------------------------------
169    ldap_create_sort_keylist
170    
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.
174    
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().
179                                                 
180    keyString      (IN)  Points to a string of one or more sort keys.                      
181    
182    ---------------------------------------------------------------------------*/
183
184 int
185 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
186 {
187         int         numKeys, rc, i;
188         char        *nextKey;
189         LDAPSortKey **keyList = NULL;
190
191         assert( sortKeyList != NULL );
192         assert( keyString != NULL );
193
194         *sortKeyList = NULL;
195
196         /* Determine the number of sort keys so we can allocate memory. */
197         if (( numKeys = countKeys(keyString)) == 0) {
198                 return LDAP_PARAM_ERROR;
199         }
200
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;
204
205         /* For each sort key in the string, create an LDAPSortKey structure
206            and add it to the list.
207         */
208         nextKey = keyString;              /* Points to the next key in the string */
209         for (i=0; i < numKeys; i++) {
210                 rc = readNextKey(&nextKey, &keyList[i]);
211
212                 if (rc != LDAP_SUCCESS) {
213                         ldap_free_sort_keylist(keyList);
214                         return rc;
215                 }
216         }
217
218         *sortKeyList = keyList;
219         return LDAP_SUCCESS;
220 }
221
222
223 /* ---------------------------------------------------------------------------
224    ldap_free_sort_keylist
225    
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.
230    
231    keyList     (IN) Points to an array of pointers to LDAPSortKey structures.
232    ---------------------------------------------------------------------------*/
233
234 void
235 ldap_free_sort_keylist ( LDAPSortKey **keyList )
236 {
237         int i;
238         LDAPSortKey *nextKeyp;
239
240         if (keyList == NULL) return;
241
242         i=0;
243         while ( 0 != (nextKeyp = keyList[i++]) ) {
244                 if (nextKeyp->attributeType) {
245                         LBER_FREE(nextKeyp->attributeType);
246                 }
247
248                 if (nextKeyp->orderingRule != NULL) {
249                         LBER_FREE(nextKeyp->orderingRule);
250                 }
251
252                 LBER_FREE(nextKeyp);
253         }
254
255         LBER_FREE(keyList);
256 }
257
258
259 /* ---------------------------------------------------------------------------
260    ldap_create_sort_control_value
261    
262    Create and encode the value of the server-side sort control.
263    
264    ld          (IN) An LDAP session handle, as obtained from a call to
265                                         ldap_init().
266
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.
272                            
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.
275    
276    
277    Ber encoding
278    
279    SortKeyList ::= SEQUENCE OF SEQUENCE {
280                    attributeType   AttributeDescription,
281                    orderingRule    [0] MatchingRuleId OPTIONAL,
282                    reverseOrder    [1] BOOLEAN DEFAULT FALSE }
283    
284    ---------------------------------------------------------------------------*/
285
286 int
287 ldap_create_sort_control_value(
288         LDAP *ld,
289         LDAPSortKey **keyList,
290         struct berval *value )
291 {
292         int             i;
293         BerElement      *ber = NULL;
294         ber_tag_t       tag;
295
296         assert( ld != NULL );
297         assert( LDAP_VALID( ld ) );
298
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;
303         }
304
305         value->bv_val = NULL;
306         value->bv_len = 0;
307         ld->ld_errno = LDAP_SUCCESS;
308
309         ber = ldap_alloc_ber_with_options( ld );
310         if ( ber == NULL) {
311                 ld->ld_errno = LDAP_NO_MEMORY;
312                 return ld->ld_errno;
313         }
314
315         tag = ber_printf( ber, "{" /*}*/ );
316         if ( tag == LBER_ERROR ) {
317                 goto error_return;
318         }
319
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;
324                 }
325
326                 if ( keyList[i]->orderingRule != NULL ) {
327                         tag = ber_printf( ber, "ts",
328                                 LDAP_MATCHRULE_IDENTIFIER,
329                                 keyList[i]->orderingRule );
330
331                         if ( tag == LBER_ERROR ) {
332                                 goto error_return;
333                         }
334                 }
335
336                 if ( keyList[i]->reverseOrder ) {
337                         tag = ber_printf( ber, "tb",
338                                 LDAP_REVERSEORDER_IDENTIFIER,
339                                 keyList[i]->reverseOrder );
340
341                         if ( tag == LBER_ERROR ) {
342                                 goto error_return;
343                         }
344                 }
345
346                 tag = ber_printf( ber, /*{*/ "N}" );
347                 if ( tag == LBER_ERROR ) {
348                         goto error_return;
349                 }
350         }
351
352         tag = ber_printf( ber, /*{*/ "N}" );
353         if ( tag == LBER_ERROR ) {
354                 goto error_return;
355         }
356
357         if ( ber_flatten2( ber, value, 1 ) == -1 ) {
358                 ld->ld_errno = LDAP_NO_MEMORY;
359         }
360
361         if ( 0 ) {
362 error_return:;
363                 ld->ld_errno =  LDAP_ENCODING_ERROR;
364         }
365
366         if ( ber != NULL ) {
367                 ber_free( ber, 1 );
368         }
369
370         return ld->ld_errno;
371 }
372
373
374 /* ---------------------------------------------------------------------------
375    ldap_create_sort_control
376    
377    Create and encode the server-side sort control.
378    
379    ld          (IN) An LDAP session handle, as obtained from a call to
380                                         ldap_init().
381
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.
387                            
388    isCritical  (IN) 0 - Indicates the control is not critical to the operation.
389                                         non-zero - The control is critical to the operation.
390                                          
391    ctrlp      (OUT) Returns a pointer to the LDAPControl created.  This control
392                                         SHOULD be freed by calling ldap_control_free() when done.
393    
394    
395    Ber encoding
396    
397    SortKeyList ::= SEQUENCE OF SEQUENCE {
398                    attributeType   AttributeDescription,
399                    orderingRule    [0] MatchingRuleId OPTIONAL,
400                    reverseOrder    [1] BOOLEAN DEFAULT FALSE }
401    
402    ---------------------------------------------------------------------------*/
403
404 int
405 ldap_create_sort_control(
406         LDAP *ld,
407         LDAPSortKey **keyList,
408         int isCritical,
409         LDAPControl **ctrlp )
410 {
411         struct berval   value;
412
413         assert( ld != NULL );
414         assert( LDAP_VALID( ld ) );
415
416         if ( ld == NULL ) {
417                 return LDAP_PARAM_ERROR;
418         }
419
420         if ( ctrlp == NULL ) {
421                 ld->ld_errno = LDAP_PARAM_ERROR;
422                 return ld->ld_errno;
423         }
424
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 );
431                 }
432         }
433
434         return ld->ld_errno;
435 }
436
437
438 /* ---------------------------------------------------------------------------
439    ldap_parse_sortedresult_control
440    
441    Decode the server-side sort control return information.
442
443    ld          (IN) An LDAP session handle, as obtained from a call to
444                                         ldap_init().
445
446    ctrl        (IN) The address of the LDAP Control Structure.
447                                   
448    returnCode (OUT) This result parameter is filled in with the sort control
449                                         result code.  This parameter MUST not be NULL.
450                                   
451    attribute  (OUT) If an error occured 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.
456    
457                            
458    Ber encoding for sort control
459          
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)
481                         },
482           attributeType [0] AttributeDescription OPTIONAL }
483    ---------------------------------------------------------------------------*/
484
485 int
486 ldap_parse_sortresponse_control(
487         LDAP *ld,
488         LDAPControl *ctrl,
489         ber_int_t *returnCode,
490         char **attribute )
491 {
492         BerElement *ber;
493         ber_tag_t tag, berTag;
494         ber_len_t berLen;
495
496         assert( ld != NULL );
497         assert( LDAP_VALID( ld ) );
498
499         if (ld == NULL) {
500                 return LDAP_PARAM_ERROR;
501         }
502
503         if (ctrl == NULL) {
504                 ld->ld_errno =  LDAP_PARAM_ERROR;
505                 return(ld->ld_errno);
506         }
507
508         if (attribute) {
509                 *attribute = NULL;
510         }
511
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);
516         }
517
518         /* Create a BerElement from the berval returned in the control. */
519         ber = ber_init(&ctrl->ldctl_value);
520
521         if (ber == NULL) {
522                 ld->ld_errno = LDAP_NO_MEMORY;
523                 return(ld->ld_errno);
524         }
525
526         /* Extract the result code from the control. */
527         tag = ber_scanf(ber, "{e" /*}*/, returnCode);
528
529         if( tag == LBER_ERROR ) {
530                 ber_free(ber, 1);
531                 ld->ld_errno = LDAP_DECODING_ERROR;
532                 return(ld->ld_errno);
533         }
534
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)))
538         {
539                 tag = ber_scanf(ber, "ta", &berTag, attribute);
540
541                 if (tag == LBER_ERROR ) {
542                         ber_free(ber, 1);
543                         ld->ld_errno = LDAP_DECODING_ERROR;
544                         return(ld->ld_errno);
545                 }
546         }
547
548         ber_free(ber,1);
549
550         ld->ld_errno = LDAP_SUCCESS;
551         return(ld->ld_errno);
552 }