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_pvt_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
352 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS, "ldap_pvt_put_filter: \"%s\"\n",
355 Debug( LDAP_DEBUG_TRACE, "put_filter: \"%s\"\n", str_in, 0, 0 );
358 freeme = LDAP_STRDUP( str_in );
359 if( freeme == NULL ) return LDAP_NO_MEMORY;
370 while( LDAP_SPACE( *str ) ) str++;
375 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
376 "ldap_pvt_put_filter: AND\n" ));
378 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
382 str = put_complex_filter( ber, str,
383 LDAP_FILTER_AND, 0 );
394 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
395 "ldap_pvt_put_filter: OR\n" ));
397 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
401 str = put_complex_filter( ber, str,
413 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
414 "ldap_pvt_put_filter: NOT\n" ));
416 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
420 str = put_complex_filter( ber, str,
421 LDAP_FILTER_NOT, 0 );
432 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
433 "ldap_pvt_put_filter: simple\n" ));
435 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
443 while ( *next && balance ) {
445 if ( *next == '(' ) {
447 } else if ( *next == ')' ) {
452 if ( *next == '\\' && ! escape ) {
458 if ( balance ) next++;
461 if ( balance != 0 ) {
468 if ( put_simple_filter( ber, str ) == -1 ) {
473 *next++ = /*'('*/ ')';
483 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
484 "ldap_pvt_put_filter: end\n" ));
486 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n",
489 if ( ber_printf( ber, /*"["*/ "]" ) == -1 ) {
501 default: /* assume it's a simple type=value filter */
503 LDAP_LOG (( "filter", LDAP_LEVEL_DETAIL1,
504 "ldap_pvt_put_filter: default\n" ));
506 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n",
509 next = strchr( str, '\0' );
510 if ( put_simple_filter( ber, str ) == -1 ) {
519 rc = parens ? -1 : 0;
527 * Put a list of filters like this "(filter1)(filter2)..."
531 put_filter_list( BerElement *ber, char *str, ber_tag_t tag )
537 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS,
538 "put_filter_list \"%s\"\n", str ));
540 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n",
545 while ( *str && LDAP_SPACE( (unsigned char) *str ) ) {
548 if ( *str == '\0' ) break;
550 if ( (next = find_right_paren( str + 1 )) == NULL ) {
555 /* now we have "(filter)" with str pointing to it */
557 if ( ldap_pvt_put_filter( ber, str ) == -1 ) return -1;
561 if( tag == LDAP_FILTER_NOT ) break;
564 if( tag == LDAP_FILTER_NOT && ( next == NULL || *str )) {
582 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS,
583 "put_simple_filter: \"%s\"\n", str ));
585 Debug( LDAP_DEBUG_TRACE, "put_simple_filter: \"%s\"\n",
589 str = LDAP_STRDUP( str );
590 if( str == NULL ) return -1;
592 if ( (s = strchr( str, '=' )) == NULL ) {
601 ftype = LDAP_FILTER_LE;
606 ftype = LDAP_FILTER_GE;
611 ftype = LDAP_FILTER_APPROX;
616 /* RFC2254 extensible filters are off the form:
617 * type [:dn] [:rule] := value
618 * or [:dn]:rule := value
620 ftype = LDAP_FILTER_EXT;
624 char *dn = strchr( str, ':' );
629 rule = strchr( dn, ':' );
633 if ( strcmp(dn, "dn") == 0 ) {
634 /* must have attribute */
635 if( !ldap_is_desc( str ) ) {
650 if ( strcmp(dn, "dn") != 0 ) {
658 if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
659 /* must have either type or rule */
663 if ( *str != '\0' && !ldap_is_desc( str ) ) {
667 if ( rule && *rule != '\0' && !ldap_is_oid( rule ) ) {
671 rc = ber_printf( ber, "t{" /*"}"*/, ftype );
673 if( rc != -1 && rule && *rule != '\0' ) {
674 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
677 if( rc != -1 && *str != '\0' ) {
678 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
682 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
685 rc = ber_printf( ber, "to",
686 LDAP_FILTER_EXT_VALUE, value, len );
692 if( rc != -1 && dn ) {
693 rc = ber_printf( ber, "tb",
694 LDAP_FILTER_EXT_DNATTRS, (ber_int_t) 1 );
698 rc = ber_printf( ber, /*"{"*/ "N}" );
704 if( !ldap_is_desc( str ) ) {
708 char *nextstar = ldap_pvt_find_wildcard( value );
710 if ( nextstar == NULL ) {
713 } else if ( *nextstar == '\0' ) {
714 ftype = LDAP_FILTER_EQUALITY;
716 } else if ( strcmp( value, "*" ) == 0 ) {
717 ftype = LDAP_FILTER_PRESENT;
720 rc = put_substring_filter( ber, str, value );
726 if( !ldap_is_desc( str ) ) goto done;
728 if ( ftype == LDAP_FILTER_PRESENT ) {
729 rc = ber_printf( ber, "ts", ftype, str );
732 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
735 rc = ber_printf( ber, "t{soN}",
736 ftype, str, value, len );
741 if( rc != -1 ) rc = 0;
747 put_substring_filter( BerElement *ber, char *type, char *val )
751 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
754 LDAP_LOG (( "filter", LDAP_LEVEL_ARGS,
755 "put_substring_filter \"%s=%s\"\n", type, val ));
757 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n",
761 if ( ber_printf( ber, "t{s{" /*"}}"*/, ftype, type ) == -1 ) {
765 for( ; *val; val=nextstar ) {
766 nextstar = ldap_pvt_find_wildcard( val );
768 if ( nextstar == NULL ) {
772 if ( *nextstar == '\0' ) {
773 ftype = LDAP_SUBSTRING_FINAL;
776 if ( gotstar++ == 0 ) {
777 ftype = LDAP_SUBSTRING_INITIAL;
779 ftype = LDAP_SUBSTRING_ANY;
783 if ( *val != '\0' || ftype == LDAP_SUBSTRING_ANY ) {
784 ber_slen_t len = ldap_pvt_filter_value_unescape( val );
790 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
796 if ( ber_printf( ber, /*"{{"*/ "N}N}" ) == -1 ) {