3 * Copyright 1998-2002 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 */
189 if( s[1] == '\0' ) return NULL;
191 if( LDAP_HEX( s[1] ) && LDAP_HEX( s[2] ) ) {
194 } else switch( s[1] ) {
198 /* allow RFC 1960 escapes */
211 /* unescape filter value */
212 /* support both LDAP v2 and v3 escapes */
213 /* output can include nul characters! */
215 ldap_pvt_filter_value_unescape( char *fval )
220 for( r=v=0; fval[v] != '\0'; v++ ) {
231 if ( fval[v] == '\0' ) {
232 /* escape at end of string */
236 if (( v1 = hex2value( fval[v] )) >= 0 ) {
238 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
239 /* must be two digit code */
243 fval[r++] = v1 * 16 + v2;
272 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
277 * We have (x(filter)...) with str sitting on
278 * the x. We have to find the paren matching
279 * the one before the x and put the intervening
280 * filters by calling put_filter_list().
283 /* put explicit tag */
284 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
289 if ( (next = find_right_paren( str )) == NULL ) {
294 if ( put_filter_list( ber, str, tag ) == -1 ) {
301 /* flush explicit tagged thang */
302 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
310 ldap_int_put_filter( BerElement *ber, const char *str_in )
316 int parens, balance, escape;
319 * A Filter looks like this:
320 * Filter ::= CHOICE {
321 * and [0] SET OF Filter,
322 * or [1] SET OF Filter,
324 * equalityMatch [3] AttributeValueAssertion,
325 * substrings [4] SubstringFilter,
326 * greaterOrEqual [5] AttributeValueAssertion,
327 * lessOrEqual [6] AttributeValueAssertion,
328 * present [7] AttributeType,
329 * approxMatch [8] AttributeValueAssertion,
330 * extensibleMatch [9] MatchingRuleAssertion -- LDAPv3
333 * SubstringFilter ::= SEQUENCE {
334 * type AttributeType,
335 * SEQUENCE OF CHOICE {
336 * initial [0] IA5String,
338 * final [2] IA5String
342 * MatchingRuleAssertion ::= SEQUENCE { -- LDAPv3
343 * matchingRule [1] MatchingRuleId OPTIONAL,
344 * type [2] AttributeDescription OPTIONAL,
345 * matchValue [3] AssertionValue,
346 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
348 * Note: tags in a choice are always explicit
351 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
353 freeme = LDAP_STRDUP( str_in );
354 if( freeme == NULL ) return LDAP_NO_MEMORY;
365 while( LDAP_SPACE( *str ) ) str++;
369 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
372 str = put_complex_filter( ber, str,
373 LDAP_FILTER_AND, 0 );
383 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
386 str = put_complex_filter( ber, str,
397 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
400 str = put_complex_filter( ber, str,
401 LDAP_FILTER_NOT, 0 );
411 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
418 while ( *next && balance ) {
420 if ( *next == '(' ) {
422 } else if ( *next == ')' ) {
427 if ( *next == '\\' && ! escape ) {
433 if ( balance ) next++;
436 if ( balance != 0 ) {
443 if ( put_simple_filter( ber, str ) == -1 ) {
448 *next++ = /*'('*/ ')';
457 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
459 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
471 default: /* assume it's a simple type=value filter */
472 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
474 next = strchr( str, '\0' );
475 if ( put_simple_filter( ber, str ) == -1 ) {
484 rc = parens ? -1 : 0;
492 * Put a list of filters like this "(filter1)(filter2)..."
496 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
501 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
505 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
508 if ( *str == '\0' ) break;
510 if ( (next = find_right_paren( str + 1 )) == NULL ) {
515 /* now we have "(filter)" with str pointing to it */
517 if ( ldap_int_put_filter( ber, str ) == -1 ) return -1;
521 if( tag == LDAP_FILTER_NOT ) break;
524 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
541 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
544 str = LDAP_STRDUP( str );
545 if( str == NULL ) return -1;
547 if ( (s = strchr( str, '=' )) == NULL ) {
556 ftype = LDAP_FILTER_LE;
561 ftype = LDAP_FILTER_GE;
566 ftype = LDAP_FILTER_APPROX;
571 /* RFC2254 extensible filters are off the form:
572 * type [:dn] [:rule] := value
573 * or [:dn]:rule := value
575 ftype = LDAP_FILTER_EXT;
579 char *dn = strchr( str, ':' );
584 rule = strchr( dn, ':' );
588 if ( strcmp(dn, "dn") == 0 ) {
589 /* must have attribute */
590 if( !ldap_is_desc( str ) ) {
605 if ( strcmp(dn, "dn") != 0 ) {
613 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
614 /* must have either type or rule */
618 if ( *str != '\0' && !ldap_is_desc( str ) ) {
622 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
626 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
628 if( rc != -1 && rule && *rule != '\0' ) {
629 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
632 if( rc != -1 && *str != '\0' ) {
633 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
637 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
640 rc = ber_printf( ber, "to",
641 LDAP_FILTER_EXT_VALUE, value, len );
647 if( rc != -1 && dn ) {
648 rc = ber_printf( ber, "tb",
649 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
653 rc = ber_printf( ber, /*"{"*/ "N}" );
659 if( !ldap_is_desc( str ) ) {
663 char *nextstar = ldap_pvt_find_wildcard( value );
665 if ( nextstar == NULL ) {
668 } else if ( *nextstar == '\0' ) {
669 ftype = LDAP_FILTER_EQUALITY;
671 } else if ( strcmp( value, "*" ) == 0 ) {
672 ftype = LDAP_FILTER_PRESENT;
675 rc = put_substring_filter( ber, str, value );
681 if( !ldap_is_desc( str ) ) goto done;
683 if ( ftype == LDAP_FILTER_PRESENT ) {
684 rc = ber_printf( ber, "ts", ftype, str );
687 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
690 rc = ber_printf( ber, "t{soN}",
691 ftype, str, value, len );
696 if( rc != -1 ) rc = 0;
702 put_substring_filter( BerElement *ber, char *type, char *val )
706 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
708 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
711 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
715 for( ; *val; val=nextstar ) {
716 nextstar = ldap_pvt_find_wildcard( val );
718 if ( nextstar == NULL ) {
722 if ( *nextstar == '\0' ) {
723 ftype = LDAP_SUBSTRING_FINAL;
724 } else if ( gotstar++ == 0 ) {
725 ftype = LDAP_SUBSTRING_INITIAL;
727 ftype = LDAP_SUBSTRING_ANY;
732 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
733 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
739 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
745 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {