3 * Copyright 1998-2000 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 char *put_complex_filter LDAP_P((
31 static int put_simple_filter LDAP_P((
35 static int put_substring_filter LDAP_P((
40 static int put_filter_list LDAP_P((
45 static int ldap_is_oid ( const char *str )
49 if( LDAP_ALPHA( str[0] )) {
50 for( i=1; str[i]; i++ ) {
51 if( !LDAP_LDH( str[i] )) {
57 } else if LDAP_DIGIT( str[0] ) {
59 for( i=1; str[i]; i++ ) {
60 if( LDAP_DIGIT( str[i] )) {
63 } else if ( str[i] == '.' ) {
65 if( ++dot > 1 ) return 0;
77 static int ldap_is_desc ( const char *str )
81 if( LDAP_ALPHA( str[0] )) {
82 for( i=1; str[i]; i++ ) {
88 if( !LDAP_LDH( str[i] )) {
94 } else if LDAP_DIGIT( str[0] ) {
96 for( i=1; str[i]; i++ ) {
103 if( LDAP_DIGIT( str[i] )) {
106 } else if ( str[i] == '.' ) {
108 if( ++dot > 1 ) return 0;
120 if( !LDAP_LDH( str[0] )) {
123 for( i=1; str[i]; i++ ) {
124 if( str[i] == ';' ) {
128 if( !LDAP_LDH( str[i] )) {
136 find_right_paren( char *s )
142 while ( *s && balance ) {
146 } else if ( *s == ')' ) {
151 escape = ( *s == '\\' && !escape );
156 return *s ? s : NULL;
159 static int hex2value( int c )
161 if( c >= '0' && c <= '9' ) {
165 if( c >= 'A' && c <= 'F' ) {
166 return c + (10 - (int) 'A');
169 if( c >= 'a' && c <= 'f' ) {
170 return c + (10 - (int) 'a');
177 ldap_pvt_find_wildcard( const char *s )
181 case '*': /* found wildcard */
185 if( s[1] == '\0' ) return NULL;
187 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
190 } else switch( s[1] ) {
194 /* allow RFC 1960 escapes */
207 /* unescape filter value */
208 /* support both LDAP v2 and v3 escapes */
209 /* output can include nul characters! */
211 ldap_pvt_filter_value_unescape( char *fval )
216 for( r=v=0; fval[v] != '\0'; v++ ) {
222 if ( fval[v] == '\0' ) {
223 /* escape at end of string */
227 if (( v1 = hex2value( fval[v] )) >= 0 ) {
229 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
230 /* must be two digit code */
234 fval[r++] = v1 * 16 + v2;
263 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
268 * We have (x(filter)...) with str sitting on
269 * the x. We have to find the paren matching
270 * the one before the x and put the intervening
271 * filters by calling put_filter_list().
274 /* put explicit tag */
275 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
280 if ( (next = find_right_paren( str )) == NULL ) {
285 if ( put_filter_list( ber, str, tag ) == -1 ) {
292 /* flush explicit tagged thang */
293 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
301 ldap_int_put_filter( BerElement *ber, const char *str_in )
307 int parens, balance, escape;
310 * A Filter looks like this:
311 * Filter ::= CHOICE {
312 * and [0] SET OF Filter,
313 * or [1] SET OF Filter,
315 * equalityMatch [3] AttributeValueAssertion,
316 * substrings [4] SubstringFilter,
317 * greaterOrEqual [5] AttributeValueAssertion,
318 * lessOrEqual [6] AttributeValueAssertion,
319 * present [7] AttributeType,
320 * approxMatch [8] AttributeValueAssertion,
321 * extensibleMatch [9] MatchingRuleAssertion -- LDAPv3
324 * SubstringFilter ::= SEQUENCE {
325 * type AttributeType,
326 * SEQUENCE OF CHOICE {
327 * initial [0] IA5String,
329 * final [2] IA5String
333 * MatchingRuleAssertion ::= SEQUENCE { -- LDAPv3
334 * matchingRule [1] MatchingRuleId OPTIONAL,
335 * type [2] AttributeDescription OPTIONAL,
336 * matchValue [3] AssertionValue,
337 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
339 * Note: tags in a choice are always explicit
342 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
344 freeme = LDAP_STRDUP( str_in );
345 if( freeme == NULL ) return LDAP_NO_MEMORY;
356 while( LDAP_SPACE( *str ) ) str++;
360 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
363 str = put_complex_filter( ber, str,
364 LDAP_FILTER_AND, 0 );
374 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
377 str = put_complex_filter( ber, str,
388 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
391 str = put_complex_filter( ber, str,
392 LDAP_FILTER_NOT, 0 );
402 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
409 while ( *next && balance ) {
411 if ( *next == '(' ) {
413 } else if ( *next == ')' ) {
418 if ( *next == '\\' && ! escape ) {
424 if ( balance ) next++;
427 if ( balance != 0 ) {
434 if ( put_simple_filter( ber, str ) == -1 ) {
439 *next++ = /*'('*/ ')';
448 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
450 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
462 default: /* assume it's a simple type=value filter */
463 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
465 next = strchr( str, '\0' );
466 if ( put_simple_filter( ber, str ) == -1 ) {
475 rc = parens ? -1 : 0;
483 * Put a list of filters like this "(filter1)(filter2)..."
487 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
492 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
496 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
499 if ( *str == '\0' ) break;
501 if ( (next = find_right_paren( str + 1 )) == NULL ) {
506 /* now we have "(filter)" with str pointing to it */
508 if ( ldap_int_put_filter( ber, str ) == -1 ) return -1;
512 if( tag == LDAP_FILTER_NOT ) break;
515 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
532 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
535 str = LDAP_STRDUP( str );
536 if( str == NULL ) return -1;
538 if ( (s = strchr( str, '=' )) == NULL ) {
547 ftype = LDAP_FILTER_LE;
552 ftype = LDAP_FILTER_GE;
557 ftype = LDAP_FILTER_APPROX;
562 /* RFC2254 extensible filters are off the form:
563 * type [:dn] [:rule] := value
564 * or [:dn]:rule := value
566 ftype = LDAP_FILTER_EXT;
570 char *dn = strchr( str, ':' );
575 rule = strchr( dn, ':' );
579 if ( strcmp(dn, "dn") == 0 ) {
580 /* must have attribute */
581 if( !ldap_is_desc( str ) ) {
596 if ( strcmp(dn, "dn") != 0 ) {
604 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
605 /* must have either type or rule */
609 if ( *str != '\0' && !ldap_is_desc( str ) ) {
613 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
617 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
619 if( rc != -1 && rule && *rule != '\0' ) {
620 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
623 if( rc != -1 && *str != '\0' ) {
624 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
628 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
631 rc = ber_printf( ber, "to",
632 LDAP_FILTER_EXT_VALUE, value, len );
638 if( rc != -1 && dn ) {
639 rc = ber_printf( ber, "tb",
640 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
644 rc = ber_printf( ber, /*"{"*/ "N}" );
650 if( !ldap_is_desc( str ) ) {
654 char *nextstar = ldap_pvt_find_wildcard( value );
656 if ( nextstar == NULL ) {
659 } else if ( *nextstar == '\0' ) {
660 ftype = LDAP_FILTER_EQUALITY;
662 } else if ( strcmp( value, "*" ) == 0 ) {
663 ftype = LDAP_FILTER_PRESENT;
666 rc = put_substring_filter( ber, str, value );
672 if( !ldap_is_desc( str ) ) goto done;
674 if ( ftype == LDAP_FILTER_PRESENT ) {
675 rc = ber_printf( ber, "ts", ftype, str );
678 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
681 rc = ber_printf( ber, "t{soN}",
682 ftype, str, value, len );
687 if( rc != -1 ) rc = 0;
693 put_substring_filter( BerElement *ber, char *type, char *val )
697 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
699 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
702 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
706 for( ; *val; val=nextstar ) {
707 nextstar = ldap_pvt_find_wildcard( val );
709 if ( nextstar == NULL ) {
713 if ( *nextstar == '\0' ) {
714 ftype = LDAP_SUBSTRING_FINAL;
715 } else if ( gotstar++ == 0 ) {
716 ftype = LDAP_SUBSTRING_INITIAL;
718 ftype = LDAP_SUBSTRING_ANY;
723 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
724 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
730 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
736 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {