3 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright (c) 1990 Regents of the University of Michigan.
17 #include <ac/stdlib.h>
19 #include <ac/socket.h>
20 #include <ac/string.h>
25 static int put_simple_vrFilter LDAP_P((
29 static int put_vrFilter_list LDAP_P((
33 static char *put_complex_filter LDAP_P((
39 static int put_simple_filter LDAP_P((
43 static int put_substring_filter LDAP_P((
48 static int put_filter_list LDAP_P((
53 static int ldap_is_oid ( const char *str )
57 if( LDAP_ALPHA( str[0] )) {
58 for( i=1; str[i]; i++ ) {
59 if( !LDAP_LDH( str[i] )) {
65 } else if LDAP_DIGIT( str[0] ) {
67 for( i=1; str[i]; i++ ) {
68 if( LDAP_DIGIT( str[i] )) {
71 } else if ( str[i] == '.' ) {
73 if( ++dot > 1 ) return 0;
85 static int ldap_is_desc ( const char *str )
89 if( LDAP_ALPHA( str[0] )) {
90 for( i=1; str[i]; i++ ) {
96 if( !LDAP_LDH( str[i] )) {
102 } else if LDAP_DIGIT( str[0] ) {
104 for( i=1; str[i]; i++ ) {
105 if( str[i] == ';' ) {
111 if( LDAP_DIGIT( str[i] )) {
114 } else if ( str[i] == '.' ) {
116 if( ++dot > 1 ) return 0;
128 if( !LDAP_LDH( str[0] )) {
131 for( i=1; str[i]; i++ ) {
132 if( str[i] == ';' ) {
136 if( !LDAP_LDH( str[i] )) {
144 find_right_paren( char *s )
150 while ( *s && balance ) {
154 } else if ( *s == ')' ) {
159 escape = ( *s == '\\' && !escape );
164 return *s ? s : NULL;
167 static int hex2value( int c )
169 if( c >= '0' && c <= '9' ) {
173 if( c >= 'A' && c <= 'F' ) {
174 return c + (10 - (int) 'A');
177 if( c >= 'a' && c <= 'f' ) {
178 return c + (10 - (int) 'a');
185 ldap_pvt_find_wildcard( const char *s )
189 case '*': /* found wildcard */
197 if( s[1] == '\0' ) return NULL;
199 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
202 } else switch( s[1] ) {
206 /* allow RFC 1960 escapes */
219 /* unescape filter value */
220 /* support both LDAP v2 and v3 escapes */
221 /* output can include nul characters! */
223 ldap_pvt_filter_value_unescape( char *fval )
228 for( r=v=0; fval[v] != '\0'; v++ ) {
239 if ( fval[v] == '\0' ) {
240 /* escape at end of string */
244 if (( v1 = hex2value( fval[v] )) >= 0 ) {
246 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
247 /* must be two digit code */
251 fval[r++] = v1 * 16 + v2;
280 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
285 * We have (x(filter)...) with str sitting on
286 * the x. We have to find the paren matching
287 * the one before the x and put the intervening
288 * filters by calling put_filter_list().
291 /* put explicit tag */
292 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
297 if ( (next = find_right_paren( str )) == NULL ) {
302 if ( put_filter_list( ber, str, tag ) == -1 ) {
309 /* flush explicit tagged thang */
310 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
318 ldap_pvt_put_filter( BerElement *ber, const char *str_in )
324 int parens, balance, escape;
327 * A Filter looks like this:
328 * Filter ::= CHOICE {
329 * and [0] SET OF Filter,
330 * or [1] SET OF Filter,
332 * equalityMatch [3] AttributeValueAssertion,
333 * substrings [4] SubstringFilter,
334 * greaterOrEqual [5] AttributeValueAssertion,
335 * lessOrEqual [6] AttributeValueAssertion,
336 * present [7] AttributeType,
337 * approxMatch [8] AttributeValueAssertion,
338 * extensibleMatch [9] MatchingRuleAssertion -- LDAPv3
341 * SubstringFilter ::= SEQUENCE {
342 * type AttributeType,
343 * SEQUENCE OF CHOICE {
344 * initial [0] IA5String,
346 * final [2] IA5String
350 * MatchingRuleAssertion ::= SEQUENCE { -- LDAPv3
351 * matchingRule [1] MatchingRuleId OPTIONAL,
352 * type [2] AttributeDescription OPTIONAL,
353 * matchValue [3] AssertionValue,
354 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
356 * Note: tags in a choice are always explicit
360 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS, "ldap_pvt_put_filter: \"%s\"\n",
363 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
366 freeme = LDAP_STRDUP( str_in );
367 if( freeme == NULL ) return LDAP_NO_MEMORY;
378 while( LDAP_SPACE( *str ) ) str++;
383 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
384 "ldap_pvt_put_filter: AND\n" ));
386 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
390 str = put_complex_filter( ber, str,
391 LDAP_FILTER_AND, 0 );
402 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
403 "ldap_pvt_put_filter: OR\n" ));
405 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
409 str = put_complex_filter( ber, str,
421 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
422 "ldap_pvt_put_filter: NOT\n" ));
424 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
428 str = put_complex_filter( ber, str,
429 LDAP_FILTER_NOT, 0 );
440 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
441 "ldap_pvt_put_filter: simple\n" ));
443 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
451 while ( *next && balance ) {
453 if ( *next == '(' ) {
455 } else if ( *next == ')' ) {
460 if ( *next == '\\' && ! escape ) {
466 if ( balance ) next++;
469 if ( balance != 0 ) {
476 if ( put_simple_filter( ber, str ) == -1 ) {
481 *next++ = /*'('*/ ')';
491 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
492 "ldap_pvt_put_filter: end\n" ));
494 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
497 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
509 default: /* assume it's a simple type=value filter */
511 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
512 "ldap_pvt_put_filter: default\n" ));
514 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
517 next = strchr( str, '\0' );
518 if ( put_simple_filter( ber, str ) == -1 ) {
527 rc = parens ? -1 : 0;
535 * Put a list of filters like this "(filter1)(filter2)..."
539 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
545 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS,
546 "put_filter_list \"%s\"\n", str ));
548 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
553 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
556 if ( *str == '\0' ) break;
558 if ( (next = find_right_paren( str + 1 )) == NULL ) {
563 /* now we have "(filter)" with str pointing to it */
565 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1;
569 if( tag == LDAP_FILTER_NOT ) break;
572 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
590 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS,
591 "put_simple_filter: \"%s\"\n", str ));
593 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
597 str = LDAP_STRDUP( str );
598 if( str == NULL ) return -1;
600 if ( (s = strchr( str, '=' )) == NULL ) {
609 ftype = LDAP_FILTER_LE;
614 ftype = LDAP_FILTER_GE;
619 ftype = LDAP_FILTER_APPROX;
624 /* RFC2254 extensible filters are off the form:
625 * type [:dn] [:rule] := value
626 * or [:dn]:rule := value
628 ftype = LDAP_FILTER_EXT;
632 char *dn = strchr( str, ':' );
637 rule = strchr( dn, ':' );
641 if ( strcmp(dn, "dn") == 0 ) {
642 /* must have attribute */
643 if( !ldap_is_desc( str ) ) {
658 if ( strcmp(dn, "dn") != 0 ) {
666 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
667 /* must have either type or rule */
671 if ( *str != '\0' && !ldap_is_desc( str ) ) {
675 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
679 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
681 if( rc != -1 && rule && *rule != '\0' ) {
682 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
685 if( rc != -1 && *str != '\0' ) {
686 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
690 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
693 rc = ber_printf( ber, "to",
694 LDAP_FILTER_EXT_VALUE, value, len );
700 if( rc != -1 && dn ) {
701 rc = ber_printf( ber, "tb",
702 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
706 rc = ber_printf( ber, /*"{"*/ "N}" );
712 if( !ldap_is_desc( str ) ) {
716 char *nextstar = ldap_pvt_find_wildcard( value );
718 if ( nextstar == NULL ) {
721 } else if ( *nextstar == '\0' ) {
722 ftype = LDAP_FILTER_EQUALITY;
724 } else if ( strcmp( value, "*" ) == 0 ) {
725 ftype = LDAP_FILTER_PRESENT;
728 rc = put_substring_filter( ber, str, value );
734 if( !ldap_is_desc( str ) ) goto done;
736 if ( ftype == LDAP_FILTER_PRESENT ) {
737 rc = ber_printf( ber, "ts", ftype, str );
740 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
743 rc = ber_printf( ber, "t{soN}",
744 ftype, str, value, len );
749 if( rc != -1 ) rc = 0;
755 put_substring_filter( BerElement *ber, char *type, char *val )
759 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
762 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS,
763 "put_substring_filter \"%s=%s\"\n", type, val ));
765 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
769 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
773 for( ; *val; val=nextstar ) {
774 nextstar = ldap_pvt_find_wildcard( val );
776 if ( nextstar == NULL ) {
780 if ( *nextstar == '\0' ) {
781 ftype = LDAP_SUBSTRING_FINAL;
784 if ( gotstar++ == 0 ) {
785 ftype = LDAP_SUBSTRING_INITIAL;
787 ftype = LDAP_SUBSTRING_ANY;
791 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
792 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
798 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
804 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {
812 ldap_pvt_put_vrFilter( BerElement *ber, const char *str_in )
818 int parens, balance, escape;
821 * A ValuesReturnFilter looks like this:
823 * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
824 * SimpleFilterItem ::= CHOICE {
825 * equalityMatch [3] AttributeValueAssertion,
826 * substrings [4] SubstringFilter,
827 * greaterOrEqual [5] AttributeValueAssertion,
828 * lessOrEqual [6] AttributeValueAssertion,
829 * present [7] AttributeType,
830 * approxMatch [8] AttributeValueAssertion,
831 * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3
834 * SubstringFilter ::= SEQUENCE {
835 * type AttributeType,
836 * SEQUENCE OF CHOICE {
837 * initial [0] IA5String,
839 * final [2] IA5String
843 * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
844 * matchingRule [1] MatchingRuleId OPTIONAL,
845 * type [2] AttributeDescription OPTIONAL,
846 * matchValue [3] AssertionValue }
850 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS, "ldap_pvt_put_vrFilter: \"%s\"\n",
853 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
856 freeme = LDAP_STRDUP( str_in );
857 if( freeme == NULL ) return LDAP_NO_MEMORY;
868 while( LDAP_SPACE( *str ) ) str++;
872 if ( (next = find_right_paren( str )) == NULL ) {
879 if ( put_vrFilter_list( ber, str ) == -1 ) {
895 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
896 "ldap_pvt_put_vrFilter: simple\n" ));
898 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n",
906 while ( *next && balance ) {
908 if ( *next == '(' ) {
910 } else if ( *next == ')' ) {
915 if ( *next == '\\' && ! escape ) {
921 if ( balance ) next++;
924 if ( balance != 0 ) {
931 if ( put_simple_vrFilter( ber, str ) == -1 ) {
936 *next++ = /*'('*/ ')';
946 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
947 "ldap_pvt_put_filter: end\n" ));
949 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
952 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
964 default: /* assume it's a simple type=value filter */
966 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
967 "ldap_pvt_put_filter: default\n" ));
969 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
972 next = strchr( str, '\0' );
973 if ( put_simple_filter( ber, str ) == -1 ) {
982 rc = parens ? -1 : 0;
990 put_vrFilter( BerElement *ber, const char *str_in )
994 if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) {
998 rc = ldap_pvt_put_vrFilter( ber, str_in );
1000 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
1008 put_vrFilter_list( BerElement *ber, char *str )
1014 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS,
1015 "put_vrFilter_list \"%s\"\n", str ));
1017 Debug( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n",
1022 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
1025 if ( *str == '\0' ) break;
1027 if ( (next = find_right_paren( str + 1 )) == NULL ) {
1032 /* now we have "(filter)" with str pointing to it */
1034 if ( ldap_pvt_put_vrFilter( ber, str ) == -1 ) return -1;
1043 put_simple_vrFilter(
1053 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS,
1054 "put_simple_vrFilter: \"%s\"\n", str ));
1056 Debug( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n",
1060 str = LDAP_STRDUP( str );
1061 if( str == NULL ) return -1;
1063 if ( (s = strchr( str, '=' )) == NULL ) {
1072 ftype = LDAP_FILTER_LE;
1077 ftype = LDAP_FILTER_GE;
1082 ftype = LDAP_FILTER_APPROX;
1087 /* According to ValuesReturnFilter control definition
1088 * extensible filters are off the form:
1089 * type [:rule] := value
1092 ftype = LDAP_FILTER_EXT;
1096 char *rule = strchr( str, ':' );
1099 if( rule == NULL ) {
1100 /* must have attribute */
1101 if( !ldap_is_desc( str ) ) {
1111 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
1112 /* must have either type or rule */
1116 if ( *str != '\0' && !ldap_is_desc( str ) ) {
1120 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
1124 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
1126 if( rc != -1 && rule && *rule != '\0' ) {
1127 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
1130 if( rc != -1 && *str != '\0' ) {
1131 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
1135 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1138 rc = ber_printf( ber, "to",
1139 LDAP_FILTER_EXT_VALUE, value, len );
1146 rc = ber_printf( ber, /*"{"*/ "N}" );
1152 if( !ldap_is_desc( str ) ) {
1156 char *nextstar = ldap_pvt_find_wildcard( value );
1158 if ( nextstar == NULL ) {
1161 } else if ( *nextstar == '\0' ) {
1162 ftype = LDAP_FILTER_EQUALITY;
1164 } else if ( strcmp( value, "*" ) == 0 ) {
1165 ftype = LDAP_FILTER_PRESENT;
1168 rc = put_substring_filter( ber, str, value );
1174 if( !ldap_is_desc( str ) ) goto done;
1176 if ( ftype == LDAP_FILTER_PRESENT ) {
1177 rc = ber_printf( ber, "ts", ftype, str );
1180 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1183 rc = ber_printf( ber, "t{soN}",
1184 ftype, str, value, len );
1189 if( rc != -1 ) rc = 0;