2 * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6 * Copyright (c) 1990 Regents of the University of Michigan.
16 #include <ac/stdlib.h>
19 #include <ac/socket.h>
20 #include <ac/string.h>
25 static int ldap_is_attr_oid LDAP_P((
28 static int ldap_is_attr_desc LDAP_P((
31 static int hex2value LDAP_P((
34 static ber_slen_t filter_value_unescape LDAP_P((
37 static char *find_right_paren LDAP_P((
40 static char *find_wildcard LDAP_P((
43 static char *put_complex_filter LDAP_P((
49 static int put_filter LDAP_P((
53 static int put_simple_filter LDAP_P((
57 static int put_substring_filter LDAP_P((
62 static int put_filter_list LDAP_P((
67 * ldap_search_ext - initiate an ldap search operation.
72 * base DN of the base object
73 * scope the search scope - one of LDAP_SCOPE_BASE,
74 * LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
75 * filter a string containing the search filter
76 * (e.g., "(|(cn=bob)(sn=bob))")
77 * attrs list of attribute types to return for matches
78 * attrsonly 1 => attributes only 0 => attributes and values
81 * char *attrs[] = { "mail", "title", 0 };
82 * ldap_search_ext( ld, "c=us,o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
83 * attrs, attrsonly, sctrls, ctrls, timeout, sizelimit,
89 LDAP_CONST char *base,
91 LDAP_CONST char *filter,
96 struct timeval *timeout,
103 Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
106 * if timeout is provided, use only tv_sec as timelimit.
107 * otherwise, use default.
109 timelimit = (timeout != NULL)
113 ber = ldap_build_search_req( ld, base, scope, filter, attrs,
114 attrsonly, sctrls, cctrls, timelimit, sizelimit );
121 if ( ld->ld_cache != NULL ) {
122 if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
124 ld->ld_errno = LDAP_SUCCESS;
125 *msgidp = ld->ld_msgid;
128 ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
130 #endif /* LDAP_NOCACHE */
132 /* send the message */
133 *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber );
144 LDAP_CONST char *base,
146 LDAP_CONST char *filter,
149 LDAPControl **sctrls,
150 LDAPControl **cctrls,
151 struct timeval *timeout,
158 rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly,
159 sctrls, cctrls, timeout, sizelimit, &msgid );
161 if ( rc != LDAP_SUCCESS ) {
165 if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 )
166 return( ld->ld_errno );
168 return( ldap_result2error( ld, *res, 0 ) );
172 * ldap_search - initiate an ldap search operation.
177 * base DN of the base object
178 * scope the search scope - one of LDAP_SCOPE_BASE,
179 * LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
180 * filter a string containing the search filter
181 * (e.g., "(|(cn=bob)(sn=bob))")
182 * attrs list of attribute types to return for matches
183 * attrsonly 1 => attributes only 0 => attributes and values
186 * char *attrs[] = { "mail", "title", 0 };
187 * msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
188 * attrs, attrsonly );
192 LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
193 char **attrs, int attrsonly )
197 Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
199 ber = ldap_build_search_req( ld, base, scope, filter, attrs,
200 attrsonly, NULL, NULL, -1, -1 );
207 if ( ld->ld_cache != NULL ) {
208 if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
210 ld->ld_errno = LDAP_SUCCESS;
211 return( ld->ld_msgid );
213 ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
215 #endif /* LDAP_NOCACHE */
217 /* send the message */
218 return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber ));
223 ldap_build_search_req(
225 LDAP_CONST char *base_in,
227 LDAP_CONST char *filter_in,
230 LDAPControl **sctrls,
231 LDAPControl **cctrls,
233 ber_int_t sizelimit )
241 * Create the search request. It looks like this:
242 * SearchRequest := [APPLICATION 3] SEQUENCE {
243 * baseObject DistinguishedName,
249 * derefAliases ENUMERATED {
250 * neverDerefaliases (0),
251 * derefInSearching (1),
252 * derefFindingBaseObj (2),
253 * alwaysDerefAliases (3)
255 * sizelimit INTEGER (0 .. 65535),
256 * timelimit INTEGER (0 .. 65535),
259 * attributes SEQUENCE OF AttributeType
261 * wrapped in an ldap message.
264 /* create a message to send */
265 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
269 if ( base_in == NULL ) {
270 /* no base provided, use session default base */
271 base = ld->ld_options.ldo_defbase;
273 base = (char *) base_in;
276 if ( base == NULL ) {
277 /* no session default base, use top */
281 #ifdef LDAP_CONNECTIONLESS
282 if ( ld->ld_cldapnaddr > 0 ) {
283 err = ber_printf( ber, "{ist{seeiib", ++ld->ld_msgid,
284 ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
285 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
286 (timelimit < 0) ? ld->ld_timelimit : timelimit,
289 #endif /* LDAP_CONNECTIONLESS */
290 err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid,
291 LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
292 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
293 (timelimit < 0) ? ld->ld_timelimit : timelimit,
295 #ifdef LDAP_CONNECTIONLESS
297 #endif /* LDAP_CONNECTIONLESS */
300 ld->ld_errno = LDAP_ENCODING_ERROR;
305 filter = LDAP_STRDUP( filter_in );
306 err = put_filter( ber, filter );
310 ld->ld_errno = LDAP_FILTER_ERROR;
315 if ( ber_printf( ber, /*{*/ "{v}}", attrs ) == -1 ) {
316 ld->ld_errno = LDAP_ENCODING_ERROR;
321 /* Put Server Controls */
322 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
327 if ( ber_printf( ber, /*{*/ "}", attrs ) == -1 ) {
328 ld->ld_errno = LDAP_ENCODING_ERROR;
336 static int ldap_is_attr_oid LDAP_P(( const char *attr ))
340 for( i=0 ; c = attr[i] ; i++ ) {
341 if( c >= '0' && c <= '9' ) {
344 } else if ( c != '.' ) {
345 /* not digit nor '.' */
348 } else if ( !digit ) {
349 /* '.' but prev not digit */
362 static int ldap_is_attr_desc LDAP_P(( const char *attr ))
364 /* cheap attribute description check */
367 for( i=0; c = attr[i]; i++ ) {
368 if (( c >= '0' && c <= '9' )
369 || ( c >= 'A' && c <= 'Z' )
370 || ( c >= 'a' && c <= 'z' )
371 || ( c == '.' || c == '-' )
372 || ( c == ';' )) continue;
381 find_right_paren( char *s )
387 while ( *s && balance ) {
391 else if ( *s == ')' )
394 if ( *s == '\\' && ! escape )
402 return( *s ? s : NULL );
405 static int hex2value( int c )
407 if( c >= '0' && c <= '9' ) {
411 if( c >= 'A' && c <= 'F' ) {
412 return c + (10 - (int) 'A');
415 if( c >= 'a' && c <= 'f' ) {
416 return c + (10 - (int) 'a');
423 find_wildcard( char *s )
425 for( ; *s != '\0' ; s++ ) {
427 case '*': /* found wildcard */
431 s++; /* skip over escape */
432 if( hex2value( s[0] ) >= 0 && hex2value( s[1] ) >= 0 ) {
433 /* skip over lead digit of two hex digit code */
442 /* unescape filter value */
443 /* support both LDAP v2 and v3 escapes */
444 /* output can include nul characters */
446 filter_value_unescape( char *fval )
451 for( r=v=0; fval[v] != '\0'; v++ ) {
457 if ( fval[v] == '\0' ) {
458 /* escape at end of string */
461 } else if (( v1 = hex2value( fval[v] )) < 0 ) {
464 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
465 /* must be two digit code */
469 fval[r++] = v1 * 16 + v2;
489 put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
494 * We have (x(filter)...) with str sitting on
495 * the x. We have to find the paren matching
496 * the one before the x and put the intervening
497 * filters by calling put_filter_list().
500 /* put explicit tag */
501 if ( ber_printf( ber, "t{" /*}*/, tag ) == -1 )
505 if ( (next = find_right_paren( str )) == NULL )
509 if ( put_filter_list( ber, str ) == -1 )
513 /* flush explicit tagged thang */
514 if ( ber_printf( ber, /*{*/ "}" ) == -1 )
521 put_filter( BerElement *ber, char *str )
524 int parens, balance, escape;
527 * A Filter looks like this:
528 * Filter ::= CHOICE {
529 * and [0] SET OF Filter,
530 * or [1] SET OF Filter,
532 * equalityMatch [3] AttributeValueAssertion,
533 * substrings [4] SubstringFilter,
534 * greaterOrEqual [5] AttributeValueAssertion,
535 * lessOrEqual [6] AttributeValueAssertion,
536 * present [7] AttributeType,
537 * approxMatch [8] AttributeValueAssertion,
538 * extensibleMatch [9] MatchingRuleAssertion -- LDAPv3
541 * SubstringFilter ::= SEQUENCE {
542 * type AttributeType,
543 * SEQUENCE OF CHOICE {
544 * initial [0] IA5String,
546 * final [2] IA5String
550 * MatchingRuleAssertion ::= SEQUENCE { -- LDAPv3
551 * matchingRule [1] MatchingRuleId OPTIONAL,
552 * type [2] AttributeDescription OPTIONAL,
553 * matchValue [3] AssertionValue,
554 * dnAttributes [4] BOOLEAN DEFAULT FALSE }
556 * Note: tags in a choice are always explicit
559 Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
569 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
572 if ( (str = put_complex_filter( ber, str,
573 LDAP_FILTER_AND, 0 )) == NULL )
580 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
583 if ( (str = put_complex_filter( ber, str,
584 LDAP_FILTER_OR, 0 )) == NULL )
591 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
594 if ( (str = put_complex_filter( ber, str,
595 LDAP_FILTER_NOT, 1 )) == NULL )
602 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
608 while ( *next && balance ) {
612 else if ( *next == ')' )
615 if ( *next == '\\' && ! escape )
626 if ( put_simple_filter( ber, str ) == -1 ) {
637 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
639 if ( ber_printf( ber, /*[*/ "]" ) == -1 )
649 default: /* assume it's a simple type=value filter */
650 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0,
652 next = strchr( str, '\0' );
653 if ( put_simple_filter( ber, str ) == -1 ) {
661 return( parens ? -1 : 0 );
665 * Put a list of filters like this "(filter1)(filter2)..."
669 put_filter_list( BerElement *ber, char *str )
674 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
677 while ( *str && isspace( (unsigned char) *str ) )
682 if ( (next = find_right_paren( str + 1 )) == NULL )
686 /* now we have "(filter)" with str pointing to it */
688 if ( put_filter( ber, str ) == -1 )
708 Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
710 str = LDAP_STRDUP( str );
711 if( str == NULL ) return -1;
713 if ( (s = strchr( str, '=' )) == NULL ) {
722 ftype = LDAP_FILTER_LE;
724 if(! ldap_is_attr_desc( str ) ) goto done;
728 ftype = LDAP_FILTER_GE;
730 if(! ldap_is_attr_desc( str ) ) goto done;
734 ftype = LDAP_FILTER_APPROX;
736 if(! ldap_is_attr_desc( str ) ) goto done;
740 /* RFC2254 extensible filters are off the form:
741 * type [:dn] [:rule] := value
742 * or [:dn]:rule := value
744 ftype = LDAP_FILTER_EXT;
748 char *dn = strchr( str, ':' );
752 if(! ldap_is_attr_desc( str ) ) goto done;
757 rule = strchr( dn, ':' );
761 if ( strcmp(dn, "dn") == 0 ) {
762 /* must have attribute */
763 if( !ldap_is_attr_desc( str ) ) {
778 if ( strcmp(dn, "dn") != 0 ) {
784 if ( *str == '\0' && *rule == '\0' ) {
785 /* must have either type or rule */
789 if ( *str != '\0' && !ldap_is_attr_desc( str ) ) {
793 if ( *rule != '\0' && !ldap_is_attr_oid( rule ) ) {
797 rc = ber_printf( ber, "t{" /*}*/, ftype );
799 if( rc != -1 && *rule != '\0' ) {
800 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
802 if( rc != -1 && *str != '\0' ) {
803 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
807 ber_slen_t len = filter_value_unescape( value );
810 rc = ber_printf( ber, "totb}",
811 LDAP_FILTER_EXT_VALUE, value, len,
812 LDAP_FILTER_EXT_DNATTRS, dn != NULL);
821 if ( find_wildcard( value ) == NULL ) {
822 ftype = LDAP_FILTER_EQUALITY;
823 } else if ( strcmp( value, "*" ) == 0 ) {
824 ftype = LDAP_FILTER_PRESENT;
826 rc = put_substring_filter( ber, str, value );
832 if ( ftype == LDAP_FILTER_PRESENT ) {
833 rc = ber_printf( ber, "ts", ftype, str );
836 ber_slen_t len = filter_value_unescape( value );
839 rc = ber_printf( ber, "t{so}",
840 ftype, str, value, len );
844 if( rc != -1 ) rc = 0;
852 put_substring_filter( BerElement *ber, char *type, char *val )
854 char *nextstar, gotstar = 0;
855 ber_tag_t ftype = LDAP_FILTER_SUBSTRINGS;
857 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
860 if ( ber_printf( ber, "t{s{", ftype, type ) == -1 )
863 for( ; val != NULL; val=nextstar ) {
864 if ( (nextstar = find_wildcard( val )) != NULL )
867 if ( gotstar == 0 ) {
868 ftype = LDAP_SUBSTRING_INITIAL;
869 } else if ( nextstar == NULL ) {
870 ftype = LDAP_SUBSTRING_FINAL;
872 ftype = LDAP_SUBSTRING_ANY;
875 if ( *val != '\0' ) {
876 ber_slen_t len = filter_value_unescape( val );
882 if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
890 if ( ber_printf( ber, /* {{ */ "}}" ) == -1 )
898 LDAP *ld, LDAP_CONST char *base, int scope,
899 LDAP_CONST char *filter, char **attrs,
900 int attrsonly, struct timeval *timeout, LDAPMessage **res )
904 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
906 return( ld->ld_errno );
908 if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 )
909 return( ld->ld_errno );
911 if ( ld->ld_errno == LDAP_TIMEOUT ) {
912 (void) ldap_abandon( ld, msgid );
913 ld->ld_errno = LDAP_TIMEOUT;
914 return( ld->ld_errno );
917 return( ldap_result2error( ld, *res, 0 ) );
923 LDAP_CONST char *base,
925 LDAP_CONST char *filter,
932 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
934 return( ld->ld_errno );
936 if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, res ) == -1 )
937 return( ld->ld_errno );
939 return( ldap_result2error( ld, *res, 0 ) );