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 )
279 if ( (next = find_right_paren( str )) == NULL )
283 if ( put_filter_list( ber, str, tag ) == -1 )
289 /* flush explicit tagged thang */
290 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 )
297 ldap_int_put_filter( BerElement *ber, char *str )
300 int parens, balance, escape;
303 * A Filter looks like this:
304 * Filter ::= CHOICE {
305 * and [0] SET OF Filter,
306 * or [1] SET OF Filter,
308 * equalityMatch [3] AttributeValueAssertion,
309 * substrings [4] SubstringFilter,
310 * greaterOrEqual [5] AttributeValueAssertion,
311 * lessOrEqual [6] AttributeValueAssertion,
312 * present [7] AttributeType,
313 * approxMatch [8] AttributeValueAssertion,
314 * extensibleMatch [9] MatchingRuleAssertion -- LDAPv3
317 * SubstringFilter ::= SEQUENCE {
318 * type AttributeType,
319 * SEQUENCE OF CHOICE {
320 * initial [0] IA5String,
322 * final [2] IA5String
326 * MatchingRuleAssertion ::= SEQUENCE { -- LDAPv3
327 * matchingRule [1] MatchingRuleId OPTIONAL,
328 * type [2] AttributeDescription OPTIONAL,
329 * matchValue [3] AssertionValue,
330 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
332 * Note: tags in a choice are always explicit
335 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str, 0, 0 );
345 while( LDAP_SPACE( *str ) ) str++;
349 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
352 str = put_complex_filter( ber, str,
353 LDAP_FILTER_AND, 0 );
354 if( str == NULL ) return( -1 );
360 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
363 str = put_complex_filter( ber, str,
365 if( str == NULL ) return( -1 );
371 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
374 str = put_complex_filter( ber, str,
375 LDAP_FILTER_NOT, 0 );
376 if( str == NULL ) return( -1 );
382 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
388 while ( *next && balance ) {
392 else if ( *next == ')' )
395 if ( *next == '\\' && ! escape )
406 if ( put_simple_filter( ber, str ) == -1 ) {
417 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
419 if ( ber_printf( ber, /*"["*/ "]" ) == -1 )
429 default: /* assume it's a simple type=value filter */
430 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
432 next = strchr( str, '\0' );
433 if ( put_simple_filter( ber, str ) == -1 ) {
441 return( parens ? -1 : 0 );
445 * Put a list of filters like this "(filter1)(filter2)..."
449 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
454 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
458 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
461 if ( *str == '\0' ) break;
463 if ( (next = find_right_paren( str + 1 )) == NULL ) {
468 /* now we have "(filter)" with str pointing to it */
470 if ( ldap_int_put_filter( ber, str ) == -1 ) return -1;
474 if( tag == LDAP_FILTER_NOT ) break;
477 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
494 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
497 str = LDAP_STRDUP( str );
498 if( str == NULL ) return -1;
500 if ( (s = strchr( str, '=' )) == NULL ) {
509 ftype = LDAP_FILTER_LE;
514 ftype = LDAP_FILTER_GE;
519 ftype = LDAP_FILTER_APPROX;
524 /* RFC2254 extensible filters are off the form:
525 * type [:dn] [:rule] := value
526 * or [:dn]:rule := value
528 ftype = LDAP_FILTER_EXT;
532 char *dn = strchr( str, ':' );
537 rule = strchr( dn, ':' );
541 if ( strcmp(dn, "dn") == 0 ) {
542 /* must have attribute */
543 if( !ldap_is_desc( str ) ) {
558 if ( strcmp(dn, "dn") != 0 ) {
566 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
567 /* must have either type or rule */
571 if ( *str != '\0' && !ldap_is_desc( str ) ) {
575 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
579 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
581 if( rc != -1 && rule && *rule != '\0' ) {
582 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
584 if( rc != -1 && *str != '\0' ) {
585 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
588 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
591 rc = ber_printf( ber, "to",
592 LDAP_FILTER_EXT_VALUE, value, len );
597 if( rc != -1 && dn ) {
598 rc = ber_printf( ber, "tb",
599 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
602 rc = ber_printf( ber, /*"{"*/ "N}" );
609 char *nextstar = ldap_pvt_find_wildcard( value );
610 if ( nextstar == NULL ) {
612 } else if ( *nextstar == '\0' ) {
613 ftype = LDAP_FILTER_EQUALITY;
614 } else if ( strcmp( value, "*" ) == 0 ) {
615 ftype = LDAP_FILTER_PRESENT;
617 rc = put_substring_filter( ber, str, value );
623 if( !ldap_is_desc( str ) ) goto done;
625 if ( ftype == LDAP_FILTER_PRESENT ) {
626 rc = ber_printf( ber, "ts", ftype, str );
629 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
632 rc = ber_printf( ber, "t{soN}",
633 ftype, str, value, len );
638 if( rc != -1 ) rc = 0;
644 put_substring_filter( BerElement *ber, char *type, char *val )
648 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
650 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
653 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 )
656 for( ; *val; val=nextstar ) {
657 nextstar = ldap_pvt_find_wildcard( val );
659 if ( nextstar == NULL ) {
663 if ( *nextstar == '\0' ) {
664 ftype = LDAP_SUBSTRING_FINAL;
665 } else if ( gotstar++ == 0 ) {
666 ftype = LDAP_SUBSTRING_INITIAL;
668 ftype = LDAP_SUBSTRING_ANY;
673 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
674 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
680 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
686 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 )