1 /* $NetBSD: sortctrl.c,v 1.1.1.3 2010/12/12 15:21:37 adam Exp $ */ 2 3 /* OpenLDAP: pkg/ldap/libraries/libldap/sortctrl.c,v 1.19.2.7 2010/04/13 20:23:00 kurt Exp */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2010 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 "portable.h" 34 35 #include <stdio.h> 36 #include <ac/stdlib.h> 37 #include <ac/string.h> 38 #include <ac/time.h> 39 40 #include "ldap-int.h" 41 42 #define LDAP_MATCHRULE_IDENTIFIER 0x80L 43 #define LDAP_REVERSEORDER_IDENTIFIER 0x81L 44 #define LDAP_ATTRTYPES_IDENTIFIER 0x80L 45 46 47 48 /* --------------------------------------------------------------------------- 49 countKeys 50 51 Internal function to determine the number of keys in the string. 52 53 keyString (IN) String of items separated by whitespace. 54 ---------------------------------------------------------------------------*/ 55 56 static int countKeys(char *keyString) 57 { 58 char *p = keyString; 59 int count = 0; 60 61 for (;;) 62 { 63 while (LDAP_SPACE(*p)) /* Skip leading whitespace */ 64 p++; 65 66 if (*p == '\0') /* End of string? */ 67 return count; 68 69 count++; /* Found start of a key */ 70 71 while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */ 72 if (*p++ == '\0') 73 return count; 74 } 75 } 76 77 78 /* --------------------------------------------------------------------------- 79 readNextKey 80 81 Internal function to parse the next sort key in the string. 82 Allocate an LDAPSortKey structure and initialize it with 83 attribute name, reverse flag, and matching rule OID. 84 85 Each sort key in the string has the format: 86 [whitespace][-]attribute[:[OID]] 87 88 pNextKey (IN/OUT) Points to the next key in the sortkey string to parse. 89 The pointer is updated to point to the next character 90 after the sortkey being parsed. 91 92 key (OUT) Points to the address of an LDAPSortKey stucture 93 which has been allocated by this routine and 94 initialized with information from the next sortkey. 95 ---------------------------------------------------------------------------*/ 96 97 static int readNextKey( char **pNextKey, LDAPSortKey **key) 98 { 99 char *p = *pNextKey; 100 int rev = 0; 101 char *attrStart; 102 int attrLen; 103 char *oidStart = NULL; 104 int oidLen = 0; 105 106 /* Skip leading white space. */ 107 while (LDAP_SPACE(*p)) 108 p++; 109 110 if (*p == '-') /* Check if the reverse flag is present. */ 111 { 112 rev=1; 113 p++; 114 } 115 116 /* We're now positioned at the start of the attribute. */ 117 attrStart = p; 118 119 /* Get the length of the attribute until the next whitespace or ":". */ 120 attrLen = strcspn(p, " \t:"); 121 p += attrLen; 122 123 if (attrLen == 0) /* If no attribute name was present, quit. */ 124 return LDAP_PARAM_ERROR; 125 126 if (*p == ':') 127 { 128 oidStart = ++p; /* Start of the OID, after the colon */ 129 oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */ 130 p += oidLen; 131 } 132 133 *pNextKey = p; /* Update argument to point to next key */ 134 135 /* Allocate an LDAPSortKey structure */ 136 *key = LDAP_MALLOC(sizeof(LDAPSortKey)); 137 if (*key == NULL) return LDAP_NO_MEMORY; 138 139 /* Allocate memory for the attribute and copy to it. */ 140 (*key)->attributeType = LDAP_MALLOC(attrLen+1); 141 if ((*key)->attributeType == NULL) { 142 LDAP_FREE(*key); 143 return LDAP_NO_MEMORY; 144 } 145 146 strncpy((*key)->attributeType, attrStart, attrLen); 147 (*key)->attributeType[attrLen] = 0; 148 149 /* If present, allocate memory for the OID and copy to it. */ 150 if (oidLen) { 151 (*key)->orderingRule = LDAP_MALLOC(oidLen+1); 152 if ((*key)->orderingRule == NULL) { 153 LDAP_FREE((*key)->attributeType); 154 LDAP_FREE(*key); 155 return LDAP_NO_MEMORY; 156 } 157 strncpy((*key)->orderingRule, oidStart, oidLen); 158 (*key)->orderingRule[oidLen] = 0; 159 160 } else { 161 (*key)->orderingRule = NULL; 162 } 163 164 (*key)->reverseOrder = rev; 165 166 return LDAP_SUCCESS; 167 } 168 169 170 /* --------------------------------------------------------------------------- 171 ldap_create_sort_keylist 172 173 Create an array of pointers to LDAPSortKey structures, containing the 174 information specified by the string representation of one or more 175 sort keys. 176 177 sortKeyList (OUT) Points to a null-terminated array of pointers to 178 LDAPSortKey structures allocated by this routine. 179 This memory SHOULD be freed by the calling program 180 using ldap_free_sort_keylist(). 181 182 keyString (IN) Points to a string of one or more sort keys. 183 184 ---------------------------------------------------------------------------*/ 185 186 int 187 ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString ) 188 { 189 int numKeys, rc, i; 190 char *nextKey; 191 LDAPSortKey **keyList = NULL; 192 193 assert( sortKeyList != NULL ); 194 assert( keyString != NULL ); 195 196 *sortKeyList = NULL; 197 198 /* Determine the number of sort keys so we can allocate memory. */ 199 if (( numKeys = countKeys(keyString)) == 0) { 200 return LDAP_PARAM_ERROR; 201 } 202 203 /* Allocate the array of pointers. Initialize to NULL. */ 204 keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*)); 205 if ( keyList == NULL) return LDAP_NO_MEMORY; 206 207 /* For each sort key in the string, create an LDAPSortKey structure 208 and add it to the list. 209 */ 210 nextKey = keyString; /* Points to the next key in the string */ 211 for (i=0; i < numKeys; i++) { 212 rc = readNextKey(&nextKey, &keyList[i]); 213 214 if (rc != LDAP_SUCCESS) { 215 ldap_free_sort_keylist(keyList); 216 return rc; 217 } 218 } 219 220 *sortKeyList = keyList; 221 return LDAP_SUCCESS; 222 } 223 224 225 /* --------------------------------------------------------------------------- 226 ldap_free_sort_keylist 227 228 Frees the sort key structures created by ldap_create_sort_keylist(). 229 Frees the memory referenced by the LDAPSortKey structures, 230 the LDAPSortKey structures themselves, and the array of pointers 231 to the structures. 232 233 keyList (IN) Points to an array of pointers to LDAPSortKey structures. 234 ---------------------------------------------------------------------------*/ 235 236 void 237 ldap_free_sort_keylist ( LDAPSortKey **keyList ) 238 { 239 int i; 240 LDAPSortKey *nextKeyp; 241 242 if (keyList == NULL) return; 243 244 i=0; 245 while ( 0 != (nextKeyp = keyList[i++]) ) { 246 if (nextKeyp->attributeType) { 247 LBER_FREE(nextKeyp->attributeType); 248 } 249 250 if (nextKeyp->orderingRule != NULL) { 251 LBER_FREE(nextKeyp->orderingRule); 252 } 253 254 LBER_FREE(nextKeyp); 255 } 256 257 LBER_FREE(keyList); 258 } 259 260 261 /* --------------------------------------------------------------------------- 262 ldap_create_sort_control_value 263 264 Create and encode the value of the server-side sort control. 265 266 ld (IN) An LDAP session handle, as obtained from a call to 267 ldap_init(). 268 269 keyList (IN) Points to a null-terminated array of pointers to 270 LDAPSortKey structures, containing a description of 271 each of the sort keys to be used. The description 272 consists of an attribute name, ascending/descending flag, 273 and an optional matching rule (OID) to use. 274 275 value (OUT) Contains the control value; the bv_val member of the berval structure 276 SHOULD be freed by calling ldap_memfree() when done. 277 278 279 Ber encoding 280 281 SortKeyList ::= SEQUENCE OF SEQUENCE { 282 attributeType AttributeDescription, 283 orderingRule [0] MatchingRuleId OPTIONAL, 284 reverseOrder [1] BOOLEAN DEFAULT FALSE } 285 286 ---------------------------------------------------------------------------*/ 287 288 int 289 ldap_create_sort_control_value( 290 LDAP *ld, 291 LDAPSortKey **keyList, 292 struct berval *value ) 293 { 294 int i; 295 BerElement *ber = NULL; 296 ber_tag_t tag; 297 298 assert( ld != NULL ); 299 assert( LDAP_VALID( ld ) ); 300 301 if ( ld == NULL ) return LDAP_PARAM_ERROR; 302 if ( keyList == NULL || value == NULL ) { 303 ld->ld_errno = LDAP_PARAM_ERROR; 304 return LDAP_PARAM_ERROR; 305 } 306 307 value->bv_val = NULL; 308 value->bv_len = 0; 309 ld->ld_errno = LDAP_SUCCESS; 310 311 ber = ldap_alloc_ber_with_options( ld ); 312 if ( ber == NULL) { 313 ld->ld_errno = LDAP_NO_MEMORY; 314 return ld->ld_errno; 315 } 316 317 tag = ber_printf( ber, "{" /*}*/ ); 318 if ( tag == LBER_ERROR ) { 319 goto error_return; 320 } 321 322 for ( i = 0; keyList[i] != NULL; i++ ) { 323 tag = ber_printf( ber, "{s" /*}*/, keyList[i]->attributeType ); 324 if ( tag == LBER_ERROR ) { 325 goto error_return; 326 } 327 328 if ( keyList[i]->orderingRule != NULL ) { 329 tag = ber_printf( ber, "ts", 330 LDAP_MATCHRULE_IDENTIFIER, 331 keyList[i]->orderingRule ); 332 333 if ( tag == LBER_ERROR ) { 334 goto error_return; 335 } 336 } 337 338 if ( keyList[i]->reverseOrder ) { 339 tag = ber_printf( ber, "tb", 340 LDAP_REVERSEORDER_IDENTIFIER, 341 keyList[i]->reverseOrder ); 342 343 if ( tag == LBER_ERROR ) { 344 goto error_return; 345 } 346 } 347 348 tag = ber_printf( ber, /*{*/ "N}" ); 349 if ( tag == LBER_ERROR ) { 350 goto error_return; 351 } 352 } 353 354 tag = ber_printf( ber, /*{*/ "N}" ); 355 if ( tag == LBER_ERROR ) { 356 goto error_return; 357 } 358 359 if ( ber_flatten2( ber, value, 1 ) == -1 ) { 360 ld->ld_errno = LDAP_NO_MEMORY; 361 } 362 363 if ( 0 ) { 364 error_return:; 365 ld->ld_errno = LDAP_ENCODING_ERROR; 366 } 367 368 if ( ber != NULL ) { 369 ber_free( ber, 1 ); 370 } 371 372 return ld->ld_errno; 373 } 374 375 376 /* --------------------------------------------------------------------------- 377 ldap_create_sort_control 378 379 Create and encode the server-side sort control. 380 381 ld (IN) An LDAP session handle, as obtained from a call to 382 ldap_init(). 383 384 keyList (IN) Points to a null-terminated array of pointers to 385 LDAPSortKey structures, containing a description of 386 each of the sort keys to be used. The description 387 consists of an attribute name, ascending/descending flag, 388 and an optional matching rule (OID) to use. 389 390 isCritical (IN) 0 - Indicates the control is not critical to the operation. 391 non-zero - The control is critical to the operation. 392 393 ctrlp (OUT) Returns a pointer to the LDAPControl created. This control 394 SHOULD be freed by calling ldap_control_free() when done. 395 396 397 Ber encoding 398 399 SortKeyList ::= SEQUENCE OF SEQUENCE { 400 attributeType AttributeDescription, 401 orderingRule [0] MatchingRuleId OPTIONAL, 402 reverseOrder [1] BOOLEAN DEFAULT FALSE } 403 404 ---------------------------------------------------------------------------*/ 405 406 int 407 ldap_create_sort_control( 408 LDAP *ld, 409 LDAPSortKey **keyList, 410 int isCritical, 411 LDAPControl **ctrlp ) 412 { 413 struct berval value; 414 415 assert( ld != NULL ); 416 assert( LDAP_VALID( ld ) ); 417 418 if ( ld == NULL ) { 419 return LDAP_PARAM_ERROR; 420 } 421 422 if ( ctrlp == NULL ) { 423 ld->ld_errno = LDAP_PARAM_ERROR; 424 return ld->ld_errno; 425 } 426 427 ld->ld_errno = ldap_create_sort_control_value( ld, keyList, &value ); 428 if ( ld->ld_errno == LDAP_SUCCESS ) { 429 ld->ld_errno = ldap_control_create( LDAP_CONTROL_SORTREQUEST, 430 isCritical, &value, 0, ctrlp ); 431 if ( ld->ld_errno != LDAP_SUCCESS ) { 432 LDAP_FREE( value.bv_val ); 433 } 434 } 435 436 return ld->ld_errno; 437 } 438 439 440 /* --------------------------------------------------------------------------- 441 ldap_parse_sortedresult_control 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 ctrl (IN) The address of the LDAP Control Structure. 449 450 returnCode (OUT) This result parameter is filled in with the sort control 451 result code. This parameter MUST not be NULL. 452 453 attribute (OUT) If an error occured the server may return a string 454 indicating the first attribute in the sortkey list 455 that was in error. If a string is returned, the memory 456 should be freed with ldap_memfree. If this parameter is 457 NULL, no string is returned. 458 459 460 Ber encoding for sort control 461 462 SortResult ::= SEQUENCE { 463 sortResult ENUMERATED { 464 success (0), -- results are sorted 465 operationsError (1), -- server internal failure 466 timeLimitExceeded (3), -- timelimit reached before 467 -- sorting was completed 468 strongAuthRequired (8), -- refused to return sorted 469 -- results via insecure 470 -- protocol 471 adminLimitExceeded (11), -- too many matching entries 472 -- for the server to sort 473 noSuchAttribute (16), -- unrecognized attribute 474 -- type in sort key 475 inappropriateMatching (18), -- unrecognized or inappro- 476 -- priate matching rule in 477 -- sort key 478 insufficientAccessRights (50), -- refused to return sorted 479 -- results to this client 480 busy (51), -- too busy to process 481 unwillingToPerform (53), -- unable to sort 482 other (80) 483 }, 484 attributeType [0] AttributeDescription OPTIONAL } 485 ---------------------------------------------------------------------------*/ 486 487 int 488 ldap_parse_sortresponse_control( 489 LDAP *ld, 490 LDAPControl *ctrl, 491 ber_int_t *returnCode, 492 char **attribute ) 493 { 494 BerElement *ber; 495 ber_tag_t tag, berTag; 496 ber_len_t berLen; 497 498 assert( ld != NULL ); 499 assert( LDAP_VALID( ld ) ); 500 501 if (ld == NULL) { 502 return LDAP_PARAM_ERROR; 503 } 504 505 if (ctrl == NULL) { 506 ld->ld_errno = LDAP_PARAM_ERROR; 507 return(ld->ld_errno); 508 } 509 510 if (attribute) { 511 *attribute = NULL; 512 } 513 514 if ( strcmp(LDAP_CONTROL_SORTRESPONSE, ctrl->ldctl_oid) != 0 ) { 515 /* Not sort result control */ 516 ld->ld_errno = LDAP_CONTROL_NOT_FOUND; 517 return(ld->ld_errno); 518 } 519 520 /* Create a BerElement from the berval returned in the control. */ 521 ber = ber_init(&ctrl->ldctl_value); 522 523 if (ber == NULL) { 524 ld->ld_errno = LDAP_NO_MEMORY; 525 return(ld->ld_errno); 526 } 527 528 /* Extract the result code from the control. */ 529 tag = ber_scanf(ber, "{e" /*}*/, returnCode); 530 531 if( tag == LBER_ERROR ) { 532 ber_free(ber, 1); 533 ld->ld_errno = LDAP_DECODING_ERROR; 534 return(ld->ld_errno); 535 } 536 537 /* If caller wants the attribute name, and if it's present in the control, 538 extract the attribute name which caused the error. */ 539 if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen))) 540 { 541 tag = ber_scanf(ber, "ta", &berTag, attribute); 542 543 if (tag == LBER_ERROR ) { 544 ber_free(ber, 1); 545 ld->ld_errno = LDAP_DECODING_ERROR; 546 return(ld->ld_errno); 547 } 548 } 549 550 ber_free(ber,1); 551 552 ld->ld_errno = LDAP_SUCCESS; 553 return(ld->ld_errno); 554 } 555