1 /* $NetBSD: sortctrl.c,v 1.3 2021/08/14 16:14:56 christos Exp $ */
2
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1998-2021 The OpenLDAP Foundation.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
11 * Public License.
12 *
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
16 */
17 /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
18 *
19 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
20 * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
21 * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
22 * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
23 * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
24 * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
25 * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
26 * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
27 */
28 /* Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
29 * can be found in the file "build/LICENSE-2.0.1" in this distribution
30 * of OpenLDAP Software.
31 */
32
33 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: sortctrl.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
35
36 #include "portable.h"
37
38 #include <stdio.h>
39 #include <ac/stdlib.h>
40 #include <ac/string.h>
41 #include <ac/time.h>
42
43 #include "ldap-int.h"
44
45 #define LDAP_MATCHRULE_IDENTIFIER 0x80L
46 #define LDAP_REVERSEORDER_IDENTIFIER 0x81L
47 #define LDAP_ATTRTYPES_IDENTIFIER 0x80L
48
49
50
51 /* ---------------------------------------------------------------------------
52 countKeys
53
54 Internal function to determine the number of keys in the string.
55
56 keyString (IN) String of items separated by whitespace.
57 ---------------------------------------------------------------------------*/
58
countKeys(char * keyString)59 static int countKeys(char *keyString)
60 {
61 char *p = keyString;
62 int count = 0;
63
64 for (;;)
65 {
66 while (LDAP_SPACE(*p)) /* Skip leading whitespace */
67 p++;
68
69 if (*p == '\0') /* End of string? */
70 return count;
71
72 count++; /* Found start of a key */
73
74 while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */
75 if (*p++ == '\0')
76 return count;
77 }
78 }
79
80
81 /* ---------------------------------------------------------------------------
82 readNextKey
83
84 Internal function to parse the next sort key in the string.
85 Allocate an LDAPSortKey structure and initialize it with
86 attribute name, reverse flag, and matching rule OID.
87
88 Each sort key in the string has the format:
89 [whitespace][-]attribute[:[OID]]
90
91 pNextKey (IN/OUT) Points to the next key in the sortkey string to parse.
92 The pointer is updated to point to the next character
93 after the sortkey being parsed.
94
95 key (OUT) Points to the address of an LDAPSortKey structure
96 which has been allocated by this routine and
97 initialized with information from the next sortkey.
98 ---------------------------------------------------------------------------*/
99
readNextKey(char ** pNextKey,LDAPSortKey ** key)100 static int readNextKey( char **pNextKey, LDAPSortKey **key)
101 {
102 char *p = *pNextKey;
103 int rev = 0;
104 char *attrStart;
105 int attrLen;
106 char *oidStart = NULL;
107 int oidLen = 0;
108
109 /* Skip leading white space. */
110 while (LDAP_SPACE(*p))
111 p++;
112
113 if (*p == '-') /* Check if the reverse flag is present. */
114 {
115 rev=1;
116 p++;
117 }
118
119 /* We're now positioned at the start of the attribute. */
120 attrStart = p;
121
122 /* Get the length of the attribute until the next whitespace or ":". */
123 attrLen = strcspn(p, " \t:");
124 p += attrLen;
125
126 if (attrLen == 0) /* If no attribute name was present, quit. */
127 return LDAP_PARAM_ERROR;
128
129 if (*p == ':')
130 {
131 oidStart = ++p; /* Start of the OID, after the colon */
132 oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */
133 p += oidLen;
134 }
135
136 *pNextKey = p; /* Update argument to point to next key */
137
138 /* Allocate an LDAPSortKey structure */
139 *key = LDAP_MALLOC(sizeof(LDAPSortKey));
140 if (*key == NULL) return LDAP_NO_MEMORY;
141
142 /* Allocate memory for the attribute and copy to it. */
143 (*key)->attributeType = LDAP_MALLOC(attrLen+1);
144 if ((*key)->attributeType == NULL) {
145 LDAP_FREE(*key);
146 return LDAP_NO_MEMORY;
147 }
148
149 strncpy((*key)->attributeType, attrStart, attrLen);
150 (*key)->attributeType[attrLen] = 0;
151
152 /* If present, allocate memory for the OID and copy to it. */
153 if (oidLen) {
154 (*key)->orderingRule = LDAP_MALLOC(oidLen+1);
155 if ((*key)->orderingRule == NULL) {
156 LDAP_FREE((*key)->attributeType);
157 LDAP_FREE(*key);
158 return LDAP_NO_MEMORY;
159 }
160 strncpy((*key)->orderingRule, oidStart, oidLen);
161 (*key)->orderingRule[oidLen] = 0;
162
163 } else {
164 (*key)->orderingRule = NULL;
165 }
166
167 (*key)->reverseOrder = rev;
168
169 return LDAP_SUCCESS;
170 }
171
172
173 /* ---------------------------------------------------------------------------
174 ldap_create_sort_keylist
175
176 Create an array of pointers to LDAPSortKey structures, containing the
177 information specified by the string representation of one or more
178 sort keys.
179
180 sortKeyList (OUT) Points to a null-terminated array of pointers to
181 LDAPSortKey structures allocated by this routine.
182 This memory SHOULD be freed by the calling program
183 using ldap_free_sort_keylist().
184
185 keyString (IN) Points to a string of one or more sort keys.
186
187 ---------------------------------------------------------------------------*/
188
189 int
ldap_create_sort_keylist(LDAPSortKey *** sortKeyList,char * keyString)190 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
191 {
192 int numKeys, rc, i;
193 char *nextKey;
194 LDAPSortKey **keyList = NULL;
195
196 assert( sortKeyList != NULL );
197 assert( keyString != NULL );
198
199 *sortKeyList = NULL;
200
201 /* Determine the number of sort keys so we can allocate memory. */
202 if (( numKeys = countKeys(keyString)) == 0) {
203 return LDAP_PARAM_ERROR;
204 }
205
206 /* Allocate the array of pointers. Initialize to NULL. */
207 keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*));
208 if ( keyList == NULL) return LDAP_NO_MEMORY;
209
210 /* For each sort key in the string, create an LDAPSortKey structure
211 and add it to the list.
212 */
213 nextKey = keyString; /* Points to the next key in the string */
214 for (i=0; i < numKeys; i++) {
215 rc = readNextKey(&nextKey, &keyList[i]);
216
217 if (rc != LDAP_SUCCESS) {
218 ldap_free_sort_keylist(keyList);
219 return rc;
220 }
221 }
222
223 *sortKeyList = keyList;
224 return LDAP_SUCCESS;
225 }
226
227
228 /* ---------------------------------------------------------------------------
229 ldap_free_sort_keylist
230
231 Frees the sort key structures created by ldap_create_sort_keylist().
232 Frees the memory referenced by the LDAPSortKey structures,
233 the LDAPSortKey structures themselves, and the array of pointers
234 to the structures.
235
236 keyList (IN) Points to an array of pointers to LDAPSortKey structures.
237 ---------------------------------------------------------------------------*/
238
239 void
ldap_free_sort_keylist(LDAPSortKey ** keyList)240 ldap_free_sort_keylist ( LDAPSortKey **keyList )
241 {
242 int i;
243 LDAPSortKey *nextKeyp;
244
245 if (keyList == NULL) return;
246
247 i=0;
248 while ( 0 != (nextKeyp = keyList[i++]) ) {
249 if (nextKeyp->attributeType) {
250 LBER_FREE(nextKeyp->attributeType);
251 }
252
253 if (nextKeyp->orderingRule != NULL) {
254 LBER_FREE(nextKeyp->orderingRule);
255 }
256
257 LBER_FREE(nextKeyp);
258 }
259
260 LBER_FREE(keyList);
261 }
262
263
264 /* ---------------------------------------------------------------------------
265 ldap_create_sort_control_value
266
267 Create and encode the value of the server-side sort control.
268
269 ld (IN) An LDAP session handle, as obtained from a call to
270 ldap_init().
271
272 keyList (IN) Points to a null-terminated array of pointers to
273 LDAPSortKey structures, containing a description of
274 each of the sort keys to be used. The description
275 consists of an attribute name, ascending/descending flag,
276 and an optional matching rule (OID) to use.
277
278 value (OUT) Contains the control value; the bv_val member of the berval structure
279 SHOULD be freed by calling ldap_memfree() when done.
280
281
282 Ber encoding
283
284 SortKeyList ::= SEQUENCE OF SEQUENCE {
285 attributeType AttributeDescription,
286 orderingRule [0] MatchingRuleId OPTIONAL,
287 reverseOrder [1] BOOLEAN DEFAULT FALSE }
288
289 ---------------------------------------------------------------------------*/
290
291 int
ldap_create_sort_control_value(LDAP * ld,LDAPSortKey ** keyList,struct berval * value)292 ldap_create_sort_control_value(
293 LDAP *ld,
294 LDAPSortKey **keyList,
295 struct berval *value )
296 {
297 int i;
298 BerElement *ber = NULL;
299 ber_tag_t tag;
300
301 assert( ld != NULL );
302 assert( LDAP_VALID( ld ) );
303
304 if ( ld == NULL ) return LDAP_PARAM_ERROR;
305 if ( keyList == NULL || value == NULL ) {
306 ld->ld_errno = LDAP_PARAM_ERROR;
307 return LDAP_PARAM_ERROR;
308 }
309
310 value->bv_val = NULL;
311 value->bv_len = 0;
312 ld->ld_errno = LDAP_SUCCESS;
313
314 ber = ldap_alloc_ber_with_options( ld );
315 if ( ber == NULL) {
316 ld->ld_errno = LDAP_NO_MEMORY;
317 return ld->ld_errno;
318 }
319
320 tag = ber_printf( ber, "{" /*}*/ );
321 if ( tag == LBER_ERROR ) {
322 goto error_return;
323 }
324
325 for ( i = 0; keyList[i] != NULL; i++ ) {
326 tag = ber_printf( ber, "{s" /*}*/, keyList[i]->attributeType );
327 if ( tag == LBER_ERROR ) {
328 goto error_return;
329 }
330
331 if ( keyList[i]->orderingRule != NULL ) {
332 tag = ber_printf( ber, "ts",
333 LDAP_MATCHRULE_IDENTIFIER,
334 keyList[i]->orderingRule );
335
336 if ( tag == LBER_ERROR ) {
337 goto error_return;
338 }
339 }
340
341 if ( keyList[i]->reverseOrder ) {
342 tag = ber_printf( ber, "tb",
343 LDAP_REVERSEORDER_IDENTIFIER,
344 keyList[i]->reverseOrder );
345
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
357 tag = ber_printf( ber, /*{*/ "N}" );
358 if ( tag == LBER_ERROR ) {
359 goto error_return;
360 }
361
362 if ( ber_flatten2( ber, value, 1 ) == -1 ) {
363 ld->ld_errno = LDAP_NO_MEMORY;
364 }
365
366 if ( 0 ) {
367 error_return:;
368 ld->ld_errno = LDAP_ENCODING_ERROR;
369 }
370
371 if ( ber != NULL ) {
372 ber_free( ber, 1 );
373 }
374
375 return ld->ld_errno;
376 }
377
378
379 /* ---------------------------------------------------------------------------
380 ldap_create_sort_control
381
382 Create and encode the server-side sort control.
383
384 ld (IN) An LDAP session handle, as obtained from a call to
385 ldap_init().
386
387 keyList (IN) Points to a null-terminated array of pointers to
388 LDAPSortKey structures, containing a description of
389 each of the sort keys to be used. The description
390 consists of an attribute name, ascending/descending flag,
391 and an optional matching rule (OID) to use.
392
393 isCritical (IN) 0 - Indicates the control is not critical to the operation.
394 non-zero - The control is critical to the operation.
395
396 ctrlp (OUT) Returns a pointer to the LDAPControl created. This control
397 SHOULD be freed by calling ldap_control_free() when done.
398
399
400 Ber encoding
401
402 SortKeyList ::= SEQUENCE OF SEQUENCE {
403 attributeType AttributeDescription,
404 orderingRule [0] MatchingRuleId OPTIONAL,
405 reverseOrder [1] BOOLEAN DEFAULT FALSE }
406
407 ---------------------------------------------------------------------------*/
408
409 int
ldap_create_sort_control(LDAP * ld,LDAPSortKey ** keyList,int isCritical,LDAPControl ** ctrlp)410 ldap_create_sort_control(
411 LDAP *ld,
412 LDAPSortKey **keyList,
413 int isCritical,
414 LDAPControl **ctrlp )
415 {
416 struct berval value;
417
418 assert( ld != NULL );
419 assert( LDAP_VALID( ld ) );
420
421 if ( ld == NULL ) {
422 return LDAP_PARAM_ERROR;
423 }
424
425 if ( ctrlp == NULL ) {
426 ld->ld_errno = LDAP_PARAM_ERROR;
427 return ld->ld_errno;
428 }
429
430 ld->ld_errno = ldap_create_sort_control_value( ld, keyList, &value );
431 if ( ld->ld_errno == LDAP_SUCCESS ) {
432 ld->ld_errno = ldap_control_create( LDAP_CONTROL_SORTREQUEST,
433 isCritical, &value, 0, ctrlp );
434 if ( ld->ld_errno != LDAP_SUCCESS ) {
435 LDAP_FREE( value.bv_val );
436 }
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 occurred 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
ldap_parse_sortresponse_control(LDAP * ld,LDAPControl * ctrl,ber_int_t * returnCode,char ** attribute)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 }
558