1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1998-2011 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 54static 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 95static 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 184int 185ldap_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 234void 235ldap_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 286int 287ldap_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 ) { 362error_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 404int 405ldap_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 apple specific code 440 ldap_parse_sort_control - APPLE - WRAPPER method added during upgrade from 2.3.27 to 2.4.11 441 to support older clients 442 443 Decode the server-side sort control return information. 444 445 ld (IN) An LDAP session handle, as obtained from a call to 446 ldap_init(). 447 448 ctrls (IN) The address of a NULL-terminated array of LDAPControl 449 structures, typically obtained by a call to 450 ldap_parse_result(). 451 452 returnCode (OUT) This result parameter is filled in with the sort control 453 result code. This parameter MUST not be NULL. 454 455 attribute (OUT) If an error occured the server may return a string 456 indicating the first attribute in the sortkey list 457 that was in error. If a string is returned, the memory 458 should be freed with ldap_memfree. If this parameter is 459 NULL, no string is returned. 460 461 462 Ber encoding for sort control 463 464 SortResult ::= SEQUENCE { 465 sortResult ENUMERATED { 466 success (0), -- results are sorted 467 operationsError (1), -- server internal failure 468 timeLimitExceeded (3), -- timelimit reached before 469 -- sorting was completed 470 strongAuthRequired (8), -- refused to return sorted 471 -- results via insecure 472 -- protocol 473 adminLimitExceeded (11), -- too many matching entries 474 -- for the server to sort 475 noSuchAttribute (16), -- unrecognized attribute 476 -- type in sort key 477 inappropriateMatching (18), -- unrecognized or inappro- 478 -- priate matching rule in 479 -- sort key 480 insufficientAccessRights (50), -- refused to return sorted 481 -- results to this client 482 busy (51), -- too busy to process 483 unwillingToPerform (53), -- unable to sort 484 other (80) 485 }, 486 attributeType [0] AttributeDescription OPTIONAL } 487 ---------------------------------------------------------------------------*/ 488 489int 490ldap_parse_sort_control( 491 LDAP *ld, 492 LDAPControl **ctrls, 493 unsigned long *returnCode, 494 char **attribute ) 495{ 496 LDAPControl *pControl; 497 int i; 498 499 if (ld == NULL) { 500 ld->ld_errno = LDAP_PARAM_ERROR; 501 return(ld->ld_errno); 502 } 503 504 if (ctrls == NULL) { 505 ld->ld_errno = LDAP_CONTROL_NOT_FOUND; 506 return(ld->ld_errno); 507 } 508 509 if (attribute) { 510 *attribute = NULL; 511 } 512 513 /* Search the list of control responses for a sort control. */ 514 for (i=0; ctrls[i]; i++) { 515 pControl = ctrls[i]; 516 if (!strcmp(LDAP_CONTROL_SORTRESPONSE, pControl->ldctl_oid)) 517 return ldap_parse_sortresponse_control(ld,pControl,(ber_int_t *)returnCode, attribute); 518 } 519 520 /* No sort control was found. */ 521 ld->ld_errno = LDAP_CONTROL_NOT_FOUND; 522 return(ld->ld_errno); 523 524} 525 526/* --------------------------------------------------------------------------- 527 ldap_parse_sortresponse_control 528 529 Decode the server-side sort control return information. 530 531 ld (IN) An LDAP session handle, as obtained from a call to 532 ldap_init(). 533 534 ctrl (IN) The address of the LDAP Control Structure. 535 536 returnCode (OUT) This result parameter is filled in with the sort control 537 result code. This parameter MUST not be NULL. 538 539 attribute (OUT) If an error occured the server may return a string 540 indicating the first attribute in the sortkey list 541 that was in error. If a string is returned, the memory 542 should be freed with ldap_memfree. If this parameter is 543 NULL, no string is returned. 544 545 546 Ber encoding for sort control 547 548 SortResult ::= SEQUENCE { 549 sortResult ENUMERATED { 550 success (0), -- results are sorted 551 operationsError (1), -- server internal failure 552 timeLimitExceeded (3), -- timelimit reached before 553 -- sorting was completed 554 strongAuthRequired (8), -- refused to return sorted 555 -- results via insecure 556 -- protocol 557 adminLimitExceeded (11), -- too many matching entries 558 -- for the server to sort 559 noSuchAttribute (16), -- unrecognized attribute 560 -- type in sort key 561 inappropriateMatching (18), -- unrecognized or inappro- 562 -- priate matching rule in 563 -- sort key 564 insufficientAccessRights (50), -- refused to return sorted 565 -- results to this client 566 busy (51), -- too busy to process 567 unwillingToPerform (53), -- unable to sort 568 other (80) 569 }, 570 attributeType [0] AttributeDescription OPTIONAL } 571 ---------------------------------------------------------------------------*/ 572 573int 574ldap_parse_sortresponse_control( 575 LDAP *ld, 576 LDAPControl *ctrl, 577 ber_int_t *returnCode, 578 char **attribute ) 579{ 580 BerElement *ber; 581 ber_tag_t tag, berTag; 582 ber_len_t berLen; 583 584 assert( ld != NULL ); 585 assert( LDAP_VALID( ld ) ); 586 587 if (ld == NULL) { 588 return LDAP_PARAM_ERROR; 589 } 590 591 if (ctrl == NULL) { 592 ld->ld_errno = LDAP_PARAM_ERROR; 593 return(ld->ld_errno); 594 } 595 596 if (attribute) { 597 *attribute = NULL; 598 } 599 600 if ( strcmp(LDAP_CONTROL_SORTRESPONSE, ctrl->ldctl_oid) != 0 ) { 601 /* Not sort result control */ 602 ld->ld_errno = LDAP_CONTROL_NOT_FOUND; 603 return(ld->ld_errno); 604 } 605 606 /* Create a BerElement from the berval returned in the control. */ 607 ber = ber_init(&ctrl->ldctl_value); 608 609 if (ber == NULL) { 610 ld->ld_errno = LDAP_NO_MEMORY; 611 return(ld->ld_errno); 612 } 613 614 /* Extract the result code from the control. */ 615 tag = ber_scanf(ber, "{e" /*}*/, returnCode); 616 617 if( tag == LBER_ERROR ) { 618 ber_free(ber, 1); 619 ld->ld_errno = LDAP_DECODING_ERROR; 620 return(ld->ld_errno); 621 } 622 623 /* If caller wants the attribute name, and if it's present in the control, 624 extract the attribute name which caused the error. */ 625 if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen))) 626 { 627 tag = ber_scanf(ber, "ta", &berTag, attribute); 628 629 if (tag == LBER_ERROR ) { 630 ber_free(ber, 1); 631 ld->ld_errno = LDAP_DECODING_ERROR; 632 return(ld->ld_errno); 633 } 634 } 635 636 ber_free(ber,1); 637 638 ld->ld_errno = LDAP_SUCCESS; 639 return(ld->ld_errno); 640} 641