]> git.sur5r.net Git - openldap/blob - libraries/libldap/sortctrl.c
Make LDAP_MEMORY_DEBUG a bitmask. #define LDAP_MEMORY_DEBUG_ASSERT. ITS#4990.
[openldap] / libraries / libldap / sortctrl.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2007 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
308         ber = ldap_alloc_ber_with_options( ld );
309         if ( ber == NULL) {
310                 ld->ld_errno = LDAP_NO_MEMORY;
311                 return ld->ld_errno;
312         }
313
314         tag = ber_printf( ber, "{" /*}*/ );
315         if ( tag == LBER_ERROR ) {
316                 goto error_return;
317         }
318
319         for ( i = 0; keyList[i] != NULL; i++ ) {
320                 tag = ber_printf( ber, "{s" /*}*/, keyList[i]->attributeType );
321                 if ( tag == LBER_ERROR ) {
322                         goto error_return;
323                 }
324
325                 if ( keyList[i]->orderingRule != NULL ) {
326                         tag = ber_printf( ber, "ts",
327                                 LDAP_MATCHRULE_IDENTIFIER,
328                                 keyList[i]->orderingRule );
329
330                         if ( tag == LBER_ERROR ) {
331                                 goto error_return;
332                         }
333                 }
334
335                 if ( keyList[i]->reverseOrder ) {
336                         tag = ber_printf( ber, "tb",
337                                 LDAP_REVERSEORDER_IDENTIFIER,
338                                 keyList[i]->reverseOrder );
339
340                         if ( tag == LBER_ERROR ) {
341                                 goto error_return;
342                         }
343                 }
344
345                 tag = ber_printf( ber, /*{*/ "N}" );
346                 if ( tag == LBER_ERROR ) {
347                         goto error_return;
348                 }
349         }
350
351         tag = ber_printf( ber, /*{*/ "N}" );
352         if ( tag == LBER_ERROR ) {
353                 goto error_return;
354         }
355
356         if ( ber_flatten2( ber, value, 1 ) == -1 ) {
357                 ld->ld_errno = LDAP_NO_MEMORY;
358         }
359
360         if ( 0 ) {
361 error_return:;
362                 ld->ld_errno =  LDAP_ENCODING_ERROR;
363         }
364
365         if ( ber != NULL ) {
366                 ber_free( ber, 1 );
367         }
368
369         return ld->ld_errno;
370 }
371
372
373 /* ---------------------------------------------------------------------------
374    ldap_create_sort_control
375    
376    Create and encode the server-side sort control.
377    
378    ld          (IN) An LDAP session handle, as obtained from a call to
379                                         ldap_init().
380
381    keyList     (IN) Points to a null-terminated array of pointers to
382                                         LDAPSortKey structures, containing a description of
383                                         each of the sort keys to be used.  The description
384                                         consists of an attribute name, ascending/descending flag,
385                                         and an optional matching rule (OID) to use.
386                            
387    isCritical  (IN) 0 - Indicates the control is not critical to the operation.
388                                         non-zero - The control is critical to the operation.
389                                          
390    ctrlp      (OUT) Returns a pointer to the LDAPControl created.  This control
391                                         SHOULD be freed by calling ldap_control_free() when done.
392    
393    
394    Ber encoding
395    
396    SortKeyList ::= SEQUENCE OF SEQUENCE {
397                    attributeType   AttributeDescription,
398                    orderingRule    [0] MatchingRuleId OPTIONAL,
399                    reverseOrder    [1] BOOLEAN DEFAULT FALSE }
400    
401    ---------------------------------------------------------------------------*/
402
403 int
404 ldap_create_sort_control(
405         LDAP *ld,
406         LDAPSortKey **keyList,
407         int isCritical,
408         LDAPControl **ctrlp )
409 {
410         struct berval   value;
411         BerElement      *ber;
412
413         assert( ld != NULL );
414         assert( LDAP_VALID( ld ) );
415
416         if ( ld == NULL ) return LDAP_PARAM_ERROR;
417         if ( ctrlp == NULL ) {
418                 ld->ld_errno = LDAP_PARAM_ERROR;
419                 return ld->ld_errno;
420         }
421
422         ld->ld_errno = ldap_create_sort_control_value( ld, keyList, &value );
423         if ( ld->ld_errno == LDAP_SUCCESS ) {
424                 if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) {
425                         ld->ld_errno = LDAP_NO_MEMORY;
426                         return LDAP_NO_MEMORY;
427                 }
428         
429                 ld->ld_errno = ldap_create_control( LDAP_CONTROL_SORTREQUEST,
430                         ber, isCritical, ctrlp );
431                 if ( ld->ld_errno == LDAP_SUCCESS ) {
432                         (*ctrlp)->ldctl_value = value;
433                 } else {
434                         LDAP_FREE( value.bv_val );
435                 }
436                 ber_free(ber, 1);
437         }
438
439         return ld->ld_errno;
440 }
441
442
443 /* ---------------------------------------------------------------------------
444    ldap_parse_sortedresult_control
445    
446    Decode the server-side sort control return information.
447
448    ld          (IN) An LDAP session handle, as obtained from a call to
449                                         ldap_init().
450
451    ctrl        (IN) The address of the LDAP Control Structure.
452                                   
453    returnCode (OUT) This result parameter is filled in with the sort control
454                                         result code.  This parameter MUST not be NULL.
455                                   
456    attribute  (OUT) If an error occured the server may return a string
457                                         indicating the first attribute in the sortkey list
458                                         that was in error.  If a string is returned, the memory
459                                         should be freed with ldap_memfree.  If this parameter is
460                                         NULL, no string is returned.
461    
462                            
463    Ber encoding for sort control
464          
465          SortResult ::= SEQUENCE {
466                 sortResult  ENUMERATED {
467                         success                   (0), -- results are sorted
468                         operationsError           (1), -- server internal failure
469                         timeLimitExceeded         (3), -- timelimit reached before
470                                                                                    -- sorting was completed
471                         strongAuthRequired        (8), -- refused to return sorted
472                                                                                    -- results via insecure
473                                                                                    -- protocol
474                         adminLimitExceeded       (11), -- too many matching entries
475                                                                                    -- for the server to sort
476                         noSuchAttribute          (16), -- unrecognized attribute
477                                                                                    -- type in sort key
478                         inappropriateMatching    (18), -- unrecognized or inappro-
479                                                                                    -- priate matching rule in
480                                                                                    -- sort key
481                         insufficientAccessRights (50), -- refused to return sorted
482                                                                                    -- results to this client
483                         busy                     (51), -- too busy to process
484                         unwillingToPerform       (53), -- unable to sort
485                         other                    (80)
486                         },
487           attributeType [0] AttributeDescription OPTIONAL }
488    ---------------------------------------------------------------------------*/
489
490 int
491 ldap_parse_sortresponse_control(
492         LDAP *ld,
493         LDAPControl *ctrl,
494         ber_int_t *returnCode,
495         char **attribute )
496 {
497         BerElement *ber;
498         ber_tag_t tag, berTag;
499         ber_len_t berLen;
500
501         assert( ld != NULL );
502         assert( LDAP_VALID( ld ) );
503
504         if (ld == NULL) {
505                 return LDAP_PARAM_ERROR;
506         }
507
508         if (ctrl == NULL) {
509                 ld->ld_errno =  LDAP_PARAM_ERROR;
510                 return(ld->ld_errno);
511         }
512
513         if (attribute) {
514                 *attribute = NULL;
515         }
516
517         if ( strcmp(LDAP_CONTROL_SORTRESPONSE, ctrl->ldctl_oid) != 0 ) {
518                 /* Not sort result control */
519                 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
520                 return(ld->ld_errno);
521         }
522
523         /* Create a BerElement from the berval returned in the control. */
524         ber = ber_init(&ctrl->ldctl_value);
525
526         if (ber == NULL) {
527                 ld->ld_errno = LDAP_NO_MEMORY;
528                 return(ld->ld_errno);
529         }
530
531         /* Extract the result code from the control. */
532         tag = ber_scanf(ber, "{e" /*}*/, returnCode);
533
534         if( tag == LBER_ERROR ) {
535                 ber_free(ber, 1);
536                 ld->ld_errno = LDAP_DECODING_ERROR;
537                 return(ld->ld_errno);
538         }
539
540         /* If caller wants the attribute name, and if it's present in the control,
541            extract the attribute name which caused the error. */
542         if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen)))
543         {
544                 tag = ber_scanf(ber, "ta", &berTag, attribute);
545
546                 if (tag == LBER_ERROR ) {
547                         ber_free(ber, 1);
548                         ld->ld_errno = LDAP_DECODING_ERROR;
549                         return(ld->ld_errno);
550                 }
551         }
552
553         ber_free(ber,1);
554
555         ld->ld_errno = LDAP_SUCCESS;
556         return(ld->ld_errno);
557 }