3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2004 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.
19 /* Portions Copyright (C) The Internet Society (1997).
20 * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
27 #include <ac/stdlib.h>
29 #include <ac/socket.h>
30 #include <ac/string.h>
35 static int put_simple_vrFilter LDAP_P((
39 static int put_vrFilter_list LDAP_P((
43 static char *put_complex_filter LDAP_P((
49 static int put_simple_filter LDAP_P((
53 static int put_substring_filter LDAP_P((
58 static int put_filter_list LDAP_P((
63 static int ldap_is_oid ( const char *str )
67 if( LDAP_ALPHA( str[0] )) {
68 for( i=1; str[i]; i++ ) {
69 if( !LDAP_LDH( str[i] )) {
75 } else if LDAP_DIGIT( str[0] ) {
77 for( i=1; str[i]; i++ ) {
78 if( LDAP_DIGIT( str[i] )) {
81 } else if ( str[i] == '.' ) {
83 if( ++dot > 1 ) return 0;
95 static int ldap_is_desc ( const char *str )
99 if( LDAP_ALPHA( str[0] )) {
100 for( i=1; str[i]; i++ ) {
101 if( str[i] == ';' ) {
106 if( !LDAP_LDH( str[i] )) {
112 } else if LDAP_DIGIT( str[0] ) {
114 for( i=1; str[i]; i++ ) {
115 if( str[i] == ';' ) {
121 if( LDAP_DIGIT( str[i] )) {
124 } else if ( str[i] == '.' ) {
126 if( ++dot > 1 ) return 0;
138 if( !LDAP_LDH( str[0] )) {
141 for( i=1; str[i]; i++ ) {
142 if( str[i] == ';' ) {
146 if( !LDAP_LDH( str[i] )) {
154 find_right_paren( char *s )
160 while ( *s && balance ) {
164 } else if ( *s == ')' ) {
169 escape = ( *s == '\\' && !escape );
174 return *s ? s : NULL;
177 static int hex2value( int c )
179 if( c >= '0' && c <= '9' ) {
183 if( c >= 'A' && c <= 'F' ) {
184 return c + (10 - (int) 'A');
187 if( c >= 'a' && c <= 'f' ) {
188 return c + (10 - (int) 'a');
195 ldap_pvt_find_wildcard( const char *s )
199 case '*': /* found wildcard */
207 if( s[1] == '\0' ) return NULL;
209 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
212 } else switch( s[1] ) {
216 /* allow RFC 1960 escapes */
229 /* unescape filter value */
230 /* support both LDAP v2 and v3 escapes */
231 /* output can include nul characters! */
233 ldap_pvt_filter_value_unescape( char *fval )
238 for( r=v=0; fval[v] != '\0'; v++ ) {
249 if ( fval[v] == '\0' ) {
250 /* escape at end of string */
254 if (( v1 = hex2value( fval[v] )) >= 0 ) {
256 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
257 /* must be two digit code */
261 fval[r++] = v1 * 16 + v2;
290 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
295 * We have (x(filter)...) with str sitting on
296 * the x. We have to find the paren matching
297 * the one before the x and put the intervening
298 * filters by calling put_filter_list().
301 /* put explicit tag */
302 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
307 if ( (next = find_right_paren( str )) == NULL ) {
312 if ( put_filter_list( ber, str, tag ) == -1 ) {
319 /* flush explicit tagged thang */
320 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
328 ldap_pvt_put_filter( BerElement *ber, const char *str_in )
334 int parens, balance, escape;
337 * A Filter looks like this:
338 * Filter ::= CHOICE {
339 * and [0] SET OF Filter,
340 * or [1] SET OF Filter,
342 * equalityMatch [3] AttributeValueAssertion,
343 * substrings [4] SubstringFilter,
344 * greaterOrEqual [5] AttributeValueAssertion,
345 * lessOrEqual [6] AttributeValueAssertion,
346 * present [7] AttributeType,
347 * approxMatch [8] AttributeValueAssertion,
348 * extensibleMatch [9] MatchingRuleAssertion -- LDAPv3
351 * SubstringFilter ::= SEQUENCE {
352 * type AttributeType,
353 * SEQUENCE OF CHOICE {
354 * initial [0] IA5String,
356 * final [2] IA5String
360 * MatchingRuleAssertion ::= SEQUENCE { -- LDAPv3
361 * matchingRule [1] MatchingRuleId OPTIONAL,
362 * type [2] AttributeDescription OPTIONAL,
363 * matchValue [3] AssertionValue,
364 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
366 * Note: tags in a choice are always explicit
370 LDAP_LOG ( FILTER, ARGS, "ldap_pvt_put_filter: \"%s\"\n", str_in,0,0 );
372 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
375 freeme = LDAP_STRDUP( str_in );
376 if( freeme == NULL ) return LDAP_NO_MEMORY;
387 while( LDAP_SPACE( *str ) ) str++;
392 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: AND\n", 0,0,0 );
394 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
398 str = put_complex_filter( ber, str,
399 LDAP_FILTER_AND, 0 );
410 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: OR\n", 0,0,0 );
412 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
416 str = put_complex_filter( ber, str,
428 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: NOT\n", 0,0,0 );
430 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
434 str = put_complex_filter( ber, str,
435 LDAP_FILTER_NOT, 0 );
446 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: simple\n", 0,0,0);
448 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
456 while ( *next && balance ) {
458 if ( *next == '(' ) {
460 } else if ( *next == ')' ) {
465 if ( *next == '\\' && ! escape ) {
471 if ( balance ) next++;
474 if ( balance != 0 ) {
481 if ( put_simple_filter( ber, str ) == -1 ) {
486 *next++ = /*'('*/ ')';
496 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: end\n", 0,0,0 );
498 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
501 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
513 default: /* assume it's a simple type=value filter */
515 LDAP_LOG ( FILTER, DETAIL1, "ldap_pvt_put_filter: default\n", 0,0,0 );
517 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
520 next = strchr( str, '\0' );
521 if ( put_simple_filter( ber, str ) == -1 ) {
530 rc = parens ? -1 : 0;
538 * Put a list of filters like this "(filter1)(filter2)..."
542 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
548 LDAP_LOG ( FILTER, ARGS, "put_filter_list \"%s\"\n", str,0,0 );
550 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
555 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
558 if ( *str == '\0' ) break;
560 if ( (next = find_right_paren( str + 1 )) == NULL ) {
565 /* now we have "(filter)" with str pointing to it */
567 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1;
571 if( tag == LDAP_FILTER_NOT ) break;
574 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
592 LDAP_LOG ( FILTER, ARGS, "put_simple_filter: \"%s\"\n", str,0,0 );
594 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
598 str = LDAP_STRDUP( str );
599 if( str == NULL ) return -1;
601 if ( (s = strchr( str, '=' )) == NULL ) {
610 ftype = LDAP_FILTER_LE;
615 ftype = LDAP_FILTER_GE;
620 ftype = LDAP_FILTER_APPROX;
625 /* RFC2254 extensible filters are off the form:
626 * type [:dn] [:rule] := value
627 * or [:dn]:rule := value
629 ftype = LDAP_FILTER_EXT;
633 char *dn = strchr( str, ':' );
638 rule = strchr( dn, ':' );
642 if ( strcmp(dn, "dn") == 0 ) {
643 /* must have attribute */
644 if( !ldap_is_desc( str ) ) {
659 if ( strcmp(dn, "dn") != 0 ) {
667 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
668 /* must have either type or rule */
672 if ( *str != '\0' && !ldap_is_desc( str ) ) {
676 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
680 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
682 if( rc != -1 && rule && *rule != '\0' ) {
683 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
686 if( rc != -1 && *str != '\0' ) {
687 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
691 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
694 rc = ber_printf( ber, "to",
695 LDAP_FILTER_EXT_VALUE, value, len );
701 if( rc != -1 && dn ) {
702 rc = ber_printf( ber, "tb",
703 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
707 rc = ber_printf( ber, /*"{"*/ "N}" );
713 if( !ldap_is_desc( str ) ) {
717 char *nextstar = ldap_pvt_find_wildcard( value );
719 if ( nextstar == NULL ) {
722 } else if ( *nextstar == '\0' ) {
723 ftype = LDAP_FILTER_EQUALITY;
725 } else if ( strcmp( value, "*" ) == 0 ) {
726 ftype = LDAP_FILTER_PRESENT;
729 rc = put_substring_filter( ber, str, value );
735 if( !ldap_is_desc( str ) ) goto done;
737 if ( ftype == LDAP_FILTER_PRESENT ) {
738 rc = ber_printf( ber, "ts", ftype, str );
741 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
744 rc = ber_printf( ber, "t{soN}",
745 ftype, str, value, len );
750 if( rc != -1 ) rc = 0;
756 put_substring_filter( BerElement *ber, char *type, char *val )
760 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
763 LDAP_LOG ( FILTER, ARGS, "put_substring_filter \"%s=%s\"\n", type, val, 0 );
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 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, ARGS, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
852 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: \"%s\"\n", str_in, 0, 0 );
855 freeme = LDAP_STRDUP( str_in );
856 if( freeme == NULL ) return LDAP_NO_MEMORY;
867 while( LDAP_SPACE( *str ) ) str++;
871 if ( (next = find_right_paren( str )) == NULL ) {
878 if ( put_vrFilter_list( ber, str ) == -1 ) {
894 LDAP_LOG ( FILTER, DETAIL1,
895 "put_vrFilter: simple\n", 0, 0, 0 );
897 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: simple\n",
905 while ( *next && balance ) {
907 if ( *next == '(' ) {
909 } else if ( *next == ')' ) {
914 if ( *next == '\\' && ! escape ) {
920 if ( balance ) next++;
923 if ( balance != 0 ) {
930 if ( put_simple_vrFilter( ber, str ) == -1 ) {
935 *next++ = /*'('*/ ')';
945 LDAP_LOG ( FILTER, DETAIL1, "put_vrFilter: end\n", 0, 0, 0 );
947 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: end\n",
950 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
962 default: /* assume it's a simple type=value filter */
964 LDAP_LOG ( FILTER, DETAIL1, "put_vrFilter: default\n",
967 Debug( LDAP_DEBUG_TRACE, "put_vrFilter: default\n",
970 next = strchr( str, '\0' );
971 if ( put_simple_vrFilter( ber, str ) == -1 ) {
980 rc = parens ? -1 : 0;
988 ldap_put_vrFilter( BerElement *ber, const char *str_in )
992 if ( ber_printf( ber, "{" /*"}"*/ ) == -1 ) {
996 rc = put_vrFilter( ber, str_in );
998 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
1006 put_vrFilter_list( BerElement *ber, char *str )
1012 LDAP_LOG ( FILTER, ARGS, "put_vrFilter_list \"%s\"\n", str, 0, 0 );
1014 Debug( LDAP_DEBUG_TRACE, "put_vrFilter_list \"%s\"\n",
1019 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
1022 if ( *str == '\0' ) break;
1024 if ( (next = find_right_paren( str + 1 )) == NULL ) {
1029 /* now we have "(filter)" with str pointing to it */
1031 if ( put_vrFilter( ber, str ) == -1 ) return -1;
1040 put_simple_vrFilter(
1050 LDAP_LOG ( FILTER, ARGS, "put_simple_vrFilter: \"%s\"\n", str, 0, 0 );
1052 Debug( LDAP_DEBUG_TRACE, "put_simple_vrFilter: \"%s\"\n",
1056 str = LDAP_STRDUP( str );
1057 if( str == NULL ) return -1;
1059 if ( (s = strchr( str, '=' )) == NULL ) {
1068 ftype = LDAP_FILTER_LE;
1073 ftype = LDAP_FILTER_GE;
1078 ftype = LDAP_FILTER_APPROX;
1083 /* According to ValuesReturnFilter control definition
1084 * extensible filters are off the form:
1085 * type [:rule] := value
1088 ftype = LDAP_FILTER_EXT;
1092 char *rule = strchr( str, ':' );
1095 if( rule == NULL ) {
1096 /* must have attribute */
1097 if( !ldap_is_desc( str ) ) {
1103 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
1104 /* must have either type or rule */
1108 if ( *str != '\0' && !ldap_is_desc( str ) ) {
1112 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
1116 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
1118 if( rc != -1 && rule && *rule != '\0' ) {
1119 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
1122 if( rc != -1 && *str != '\0' ) {
1123 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
1127 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1130 rc = ber_printf( ber, "to",
1131 LDAP_FILTER_EXT_VALUE, value, len );
1138 rc = ber_printf( ber, /*"{"*/ "N}" );
1144 if( !ldap_is_desc( str ) ) {
1148 char *nextstar = ldap_pvt_find_wildcard( value );
1150 if ( nextstar == NULL ) {
1153 } else if ( *nextstar == '\0' ) {
1154 ftype = LDAP_FILTER_EQUALITY;
1156 } else if ( strcmp( value, "*" ) == 0 ) {
1157 ftype = LDAP_FILTER_PRESENT;
1160 rc = put_substring_filter( ber, str, value );
1166 if( !ldap_is_desc( str ) ) goto done;
1168 if ( ftype == LDAP_FILTER_PRESENT ) {
1169 rc = ber_printf( ber, "ts", ftype, str );
1172 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
1175 rc = ber_printf( ber, "t{soN}",
1176 ftype, str, value, len );
1181 if( rc != -1 ) rc = 0;