3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2016 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((
56 static int put_filter_list LDAP_P((
61 static int ldap_is_oid ( const char *str )
65 if( LDAP_ALPHA( str[0] )) {
66 for( i=1; str[i]; i++ ) {
67 if( !LDAP_LDH( str[i] )) {
73 } else if LDAP_DIGIT( str[0] ) {
75 for( i=1; str[i]; i++ ) {
76 if( LDAP_DIGIT( str[i] )) {
79 } 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] == '.' ) {
122 if( ++dot > 1 ) return 0;
134 if( !LDAP_LDH( str[0] )) {
137 for( i=1; str[i]; i++ ) {
138 if( str[i] == ';' ) {
142 if( !LDAP_LDH( str[i] )) {
150 find_right_paren( char *s )
156 while ( *s && balance ) {
160 } else if ( *s == ')' ) {
165 escape = ( *s == '\\' && !escape );
170 return *s ? s : NULL;
173 static int hex2value( int c )
175 if( c >= '0' && c <= '9' ) {
179 if( c >= 'A' && c <= 'F' ) {
180 return c + (10 - (int) 'A');
183 if( c >= 'a' && c <= 'f' ) {
184 return c + (10 - (int) 'a');
191 ldap_pvt_find_wildcard( const char *s )
195 case '*': /* found wildcard */
203 if( s[1] == '\0' ) return NULL;
205 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
208 } else switch( s[1] ) {
212 /* allow RFC 1960 escapes */
225 /* unescape filter value */
226 /* support both LDAP v2 and v3 escapes */
227 /* output can include nul characters! */
229 ldap_pvt_filter_value_unescape( char *fval )
234 for( r=v=0; fval[v] != '\0'; v++ ) {
245 if ( fval[v] == '\0' ) {
246 /* escape at end of string */
250 if (( v1 = hex2value( fval[v] )) >= 0 ) {
252 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
253 /* must be two digit code */
257 fval[r++] = v1 * 16 + v2;
286 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
291 * We have (x(filter)...) with str sitting on
292 * the x. We have to find the paren matching
293 * the one before the x and put the intervening
294 * filters by calling put_filter_list().
297 /* put explicit tag */
298 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
303 if ( (next = find_right_paren( str )) == NULL ) {
308 if ( put_filter_list( ber, str, tag ) == -1 ) {
315 /* flush explicit tagged thang */
316 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
324 ldap_pvt_put_filter( BerElement *ber, const char *str_in )
330 int parens, balance, escape;
333 * A Filter looks like this (RFC 4511 as extended by RFC 4526):
334 * Filter ::= CHOICE {
335 * and [0] SET SIZE (0..MAX) OF filter Filter,
336 * or [1] SET SIZE (0..MAX) OF filter Filter,
338 * equalityMatch [3] AttributeValueAssertion,
339 * substrings [4] SubstringFilter,
340 * greaterOrEqual [5] AttributeValueAssertion,
341 * lessOrEqual [6] AttributeValueAssertion,
342 * present [7] AttributeDescription,
343 * approxMatch [8] AttributeValueAssertion,
344 * extensibleMatch [9] MatchingRuleAssertion,
347 * SubstringFilter ::= SEQUENCE {
348 * type AttributeDescription,
349 * substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
350 * initial [0] AssertionValue, -- only once
351 * any [1] AssertionValue,
352 * final [2] AssertionValue -- only once
356 * MatchingRuleAssertion ::= SEQUENCE {
357 * matchingRule [1] MatchingRuleId OPTIONAL,
358 * type [2] AttributeDescription OPTIONAL,
359 * matchValue [3] AssertionValue,
360 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
362 * Note: tags in a CHOICE are always explicit
365 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
367 freeme = LDAP_STRDUP( str_in );
368 if( freeme == NULL ) return LDAP_NO_MEMORY;
379 while( LDAP_SPACE( *str ) ) str++;
383 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
386 str = put_complex_filter( ber, str,
387 LDAP_FILTER_AND, 0 );
397 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
400 str = put_complex_filter( ber, str,
411 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
414 str = put_complex_filter( ber, str,
415 LDAP_FILTER_NOT, 0 );
429 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
436 while ( *next && balance ) {
438 if ( *next == '(' ) {
440 } else if ( *next == ')' ) {
445 if ( *next == '\\' && ! escape ) {
451 if ( balance ) next++;
454 if ( balance != 0 ) {
461 if ( put_simple_filter( ber, str ) == -1 ) {
466 *next++ = /*'('*/ ')';
475 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
477 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
489 default: /* assume it's a simple type=value filter */
490 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
492 next = strchr( str, '\0' );
493 if ( put_simple_filter( ber, str ) == -1 ) {
504 rc = ( parens || *str ) ? -1 : 0;
512 * Put a list of filters like this "(filter1)(filter2)..."
516 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
521 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
525 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
528 if ( *str == '\0' ) break;
530 if ( (next = find_right_paren( str + 1 )) == NULL ) {
535 /* now we have "(filter)" with str pointing to it */
537 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1;
541 if( tag == LDAP_FILTER_NOT ) break;
544 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
561 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
564 str = LDAP_STRDUP( str );
565 if( str == NULL ) return -1;
567 if ( (s = strchr( str, '=' )) == NULL ) {
576 ftype = LDAP_FILTER_LE;
581 ftype = LDAP_FILTER_GE;
586 ftype = LDAP_FILTER_APPROX;
591 /* RFC 4515 extensible filters are off the form:
592 * type [:dn] [:rule] := value
593 * or [:dn]:rule := value
595 ftype = LDAP_FILTER_EXT;
599 char *dn = strchr( str, ':' );
604 rule = strchr( dn, ':' );
608 if ( strcasecmp(dn, "dn") == 0 ) {
609 /* must have attribute */
610 if( !ldap_is_desc( str ) ) {
625 if ( strcasecmp(dn, "dn") != 0 ) {
633 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
634 /* must have either type or rule */
638 if ( *str != '\0' && !ldap_is_desc( str ) ) {
642 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
646 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
648 if( rc != -1 && rule && *rule != '\0' ) {
649 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
652 if( rc != -1 && *str != '\0' ) {
653 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
657 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
660 rc = ber_printf( ber, "to",
661 LDAP_FILTER_EXT_VALUE, value, len );
667 if( rc != -1 && dn ) {
668 rc = ber_printf( ber, "tb",
669 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
673 rc = ber_printf( ber, /*"{"*/ "N}" );
679 if( !ldap_is_desc( str ) ) {
683 char *nextstar = ldap_pvt_find_wildcard( value );
685 if ( nextstar == NULL ) {
688 } else if ( *nextstar == '\0' ) {
689 ftype = LDAP_FILTER_EQUALITY;
691 } else if ( strcmp( value, "*" ) == 0 ) {
692 ftype = LDAP_FILTER_PRESENT;
695 rc = put_substring_filter( ber, str, value, nextstar );
701 if( !ldap_is_desc( str ) ) goto done;
703 if ( ftype == LDAP_FILTER_PRESENT ) {
704 rc = ber_printf( ber, "ts", ftype, str );
707 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
710 rc = ber_printf( ber, "t{soN}",
711 ftype, str, value, len );
716 if( rc != -1 ) rc = 0;
722 put_substring_filter( BerElement *ber, char *type, char *val, char *nextstar )
725 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
727 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
730 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
734 for( ; *val; val=nextstar ) {
736 nextstar = ldap_pvt_find_wildcard( val );
738 if ( nextstar == NULL ) {
742 if ( *nextstar == '\0' ) {
743 ftype = LDAP_SUBSTRING_FINAL;
746 if ( gotstar++ == 0 ) {
747 ftype = LDAP_SUBSTRING_INITIAL;
749 ftype = LDAP_SUBSTRING_ANY;
753 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
754 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
760 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
766 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {
774 put_vrFilter( BerElement *ber, const char *str_in )
780 int parens, balance, escape;
783 * A ValuesReturnFilter looks like this:
785 * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
786 * SimpleFilterItem ::= CHOICE {
787 * equalityMatch [3] AttributeValueAssertion,
788 * substrings [4] SubstringFilter,
789 * greaterOrEqual [5] AttributeValueAssertion,
790 * lessOrEqual [6] AttributeValueAssertion,
791 * present [7] AttributeType,
792 * approxMatch [8] AttributeValueAssertion,
793 * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3
796 * SubstringFilter ::= SEQUENCE {
797 * type AttributeType,
798 * SEQUENCE OF CHOICE {
799 * initial [0] IA5String,
801 * final [2] IA5String
805 * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
806 * matchingRule [1] MatchingRuleId OPTIONAL,
807 * type [2] AttributeDescription OPTIONAL,
808 * matchValue [3] AssertionValue }
813 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
815 freeme = LDAP_STRDUP( str_in );
816 if( freeme == NULL ) return LDAP_NO_MEMORY;
827 while( LDAP_SPACE( *str ) ) str++;
831 if ( (next = find_right_paren( str )) == NULL ) {
838 if ( put_vrFilter_list( ber, str ) == -1 ) {
853 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n",
860 while ( *next && balance ) {
862 if ( *next == '(' ) {
864 } else if ( *next == ')' ) {
869 if ( *next == '\\' && ! escape ) {
875 if ( balance ) next++;
878 if ( balance != 0 ) {
885 if ( put_simple_vrFilter( ber, str ) == -1 ) {
890 *next++ = /*'('*/ ')';
899 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: end\n",
901 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
913 default: /* assume it's a simple type=value filter */
914 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: default\n",
916 next = strchr( str, '\0' );
917 if ( put_simple_vrFilter( ber, str ) == -1 ) {
926 rc = parens ? -1 : 0;
934 ldap_put_vrFilter( BerElement *ber, const char *str_in )
938 if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) {
942 rc = put_vrFilter( ber, str_in );
944 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
952 put_vrFilter_list( BerElement *ber, char *str )
957 Debug( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n",
961 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
964 if ( *str == '\0' ) break;
966 if ( (next = find_right_paren( str + 1 )) == NULL ) {
971 /* now we have "(filter)" with str pointing to it */
973 if ( put_vrFilter( ber, str ) == -1 ) return -1;
991 Debug( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n",
994 str = LDAP_STRDUP( str );
995 if( str == NULL ) return -1;
997 if ( (s = strchr( str, '=' )) == NULL ) {
1006 ftype = LDAP_FILTER_LE;
1011 ftype = LDAP_FILTER_GE;
1016 ftype = LDAP_FILTER_APPROX;
1021 /* According to ValuesReturnFilter control definition
1022 * extensible filters are off the form:
1023 * type [:rule] := value
1026 ftype = LDAP_FILTER_EXT;
1030 char *rule = strchr( str, ':' );
1032 if( rule == NULL ) {
1033 /* must have attribute */
1034 if( !ldap_is_desc( str ) ) {
1042 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
1043 /* must have either type or rule */
1047 if ( *str != '\0' && !ldap_is_desc( str ) ) {
1051 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
1055 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
1057 if( rc != -1 && rule && *rule != '\0' ) {
1058 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
1061 if( rc != -1 && *str != '\0' ) {
1062 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
1066 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1069 rc = ber_printf( ber, "to",
1070 LDAP_FILTER_EXT_VALUE, value, len );
1077 rc = ber_printf( ber, /*"{"*/ "N}" );
1083 if( !ldap_is_desc( str ) ) {
1087 char *nextstar = ldap_pvt_find_wildcard( value );
1089 if ( nextstar == NULL ) {
1092 } else if ( *nextstar == '\0' ) {
1093 ftype = LDAP_FILTER_EQUALITY;
1095 } else if ( strcmp( value, "*" ) == 0 ) {
1096 ftype = LDAP_FILTER_PRESENT;
1099 rc = put_substring_filter( ber, str, value, nextstar );
1105 if( !ldap_is_desc( str ) ) goto done;
1107 if ( ftype == LDAP_FILTER_PRESENT ) {
1108 rc = ber_printf( ber, "ts", ftype, str );
1111 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1114 rc = ber_printf( ber, "t{soN}",
1115 ftype, str, value, len );
1120 if( rc != -1 ) rc = 0;