1/* $NetBSD: filter.c,v 1.1.1.3 2010/12/12 15:21:31 adam Exp $ */ 2 3/* search.c */ 4/* OpenLDAP: pkg/ldap/libraries/libldap/filter.c,v 1.29.2.8 2010/04/13 20:22:57 kurt Exp */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2010 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18/* Portions Copyright (c) 1990 Regents of the University of Michigan. 19 * All rights reserved. 20 */ 21 22#include "portable.h" 23 24#include <stdio.h> 25 26#include <ac/stdlib.h> 27 28#include <ac/socket.h> 29#include <ac/string.h> 30#include <ac/time.h> 31 32#include "ldap-int.h" 33 34static int put_simple_vrFilter LDAP_P(( 35 BerElement *ber, 36 char *str )); 37 38static int put_vrFilter_list LDAP_P(( 39 BerElement *ber, 40 char *str )); 41 42static char *put_complex_filter LDAP_P(( 43 BerElement *ber, 44 char *str, 45 ber_tag_t tag, 46 int not )); 47 48static int put_simple_filter LDAP_P(( 49 BerElement *ber, 50 char *str )); 51 52static int put_substring_filter LDAP_P(( 53 BerElement *ber, 54 char *type, 55 char *str, 56 char *nextstar )); 57 58static int put_filter_list LDAP_P(( 59 BerElement *ber, 60 char *str, 61 ber_tag_t tag )); 62 63static int ldap_is_oid ( const char *str ) 64{ 65 int i; 66 67 if( LDAP_ALPHA( str[0] )) { 68 for( i=1; str[i]; i++ ) { 69 if( !LDAP_LDH( str[i] )) { 70 return 0; 71 } 72 } 73 return 1; 74 75 } else if LDAP_DIGIT( str[0] ) { 76 int dot=0; 77 for( i=1; str[i]; i++ ) { 78 if( LDAP_DIGIT( str[i] )) { 79 dot=0; 80 81 } else if ( str[i] == '.' ) { 82 if( dot ) return 0; 83 if( ++dot > 1 ) return 0; 84 85 } else { 86 return 0; 87 } 88 } 89 return !dot; 90 } 91 92 return 0; 93} 94 95static int ldap_is_desc ( const char *str ) 96{ 97 int i; 98 99 if( LDAP_ALPHA( str[0] )) { 100 for( i=1; str[i]; i++ ) { 101 if( str[i] == ';' ) { 102 str = &str[i+1]; 103 goto options; 104 } 105 106 if( !LDAP_LDH( str[i] )) { 107 return 0; 108 } 109 } 110 return 1; 111 112 } else if LDAP_DIGIT( str[0] ) { 113 int dot=0; 114 for( i=1; str[i]; i++ ) { 115 if( str[i] == ';' ) { 116 if( dot ) return 0; 117 str = &str[i+1]; 118 goto options; 119 } 120 121 if( LDAP_DIGIT( str[i] )) { 122 dot=0; 123 124 } else if ( str[i] == '.' ) { 125 if( dot ) return 0; 126 if( ++dot > 1 ) return 0; 127 128 } else { 129 return 0; 130 } 131 } 132 return !dot; 133 } 134 135 return 0; 136 137options: 138 if( !LDAP_LDH( str[0] )) { 139 return 0; 140 } 141 for( i=1; str[i]; i++ ) { 142 if( str[i] == ';' ) { 143 str = &str[i+1]; 144 goto options; 145 } 146 if( !LDAP_LDH( str[i] )) { 147 return 0; 148 } 149 } 150 return 1; 151} 152 153static char * 154find_right_paren( char *s ) 155{ 156 int balance, escape; 157 158 balance = 1; 159 escape = 0; 160 while ( *s && balance ) { 161 if ( !escape ) { 162 if ( *s == '(' ) { 163 balance++; 164 } else if ( *s == ')' ) { 165 balance--; 166 } 167 } 168 169 escape = ( *s == '\\' && !escape ); 170 171 if ( balance ) s++; 172 } 173 174 return *s ? s : NULL; 175} 176 177static int hex2value( int c ) 178{ 179 if( c >= '0' && c <= '9' ) { 180 return c - '0'; 181 } 182 183 if( c >= 'A' && c <= 'F' ) { 184 return c + (10 - (int) 'A'); 185 } 186 187 if( c >= 'a' && c <= 'f' ) { 188 return c + (10 - (int) 'a'); 189 } 190 191 return -1; 192} 193 194char * 195ldap_pvt_find_wildcard( const char *s ) 196{ 197 for( ; *s; s++ ) { 198 switch( *s ) { 199 case '*': /* found wildcard */ 200 return (char *) s; 201 202 case '(': 203 case ')': 204 return NULL; 205 206 case '\\': 207 if( s[1] == '\0' ) return NULL; 208 209 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) { 210 s+=2; 211 212 } else switch( s[1] ) { 213 default: 214 return NULL; 215 216 /* allow RFC 1960 escapes */ 217 case '*': 218 case '(': 219 case ')': 220 case '\\': 221 s++; 222 } 223 } 224 } 225 226 return (char *) s; 227} 228 229/* unescape filter value */ 230/* support both LDAP v2 and v3 escapes */ 231/* output can include nul characters! */ 232ber_slen_t 233ldap_pvt_filter_value_unescape( char *fval ) 234{ 235 ber_slen_t r, v; 236 int v1, v2; 237 238 for( r=v=0; fval[v] != '\0'; v++ ) { 239 switch( fval[v] ) { 240 case '(': 241 case ')': 242 case '*': 243 return -1; 244 245 case '\\': 246 /* escape */ 247 v++; 248 249 if ( fval[v] == '\0' ) { 250 /* escape at end of string */ 251 return -1; 252 } 253 254 if (( v1 = hex2value( fval[v] )) >= 0 ) { 255 /* LDAPv3 escape */ 256 if (( v2 = hex2value( fval[v+1] )) < 0 ) { 257 /* must be two digit code */ 258 return -1; 259 } 260 261 fval[r++] = v1 * 16 + v2; 262 v++; 263 264 } else { 265 /* LDAPv2 escape */ 266 switch( fval[v] ) { 267 case '(': 268 case ')': 269 case '*': 270 case '\\': 271 fval[r++] = fval[v]; 272 break; 273 default: 274 /* illegal escape */ 275 return -1; 276 } 277 } 278 break; 279 280 default: 281 fval[r++] = fval[v]; 282 } 283 } 284 285 fval[r] = '\0'; 286 return r; 287} 288 289static char * 290put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not ) 291{ 292 char *next; 293 294 /* 295 * We have (x(filter)...) with str sitting on 296 * the x. We have to find the paren matching 297 * the one before the x and put the intervening 298 * filters by calling put_filter_list(). 299 */ 300 301 /* put explicit tag */ 302 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) { 303 return NULL; 304 } 305 306 str++; 307 if ( (next = find_right_paren( str )) == NULL ) { 308 return NULL; 309 } 310 311 *next = '\0'; 312 if ( put_filter_list( ber, str, tag ) == -1 ) { 313 return NULL; 314 } 315 316 /* close the '(' */ 317 *next++ = ')'; 318 319 /* flush explicit tagged thang */ 320 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) { 321 return NULL; 322 } 323 324 return next; 325} 326 327int 328ldap_pvt_put_filter( BerElement *ber, const char *str_in ) 329{ 330 int rc; 331 char *freeme; 332 char *str; 333 char *next; 334 int parens, balance, escape; 335 336 /* 337 * A Filter looks like this (RFC 4511 as extended by RFC 4526): 338 * Filter ::= CHOICE { 339 * and [0] SET SIZE (0..MAX) OF filter Filter, 340 * or [1] SET SIZE (0..MAX) OF filter Filter, 341 * not [2] Filter, 342 * equalityMatch [3] AttributeValueAssertion, 343 * substrings [4] SubstringFilter, 344 * greaterOrEqual [5] AttributeValueAssertion, 345 * lessOrEqual [6] AttributeValueAssertion, 346 * present [7] AttributeDescription, 347 * approxMatch [8] AttributeValueAssertion, 348 * extensibleMatch [9] MatchingRuleAssertion, 349 * ... } 350 * 351 * SubstringFilter ::= SEQUENCE { 352 * type AttributeDescription, 353 * substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE { 354 * initial [0] AssertionValue, -- only once 355 * any [1] AssertionValue, 356 * final [2] AssertionValue -- only once 357 * } 358 * } 359 * 360 * MatchingRuleAssertion ::= SEQUENCE { 361 * matchingRule [1] MatchingRuleId OPTIONAL, 362 * type [2] AttributeDescription OPTIONAL, 363 * matchValue [3] AssertionValue, 364 * dnAttributes [4] BOOLEAN DEFAULT FALSE } 365 * 366 * Note: tags in a CHOICE are always explicit 367 */ 368 369 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 ); 370 371 freeme = LDAP_STRDUP( str_in ); 372 if( freeme == NULL ) return LDAP_NO_MEMORY; 373 str = freeme; 374 375 parens = 0; 376 while ( *str ) { 377 switch ( *str ) { 378 case '(': /*')'*/ 379 str++; 380 parens++; 381 382 /* skip spaces */ 383 while( LDAP_SPACE( *str ) ) str++; 384 385 switch ( *str ) { 386 case '&': 387 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n", 388 0, 0, 0 ); 389 390 str = put_complex_filter( ber, str, 391 LDAP_FILTER_AND, 0 ); 392 if( str == NULL ) { 393 rc = -1; 394 goto done; 395 } 396 397 parens--; 398 break; 399 400 case '|': 401 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n", 402 0, 0, 0 ); 403 404 str = put_complex_filter( ber, str, 405 LDAP_FILTER_OR, 0 ); 406 if( str == NULL ) { 407 rc = -1; 408 goto done; 409 } 410 411 parens--; 412 break; 413 414 case '!': 415 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n", 416 0, 0, 0 ); 417 418 str = put_complex_filter( ber, str, 419 LDAP_FILTER_NOT, 0 ); 420 if( str == NULL ) { 421 rc = -1; 422 goto done; 423 } 424 425 parens--; 426 break; 427 428 case '(': 429 rc = -1; 430 goto done; 431 432 default: 433 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n", 434 0, 0, 0 ); 435 436 balance = 1; 437 escape = 0; 438 next = str; 439 440 while ( *next && balance ) { 441 if ( escape == 0 ) { 442 if ( *next == '(' ) { 443 balance++; 444 } else if ( *next == ')' ) { 445 balance--; 446 } 447 } 448 449 if ( *next == '\\' && ! escape ) { 450 escape = 1; 451 } else { 452 escape = 0; 453 } 454 455 if ( balance ) next++; 456 } 457 458 if ( balance != 0 ) { 459 rc = -1; 460 goto done; 461 } 462 463 *next = '\0'; 464 465 if ( put_simple_filter( ber, str ) == -1 ) { 466 rc = -1; 467 goto done; 468 } 469 470 *next++ = /*'('*/ ')'; 471 472 str = next; 473 parens--; 474 break; 475 } 476 break; 477 478 case /*'('*/ ')': 479 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 480 0, 0, 0 ); 481 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) { 482 rc = -1; 483 goto done; 484 } 485 str++; 486 parens--; 487 break; 488 489 case ' ': 490 str++; 491 break; 492 493 default: /* assume it's a simple type=value filter */ 494 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 495 0, 0, 0 ); 496 next = strchr( str, '\0' ); 497 if ( put_simple_filter( ber, str ) == -1 ) { 498 rc = -1; 499 goto done; 500 } 501 str = next; 502 break; 503 } 504 if ( !parens ) 505 break; 506 } 507 508 rc = ( parens || *str ) ? -1 : 0; 509 510done: 511 LDAP_FREE( freeme ); 512 return rc; 513} 514 515/* 516 * Put a list of filters like this "(filter1)(filter2)..." 517 */ 518 519static int 520put_filter_list( BerElement *ber, char *str, ber_tag_t tag ) 521{ 522 char *next = NULL; 523 char save; 524 525 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", 526 str, 0, 0 ); 527 528 while ( *str ) { 529 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) { 530 str++; 531 } 532 if ( *str == '\0' ) break; 533 534 if ( (next = find_right_paren( str + 1 )) == NULL ) { 535 return -1; 536 } 537 save = *++next; 538 539 /* now we have "(filter)" with str pointing to it */ 540 *next = '\0'; 541 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1; 542 *next = save; 543 str = next; 544 545 if( tag == LDAP_FILTER_NOT ) break; 546 } 547 548 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) { 549 return -1; 550 } 551 552 return 0; 553} 554 555static int 556put_simple_filter( 557 BerElement *ber, 558 char *str ) 559{ 560 char *s; 561 char *value; 562 ber_tag_t ftype; 563 int rc = -1; 564 565 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n", 566 str, 0, 0 ); 567 568 str = LDAP_STRDUP( str ); 569 if( str == NULL ) return -1; 570 571 if ( (s = strchr( str, '=' )) == NULL ) { 572 goto done; 573 } 574 575 value = s + 1; 576 *s-- = '\0'; 577 578 switch ( *s ) { 579 case '<': 580 ftype = LDAP_FILTER_LE; 581 *s = '\0'; 582 break; 583 584 case '>': 585 ftype = LDAP_FILTER_GE; 586 *s = '\0'; 587 break; 588 589 case '~': 590 ftype = LDAP_FILTER_APPROX; 591 *s = '\0'; 592 break; 593 594 case ':': 595 /* RFC 4515 extensible filters are off the form: 596 * type [:dn] [:rule] := value 597 * or [:dn]:rule := value 598 */ 599 ftype = LDAP_FILTER_EXT; 600 *s = '\0'; 601 602 { 603 char *dn = strchr( str, ':' ); 604 char *rule = NULL; 605 606 if( dn != NULL ) { 607 *dn++ = '\0'; 608 rule = strchr( dn, ':' ); 609 610 if( rule == NULL ) { 611 /* one colon */ 612 if ( strcasecmp(dn, "dn") == 0 ) { 613 /* must have attribute */ 614 if( !ldap_is_desc( str ) ) { 615 goto done; 616 } 617 618 rule = ""; 619 620 } else { 621 rule = dn; 622 dn = NULL; 623 } 624 625 } else { 626 /* two colons */ 627 *rule++ = '\0'; 628 629 if ( strcasecmp(dn, "dn") != 0 ) { 630 /* must have "dn" */ 631 goto done; 632 } 633 } 634 635 } 636 637 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) { 638 /* must have either type or rule */ 639 goto done; 640 } 641 642 if ( *str != '\0' && !ldap_is_desc( str ) ) { 643 goto done; 644 } 645 646 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) { 647 goto done; 648 } 649 650 rc = ber_printf( ber, "t{" /*"}"*/, ftype ); 651 652 if( rc != -1 && rule && *rule != '\0' ) { 653 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule ); 654 } 655 656 if( rc != -1 && *str != '\0' ) { 657 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str ); 658 } 659 660 if( rc != -1 ) { 661 ber_slen_t len = ldap_pvt_filter_value_unescape( value ); 662 663 if( len >= 0 ) { 664 rc = ber_printf( ber, "to", 665 LDAP_FILTER_EXT_VALUE, value, len ); 666 } else { 667 rc = -1; 668 } 669 } 670 671 if( rc != -1 && dn ) { 672 rc = ber_printf( ber, "tb", 673 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 ); 674 } 675 676 if( rc != -1 ) { 677 rc = ber_printf( ber, /*"{"*/ "N}" ); 678 } 679 } 680 goto done; 681 682 default: 683 if( !ldap_is_desc( str ) ) { 684 goto done; 685 686 } else { 687 char *nextstar = ldap_pvt_find_wildcard( value ); 688 689 if ( nextstar == NULL ) { 690 goto done; 691 692 } else if ( *nextstar == '\0' ) { 693 ftype = LDAP_FILTER_EQUALITY; 694 695 } else if ( strcmp( value, "*" ) == 0 ) { 696 ftype = LDAP_FILTER_PRESENT; 697 698 } else { 699 rc = put_substring_filter( ber, str, value, nextstar ); 700 goto done; 701 } 702 } break; 703 } 704 705 if( !ldap_is_desc( str ) ) goto done; 706 707 if ( ftype == LDAP_FILTER_PRESENT ) { 708 rc = ber_printf( ber, "ts", ftype, str ); 709 710 } else { 711 ber_slen_t len = ldap_pvt_filter_value_unescape( value ); 712 713 if( len >= 0 ) { 714 rc = ber_printf( ber, "t{soN}", 715 ftype, str, value, len ); 716 } 717 } 718 719done: 720 if( rc != -1 ) rc = 0; 721 LDAP_FREE( str ); 722 return rc; 723} 724 725static int 726put_substring_filter( BerElement *ber, char *type, char *val, char *nextstar ) 727{ 728 int gotstar = 0; 729 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS; 730 731 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", 732 type, val, 0 ); 733 734 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) { 735 return -1; 736 } 737 738 for( ; *val; val=nextstar ) { 739 if ( gotstar ) 740 nextstar = ldap_pvt_find_wildcard( val ); 741 742 if ( nextstar == NULL ) { 743 return -1; 744 } 745 746 if ( *nextstar == '\0' ) { 747 ftype = LDAP_SUBSTRING_FINAL; 748 } else { 749 *nextstar++ = '\0'; 750 if ( gotstar++ == 0 ) { 751 ftype = LDAP_SUBSTRING_INITIAL; 752 } else { 753 ftype = LDAP_SUBSTRING_ANY; 754 } 755 } 756 757 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) { 758 ber_slen_t len = ldap_pvt_filter_value_unescape( val ); 759 760 if ( len <= 0 ) { 761 return -1; 762 } 763 764 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) { 765 return -1; 766 } 767 } 768 } 769 770 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) { 771 return -1; 772 } 773 774 return 0; 775} 776 777static int 778put_vrFilter( BerElement *ber, const char *str_in ) 779{ 780 int rc; 781 char *freeme; 782 char *str; 783 char *next; 784 int parens, balance, escape; 785 786 /* 787 * A ValuesReturnFilter looks like this: 788 * 789 * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem 790 * SimpleFilterItem ::= CHOICE { 791 * equalityMatch [3] AttributeValueAssertion, 792 * substrings [4] SubstringFilter, 793 * greaterOrEqual [5] AttributeValueAssertion, 794 * lessOrEqual [6] AttributeValueAssertion, 795 * present [7] AttributeType, 796 * approxMatch [8] AttributeValueAssertion, 797 * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3 798 * } 799 * 800 * SubstringFilter ::= SEQUENCE { 801 * type AttributeType, 802 * SEQUENCE OF CHOICE { 803 * initial [0] IA5String, 804 * any [1] IA5String, 805 * final [2] IA5String 806 * } 807 * } 808 * 809 * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3 810 * matchingRule [1] MatchingRuleId OPTIONAL, 811 * type [2] AttributeDescription OPTIONAL, 812 * matchValue [3] AssertionValue } 813 * 814 * (Source: RFC 3876) 815 */ 816 817 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in, 0, 0 ); 818 819 freeme = LDAP_STRDUP( str_in ); 820 if( freeme == NULL ) return LDAP_NO_MEMORY; 821 str = freeme; 822 823 parens = 0; 824 while ( *str ) { 825 switch ( *str ) { 826 case '(': /*')'*/ 827 str++; 828 parens++; 829 830 /* skip spaces */ 831 while( LDAP_SPACE( *str ) ) str++; 832 833 switch ( *str ) { 834 case '(': 835 if ( (next = find_right_paren( str )) == NULL ) { 836 rc = -1; 837 goto done; 838 } 839 840 *next = '\0'; 841 842 if ( put_vrFilter_list( ber, str ) == -1 ) { 843 rc = -1; 844 goto done; 845 } 846 847 /* close the '(' */ 848 *next++ = ')'; 849 850 str = next; 851 852 parens--; 853 break; 854 855 856 default: 857 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n", 858 0, 0, 0 ); 859 860 balance = 1; 861 escape = 0; 862 next = str; 863 864 while ( *next && balance ) { 865 if ( escape == 0 ) { 866 if ( *next == '(' ) { 867 balance++; 868 } else if ( *next == ')' ) { 869 balance--; 870 } 871 } 872 873 if ( *next == '\\' && ! escape ) { 874 escape = 1; 875 } else { 876 escape = 0; 877 } 878 879 if ( balance ) next++; 880 } 881 882 if ( balance != 0 ) { 883 rc = -1; 884 goto done; 885 } 886 887 *next = '\0'; 888 889 if ( put_simple_vrFilter( ber, str ) == -1 ) { 890 rc = -1; 891 goto done; 892 } 893 894 *next++ = /*'('*/ ')'; 895 896 str = next; 897 parens--; 898 break; 899 } 900 break; 901 902 case /*'('*/ ')': 903 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: end\n", 904 0, 0, 0 ); 905 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) { 906 rc = -1; 907 goto done; 908 } 909 str++; 910 parens--; 911 break; 912 913 case ' ': 914 str++; 915 break; 916 917 default: /* assume it's a simple type=value filter */ 918 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: default\n", 919 0, 0, 0 ); 920 next = strchr( str, '\0' ); 921 if ( put_simple_vrFilter( ber, str ) == -1 ) { 922 rc = -1; 923 goto done; 924 } 925 str = next; 926 break; 927 } 928 } 929 930 rc = parens ? -1 : 0; 931 932done: 933 LDAP_FREE( freeme ); 934 return rc; 935} 936 937int 938ldap_put_vrFilter( BerElement *ber, const char *str_in ) 939{ 940 int rc =0; 941 942 if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) { 943 rc = -1; 944 } 945 946 rc = put_vrFilter( ber, str_in ); 947 948 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) { 949 rc = -1; 950 } 951 952 return rc; 953} 954 955static int 956put_vrFilter_list( BerElement *ber, char *str ) 957{ 958 char *next = NULL; 959 char save; 960 961 Debug( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n", 962 str, 0, 0 ); 963 964 while ( *str ) { 965 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) { 966 str++; 967 } 968 if ( *str == '\0' ) break; 969 970 if ( (next = find_right_paren( str + 1 )) == NULL ) { 971 return -1; 972 } 973 save = *++next; 974 975 /* now we have "(filter)" with str pointing to it */ 976 *next = '\0'; 977 if ( put_vrFilter( ber, str ) == -1 ) return -1; 978 *next = save; 979 str = next; 980 } 981 982 return 0; 983} 984 985static int 986put_simple_vrFilter( 987 BerElement *ber, 988 char *str ) 989{ 990 char *s; 991 char *value; 992 ber_tag_t ftype; 993 int rc = -1; 994 995 Debug( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n", 996 str, 0, 0 ); 997 998 str = LDAP_STRDUP( str ); 999 if( str == NULL ) return -1; 1000 1001 if ( (s = strchr( str, '=' )) == NULL ) { 1002 goto done; 1003 } 1004 1005 value = s + 1; 1006 *s-- = '\0'; 1007 1008 switch ( *s ) { 1009 case '<': 1010 ftype = LDAP_FILTER_LE; 1011 *s = '\0'; 1012 break; 1013 1014 case '>': 1015 ftype = LDAP_FILTER_GE; 1016 *s = '\0'; 1017 break; 1018 1019 case '~': 1020 ftype = LDAP_FILTER_APPROX; 1021 *s = '\0'; 1022 break; 1023 1024 case ':': 1025 /* According to ValuesReturnFilter control definition 1026 * extensible filters are off the form: 1027 * type [:rule] := value 1028 * or :rule := value 1029 */ 1030 ftype = LDAP_FILTER_EXT; 1031 *s = '\0'; 1032 1033 { 1034 char *rule = strchr( str, ':' ); 1035 1036 if( rule == NULL ) { 1037 /* must have attribute */ 1038 if( !ldap_is_desc( str ) ) { 1039 goto done; 1040 } 1041 rule = ""; 1042 } else { 1043 *rule++ = '\0'; 1044 } 1045 1046 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) { 1047 /* must have either type or rule */ 1048 goto done; 1049 } 1050 1051 if ( *str != '\0' && !ldap_is_desc( str ) ) { 1052 goto done; 1053 } 1054 1055 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) { 1056 goto done; 1057 } 1058 1059 rc = ber_printf( ber, "t{" /*"}"*/, ftype ); 1060 1061 if( rc != -1 && rule && *rule != '\0' ) { 1062 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule ); 1063 } 1064 1065 if( rc != -1 && *str != '\0' ) { 1066 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str ); 1067 } 1068 1069 if( rc != -1 ) { 1070 ber_slen_t len = ldap_pvt_filter_value_unescape( value ); 1071 1072 if( len >= 0 ) { 1073 rc = ber_printf( ber, "to", 1074 LDAP_FILTER_EXT_VALUE, value, len ); 1075 } else { 1076 rc = -1; 1077 } 1078 } 1079 1080 if( rc != -1 ) { 1081 rc = ber_printf( ber, /*"{"*/ "N}" ); 1082 } 1083 } 1084 goto done; 1085 1086 default: 1087 if( !ldap_is_desc( str ) ) { 1088 goto done; 1089 1090 } else { 1091 char *nextstar = ldap_pvt_find_wildcard( value ); 1092 1093 if ( nextstar == NULL ) { 1094 goto done; 1095 1096 } else if ( *nextstar == '\0' ) { 1097 ftype = LDAP_FILTER_EQUALITY; 1098 1099 } else if ( strcmp( value, "*" ) == 0 ) { 1100 ftype = LDAP_FILTER_PRESENT; 1101 1102 } else { 1103 rc = put_substring_filter( ber, str, value, nextstar ); 1104 goto done; 1105 } 1106 } break; 1107 } 1108 1109 if( !ldap_is_desc( str ) ) goto done; 1110 1111 if ( ftype == LDAP_FILTER_PRESENT ) { 1112 rc = ber_printf( ber, "ts", ftype, str ); 1113 1114 } else { 1115 ber_slen_t len = ldap_pvt_filter_value_unescape( value ); 1116 1117 if( len >= 0 ) { 1118 rc = ber_printf( ber, "t{soN}", 1119 ftype, str, value, len ); 1120 } 1121 } 1122 1123done: 1124 if( rc != -1 ) rc = 0; 1125 LDAP_FREE( str ); 1126 return rc; 1127} 1128 1129