3 * Copyright 1998-2003 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, ARGS, "ldap_pvt_put_filter: \"%s\"\n", str_in,0,0 );
362 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
365 freeme = LDAP_STRDUP( str_in );
366 if( freeme == NULL ) return LDAP_NO_MEMORY;
377 while( LDAP_SPACE( *str ) ) str++;
382 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: AND\n", 0,0,0 );
384 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
388 str = put_complex_filter( ber, str,
389 LDAP_FILTER_AND, 0 );
400 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: OR\n", 0,0,0 );
402 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
406 str = put_complex_filter( ber, str,
418 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: NOT\n", 0,0,0 );
420 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
424 str = put_complex_filter( ber, str,
425 LDAP_FILTER_NOT, 0 );
436 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: simple\n", 0,0,0);
438 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
446 while ( *next && balance ) {
448 if ( *next == '(' ) {
450 } else if ( *next == ')' ) {
455 if ( *next == '\\' && ! escape ) {
461 if ( balance ) next++;
464 if ( balance != 0 ) {
471 if ( put_simple_filter( ber, str ) == -1 ) {
476 *next++ = /*'('*/ ')';
486 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: end\n", 0,0,0 );
488 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
491 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
503 default: /* assume it's a simple type=value filter */
505 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: default\n", 0,0,0 );
507 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
510 next = strchr( str, '\0' );
511 if ( put_simple_filter( ber, str ) == -1 ) {
520 rc = parens ? -1 : 0;
528 * Put a list of filters like this "(filter1)(filter2)..."
532 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
538 LDAP_LOG ( FILTER, ARGS, "put_filter_list \"%s\"\n", str,0,0 );
540 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
545 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
548 if ( *str == '\0' ) break;
550 if ( (next = find_right_paren( str + 1 )) == NULL ) {
555 /* now we have "(filter)" with str pointing to it */
557 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1;
561 if( tag == LDAP_FILTER_NOT ) break;
564 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
582 LDAP_LOG ( FILTER, ARGS, "put_simple_filter: \"%s\"\n", str,0,0 );
584 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
588 str = LDAP_STRDUP( str );
589 if( str == NULL ) return -1;
591 if ( (s = strchr( str, '=' )) == NULL ) {
600 ftype = LDAP_FILTER_LE;
605 ftype = LDAP_FILTER_GE;
610 ftype = LDAP_FILTER_APPROX;
615 /* RFC2254 extensible filters are off the form:
616 * type [:dn] [:rule] := value
617 * or [:dn]:rule := value
619 ftype = LDAP_FILTER_EXT;
623 char *dn = strchr( str, ':' );
628 rule = strchr( dn, ':' );
632 if ( strcmp(dn, "dn") == 0 ) {
633 /* must have attribute */
634 if( !ldap_is_desc( str ) ) {
649 if ( strcmp(dn, "dn") != 0 ) {
657 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
658 /* must have either type or rule */
662 if ( *str != '\0' && !ldap_is_desc( str ) ) {
666 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
670 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
672 if( rc != -1 && rule && *rule != '\0' ) {
673 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
676 if( rc != -1 && *str != '\0' ) {
677 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
681 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
684 rc = ber_printf( ber, "to",
685 LDAP_FILTER_EXT_VALUE, value, len );
691 if( rc != -1 && dn ) {
692 rc = ber_printf( ber, "tb",
693 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
697 rc = ber_printf( ber, /*"{"*/ "N}" );
703 if( !ldap_is_desc( str ) ) {
707 char *nextstar = ldap_pvt_find_wildcard( value );
709 if ( nextstar == NULL ) {
712 } else if ( *nextstar == '\0' ) {
713 ftype = LDAP_FILTER_EQUALITY;
715 } else if ( strcmp( value, "*" ) == 0 ) {
716 ftype = LDAP_FILTER_PRESENT;
719 rc = put_substring_filter( ber, str, value );
725 if( !ldap_is_desc( str ) ) goto done;
727 if ( ftype == LDAP_FILTER_PRESENT ) {
728 rc = ber_printf( ber, "ts", ftype, str );
731 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
734 rc = ber_printf( ber, "t{soN}",
735 ftype, str, value, len );
740 if( rc != -1 ) rc = 0;
746 put_substring_filter( BerElement *ber, char *type, char *val )
750 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
753 LDAP_LOG ( FILTER, ARGS, "put_substring_filter \"%s=%s\"\n", type, val, 0 );
755 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
759 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
763 for( ; *val; val=nextstar ) {
764 nextstar = ldap_pvt_find_wildcard( val );
766 if ( nextstar == NULL ) {
770 if ( *nextstar == '\0' ) {
771 ftype = LDAP_SUBSTRING_FINAL;
774 if ( gotstar++ == 0 ) {
775 ftype = LDAP_SUBSTRING_INITIAL;
777 ftype = LDAP_SUBSTRING_ANY;
781 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
782 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
788 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
794 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {
802 put_vrFilter( BerElement *ber, const char *str_in )
808 int parens, balance, escape;
811 * A ValuesReturnFilter looks like this:
813 * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
814 * SimpleFilterItem ::= CHOICE {
815 * equalityMatch [3] AttributeValueAssertion,
816 * substrings [4] SubstringFilter,
817 * greaterOrEqual [5] AttributeValueAssertion,
818 * lessOrEqual [6] AttributeValueAssertion,
819 * present [7] AttributeType,
820 * approxMatch [8] AttributeValueAssertion,
821 * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3
824 * SubstringFilter ::= SEQUENCE {
825 * type AttributeType,
826 * SEQUENCE OF CHOICE {
827 * initial [0] IA5String,
829 * final [2] IA5String
833 * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
834 * matchingRule [1] MatchingRuleId OPTIONAL,
835 * type [2] AttributeDescription OPTIONAL,
836 * matchValue [3] AssertionValue }
840 LDAP_LOG ( FILTER, ARGS, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
842 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
845 freeme = LDAP_STRDUP( str_in );
846 if( freeme == NULL ) return LDAP_NO_MEMORY;
857 while( LDAP_SPACE( *str ) ) str++;
861 if ( (next = find_right_paren( str )) == NULL ) {
868 if ( put_vrFilter_list( ber, str ) == -1 ) {
884 LDAP_LOG ( FILTER, DETAIL1,
885 "put_vrFilter: simple\n", 0, 0, 0 );
887 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n",
895 while ( *next && balance ) {
897 if ( *next == '(' ) {
899 } else if ( *next == ')' ) {
904 if ( *next == '\\' && ! escape ) {
910 if ( balance ) next++;
913 if ( balance != 0 ) {
920 if ( put_simple_vrFilter( ber, str ) == -1 ) {
925 *next++ = /*'('*/ ')';
935 LDAP_LOG ( FILTER, DETAIL1, "put_vrFilter: end\n", 0, 0, 0 );
937 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: end\n",
940 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
952 default: /* assume it's a simple type=value filter */
954 LDAP_LOG ( FILTER, DETAIL1, "put_vrFilter: default\n",
957 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: default\n",
960 next = strchr( str, '\0' );
961 if ( put_simple_filter( ber, str ) == -1 ) {
970 rc = parens ? -1 : 0;
978 ldap_put_vrFilter( BerElement *ber, const char *str_in )
982 if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) {
986 rc = put_vrFilter( ber, str_in );
988 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
996 put_vrFilter_list( BerElement *ber, char *str )
1002 LDAP_LOG ( FILTER, ARGS, "put_vrFilter_list \"%s\"\n", str, 0, 0 );
1004 Debug( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n",
1009 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
1012 if ( *str == '\0' ) break;
1014 if ( (next = find_right_paren( str + 1 )) == NULL ) {
1019 /* now we have "(filter)" with str pointing to it */
1021 if ( put_vrFilter( ber, str ) == -1 ) return -1;
1030 put_simple_vrFilter(
1040 LDAP_LOG ( FILTER, ARGS, "put_simple_vrFilter: \"%s\"\n", str, 0, 0 );
1042 Debug( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n",
1046 str = LDAP_STRDUP( str );
1047 if( str == NULL ) return -1;
1049 if ( (s = strchr( str, '=' )) == NULL ) {
1058 ftype = LDAP_FILTER_LE;
1063 ftype = LDAP_FILTER_GE;
1068 ftype = LDAP_FILTER_APPROX;
1073 /* According to ValuesReturnFilter control definition
1074 * extensible filters are off the form:
1075 * type [:rule] := value
1078 ftype = LDAP_FILTER_EXT;
1082 char *rule = strchr( str, ':' );
1085 if( rule == NULL ) {
1086 /* must have attribute */
1087 if( !ldap_is_desc( str ) ) {
1097 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
1098 /* must have either type or rule */
1102 if ( *str != '\0' && !ldap_is_desc( str ) ) {
1106 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
1110 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
1112 if( rc != -1 && rule && *rule != '\0' ) {
1113 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
1116 if( rc != -1 && *str != '\0' ) {
1117 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
1121 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1124 rc = ber_printf( ber, "to",
1125 LDAP_FILTER_EXT_VALUE, value, len );
1132 rc = ber_printf( ber, /*"{"*/ "N}" );
1138 if( !ldap_is_desc( str ) ) {
1142 char *nextstar = ldap_pvt_find_wildcard( value );
1144 if ( nextstar == NULL ) {
1147 } else if ( *nextstar == '\0' ) {
1148 ftype = LDAP_FILTER_EQUALITY;
1150 } else if ( strcmp( value, "*" ) == 0 ) {
1151 ftype = LDAP_FILTER_PRESENT;
1154 rc = put_substring_filter( ber, str, value );
1160 if( !ldap_is_desc( str ) ) goto done;
1162 if ( ftype == LDAP_FILTER_PRESENT ) {
1163 rc = ber_printf( ber, "ts", ftype, str );
1166 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1169 rc = ber_printf( ber, "t{soN}",
1170 ftype, str, value, len );
1175 if( rc != -1 ) rc = 0;