2 * Copyright (c) 1990 Regents of the University of Michigan.
11 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
18 #include <ac/socket.h>
19 #include <ac/string.h>
26 static char *find_right_paren LDAP_P(( char *s ));
27 static char *put_complex_filter LDAP_P(( BerElement *ber, char *str,
28 unsigned long tag, int not ));
29 static int put_filter LDAP_P(( BerElement *ber, char *str ));
30 static int put_simple_filter LDAP_P(( BerElement *ber, char *str ));
31 static int put_substring_filter LDAP_P(( BerElement *ber, char *type, char *str ));
32 static int put_filter_list LDAP_P(( BerElement *ber, char *str ));
35 * ldap_search - initiate an ldap (and X.500) search operation. Parameters:
38 * base DN of the base object
39 * scope the search scope - one of LDAP_SCOPE_BASE,
40 * LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
41 * filter a string containing the search filter
42 * (e.g., "(|(cn=bob)(sn=bob))")
43 * attrs list of attribute types to return for matches
44 * attrsonly 1 => attributes only 0 => attributes and values
47 * char *attrs[] = { "mail", "title", 0 };
48 * msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
52 ldap_search( LDAP *ld, char *base, int scope, char *filter,
53 char **attrs, int attrsonly )
57 Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
59 if (( ber = ldap_build_search_req( ld, base, scope, filter, attrs,
60 attrsonly )) == NULLBER ) {
65 if ( ld->ld_cache != NULL ) {
66 if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
68 ld->ld_errno = LDAP_SUCCESS;
69 return( ld->ld_msgid );
71 ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
73 #endif /* LDAP_NOCACHE */
75 /* send the message */
76 return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber ));
81 ldap_build_search_req( LDAP *ld, char *base, int scope, char *filter,
82 char **attrs, int attrsonly )
88 * Create the search request. It looks like this:
89 * SearchRequest := [APPLICATION 3] SEQUENCE {
90 * baseObject DistinguishedName,
96 * derefAliases ENUMERATED {
97 * neverDerefaliases (0),
98 * derefInSearching (1),
99 * derefFindingBaseObj (2),
100 * alwaysDerefAliases (3)
102 * sizelimit INTEGER (0 .. 65535),
103 * timelimit INTEGER (0 .. 65535),
106 * attributes SEQUENCE OF AttributeType
108 * wrapped in an ldap message.
111 /* create a message to send */
112 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULLBER ) {
116 if ( base == NULL ) {
120 #ifdef LDAP_CONNECTIONLESS
121 if ( ld->ld_sb.sb_naddr > 0 ) {
122 err = ber_printf( ber, "{ist{seeiib", ++ld->ld_msgid,
123 ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
124 ld->ld_sizelimit, ld->ld_timelimit, attrsonly );
126 #endif /* LDAP_CONNECTIONLESS */
127 err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid,
128 LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
129 ld->ld_sizelimit, ld->ld_timelimit, attrsonly );
130 #ifdef LDAP_CONNECTIONLESS
132 #endif /* LDAP_CONNECTIONLESS */
135 ld->ld_errno = LDAP_ENCODING_ERROR;
140 filter = strdup( filter );
141 err = put_filter( ber, filter );
145 ld->ld_errno = LDAP_FILTER_ERROR;
150 if ( ber_printf( ber, "{v}}}", attrs ) == -1 ) {
151 ld->ld_errno = LDAP_ENCODING_ERROR;
160 find_right_paren( char *s )
166 while ( *s && balance ) {
170 else if ( *s == ')' )
173 if ( *s == '\\' && ! escape )
181 return( *s ? s : NULL );
185 put_complex_filter( BerElement *ber, char *str, unsigned long tag, int not )
190 * We have (x(filter)...) with str sitting on
191 * the x. We have to find the paren matching
192 * the one before the x and put the intervening
193 * filters by calling put_filter_list().
196 /* put explicit tag */
197 if ( ber_printf( ber, "t{", tag ) == -1 )
200 if ( !not && ber_printf( ber, "{" ) == -1 )
205 if ( (next = find_right_paren( str )) == NULL )
209 if ( put_filter_list( ber, str ) == -1 )
213 /* flush explicit tagged thang */
214 if ( ber_printf( ber, "}" ) == -1 )
217 if ( !not && ber_printf( ber, "}" ) == -1 )
225 put_filter( BerElement *ber, char *str )
227 char *next, *tmp, *s, *d;
228 int parens, balance, escape, gotescape;
231 * A Filter looks like this:
232 * Filter ::= CHOICE {
233 * and [0] SET OF Filter,
234 * or [1] SET OF Filter,
236 * equalityMatch [3] AttributeValueAssertion,
237 * substrings [4] SubstringFilter,
238 * greaterOrEqual [5] AttributeValueAssertion,
239 * lessOrEqual [6] AttributeValueAssertion,
240 * present [7] AttributeType,,
241 * approxMatch [8] AttributeValueAssertion
244 * SubstringFilter ::= SEQUENCE {
245 * type AttributeType,
246 * SEQUENCE OF CHOICE {
247 * initial [0] IA5String,
249 * final [2] IA5String
252 * Note: tags in a choice are always explicit
255 Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
257 gotescape = parens = 0;
265 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
268 if ( (str = put_complex_filter( ber, str,
269 LDAP_FILTER_AND, 0 )) == NULL )
276 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
279 if ( (str = put_complex_filter( ber, str,
280 LDAP_FILTER_OR, 0 )) == NULL )
287 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
290 if ( (str = put_complex_filter( ber, str,
291 LDAP_FILTER_NOT, 1 )) == NULL )
298 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
304 while ( *next && balance ) {
308 else if ( *next == ')' )
311 if ( *next == '\\' && ! escape )
312 gotescape = escape = 1;
325 for ( s = d = tmp; *s; s++ ) {
326 if ( *s != '\\' || escape ) {
335 if ( put_simple_filter( ber, tmp ) == -1 ) {
348 Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
350 if ( ber_printf( ber, "]" ) == -1 )
360 default: /* assume it's a simple type=value filter */
361 Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0,
363 next = strchr( str, '\0' );
365 if ( strchr( tmp, '\\' ) != NULL ) {
367 for ( s = d = tmp; *s; s++ ) {
368 if ( *s != '\\' || escape ) {
377 if ( put_simple_filter( ber, tmp ) == -1 ) {
387 return( parens ? -1 : 0 );
391 * Put a list of filters like this "(filter1)(filter2)..."
395 put_filter_list( BerElement *ber, char *str )
400 Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
403 while ( *str && isspace( *str ) )
408 if ( (next = find_right_paren( str + 1 )) == NULL )
412 /* now we have "(filter)" with str pointing to it */
414 if ( put_filter( ber, str ) == -1 )
425 put_simple_filter( BerElement *ber, char *str )
428 char *value, savechar;
432 Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
434 if ( (s = strchr( str, '=' )) == NULL )
442 ftype = LDAP_FILTER_LE;
446 ftype = LDAP_FILTER_GE;
450 ftype = LDAP_FILTER_APPROX;
454 if ( strchr( value, '*' ) == NULL ) {
455 ftype = LDAP_FILTER_EQUALITY;
456 } else if ( strcmp( value, "*" ) == 0 ) {
457 ftype = LDAP_FILTER_PRESENT;
459 rc = put_substring_filter( ber, str, value );
466 if ( ftype == LDAP_FILTER_PRESENT ) {
467 rc = ber_printf( ber, "ts", ftype, str );
469 rc = ber_printf( ber, "t{ss}", ftype, str, value );
474 return( rc == -1 ? rc : 0 );
478 put_substring_filter( BerElement *ber, char *type, char *val )
480 char *nextstar, gotstar = 0;
483 Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
486 if ( ber_printf( ber, "t{s{", LDAP_FILTER_SUBSTRINGS, type ) == -1 )
489 while ( val != NULL ) {
490 if ( (nextstar = strchr( val, '*' )) != NULL )
493 if ( gotstar == 0 ) {
494 ftype = LDAP_SUBSTRING_INITIAL;
495 } else if ( nextstar == NULL ) {
496 ftype = LDAP_SUBSTRING_FINAL;
498 ftype = LDAP_SUBSTRING_ANY;
500 if ( *val != '\0' ) {
501 if ( ber_printf( ber, "ts", ftype, val ) == -1 )
506 if ( nextstar != NULL )
511 if ( ber_printf( ber, "}}" ) == -1 )
518 ldap_search_st( LDAP *ld, char *base, int scope, char *filter, char **attrs,
519 int attrsonly, struct timeval *timeout, LDAPMessage **res )
523 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
525 return( ld->ld_errno );
527 if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 )
528 return( ld->ld_errno );
530 if ( ld->ld_errno == LDAP_TIMEOUT ) {
531 (void) ldap_abandon( ld, msgid );
532 ld->ld_errno = LDAP_TIMEOUT;
533 return( ld->ld_errno );
536 return( ldap_result2error( ld, *res, 0 ) );
540 ldap_search_s( LDAP *ld, char *base, int scope, char *filter, char **attrs,
541 int attrsonly, LDAPMessage **res )
545 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
547 return( ld->ld_errno );
549 if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, res ) == -1 )
550 return( ld->ld_errno );
552 return( ldap_result2error( ld, *res, 0 ) );