3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2007 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
16 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
17 * All rights reserved.
24 #include <ac/stdlib.h>
26 #include <ac/socket.h>
27 #include <ac/string.h>
32 static int put_simple_vrFilter LDAP_P((
36 static int put_vrFilter_list LDAP_P((
40 static char *put_complex_filter LDAP_P((
46 static int put_simple_filter LDAP_P((
50 static int put_substring_filter LDAP_P((
55 static int put_filter_list LDAP_P((
60 static int ldap_is_oid ( const char *str )
64 if( LDAP_ALPHA( str[0] )) {
65 for( i=1; str[i]; i++ ) {
66 if( !LDAP_LDH( str[i] )) {
72 } else if LDAP_DIGIT( str[0] ) {
74 for( i=1; str[i]; i++ ) {
75 if( LDAP_DIGIT( str[i] )) {
78 } else if ( str[i] == '.' ) {
80 if( ++dot > 1 ) return 0;
92 static int ldap_is_desc ( const char *str )
96 if( LDAP_ALPHA( str[0] )) {
97 for( i=1; str[i]; i++ ) {
103 if( !LDAP_LDH( str[i] )) {
109 } else if LDAP_DIGIT( str[0] ) {
111 for( i=1; str[i]; i++ ) {
112 if( str[i] == ';' ) {
118 if( LDAP_DIGIT( str[i] )) {
121 } else if ( str[i] == '.' ) {
123 if( ++dot > 1 ) return 0;
135 if( !LDAP_LDH( str[0] )) {
138 for( i=1; str[i]; i++ ) {
139 if( str[i] == ';' ) {
143 if( !LDAP_LDH( str[i] )) {
151 find_right_paren( char *s )
157 while ( *s && balance ) {
161 } else if ( *s == ')' ) {
166 escape = ( *s == '\\' && !escape );
171 return *s ? s : NULL;
174 static int hex2value( int c )
176 if( c >= '0' && c <= '9' ) {
180 if( c >= 'A' && c <= 'F' ) {
181 return c + (10 - (int) 'A');
184 if( c >= 'a' && c <= 'f' ) {
185 return c + (10 - (int) 'a');
192 ldap_pvt_find_wildcard( const char *s )
196 case '*': /* found wildcard */
204 if( s[1] == '\0' ) return NULL;
206 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
209 } else switch( s[1] ) {
213 /* allow RFC 1960 escapes */
226 /* unescape filter value */
227 /* support both LDAP v2 and v3 escapes */
228 /* output can include nul characters! */
230 ldap_pvt_filter_value_unescape( char *fval )
235 for( r=v=0; fval[v] != '\0'; v++ ) {
246 if ( fval[v] == '\0' ) {
247 /* escape at end of string */
251 if (( v1 = hex2value( fval[v] )) >= 0 ) {
253 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
254 /* must be two digit code */
258 fval[r++] = v1 * 16 + v2;
287 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
292 * We have (x(filter)...) with str sitting on
293 * the x. We have to find the paren matching
294 * the one before the x and put the intervening
295 * filters by calling put_filter_list().
298 /* put explicit tag */
299 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
304 if ( (next = find_right_paren( str )) == NULL ) {
309 if ( put_filter_list( ber, str, tag ) == -1 ) {
316 /* flush explicit tagged thang */
317 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
325 ldap_pvt_put_filter( BerElement *ber, const char *str_in )
331 int parens, balance, escape;
334 * A Filter looks like this (RFC 4511 as extended by RFC 4526):
335 * Filter ::= CHOICE {
336 * and [0] SET SIZE (0..MAX) OF filter Filter,
337 * or [1] SET SIZE (0..MAX) OF filter Filter,
339 * equalityMatch [3] AttributeValueAssertion,
340 * substrings [4] SubstringFilter,
341 * greaterOrEqual [5] AttributeValueAssertion,
342 * lessOrEqual [6] AttributeValueAssertion,
343 * present [7] AttributeDescription,
344 * approxMatch [8] AttributeValueAssertion,
345 * extensibleMatch [9] MatchingRuleAssertion,
348 * SubstringFilter ::= SEQUENCE {
349 * type AttributeDescription,
350 * substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
351 * initial [0] AssertionValue, -- only once
352 * any [1] AssertionValue,
353 * final [2] AssertionValue -- only once
357 * MatchingRuleAssertion ::= SEQUENCE {
358 * matchingRule [1] MatchingRuleId OPTIONAL,
359 * type [2] AttributeDescription OPTIONAL,
360 * matchValue [3] AssertionValue,
361 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
363 * Note: tags in a CHOICE are always explicit
366 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
368 freeme = LDAP_STRDUP( str_in );
369 if( freeme == NULL ) return LDAP_NO_MEMORY;
380 while( LDAP_SPACE( *str ) ) str++;
384 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
387 str = put_complex_filter( ber, str,
388 LDAP_FILTER_AND, 0 );
398 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
401 str = put_complex_filter( ber, str,
412 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
415 str = put_complex_filter( ber, str,
416 LDAP_FILTER_NOT, 0 );
430 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
437 while ( *next && balance ) {
439 if ( *next == '(' ) {
441 } else if ( *next == ')' ) {
446 if ( *next == '\\' && ! escape ) {
452 if ( balance ) next++;
455 if ( balance != 0 ) {
462 if ( put_simple_filter( ber, str ) == -1 ) {
467 *next++ = /*'('*/ ')';
476 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
478 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
490 default: /* assume it's a simple type=value filter */
491 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
493 next = strchr( str, '\0' );
494 if ( put_simple_filter( ber, str ) == -1 ) {
505 rc = ( parens || *str ) ? -1 : 0;
513 * Put a list of filters like this "(filter1)(filter2)..."
517 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
522 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
526 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
529 if ( *str == '\0' ) break;
531 if ( (next = find_right_paren( str + 1 )) == NULL ) {
536 /* now we have "(filter)" with str pointing to it */
538 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1;
542 if( tag == LDAP_FILTER_NOT ) break;
545 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
562 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
565 str = LDAP_STRDUP( str );
566 if( str == NULL ) return -1;
568 if ( (s = strchr( str, '=' )) == NULL ) {
577 ftype = LDAP_FILTER_LE;
582 ftype = LDAP_FILTER_GE;
587 ftype = LDAP_FILTER_APPROX;
592 /* RFC 4515 extensible filters are off the form:
593 * type [:dn] [:rule] := value
594 * or [:dn]:rule := value
596 ftype = LDAP_FILTER_EXT;
600 char *dn = strchr( str, ':' );
605 rule = strchr( dn, ':' );
609 if ( strcasecmp(dn, "dn") == 0 ) {
610 /* must have attribute */
611 if( !ldap_is_desc( str ) ) {
626 if ( strcasecmp(dn, "dn") != 0 ) {
634 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
635 /* must have either type or rule */
639 if ( *str != '\0' && !ldap_is_desc( str ) ) {
643 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
647 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
649 if( rc != -1 && rule && *rule != '\0' ) {
650 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
653 if( rc != -1 && *str != '\0' ) {
654 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
658 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
661 rc = ber_printf( ber, "to",
662 LDAP_FILTER_EXT_VALUE, value, len );
668 if( rc != -1 && dn ) {
669 rc = ber_printf( ber, "tb",
670 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
674 rc = ber_printf( ber, /*"{"*/ "N}" );
680 if( !ldap_is_desc( str ) ) {
684 char *nextstar = ldap_pvt_find_wildcard( value );
686 if ( nextstar == NULL ) {
689 } else if ( *nextstar == '\0' ) {
690 ftype = LDAP_FILTER_EQUALITY;
692 } else if ( strcmp( value, "*" ) == 0 ) {
693 ftype = LDAP_FILTER_PRESENT;
696 rc = put_substring_filter( ber, str, value );
702 if( !ldap_is_desc( str ) ) goto done;
704 if ( ftype == LDAP_FILTER_PRESENT ) {
705 rc = ber_printf( ber, "ts", ftype, str );
708 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
711 rc = ber_printf( ber, "t{soN}",
712 ftype, str, value, len );
717 if( rc != -1 ) rc = 0;
723 put_substring_filter( BerElement *ber, char *type, char *val )
727 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
729 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
732 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
736 for( ; *val; val=nextstar ) {
737 nextstar = ldap_pvt_find_wildcard( val );
739 if ( nextstar == NULL ) {
743 if ( *nextstar == '\0' ) {
744 ftype = LDAP_SUBSTRING_FINAL;
747 if ( gotstar++ == 0 ) {
748 ftype = LDAP_SUBSTRING_INITIAL;
750 ftype = LDAP_SUBSTRING_ANY;
754 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
755 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
761 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
767 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {
775 put_vrFilter( BerElement *ber, const char *str_in )
781 int parens, balance, escape;
784 * A ValuesReturnFilter looks like this:
786 * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
787 * SimpleFilterItem ::= CHOICE {
788 * equalityMatch [3] AttributeValueAssertion,
789 * substrings [4] SubstringFilter,
790 * greaterOrEqual [5] AttributeValueAssertion,
791 * lessOrEqual [6] AttributeValueAssertion,
792 * present [7] AttributeType,
793 * approxMatch [8] AttributeValueAssertion,
794 * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3
797 * SubstringFilter ::= SEQUENCE {
798 * type AttributeType,
799 * SEQUENCE OF CHOICE {
800 * initial [0] IA5String,
802 * final [2] IA5String
806 * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
807 * matchingRule [1] MatchingRuleId OPTIONAL,
808 * type [2] AttributeDescription OPTIONAL,
809 * matchValue [3] AssertionValue }
814 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
816 freeme = LDAP_STRDUP( str_in );
817 if( freeme == NULL ) return LDAP_NO_MEMORY;
828 while( LDAP_SPACE( *str ) ) str++;
832 if ( (next = find_right_paren( str )) == NULL ) {
839 if ( put_vrFilter_list( ber, str ) == -1 ) {
854 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n",
861 while ( *next && balance ) {
863 if ( *next == '(' ) {
865 } else if ( *next == ')' ) {
870 if ( *next == '\\' && ! escape ) {
876 if ( balance ) next++;
879 if ( balance != 0 ) {
886 if ( put_simple_vrFilter( ber, str ) == -1 ) {
891 *next++ = /*'('*/ ')';
900 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: end\n",
902 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
914 default: /* assume it's a simple type=value filter */
915 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: default\n",
917 next = strchr( str, '\0' );
918 if ( put_simple_vrFilter( ber, str ) == -1 ) {
927 rc = parens ? -1 : 0;
935 ldap_put_vrFilter( BerElement *ber, const char *str_in )
939 if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) {
943 rc = put_vrFilter( ber, str_in );
945 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
953 put_vrFilter_list( BerElement *ber, char *str )
958 Debug( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n",
962 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
965 if ( *str == '\0' ) break;
967 if ( (next = find_right_paren( str + 1 )) == NULL ) {
972 /* now we have "(filter)" with str pointing to it */
974 if ( put_vrFilter( ber, str ) == -1 ) return -1;
992 Debug( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n",
995 str = LDAP_STRDUP( str );
996 if( str == NULL ) return -1;
998 if ( (s = strchr( str, '=' )) == NULL ) {
1007 ftype = LDAP_FILTER_LE;
1012 ftype = LDAP_FILTER_GE;
1017 ftype = LDAP_FILTER_APPROX;
1022 /* According to ValuesReturnFilter control definition
1023 * extensible filters are off the form:
1024 * type [:rule] := value
1027 ftype = LDAP_FILTER_EXT;
1031 char *rule = strchr( str, ':' );
1033 if( rule == NULL ) {
1034 /* must have attribute */
1035 if( !ldap_is_desc( str ) ) {
1043 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
1044 /* must have either type or rule */
1048 if ( *str != '\0' && !ldap_is_desc( str ) ) {
1052 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
1056 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
1058 if( rc != -1 && rule && *rule != '\0' ) {
1059 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
1062 if( rc != -1 && *str != '\0' ) {
1063 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
1067 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1070 rc = ber_printf( ber, "to",
1071 LDAP_FILTER_EXT_VALUE, value, len );
1078 rc = ber_printf( ber, /*"{"*/ "N}" );
1084 if( !ldap_is_desc( str ) ) {
1088 char *nextstar = ldap_pvt_find_wildcard( value );
1090 if ( nextstar == NULL ) {
1093 } else if ( *nextstar == '\0' ) {
1094 ftype = LDAP_FILTER_EQUALITY;
1096 } else if ( strcmp( value, "*" ) == 0 ) {
1097 ftype = LDAP_FILTER_PRESENT;
1100 rc = put_substring_filter( ber, str, value );
1106 if( !ldap_is_desc( str ) ) goto done;
1108 if ( ftype == LDAP_FILTER_PRESENT ) {
1109 rc = ber_printf( ber, "ts", ftype, str );
1112 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1115 rc = ber_printf( ber, "t{soN}",
1116 ftype, str, value, len );
1121 if( rc != -1 ) rc = 0;