#ifdef NOTDEF
#ifndef lint
static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
#endif
#endif
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef MACOS
#include <stdlib.h>
#include "macos.h"
#endif
#if defined( DOS ) || defined( _WIN32 )
#include "msdos.h"
#endif
#if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 )
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#endif
#include <NetInfo/config.h>
#ifdef _UNIX_BSD_43_
extern char *strdup(char *);
#endif
#include "lber.h"
#include "ldap_ldap-int.h"
#include "ldap.h"
#ifdef NEEDPROTOS
static char *find_right_paren( char *s );
static char *put_complex_filter( BerElement *ber, char *str,
unsigned long tag, int not );
static int put_filter( BerElement *ber, char *str );
static int put_simple_filter( BerElement *ber, char *str );
static int put_substring_filter( BerElement *ber, char *type, char *str );
static int put_filter_list( BerElement *ber, char *str );
#else
static char *find_right_paren();
static char *put_complex_filter();
static int put_filter();
static int put_simple_filter();
static int put_substring_filter();
static int put_filter_list();
#endif
int
ldap_search( LDAP *ld, char *base, int scope, char *filter,
char **attrs, int attrsonly )
{
BerElement *ber;
Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
if (( ber = ldap_build_search_req( ld, base, scope, filter, attrs,
attrsonly )) == NULLBER ) {
return( -1 );
}
#ifndef NO_CACHE
if ( ld->ld_cache != NULL ) {
if ( check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
ber_free( ber, 1 );
ld->ld_errno = LDAP_SUCCESS;
return( ld->ld_msgid );
}
add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
}
#endif
return ( send_initial_request( ld, LDAP_REQ_SEARCH, base, ber ));
}
BerElement *
ldap_build_search_req( LDAP *ld, char *base, int scope, char *filter,
char **attrs, int attrsonly )
{
BerElement *ber;
int err;
if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
return( NULLBER );
}
if ( base == NULL ) {
base = (ld->ld_defbase == NULL) ? "" : ld->ld_defbase;
}
#ifdef CLDAP
if ( ld->ld_sb.sb_naddr > 0 ) {
err = ber_printf( ber, "{ist{seeiib", ++ld->ld_msgid,
ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
ld->ld_sizelimit, ld->ld_timelimit, attrsonly );
} else {
#endif
err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid,
LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
ld->ld_sizelimit, ld->ld_timelimit, attrsonly );
#ifdef CLDAP
}
#endif
if ( err == -1 ) {
ld->ld_errno = LDAP_ENCODING_ERROR;
ber_free( ber, 1 );
return( NULLBER );
}
filter = strdup( filter );
err = put_filter( ber, filter );
free( filter );
if ( err == -1 ) {
ld->ld_errno = LDAP_FILTER_ERROR;
ber_free( ber, 1 );
return( NULLBER );
}
if ( ber_printf( ber, "{v}}}", attrs ) == -1 ) {
ld->ld_errno = LDAP_ENCODING_ERROR;
ber_free( ber, 1 );
return( NULLBER );
}
return( ber );
}
static char *
find_right_paren( char *s )
{
int balance, escape;
balance = 1;
escape = 0;
while ( *s && balance ) {
if ( escape == 0 ) {
if ( *s == '(' )
balance++;
else if ( *s == ')' )
balance--;
}
if ( *s == '\\' && ! escape )
escape = 1;
else
escape = 0;
if ( balance )
s++;
}
return( *s ? s : NULL );
}
static char *
put_complex_filter( BerElement *ber, char *str, unsigned long tag, int not )
{
char *next;
if ( ber_printf( ber, "t{", tag ) == -1 )
return( NULL );
str++;
if ( (next = find_right_paren( str )) == NULL )
return( NULL );
*next = '\0';
if ( put_filter_list( ber, str ) == -1 )
return( NULL );
*next++ = ')';
if ( ber_printf( ber, "}" ) == -1 )
return( NULL );
return( next );
}
static int
put_filter( BerElement *ber, char *str )
{
char *next, *tmp, *s, *d;
int parens, balance, escape, gotescape;
Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
gotescape = parens = 0;
while ( *str ) {
switch ( *str ) {
case '(':
str++;
parens++;
switch ( *str ) {
case '&':
Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
0, 0, 0 );
if ( (str = put_complex_filter( ber, str,
LDAP_FILTER_AND, 0 )) == NULL )
return( -1 );
parens--;
break;
case '|':
Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
0, 0, 0 );
if ( (str = put_complex_filter( ber, str,
LDAP_FILTER_OR, 0 )) == NULL )
return( -1 );
parens--;
break;
case '!':
Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
0, 0, 0 );
if ( (str = put_complex_filter( ber, str,
LDAP_FILTER_NOT, 1 )) == NULL )
return( -1 );
parens--;
break;
default:
Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
0, 0, 0 );
balance = 1;
escape = 0;
next = str;
while ( *next && balance ) {
if ( escape == 0 ) {
if ( *next == '(' )
balance++;
else if ( *next == ')' )
balance--;
}
if ( *next == '\\' && ! escape )
gotescape = escape = 1;
else
escape = 0;
if ( balance )
next++;
}
if ( balance != 0 )
return( -1 );
*next = '\0';
tmp = strdup( str );
if ( gotescape ) {
escape = 0;
for ( s = d = tmp; *s; s++ ) {
if ( *s != '\\' || escape ) {
*d++ = *s;
escape = 0;
} else {
escape = 1;
}
}
*d = '\0';
}
if ( put_simple_filter( ber, tmp ) == -1 ) {
free( tmp );
return( -1 );
}
free( tmp );
*next++ = ')';
str = next;
parens--;
break;
}
break;
case ')':
Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
0 );
if ( ber_printf( ber, "]" ) == -1 )
return( -1 );
str++;
parens--;
break;
case ' ':
str++;
break;
default:
Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0,
0 );
next = strchr( str, '\0' );
tmp = strdup( str );
if ( strchr( tmp, '\\' ) != NULL ) {
escape = 0;
for ( s = d = tmp; *s; s++ ) {
if ( *s != '\\' || escape ) {
*d++ = *s;
escape = 0;
} else {
escape = 1;
}
}
*d = '\0';
}
if ( put_simple_filter( ber, tmp ) == -1 ) {
free( tmp );
return( -1 );
}
free( tmp );
str = next;
break;
}
}
return( parens ? -1 : 0 );
}
static int
put_filter_list( BerElement *ber, char *str )
{
char *next;
char save;
Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
while ( *str ) {
while ( *str && isspace( *str ) )
str++;
if ( *str == '\0' )
break;
if ( (next = find_right_paren( str + 1 )) == NULL )
return( -1 );
save = *++next;
*next = '\0';
if ( put_filter( ber, str ) == -1 )
return( -1 );
*next = save;
str = next;
}
return( 0 );
}
static int
put_simple_filter( BerElement *ber, char *str )
{
char *s;
char *value, savechar;
unsigned long ftype;
int rc;
Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
if ( (s = strchr( str, '=' )) == NULL )
return( -1 );
value = s + 1;
*s-- = '\0';
savechar = *s;
switch ( *s ) {
case '<':
ftype = LDAP_FILTER_LE;
*s = '\0';
break;
case '>':
ftype = LDAP_FILTER_GE;
*s = '\0';
break;
case '~':
ftype = LDAP_FILTER_APPROX;
*s = '\0';
break;
default:
if ( strchr( value, '*' ) == NULL ) {
ftype = LDAP_FILTER_EQUALITY;
} else if ( strcmp( value, "*" ) == 0 ) {
ftype = LDAP_FILTER_PRESENT;
} else {
rc = put_substring_filter( ber, str, value );
*(value-1) = '=';
return( rc );
}
break;
}
if ( ftype == LDAP_FILTER_PRESENT ) {
rc = ber_printf( ber, "ts", ftype, str );
} else {
rc = ber_printf( ber, "t{ss}", ftype, str, value );
}
*s = savechar;
*(value-1) = '=';
return( rc == -1 ? rc : 0 );
}
static int
put_substring_filter( BerElement *ber, char *type, char *val )
{
char *nextstar, gotstar = 0;
unsigned long ftype;
Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
val, 0 );
if ( ber_printf( ber, "t{s{", LDAP_FILTER_SUBSTRINGS, type ) == -1 )
return( -1 );
while ( val != NULL ) {
if ( (nextstar = strchr( val, '*' )) != NULL )
*nextstar++ = '\0';
if ( gotstar == 0 ) {
ftype = LDAP_SUBSTRING_INITIAL;
} else if ( nextstar == NULL ) {
ftype = LDAP_SUBSTRING_FINAL;
} else {
ftype = LDAP_SUBSTRING_ANY;
}
if ( *val != '\0' ) {
if ( ber_printf( ber, "ts", ftype, val ) == -1 )
return( -1 );
}
gotstar = 1;
if ( nextstar != NULL )
*(nextstar-1) = '*';
val = nextstar;
}
if ( ber_printf( ber, "}}" ) == -1 )
return( -1 );
return( 0 );
}
int
ldap_search_st( LDAP *ld, char *base, int scope, char *filter, char **attrs,
int attrsonly, struct timeval *timeout, LDAPMessage **res )
{
int msgid;
if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
== -1 )
return( ld->ld_errno );
if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 )
return( ld->ld_errno );
if ( ld->ld_errno == LDAP_TIMEOUT ) {
(void) ldap_abandon( ld, msgid );
ld->ld_errno = LDAP_TIMEOUT;
return( ld->ld_errno );
}
return( ldap_result2error( ld, *res, 0 ) );
}
int
ldap_search_s( LDAP *ld, char *base, int scope, char *filter, char **attrs,
int attrsonly, LDAPMessage **res )
{
int msgid;
if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
== -1 )
return( ld->ld_errno );
if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, res ) == -1 )
return( ld->ld_errno );
return( ldap_result2error( ld, *res, 0 ) );
}