3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2013 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] == '.' ) {
81 if( ++dot > 1 ) return 0;
93 static int ldap_is_desc ( const char *str )
97 if( LDAP_ALPHA( str[0] )) {
98 for( i=1; str[i]; i++ ) {
104 if( !LDAP_LDH( str[i] )) {
110 } else if LDAP_DIGIT( str[0] ) {
112 for( i=1; str[i]; i++ ) {
113 if( str[i] == ';' ) {
119 if( LDAP_DIGIT( str[i] )) {
122 } else if ( str[i] == '.' ) {
124 if( ++dot > 1 ) return 0;
136 if( !LDAP_LDH( str[0] )) {
139 for( i=1; str[i]; i++ ) {
140 if( str[i] == ';' ) {
144 if( !LDAP_LDH( str[i] )) {
152 find_right_paren( char *s )
158 while ( *s && balance ) {
162 } else if ( *s == ')' ) {
167 escape = ( *s == '\\' && !escape );
172 return *s ? s : NULL;
175 static int hex2value( int c )
177 if( c >= '0' && c <= '9' ) {
181 if( c >= 'A' && c <= 'F' ) {
182 return c + (10 - (int) 'A');
185 if( c >= 'a' && c <= 'f' ) {
186 return c + (10 - (int) 'a');
193 ldap_pvt_find_wildcard( const char *s )
197 case '*': /* found wildcard */
205 if( s[1] == '\0' ) return NULL;
207 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
210 } else switch( s[1] ) {
214 /* allow RFC 1960 escapes */
227 /* unescape filter value */
228 /* support both LDAP v2 and v3 escapes */
229 /* output can include nul characters! */
231 ldap_pvt_filter_value_unescape( char *fval )
236 for( r=v=0; fval[v] != '\0'; v++ ) {
247 if ( fval[v] == '\0' ) {
248 /* escape at end of string */
252 if (( v1 = hex2value( fval[v] )) >= 0 ) {
254 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
255 /* must be two digit code */
259 fval[r++] = v1 * 16 + v2;
288 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
293 * We have (x(filter)...) with str sitting on
294 * the x. We have to find the paren matching
295 * the one before the x and put the intervening
296 * filters by calling put_filter_list().
299 /* put explicit tag */
300 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
305 if ( (next = find_right_paren( str )) == NULL ) {
310 if ( put_filter_list( ber, str, tag ) == -1 ) {
317 /* flush explicit tagged thang */
318 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
326 ldap_pvt_put_filter( BerElement *ber, const char *str_in )
332 int parens, balance, escape;
335 * A Filter looks like this (RFC 4511 as extended by RFC 4526):
336 * Filter ::= CHOICE {
337 * and [0] SET SIZE (0..MAX) OF filter Filter,
338 * or [1] SET SIZE (0..MAX) OF filter Filter,
340 * equalityMatch [3] AttributeValueAssertion,
341 * substrings [4] SubstringFilter,
342 * greaterOrEqual [5] AttributeValueAssertion,
343 * lessOrEqual [6] AttributeValueAssertion,
344 * present [7] AttributeDescription,
345 * approxMatch [8] AttributeValueAssertion,
346 * extensibleMatch [9] MatchingRuleAssertion,
349 * SubstringFilter ::= SEQUENCE {
350 * type AttributeDescription,
351 * substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
352 * initial [0] AssertionValue, -- only once
353 * any [1] AssertionValue,
354 * final [2] AssertionValue -- only once
358 * MatchingRuleAssertion ::= SEQUENCE {
359 * matchingRule [1] MatchingRuleId OPTIONAL,
360 * type [2] AttributeDescription OPTIONAL,
361 * matchValue [3] AssertionValue,
362 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
364 * Note: tags in a CHOICE are always explicit
367 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
369 freeme = LDAP_STRDUP( str_in );
370 if( freeme == NULL ) return LDAP_NO_MEMORY;
381 while( LDAP_SPACE( *str ) ) str++;
385 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
388 str = put_complex_filter( ber, str,
389 LDAP_FILTER_AND, 0 );
399 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
402 str = put_complex_filter( ber, str,
413 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
416 str = put_complex_filter( ber, str,
417 LDAP_FILTER_NOT, 0 );
431 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
438 while ( *next && balance ) {
440 if ( *next == '(' ) {
442 } else if ( *next == ')' ) {
447 if ( *next == '\\' && ! escape ) {
453 if ( balance ) next++;
456 if ( balance != 0 ) {
463 if ( put_simple_filter( ber, str ) == -1 ) {
468 *next++ = /*'('*/ ')';
477 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
479 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
491 default: /* assume it's a simple type=value filter */
492 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
494 next = strchr( str, '\0' );
495 if ( put_simple_filter( ber, str ) == -1 ) {
506 rc = ( parens || *str ) ? -1 : 0;
514 * Put a list of filters like this "(filter1)(filter2)..."
518 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
523 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
527 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
530 if ( *str == '\0' ) break;
532 if ( (next = find_right_paren( str + 1 )) == NULL ) {
537 /* now we have "(filter)" with str pointing to it */
539 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1;
543 if( tag == LDAP_FILTER_NOT ) break;
546 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
563 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
566 str = LDAP_STRDUP( str );
567 if( str == NULL ) return -1;
569 if ( (s = strchr( str, '=' )) == NULL ) {
578 ftype = LDAP_FILTER_LE;
583 ftype = LDAP_FILTER_GE;
588 ftype = LDAP_FILTER_APPROX;
593 /* RFC 4515 extensible filters are off the form:
594 * type [:dn] [:rule] := value
595 * or [:dn]:rule := value
597 ftype = LDAP_FILTER_EXT;
601 char *dn = strchr( str, ':' );
606 rule = strchr( dn, ':' );
610 if ( strcasecmp(dn, "dn") == 0 ) {
611 /* must have attribute */
612 if( !ldap_is_desc( str ) ) {
627 if ( strcasecmp(dn, "dn") != 0 ) {
635 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
636 /* must have either type or rule */
640 if ( *str != '\0' && !ldap_is_desc( str ) ) {
644 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
648 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
650 if( rc != -1 && rule && *rule != '\0' ) {
651 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
654 if( rc != -1 && *str != '\0' ) {
655 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
659 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
662 rc = ber_printf( ber, "to",
663 LDAP_FILTER_EXT_VALUE, value, len );
669 if( rc != -1 && dn ) {
670 rc = ber_printf( ber, "tb",
671 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
675 rc = ber_printf( ber, /*"{"*/ "N}" );
681 if( !ldap_is_desc( str ) ) {
685 char *nextstar = ldap_pvt_find_wildcard( value );
687 if ( nextstar == NULL ) {
690 } else if ( *nextstar == '\0' ) {
691 ftype = LDAP_FILTER_EQUALITY;
693 } else if ( strcmp( value, "*" ) == 0 ) {
694 ftype = LDAP_FILTER_PRESENT;
697 rc = put_substring_filter( ber, str, value, nextstar );
703 if( !ldap_is_desc( str ) ) goto done;
705 if ( ftype == LDAP_FILTER_PRESENT ) {
706 rc = ber_printf( ber, "ts", ftype, str );
709 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
712 rc = ber_printf( ber, "t{soN}",
713 ftype, str, value, len );
718 if( rc != -1 ) rc = 0;
724 put_substring_filter( BerElement *ber, char *type, char *val, char *nextstar )
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 ) {
738 nextstar = ldap_pvt_find_wildcard( val );
740 if ( nextstar == NULL ) {
744 if ( *nextstar == '\0' ) {
745 ftype = LDAP_SUBSTRING_FINAL;
748 if ( gotstar++ == 0 ) {
749 ftype = LDAP_SUBSTRING_INITIAL;
751 ftype = LDAP_SUBSTRING_ANY;
755 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
756 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
762 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
768 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {
776 put_vrFilter( BerElement *ber, const char *str_in )
782 int parens, balance, escape;
785 * A ValuesReturnFilter looks like this:
787 * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
788 * SimpleFilterItem ::= CHOICE {
789 * equalityMatch [3] AttributeValueAssertion,
790 * substrings [4] SubstringFilter,
791 * greaterOrEqual [5] AttributeValueAssertion,
792 * lessOrEqual [6] AttributeValueAssertion,
793 * present [7] AttributeType,
794 * approxMatch [8] AttributeValueAssertion,
795 * extensibleMatch [9] SimpleMatchingAssertion -- LDAPv3
798 * SubstringFilter ::= SEQUENCE {
799 * type AttributeType,
800 * SEQUENCE OF CHOICE {
801 * initial [0] IA5String,
803 * final [2] IA5String
807 * SimpleMatchingAssertion ::= SEQUENCE { -- LDAPv3
808 * matchingRule [1] MatchingRuleId OPTIONAL,
809 * type [2] AttributeDescription OPTIONAL,
810 * matchValue [3] AssertionValue }
815 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
817 freeme = LDAP_STRDUP( str_in );
818 if( freeme == NULL ) return LDAP_NO_MEMORY;
829 while( LDAP_SPACE( *str ) ) str++;
833 if ( (next = find_right_paren( str )) == NULL ) {
840 if ( put_vrFilter_list( ber, str ) == -1 ) {
855 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n",
862 while ( *next && balance ) {
864 if ( *next == '(' ) {
866 } else if ( *next == ')' ) {
871 if ( *next == '\\' && ! escape ) {
877 if ( balance ) next++;
880 if ( balance != 0 ) {
887 if ( put_simple_vrFilter( ber, str ) == -1 ) {
892 *next++ = /*'('*/ ')';
901 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: end\n",
903 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
915 default: /* assume it's a simple type=value filter */
916 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: default\n",
918 next = strchr( str, '\0' );
919 if ( put_simple_vrFilter( ber, str ) == -1 ) {
928 rc = parens ? -1 : 0;
936 ldap_put_vrFilter( BerElement *ber, const char *str_in )
940 if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) {
944 rc = put_vrFilter( ber, str_in );
946 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
954 put_vrFilter_list( BerElement *ber, char *str )
959 Debug( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n",
963 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
966 if ( *str == '\0' ) break;
968 if ( (next = find_right_paren( str + 1 )) == NULL ) {
973 /* now we have "(filter)" with str pointing to it */
975 if ( put_vrFilter( ber, str ) == -1 ) return -1;
993 Debug( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n",
996 str = LDAP_STRDUP( str );
997 if( str == NULL ) return -1;
999 if ( (s = strchr( str, '=' )) == NULL ) {
1008 ftype = LDAP_FILTER_LE;
1013 ftype = LDAP_FILTER_GE;
1018 ftype = LDAP_FILTER_APPROX;
1023 /* According to ValuesReturnFilter control definition
1024 * extensible filters are off the form:
1025 * type [:rule] := value
1028 ftype = LDAP_FILTER_EXT;
1032 char *rule = strchr( str, ':' );
1034 if( rule == NULL ) {
1035 /* must have attribute */
1036 if( !ldap_is_desc( str ) ) {
1044 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
1045 /* must have either type or rule */
1049 if ( *str != '\0' && !ldap_is_desc( str ) ) {
1053 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
1057 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
1059 if( rc != -1 && rule && *rule != '\0' ) {
1060 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
1063 if( rc != -1 && *str != '\0' ) {
1064 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
1068 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1071 rc = ber_printf( ber, "to",
1072 LDAP_FILTER_EXT_VALUE, value, len );
1079 rc = ber_printf( ber, /*"{"*/ "N}" );
1085 if( !ldap_is_desc( str ) ) {
1089 char *nextstar = ldap_pvt_find_wildcard( value );
1091 if ( nextstar == NULL ) {
1094 } else if ( *nextstar == '\0' ) {
1095 ftype = LDAP_FILTER_EQUALITY;
1097 } else if ( strcmp( value, "*" ) == 0 ) {
1098 ftype = LDAP_FILTER_PRESENT;
1101 rc = put_substring_filter( ber, str, value, nextstar );
1107 if( !ldap_is_desc( str ) ) goto done;
1109 if ( ftype == LDAP_FILTER_PRESENT ) {
1110 rc = ber_printf( ber, "ts", ftype, str );
1113 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1116 rc = ber_printf( ber, "t{soN}",
1117 ftype, str, value, len );
1122 if( rc != -1 ) rc = 0;