]> git.sur5r.net Git - openldap/blob - libraries/libldap/sortctrl.c
Consistently don't check for NULL session handle and other pointers.
[openldap] / libraries / libldap / sortctrl.c
1 /*
2  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  */
5 /* Adapted for inclusion into OpenLDAP by Kurt D. Zeilenga */
6 /*---
7  * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
8  *
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.
17  *
18  *---*/
19
20 #include "portable.h"
21
22 #include <stdio.h>
23 #include <ac/stdlib.h>
24 #include <ac/string.h>
25 #include <ac/time.h>
26
27 #include "ldap-int.h"
28
29 #define LDAP_MATCHRULE_IDENTIFIER      0x80L
30 #define LDAP_REVERSEORDER_IDENTIFIER   0x81L
31 #define LDAP_ATTRTYPES_IDENTIFIER      0x80L
32
33
34
35 /* ---------------------------------------------------------------------------
36    countKeys
37    
38    Internal function to determine the number of keys in the string.
39    
40    keyString  (IN) String of items separated by whitespace.
41    ---------------------------------------------------------------------------*/
42
43 static int countKeys(char *keyString)
44 {
45         char *p = keyString;
46         int count = 0;
47
48         for (;;)
49         {
50                 while (LDAP_SPACE(*p))           /* Skip leading whitespace */
51                         p++;
52
53                 if (*p == '\0')                 /* End of string? */
54                         return count;
55
56                 count++;                                /* Found start of a key */
57
58                 while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */
59                         if (*p++ == '\0')
60                                 return count;
61         }
62 }
63
64
65 /* ---------------------------------------------------------------------------
66    readNextKey
67    
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.
71
72    Each sort key in the string has the format:
73           [whitespace][-]attribute[:[OID]]
74
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.
78                                                 
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    ---------------------------------------------------------------------------*/
83
84 static int readNextKey( char **pNextKey, LDAPSortKey **key)
85 {
86         char *p = *pNextKey;
87         int rev = 0;
88         char *attrStart;
89         int attrLen;
90         char *oidStart = NULL;
91         int oidLen = 0;
92
93         /* Skip leading white space. */
94         while (LDAP_SPACE(*p))
95                 p++;
96
97         if (*p == '-')           /* Check if the reverse flag is present. */
98         {
99                 rev=1;
100                 p++;
101         }
102
103         /* We're now positioned at the start of the attribute. */
104         attrStart = p;
105
106         /* Get the length of the attribute until the next whitespace or ":". */
107         attrLen = strcspn(p, " \t:");
108         p += attrLen;
109
110         if (attrLen == 0)        /* If no attribute name was present, quit. */
111                 return LDAP_PARAM_ERROR;
112
113         if (*p == ':')
114         {
115                 oidStart = ++p;                          /* Start of the OID, after the colon */
116                 oidLen = strcspn(p, " \t");      /* Get length of OID till next whitespace */
117                 p += oidLen;
118         }
119
120         *pNextKey = p;           /* Update argument to point to next key */
121
122         /* Allocate an LDAPSortKey structure */
123         *key = LDAP_MALLOC(sizeof(LDAPSortKey));
124         if (*key == NULL) return LDAP_NO_MEMORY;
125
126         /* Allocate memory for the attribute and copy to it. */
127         (*key)->attributeType = LDAP_MALLOC(attrLen+1);
128         if ((*key)->attributeType == NULL) {
129                 LDAP_FREE(*key);
130                 return LDAP_NO_MEMORY;
131         }
132
133         strncpy((*key)->attributeType, attrStart, attrLen);
134         (*key)->attributeType[attrLen] = 0;
135
136         /* If present, allocate memory for the OID and copy to it. */
137         if (oidLen) {
138                 (*key)->orderingRule = LDAP_MALLOC(oidLen+1);
139                 if ((*key)->orderingRule == NULL) {
140                         LDAP_FREE((*key)->attributeType);
141                         LDAP_FREE(*key);
142                         return LDAP_NO_MEMORY;
143                 }
144                 strncpy((*key)->orderingRule, oidStart, oidLen);
145                 (*key)->orderingRule[oidLen] = 0;
146
147         } else {
148                 (*key)->orderingRule = NULL;
149         }
150
151         (*key)->reverseOrder = rev;
152
153         return LDAP_SUCCESS;
154 }
155
156
157 /* ---------------------------------------------------------------------------
158    ldap_create_sort_keylist
159    
160    Create an array of pointers to LDAPSortKey structures, containing the
161    information specified by the string representation of one or more
162    sort keys.
163    
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().
168                                                 
169    keyString      (IN)  Points to a string of one or more sort keys.                      
170    
171    ---------------------------------------------------------------------------*/
172
173 int
174 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
175 {
176         int         numKeys, rc, i;
177         char        *nextKey;
178         LDAPSortKey **keyList = NULL;
179
180         assert( sortKeyList != NULL );
181         assert( keyString != NULL );
182
183         *sortKeyList = NULL;
184
185         /* Determine the number of sort keys so we can allocate memory. */
186         if (( numKeys = countKeys(keyString)) == 0) {
187                 return LDAP_PARAM_ERROR;
188         }
189
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;
193
194         /* For each sort key in the string, create an LDAPSortKey structure
195            and add it to the list.
196         */
197         nextKey = keyString;              /* Points to the next key in the string */
198         for (i=0; i < numKeys; i++) {
199                 rc = readNextKey(&nextKey, &keyList[i]);
200
201                 if (rc != LDAP_SUCCESS) {
202                         ldap_free_sort_keylist(keyList);
203                         return rc;
204                 }
205         }
206
207         *sortKeyList = keyList;
208         return LDAP_SUCCESS;
209 }
210
211
212 /* ---------------------------------------------------------------------------
213    ldap_free_sort_keylist
214    
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
218    to the structures.
219    
220    keyList     (IN) Points to an array of pointers to LDAPSortKey structures.
221    ---------------------------------------------------------------------------*/
222
223 void
224 ldap_free_sort_keylist ( LDAPSortKey **keyList )
225 {
226         int i;
227         LDAPSortKey *nextKeyp;
228
229         if (keyList == NULL) return;
230
231         i=0;
232         while ( 0 != (nextKeyp = keyList[i++]) ) {
233                 if (nextKeyp->attributeType) {
234                         LBER_FREE(nextKeyp->attributeType);
235                 }
236
237                 if (nextKeyp->orderingRule != NULL) {
238                         LBER_FREE(nextKeyp->orderingRule);
239                 }
240
241                 LBER_FREE(nextKeyp);
242         }
243
244         LBER_FREE(keyList);
245 }
246
247
248 /* ---------------------------------------------------------------------------
249    ldap_create_sort_control
250    
251    Create and encode the server-side sort control.
252    
253    ld          (IN) An LDAP session handle, as obtained from a call to
254                                         ldap_init().
255
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.
261                            
262    isCritical  (IN) 0 - Indicates the control is not critical to the operation.
263                                         non-zero - The control is critical to the operation.
264                                          
265    ctrlp      (OUT) Returns a pointer to the LDAPControl created.  This control
266                                         SHOULD be freed by calling ldap_control_free() when done.
267    
268    
269    Ber encoding
270    
271    SortKeyList ::= SEQUENCE OF SEQUENCE {
272                    attributeType   AttributeDescription,
273                    orderingRule    [0] MatchingRuleId OPTIONAL,
274                    reverseOrder    [1] BOOLEAN DEFAULT FALSE }
275    
276    ---------------------------------------------------------------------------*/
277
278 int
279 ldap_create_sort_control (
280         LDAP *ld,
281         LDAPSortKey **keyList,
282         int isCritical,
283         LDAPControl **ctrlp )
284 {
285         int         i;
286         BerElement  *ber;
287         ber_tag_t tag;
288
289
290         if ( (ld == NULL) || (keyList == NULL) || (ctrlp == NULL) ) {
291                 ld->ld_errno = LDAP_PARAM_ERROR;
292                 return(ld->ld_errno);
293         }
294
295         if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) {
296                 ld->ld_errno = LDAP_NO_MEMORY;
297                 return( ld->ld_errno );
298         }
299
300         tag = ber_printf(ber, "{" /*}*/);
301         if (tag == LBER_ERROR) goto exit;
302
303         for (i = 0; keyList[i] != NULL; i++) {
304                 tag = ber_printf(ber, "{s" /*}*/, (keyList[i])->attributeType);
305                 if (tag == LBER_ERROR) goto exit;
306
307                 if ((keyList[i])->orderingRule != NULL) {
308                         tag = ber_printf( ber, "ts",
309                                 LDAP_MATCHRULE_IDENTIFIER,
310                                 (keyList[i])->orderingRule );
311
312                         if( tag == LBER_ERROR ) goto exit;
313                 }
314
315                 if ((keyList[i])->reverseOrder) {
316                         tag = ber_printf(ber, "tb",
317                                 LDAP_REVERSEORDER_IDENTIFIER,
318                                 (keyList[i])->reverseOrder );
319
320                         if( tag == LBER_ERROR ) goto exit;
321                 }
322
323                 tag = ber_printf(ber, /*{*/ "N}");
324                 if( tag == LBER_ERROR ) goto exit;
325         }
326
327         tag = ber_printf(ber, /*{*/ "N}");
328         if( tag == LBER_ERROR ) goto exit;
329
330         ld->ld_errno = ldap_create_control( LDAP_CONTROL_SORTREQUEST,
331                 ber, isCritical, ctrlp);
332
333         ber_free(ber, 1);
334
335         return(ld->ld_errno);
336
337 exit:
338         ber_free(ber, 1);
339         ld->ld_errno =  LDAP_ENCODING_ERROR;
340         return(ld->ld_errno);
341 }
342
343
344 /* ---------------------------------------------------------------------------
345    ldap_parse_sort_control
346    
347    Decode the server-side sort control return information.
348
349    ld          (IN) An LDAP session handle, as obtained from a call to
350                                         ldap_init().
351
352    ctrls       (IN) The address of a NULL-terminated array of LDAPControl
353                                         structures, typically obtained by a call to
354                                         ldap_parse_result().
355                                   
356    returnCode (OUT) This result parameter is filled in with the sort control
357                                         result code.  This parameter MUST not be NULL.
358                                   
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.
364    
365                            
366    Ber encoding for sort control
367          
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
376                                                                                    -- protocol
377                         adminLimitExceeded       (11), -- too many matching entries
378                                                                                    -- for the server to sort
379                         noSuchAttribute          (16), -- unrecognized attribute
380                                                                                    -- type in sort key
381                         inappropriateMatching    (18), -- unrecognized or inappro-
382                                                                                    -- priate matching rule in
383                                                                                    -- sort key
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
388                         other                    (80)
389                         },
390           attributeType [0] AttributeDescription OPTIONAL }
391    ---------------------------------------------------------------------------*/
392
393 int
394 ldap_parse_sort_control(
395         LDAP           *ld,
396         LDAPControl    **ctrls,
397         unsigned long  *returnCode,
398         char           **attribute )
399 {
400         BerElement *ber;
401         LDAPControl *pControl;
402         int i;
403         ber_tag_t tag, berTag;
404         ber_len_t berLen;
405
406         if (ld == NULL) {
407                 ld->ld_errno = LDAP_PARAM_ERROR;
408                 return(ld->ld_errno);
409         }
410
411         if (ctrls == NULL) {
412                 ld->ld_errno =  LDAP_CONTROL_NOT_FOUND;
413                 return(ld->ld_errno);
414         }
415
416         if (attribute) {
417                 *attribute = NULL;
418         }
419
420         /* Search the list of control responses for a sort control. */
421         for (i=0; ctrls[i]; i++) {
422                 pControl = ctrls[i];
423                 if (!strcmp(LDAP_CONTROL_SORTRESPONSE, pControl->ldctl_oid))
424                         goto foundSortControl;
425         }
426
427         /* No sort control was found. */
428         ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
429         return(ld->ld_errno);
430
431 foundSortControl:
432         /* Create a BerElement from the berval returned in the control. */
433         ber = ber_init(&pControl->ldctl_value);
434
435         if (ber == NULL) {
436                 ld->ld_errno = LDAP_NO_MEMORY;
437                 return(ld->ld_errno);
438         }
439
440         /* Extract the result code from the control. */
441         tag = ber_scanf(ber, "{e" /*}*/, returnCode);
442
443         if( tag == LBER_ERROR ) {
444                 ber_free(ber, 1);
445                 ld->ld_errno = LDAP_DECODING_ERROR;
446                 return(ld->ld_errno);
447         }
448
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)))
452         {
453                 tag = ber_scanf(ber, "ta", &berTag, attribute);
454
455                 if (tag == LBER_ERROR ) {
456                         ber_free(ber, 1);
457                         ld->ld_errno = LDAP_DECODING_ERROR;
458                         return(ld->ld_errno);
459                 }
460         }
461
462         ber_free(ber,1);
463
464         ld->ld_errno = LDAP_SUCCESS;
465         return(ld->ld_errno);
466 }