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 */
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++ ) {
230 if ( fval[v] == '\0' ) {
231 /* escape at end of string */
235 if (( v1 = hex2value( fval[v] )) >= 0 ) {
237 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
238 /* must be two digit code */
242 fval[r++] = v1 * 16 + v2;
271 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
276 * We have (x(filter)...) with str sitting on
277 * the x. We have to find the paren matching
278 * the one before the x and put the intervening
279 * filters by calling put_filter_list().
282 /* put explicit tag */
283 if ( ber_printf( ber, "t{" /*"}"*/, tag ) == -1 ) {
288 if ( (next = find_right_paren( str )) == NULL ) {
293 if ( put_filter_list( ber, str, tag ) == -1 ) {
300 /* flush explicit tagged thang */
301 if ( ber_printf( ber, /*"{"*/ "N}" ) == -1 ) {
309 ldap_int_put_filter( BerElement *ber, const char *str_in )
315 int parens, balance, escape;
318 * A Filter looks like this:
319 * Filter ::= CHOICE {
320 * and [0] SET OF Filter,
321 * or [1] SET OF Filter,
323 * equalityMatch [3] AttributeValueAssertion,
324 * substrings [4] SubstringFilter,
325 * greaterOrEqual [5] AttributeValueAssertion,
326 * lessOrEqual [6] AttributeValueAssertion,
327 * present [7] AttributeType,
328 * approxMatch [8] AttributeValueAssertion,
329 * extensibleMatch [9] MatchingRuleAssertion -- LDAPv3
332 * SubstringFilter ::= SEQUENCE {
333 * type AttributeType,
334 * SEQUENCE OF CHOICE {
335 * initial [0] IA5String,
337 * final [2] IA5String
341 * MatchingRuleAssertion ::= SEQUENCE { -- LDAPv3
342 * matchingRule [1] MatchingRuleId OPTIONAL,
343 * type [2] AttributeDescription OPTIONAL,
344 * matchValue [3] AssertionValue,
345 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
347 * Note: tags in a choice are always explicit
350 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
352 freeme = LDAP_STRDUP( str_in );
353 if( freeme == NULL ) return LDAP_NO_MEMORY;
364 while( LDAP_SPACE( *str ) ) str++;
368 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
371 str = put_complex_filter( ber, str,
372 LDAP_FILTER_AND, 0 );
382 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
385 str = put_complex_filter( ber, str,
396 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
399 str = put_complex_filter( ber, str,
400 LDAP_FILTER_NOT, 0 );
410 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
417 while ( *next && balance ) {
419 if ( *next == '(' ) {
421 } else if ( *next == ')' ) {
426 if ( *next == '\\' && ! escape ) {
432 if ( balance ) next++;
435 if ( balance != 0 ) {
442 if ( put_simple_filter( ber, str ) == -1 ) {
447 *next++ = /*'('*/ ')';
456 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
458 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
470 default: /* assume it's a simple type=value filter */
471 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
473 next = strchr( str, '\0' );
474 if ( put_simple_filter( ber, str ) == -1 ) {
483 rc = parens ? -1 : 0;
491 * Put a list of filters like this "(filter1)(filter2)..."
495 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
500 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
504 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
507 if ( *str == '\0' ) break;
509 if ( (next = find_right_paren( str + 1 )) == NULL ) {
514 /* now we have "(filter)" with str pointing to it */
516 if ( ldap_int_put_filter( ber, str ) == -1 ) return -1;
520 if( tag == LDAP_FILTER_NOT ) break;
523 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
540 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
543 str = LDAP_STRDUP( str );
544 if( str == NULL ) return -1;
546 if ( (s = strchr( str, '=' )) == NULL ) {
555 ftype = LDAP_FILTER_LE;
560 ftype = LDAP_FILTER_GE;
565 ftype = LDAP_FILTER_APPROX;
570 /* RFC2254 extensible filters are off the form:
571 * type [:dn] [:rule] := value
572 * or [:dn]:rule := value
574 ftype = LDAP_FILTER_EXT;
578 char *dn = strchr( str, ':' );
583 rule = strchr( dn, ':' );
587 if ( strcmp(dn, "dn") == 0 ) {
588 /* must have attribute */
589 if( !ldap_is_desc( str ) ) {
604 if ( strcmp(dn, "dn") != 0 ) {
612 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
613 /* must have either type or rule */
617 if ( *str != '\0' && !ldap_is_desc( str ) ) {
621 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
625 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
627 if( rc != -1 && rule && *rule != '\0' ) {
628 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
631 if( rc != -1 && *str != '\0' ) {
632 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
636 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
639 rc = ber_printf( ber, "to",
640 LDAP_FILTER_EXT_VALUE, value, len );
646 if( rc != -1 && dn ) {
647 rc = ber_printf( ber, "tb",
648 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
652 rc = ber_printf( ber, /*"{"*/ "N}" );
658 if( !ldap_is_desc( str ) ) {
662 char *nextstar = ldap_pvt_find_wildcard( value );
664 if ( nextstar == NULL ) {
667 } else if ( *nextstar == '\0' ) {
668 ftype = LDAP_FILTER_EQUALITY;
670 } else if ( strcmp( value, "*" ) == 0 ) {
671 ftype = LDAP_FILTER_PRESENT;
674 rc = put_substring_filter( ber, str, value );
680 if( !ldap_is_desc( str ) ) goto done;
682 if ( ftype == LDAP_FILTER_PRESENT ) {
683 rc = ber_printf( ber, "ts", ftype, str );
686 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
689 rc = ber_printf( ber, "t{soN}",
690 ftype, str, value, len );
695 if( rc != -1 ) rc = 0;
701 put_substring_filter( BerElement *ber, char *type, char *val )
705 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
707 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
710 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
714 for( ; *val; val=nextstar ) {
715 nextstar = ldap_pvt_find_wildcard( val );
717 if ( nextstar == NULL ) {
721 if ( *nextstar == '\0' ) {
722 ftype = LDAP_SUBSTRING_FINAL;
723 } else if ( gotstar++ == 0 ) {
724 ftype = LDAP_SUBSTRING_INITIAL;
726 ftype = LDAP_SUBSTRING_ANY;
731 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
732 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
738 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
744 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {