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