1 /* 2 * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 * 5 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 6 */ 7 8 9 /* 10 * The contents of this file are subject to the Netscape Public 11 * License Version 1.1 (the "License"); you may not use this file 12 * except in compliance with the License. You may obtain a copy of 13 * the License at http://www.mozilla.org/NPL/ 14 * 15 * Software distributed under the License is distributed on an "AS 16 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 17 * implied. See the License for the specific language governing 18 * rights and limitations under the License. 19 * 20 * The Original Code is Mozilla Communicator client code, released 21 * March 31, 1998. 22 * 23 * The Initial Developer of the Original Code is Netscape 24 * Communications Corporation. Portions created by Netscape are 25 * Copyright (C) 1998-1999 Netscape Communications Corporation. All 26 * Rights Reserved. 27 * 28 * Contributor(s): 29 */ 30 /* 31 * Copyright (c) 1990 Regents of the University of Michigan. 32 * All rights reserved. 33 */ 34 /* 35 * search.c 36 */ 37 38 #if 0 39 #ifndef lint 40 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; 41 #endif 42 #endif 43 44 #include "ldap-int.h" 45 46 static int nsldapi_timeval2ldaplimit( struct timeval *timeoutp, 47 int defaultvalue ); 48 static int nsldapi_search( LDAP *ld, const char *base, int scope, 49 const char *filter, char **attrs, int attrsonly, 50 LDAPControl **serverctrls, LDAPControl **clientctrls, 51 int timelimit, int sizelimit, int *msgidp ); 52 static char *find_right_paren( char *s ); 53 static char *put_complex_filter( BerElement *ber, char *str, 54 ber_tag_t tag, int not ); 55 static int unescape_filterval( char *str ); 56 static int hexchar2int( char c ); 57 static int is_valid_attr( char *a ); 58 static int put_simple_filter( BerElement *ber, char *str ); 59 static int put_substring_filter( BerElement *ber, char *type, 60 char *str ); 61 static int put_filter_list( BerElement *ber, char *str ); 62 static int nsldapi_search_s( LDAP *ld, const char *base, int scope, 63 const char *filter, char **attrs, int attrsonly, 64 LDAPControl **serverctrls, LDAPControl **clientctrls, 65 struct timeval *localtimeoutp, int timelimit, int sizelimit, 66 LDAPMessage **res ); 67 68 /* 69 * ldap_search - initiate an ldap search operation. Parameters: 70 * 71 * ld LDAP descriptor 72 * base DN of the base object 73 * scope the search scope - one of LDAP_SCOPE_BASE, 74 * LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE 75 * filter a string containing the search filter 76 * (e.g., "(|(cn=bob)(sn=bob))") 77 * attrs list of attribute types to return for matches 78 * attrsonly 1 => attributes only 0 => attributes and values 79 * 80 * Example: 81 * char *attrs[] = { "mail", "title", 0 }; 82 * msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob", 83 * attrs, attrsonly ); 84 */ 85 int 86 LDAP_CALL 87 ldap_search( 88 LDAP *ld, 89 const char *base, 90 int scope, 91 const char *filter, 92 char **attrs, 93 int attrsonly 94 ) 95 { 96 int msgid; 97 98 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 ); 99 100 if ( ldap_search_ext( ld, base, scope, filter, attrs, attrsonly, NULL, 101 NULL, NULL, -1, &msgid ) == LDAP_SUCCESS ) { 102 return( msgid ); 103 } else { 104 return( -1 ); /* error is in ld handle */ 105 } 106 } 107 108 109 /* 110 * LDAPv3 extended search. 111 * Returns an LDAP error code. 112 */ 113 int 114 LDAP_CALL 115 ldap_search_ext( 116 LDAP *ld, 117 const char *base, 118 int scope, 119 const char *filter, 120 char **attrs, 121 int attrsonly, 122 LDAPControl **serverctrls, 123 LDAPControl **clientctrls, 124 struct timeval *timeoutp, /* NULL means use ld->ld_timelimit */ 125 int sizelimit, 126 int *msgidp 127 ) 128 { 129 /* 130 * It is an error to pass in a zero'd timeval. 131 */ 132 if ( timeoutp != NULL && timeoutp->tv_sec == 0 && 133 timeoutp->tv_usec == 0 ) { 134 if ( ld != NULL ) { 135 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); 136 } 137 return( LDAP_PARAM_ERROR ); 138 } 139 140 return( nsldapi_search( ld, base, scope, filter, attrs, attrsonly, 141 serverctrls, clientctrls, 142 nsldapi_timeval2ldaplimit( timeoutp, -1 ), sizelimit, msgidp )); 143 } 144 145 146 /* 147 * Like ldap_search_ext() except an integer timelimit is passed instead of 148 * using the overloaded struct timeval *timeoutp. 149 */ 150 static int 151 nsldapi_search( 152 LDAP *ld, 153 const char *base, 154 int scope, 155 const char *filter, 156 char **attrs, 157 int attrsonly, 158 LDAPControl **serverctrls, 159 LDAPControl **clientctrls, 160 int timelimit, /* -1 means use ld->ld_timelimit */ 161 int sizelimit, /* -1 means use ld->ld_sizelimit */ 162 int *msgidp 163 ) 164 { 165 BerElement *ber; 166 int rc, rc_key; 167 unsigned long key; /* XXXmcs: memcache */ 168 169 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 ); 170 171 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { 172 return( LDAP_PARAM_ERROR ); 173 } 174 175 if ( base == NULL ) { 176 base = ""; 177 } 178 179 if ( filter == NULL ) { 180 filter = "(objectclass=*)"; 181 } 182 183 if ( msgidp == NULL || ( scope != LDAP_SCOPE_BASE 184 && scope != LDAP_SCOPE_ONELEVEL && scope != LDAP_SCOPE_SUBTREE ) 185 || ( sizelimit < -1 )) { 186 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); 187 return( LDAP_PARAM_ERROR ); 188 } 189 LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); 190 *msgidp = ++ld->ld_msgid; 191 LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); 192 193 /* 194 * XXXmcs: should use cache function pointers to hook in memcache 195 */ 196 if ( ld->ld_memcache == NULL ) { 197 rc_key = LDAP_NOT_SUPPORTED; 198 } else if (( rc_key = ldap_memcache_createkey( ld, base, scope, filter, 199 attrs, attrsonly, serverctrls, clientctrls, &key)) == LDAP_SUCCESS 200 && ldap_memcache_result( ld, *msgidp, key ) == LDAP_SUCCESS ) { 201 return LDAP_SUCCESS; 202 } 203 204 /* check the cache */ 205 if ( ld->ld_cache_on && ld->ld_cache_search != NULL ) { 206 LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK ); 207 if ( (rc = (ld->ld_cache_search)( ld, *msgidp, LDAP_REQ_SEARCH, 208 base, scope, filter, attrs, attrsonly )) != 0 ) { 209 *msgidp = rc; 210 LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); 211 return( LDAP_SUCCESS ); 212 } 213 LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK ); 214 } 215 216 /* caching off or did not find it in the cache - check the net */ 217 if (( rc = nsldapi_build_search_req( ld, base, scope, filter, attrs, 218 attrsonly, serverctrls, clientctrls, timelimit, sizelimit, 219 *msgidp, &ber )) != LDAP_SUCCESS ) { 220 return( rc ); 221 } 222 223 /* send the message */ 224 rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_SEARCH, 225 (char *) base, ber ); 226 227 /* 228 * XXXmcs: should use cache function pointers to hook in memcache 229 */ 230 if ( (rc_key == LDAP_SUCCESS) && (rc >= 0) ) { 231 ldap_memcache_new( ld, rc, key, base ); 232 } 233 234 *msgidp = rc; 235 return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS ); 236 } 237 238 239 /* 240 * Convert a non-NULL timeoutp to a value in seconds that is appropriate to 241 * send in an LDAP search request. If timeoutp is NULL, return defaultvalue. 242 */ 243 static int 244 nsldapi_timeval2ldaplimit( struct timeval *timeoutp, int defaultvalue ) 245 { 246 int timelimit; 247 248 if ( NULL == timeoutp ) { 249 timelimit = defaultvalue; 250 } else if ( timeoutp->tv_sec > 0 ) { 251 timelimit = timeoutp->tv_sec; 252 } else if ( timeoutp->tv_usec > 0 ) { 253 timelimit = 1; /* minimum we can express in LDAP */ 254 } else { 255 /* 256 * both tv_sec and tv_usec are less than one (zero?) so 257 * to maintain compatiblity with our "zero means no limit" 258 * convention we pass no limit to the server. 259 */ 260 timelimit = 0; /* no limit */ 261 } 262 263 return( timelimit ); 264 } 265 266 267 /* returns an LDAP error code and also sets it in ld */ 268 int 269 nsldapi_build_search_req( 270 LDAP *ld, 271 const char *base, 272 int scope, 273 const char *filter, 274 char **attrs, 275 int attrsonly, 276 LDAPControl **serverctrls, 277 LDAPControl **clientctrls, /* not used for anything yet */ 278 int timelimit, /* if -1, ld->ld_timelimit is used */ 279 int sizelimit, /* if -1, ld->ld_sizelimit is used */ 280 int msgid, 281 BerElement **berp 282 ) 283 { 284 BerElement *ber; 285 int err; 286 char *fdup; 287 288 /* 289 * Create the search request. It looks like this: 290 * SearchRequest := [APPLICATION 3] SEQUENCE { 291 * baseObject DistinguishedName, 292 * scope ENUMERATED { 293 * baseObject (0), 294 * singleLevel (1), 295 * wholeSubtree (2) 296 * }, 297 * derefAliases ENUMERATED { 298 * neverDerefaliases (0), 299 * derefInSearching (1), 300 * derefFindingBaseObj (2), 301 * alwaysDerefAliases (3) 302 * }, 303 * sizelimit INTEGER (0 .. 65535), 304 * timelimit INTEGER (0 .. 65535), 305 * attrsOnly BOOLEAN, 306 * filter Filter, 307 * attributes SEQUENCE OF AttributeType 308 * } 309 * wrapped in an ldap message. 310 */ 311 312 /* create a message to send */ 313 if (( err = nsldapi_alloc_ber_with_options( ld, &ber )) 314 != LDAP_SUCCESS ) { 315 return( err ); 316 } 317 318 if ( base == NULL ) { 319 base = ""; 320 } 321 322 if ( sizelimit == -1 ) { 323 sizelimit = ld->ld_sizelimit; 324 } 325 326 if ( timelimit == -1 ) { 327 timelimit = ld->ld_timelimit; 328 } 329 330 #ifdef CLDAP 331 if ( ld->ld_sbp->sb_naddr > 0 ) { 332 err = ber_printf( ber, "{ist{seeiib", msgid, 333 ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref, 334 sizelimit, timelimit, attrsonly ); 335 } else { 336 #endif /* CLDAP */ 337 err = ber_printf( ber, "{it{seeiib", msgid, 338 LDAP_REQ_SEARCH, base, scope, ld->ld_deref, 339 sizelimit, timelimit, attrsonly ); 340 #ifdef CLDAP 341 } 342 #endif /* CLDAP */ 343 344 if ( err == -1 ) { 345 LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL ); 346 ber_free( ber, 1 ); 347 return( LDAP_ENCODING_ERROR ); 348 } 349 350 fdup = nsldapi_strdup( filter ); 351 if (fdup == NULL) { 352 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL ); 353 ber_free( ber, 1 ); 354 return( LDAP_NO_MEMORY ); 355 } 356 err = ldap_put_filter( ber, fdup ); 357 NSLDAPI_FREE( fdup ); 358 359 if ( err == -1 ) { 360 LDAP_SET_LDERRNO( ld, LDAP_FILTER_ERROR, NULL, NULL ); 361 ber_free( ber, 1 ); 362 return( LDAP_FILTER_ERROR ); 363 } 364 365 if ( ber_printf( ber, "{v}}", attrs ) == -1 ) { 366 LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL ); 367 ber_free( ber, 1 ); 368 return( LDAP_ENCODING_ERROR ); 369 } 370 371 if ( (err = nsldapi_put_controls( ld, serverctrls, 1, ber )) 372 != LDAP_SUCCESS ) { 373 ber_free( ber, 1 ); 374 return( err ); 375 } 376 377 *berp = ber; 378 return( LDAP_SUCCESS ); 379 } 380 381 static char * 382 find_right_paren( char *s ) 383 { 384 int balance, escape; 385 386 balance = 1; 387 escape = 0; 388 while ( *s && balance ) { 389 if ( escape == 0 ) { 390 if ( *s == '(' ) 391 balance++; 392 else if ( *s == ')' ) 393 balance--; 394 } 395 if ( *s == '\\' && ! escape ) 396 escape = 1; 397 else 398 escape = 0; 399 if ( balance ) 400 s++; 401 } 402 403 return( *s ? s : NULL ); 404 } 405 406 static char * 407 put_complex_filter( 408 BerElement *ber, 409 char *str, 410 ber_tag_t tag, 411 int not 412 ) 413 { 414 char *next; 415 416 /* 417 * We have (x(filter)...) with str sitting on 418 * the x. We have to find the paren matching 419 * the one before the x and put the intervening 420 * filters by calling put_filter_list(). 421 */ 422 423 /* put explicit tag */ 424 if ( ber_printf( ber, "t{", tag ) == -1 ) 425 return( NULL ); 426 427 str++; 428 if ( (next = find_right_paren( str )) == NULL ) 429 return( NULL ); 430 431 *next = '\0'; 432 if ( put_filter_list( ber, str ) == -1 ) 433 return( NULL ); 434 *next++ = ')'; 435 436 /* flush explicit tagged thang */ 437 if ( ber_printf( ber, "}" ) == -1 ) 438 return( NULL ); 439 440 return( next ); 441 } 442 443 int 444 ldap_put_filter( BerElement *ber, char *str ) 445 { 446 char *next; 447 int parens, balance, escape; 448 449 /* 450 * A Filter looks like this: 451 * Filter ::= CHOICE { 452 * and [0] SET OF Filter, 453 * or [1] SET OF Filter, 454 * not [2] Filter, 455 * equalityMatch [3] AttributeValueAssertion, 456 * substrings [4] SubstringFilter, 457 * greaterOrEqual [5] AttributeValueAssertion, 458 * lessOrEqual [6] AttributeValueAssertion, 459 * present [7] AttributeType,, 460 * approxMatch [8] AttributeValueAssertion 461 * } 462 * 463 * SubstringFilter ::= SEQUENCE { 464 * type AttributeType, 465 * SEQUENCE OF CHOICE { 466 * initial [0] IA5String, 467 * any [1] IA5String, 468 * final [2] IA5String 469 * } 470 * } 471 * Note: tags in a choice are always explicit 472 */ 473 474 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 ); 475 476 parens = 0; 477 while ( *str ) { 478 switch ( *str ) { 479 case '(': 480 str++; 481 parens++; 482 switch ( *str ) { 483 case '&': 484 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: AND\n", 485 0, 0, 0 ); 486 487 if ( (str = put_complex_filter( ber, str, 488 LDAP_FILTER_AND, 0 )) == NULL ) 489 return( -1 ); 490 491 parens--; 492 break; 493 494 case '|': 495 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: OR\n", 496 0, 0, 0 ); 497 498 if ( (str = put_complex_filter( ber, str, 499 LDAP_FILTER_OR, 0 )) == NULL ) 500 return( -1 ); 501 502 parens--; 503 break; 504 505 case '!': 506 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: NOT\n", 507 0, 0, 0 ); 508 509 if ( (str = put_complex_filter( ber, str, 510 LDAP_FILTER_NOT, 1 )) == NULL ) 511 return( -1 ); 512 513 parens--; 514 break; 515 516 default: 517 LDAPDebug( LDAP_DEBUG_TRACE, 518 "put_filter: simple\n", 0, 0, 0 ); 519 520 balance = 1; 521 escape = 0; 522 next = str; 523 while ( *next && balance ) { 524 if ( escape == 0 ) { 525 if ( *next == '(' ) 526 balance++; 527 else if ( *next == ')' ) 528 balance--; 529 } 530 if ( *next == '\\' && ! escape ) 531 escape = 1; 532 else 533 escape = 0; 534 if ( balance ) 535 next++; 536 } 537 if ( balance != 0 ) 538 return( -1 ); 539 540 *next = '\0'; 541 if ( put_simple_filter( ber, str ) == -1 ) { 542 return( -1 ); 543 } 544 *next++ = ')'; 545 str = next; 546 parens--; 547 break; 548 } 549 break; 550 551 case ')': 552 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0, 553 0 ); 554 if ( ber_printf( ber, "]" ) == -1 ) 555 return( -1 ); 556 str++; 557 parens--; 558 break; 559 560 case ' ': 561 str++; 562 break; 563 564 default: /* assume it's a simple type=value filter */ 565 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0, 566 0 ); 567 next = strchr( str, '\0' ); 568 if ( put_simple_filter( ber, str ) == -1 ) { 569 return( -1 ); 570 } 571 str = next; 572 break; 573 } 574 } 575 576 return( parens ? -1 : 0 ); 577 } 578 579 580 /* 581 * Put a list of filters like this "(filter1)(filter2)..." 582 */ 583 584 static int 585 put_filter_list( BerElement *ber, char *str ) 586 { 587 char *next; 588 char save; 589 590 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 ); 591 592 while ( *str ) { 593 while ( *str && isspace( *str ) ) 594 str++; 595 if ( *str == '\0' ) 596 break; 597 598 if ( (next = find_right_paren( str + 1 )) == NULL ) 599 return( -1 ); 600 save = *++next; 601 602 /* now we have "(filter)" with str pointing to it */ 603 *next = '\0'; 604 if ( ldap_put_filter( ber, str ) == -1 ) 605 return( -1 ); 606 *next = save; 607 608 str = next; 609 } 610 611 return( 0 ); 612 } 613 614 615 /* 616 * is_valid_attr - returns 1 if a is a syntactically valid left-hand side 617 * of a filter expression, 0 otherwise. A valid string may contain only 618 * letters, numbers, hyphens, semi-colons, colons and periods. examples: 619 * cn 620 * cn;lang-fr 621 * 1.2.3.4;binary;dynamic 622 * mail;dynamic 623 * cn:dn:1.2.3.4 624 * 625 * For compatibility with older servers, we also allow underscores in 626 * attribute types, even through they are not allowed by the LDAPv3 RFCs. 627 */ 628 static int 629 is_valid_attr( char *a ) 630 { 631 for ( ; *a; a++ ) { 632 if ( !isascii( *a ) ) { 633 return( 0 ); 634 } else if ( !isalnum( *a ) ) { 635 switch ( *a ) { 636 case '-': 637 case '.': 638 case ';': 639 case ':': 640 case '_': 641 break; /* valid */ 642 default: 643 return( 0 ); 644 } 645 } 646 } 647 648 return( 1 ); 649 } 650 651 static char * 652 find_star( char *s ) 653 { 654 for ( ; *s; ++s ) { 655 switch ( *s ) { 656 case '*': return s; 657 case '\\': 658 ++s; 659 if ( hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0 ) ++s; 660 default: break; 661 } 662 } 663 return NULL; 664 } 665 666 static int 667 put_simple_filter( BerElement *ber, char *str ) 668 { 669 char *s, *s2, *s3, filterop; 670 char *value; 671 ber_uint_t ftype; 672 int rc, len; 673 char *oid; /* for v3 extended filter */ 674 int dnattr; /* for v3 extended filter */ 675 676 LDAPDebug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 ); 677 678 rc = -1; /* pessimistic */ 679 680 if (( str = nsldapi_strdup( str )) == NULL ) { 681 return( rc ); 682 } 683 684 if ( (s = strchr( str, '=' )) == NULL ) { 685 goto free_and_return; 686 } 687 value = s + 1; 688 *s-- = '\0'; 689 filterop = *s; 690 if ( filterop == '<' || filterop == '>' || filterop == '~' || 691 filterop == ':' ) { 692 *s = '\0'; 693 } 694 695 if ( ! is_valid_attr( str ) ) { 696 goto free_and_return; 697 } 698 699 switch ( filterop ) { 700 case '<': 701 ftype = LDAP_FILTER_LE; 702 break; 703 case '>': 704 ftype = LDAP_FILTER_GE; 705 break; 706 case '~': 707 ftype = LDAP_FILTER_APPROX; 708 break; 709 case ':': /* extended filter - v3 only */ 710 /* 711 * extended filter looks like this: 712 * 713 * [type][':dn'][':'oid]':='value 714 * 715 * where one of type or :oid is required. 716 * 717 */ 718 ftype = LDAP_FILTER_EXTENDED; 719 s2 = s3 = NULL; 720 if ( (s2 = strrchr( str, ':' )) == NULL ) { 721 goto free_and_return; 722 } 723 if ( strcasecmp( s2, ":dn" ) == 0 ) { 724 oid = NULL; 725 dnattr = 1; 726 *s2 = '\0'; 727 } else { 728 oid = s2 + 1; 729 dnattr = 0; 730 *s2 = '\0'; 731 if ( (s3 = strrchr( str, ':' )) != NULL ) { 732 if ( strcasecmp( s3, ":dn" ) == 0 ) { 733 dnattr = 1; 734 } else { 735 goto free_and_return; 736 } 737 *s3 = '\0'; 738 } 739 } 740 if ( (rc = ber_printf( ber, "t{", ftype )) == -1 ) { 741 goto free_and_return; 742 } 743 if ( oid != NULL ) { 744 if ( (rc = ber_printf( ber, "ts", LDAP_TAG_MRA_OID, 745 oid )) == -1 ) { 746 goto free_and_return; 747 } 748 } 749 if ( *str != '\0' ) { 750 if ( (rc = ber_printf( ber, "ts", 751 LDAP_TAG_MRA_TYPE, str )) == -1 ) { 752 goto free_and_return; 753 } 754 } 755 if (( len = unescape_filterval( value )) < 0 || 756 ( rc = ber_printf( ber, "totb}", LDAP_TAG_MRA_VALUE, 757 value, len, LDAP_TAG_MRA_DNATTRS, dnattr )) == -1 ) { 758 goto free_and_return; 759 } 760 rc = 0; 761 goto free_and_return; 762 /* break; */ 763 default: 764 if ( find_star( value ) == NULL ) { 765 ftype = LDAP_FILTER_EQUALITY; 766 } else if ( strcmp( value, "*" ) == 0 ) { 767 ftype = LDAP_FILTER_PRESENT; 768 } else { 769 rc = put_substring_filter( ber, str, value ); 770 goto free_and_return; 771 } 772 break; 773 } 774 775 if ( ftype == LDAP_FILTER_PRESENT ) { 776 rc = ber_printf( ber, "ts", ftype, str ); 777 } else if (( len = unescape_filterval( value )) >= 0 ) { 778 rc = ber_printf( ber, "t{so}", ftype, str, value, len ); 779 } 780 if ( rc != -1 ) { 781 rc = 0; 782 } 783 784 free_and_return: 785 NSLDAPI_FREE( str ); 786 return( rc ); 787 } 788 789 790 /* 791 * Undo in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape 792 * sequences within the null-terminated string 'val'. The resulting value 793 * may contain null characters. 794 * 795 * If 'val' contains invalid escape sequences we return -1. 796 * Otherwise the length of the unescaped value is returned. 797 */ 798 static int 799 unescape_filterval( char *val ) 800 { 801 int escape, firstdigit, ival; 802 char *s, *d; 803 804 escape = 0; 805 for ( s = d = val; *s; s++ ) { 806 if ( escape ) { 807 /* 808 * need to leave escaped comma as-is, i.e. 809 * val="CN=Last\, First,OU=..." 810 */ 811 if (*s == ',') { 812 *d++ = '\\'; 813 *d++ = *s; 814 escape = 0; 815 continue; 816 } 817 /* 818 * first try LDAPv3 escape (hexadecimal) sequence 819 */ 820 if (( ival = hexchar2int( *s )) < 0 ) { 821 if ( firstdigit ) { 822 /* 823 * LDAPv2 (RFC1960) escape sequence 824 */ 825 *d++ = *s; 826 escape = 0; 827 } else { 828 return(-1); 829 } 830 } 831 if ( firstdigit ) { 832 *d = ( ival<<4 ); 833 firstdigit = 0; 834 } else { 835 *d++ |= ival; 836 escape = 0; 837 } 838 839 } else if ( *s != '\\' ) { 840 *d++ = *s; 841 escape = 0; 842 843 } else { 844 escape = 1; 845 firstdigit = 1; 846 } 847 } 848 849 return( d - val ); 850 } 851 852 853 /* 854 * convert character 'c' that represents a hexadecimal digit to an integer. 855 * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned. 856 * otherwise the converted value is returned. 857 */ 858 static int 859 hexchar2int( char c ) 860 { 861 if ( c >= '0' && c <= '9' ) { 862 return( c - '0' ); 863 } 864 if ( c >= 'A' && c <= 'F' ) { 865 return( c - 'A' + 10 ); 866 } 867 if ( c >= 'a' && c <= 'f' ) { 868 return( c - 'a' + 10 ); 869 } 870 return( -1 ); 871 } 872 873 static int 874 put_substring_filter( BerElement *ber, char *type, char *val ) 875 { 876 char *nextstar, gotstar = 0; 877 ber_uint_t ftype; 878 int len; 879 880 LDAPDebug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type, 881 val, 0 ); 882 883 if ( ber_printf( ber, "t{s{", LDAP_FILTER_SUBSTRINGS, type ) == -1 ) { 884 return( -1 ); 885 } 886 887 for ( ; val != NULL; val = nextstar ) { 888 if ( (nextstar = find_star( val )) != NULL ) { 889 *nextstar++ = '\0'; 890 } 891 892 if ( gotstar == 0 ) { 893 ftype = LDAP_SUBSTRING_INITIAL; 894 } else if ( nextstar == NULL ) { 895 ftype = LDAP_SUBSTRING_FINAL; 896 } else { 897 ftype = LDAP_SUBSTRING_ANY; 898 } 899 if ( *val != '\0' ) { 900 if (( len = unescape_filterval( val )) < 0 || 901 ber_printf( ber, "to", ftype, val, len ) == -1 ) { 902 return( -1 ); 903 } 904 } 905 906 gotstar = 1; 907 } 908 909 if ( ber_printf( ber, "}}" ) == -1 ) { 910 return( -1 ); 911 } 912 913 return( 0 ); 914 } 915 916 int 917 LDAP_CALL 918 ldap_search_st( 919 LDAP *ld, 920 const char *base, 921 int scope, 922 const char *filter, 923 char **attrs, 924 int attrsonly, 925 struct timeval *timeout, 926 LDAPMessage **res 927 ) 928 { 929 return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly, 930 NULL, NULL, timeout, -1, -1, res )); 931 } 932 933 int 934 LDAP_CALL 935 ldap_search_s( 936 LDAP *ld, 937 const char *base, 938 int scope, 939 const char *filter, 940 char **attrs, 941 int attrsonly, 942 LDAPMessage **res 943 ) 944 { 945 return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly, 946 NULL, NULL, NULL, -1, -1, res )); 947 } 948 949 int LDAP_CALL 950 ldap_search_ext_s( 951 LDAP *ld, 952 const char *base, 953 int scope, 954 const char *filter, 955 char **attrs, 956 int attrsonly, 957 LDAPControl **serverctrls, 958 LDAPControl **clientctrls, 959 struct timeval *timeoutp, 960 int sizelimit, 961 LDAPMessage **res 962 ) 963 { 964 return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly, 965 serverctrls, clientctrls, timeoutp, 966 nsldapi_timeval2ldaplimit( timeoutp, -1 ), sizelimit, res )); 967 } 968 969 970 static int 971 nsldapi_search_s( 972 LDAP *ld, 973 const char *base, 974 int scope, 975 const char *filter, 976 char **attrs, 977 int attrsonly, 978 LDAPControl **serverctrls, 979 LDAPControl **clientctrls, 980 struct timeval *localtimeoutp, 981 int timelimit, /* -1 means use ld->ld_timelimit */ 982 int sizelimit, /* -1 means use ld->ld_sizelimit */ 983 LDAPMessage **res 984 ) 985 { 986 int err, msgid; 987 988 /* 989 * It is an error to pass in a zero'd timeval. 990 */ 991 if ( localtimeoutp != NULL && localtimeoutp->tv_sec == 0 && 992 localtimeoutp->tv_usec == 0 ) { 993 if ( ld != NULL ) { 994 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL ); 995 } 996 if ( res != NULL ) { 997 *res = NULL; 998 } 999 return( LDAP_PARAM_ERROR ); 1000 } 1001 1002 if (( err = nsldapi_search( ld, base, scope, filter, attrs, attrsonly, 1003 serverctrls, clientctrls, timelimit, sizelimit, &msgid )) 1004 != LDAP_SUCCESS ) { 1005 if ( res != NULL ) { 1006 *res = NULL; 1007 } 1008 return( err ); 1009 } 1010 1011 if ( ldap_result( ld, msgid, 1, localtimeoutp, res ) == -1 ) { 1012 /* 1013 * Error. ldap_result() sets *res to NULL for us. 1014 */ 1015 return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); 1016 } 1017 1018 if ( LDAP_GET_LDERRNO( ld, NULL, NULL ) == LDAP_TIMEOUT ) { 1019 (void) ldap_abandon( ld, msgid ); 1020 err = LDAP_TIMEOUT; 1021 LDAP_SET_LDERRNO( ld, err, NULL, NULL ); 1022 if ( res != NULL ) { 1023 *res = NULL; 1024 } 1025 return( err ); 1026 } 1027 1028 return( ldap_result2error( ld, *res, 0 ) ); 1029 } 1030