#include "portable.h"
#include <stdio.h>
#include <ac/stdlib.h>
#include <ac/errno.h>
#include <ac/regex.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>
#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
#include "ldap-int.h"
static int break_into_words LDAP_P((
char *str,
LDAP_CONST char *delims,
char ***wordsp ));
#define FILT_MAX_LINE_LEN 1024
static LDAPFiltDesc *
ldap_init_getfilter_buf( char *buf, ber_len_t buflen )
{
LDAPFiltDesc *lfdp;
LDAPFiltList *flp, *nextflp;
LDAPFiltInfo *fip, *nextfip;
char *tag, **tok;
int tokcnt, i;
int rc;
regex_t re;
if (( lfdp = (LDAPFiltDesc *)LDAP_CALLOC( 1, sizeof( LDAPFiltDesc))) == NULL ) {
return( NULL );
}
flp = nextflp = NULL;
fip = NULL;
tag = NULL;
while ( buflen > 0 && ( tokcnt = ldap_int_next_line_tokens( &buf, &buflen, &tok ))
> 0 ) {
switch( tokcnt ) {
case 1:
if ( tag != NULL ) {
LDAP_FREE( tag );
}
tag = tok[ 0 ];
LDAP_FREE( tok );
break;
case 4:
case 5:
if (( nextflp = (LDAPFiltList *)LDAP_CALLOC( 1, sizeof( LDAPFiltList )))
== NULL ) {
ldap_getfilter_free( lfdp );
return( NULL );
}
nextflp->lfl_tag = LDAP_STRDUP( tag );
nextflp->lfl_pattern = tok[ 0 ];
if ( (rc = regcomp( &re, nextflp->lfl_pattern, 0 )) != 0 ) {
char error[512];
regerror(rc, &re, error, sizeof(error));
ldap_getfilter_free( lfdp );
Debug( LDAP_DEBUG_ANY, "ldap_init_get_filter_buf: "
"bad regular expression %s, %s\n",
nextflp->lfl_pattern, error, 0 );
errno = EINVAL;
LDAP_VFREE( tok );
return( NULL );
}
regfree(&re);
nextflp->lfl_delims = tok[ 1 ];
nextflp->lfl_ilist = NULL;
nextflp->lfl_next = NULL;
if ( flp == NULL ) {
lfdp->lfd_filtlist = nextflp;
} else {
flp->lfl_next = nextflp;
}
flp = nextflp;
fip = NULL;
for ( i = 2; i < 5; ++i ) {
tok[ i - 2 ] = tok[ i ];
}
case 2:
case 3:
if ( nextflp != NULL ) {
if (( nextfip = (LDAPFiltInfo *)LDAP_CALLOC( 1,
sizeof( LDAPFiltInfo ))) == NULL ) {
ldap_getfilter_free( lfdp );
LDAP_VFREE( tok );
return( NULL );
}
if ( fip == NULL ) {
nextflp->lfl_ilist = nextfip;
} else {
fip->lfi_next = nextfip;
}
fip = nextfip;
nextfip->lfi_next = NULL;
nextfip->lfi_filter = tok[ 0 ];
nextfip->lfi_desc = tok[ 1 ];
if ( tok[ 2 ] != NULL ) {
if ( strcasecmp( tok[ 2 ], "subtree" ) == 0 ) {
nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;
} else if ( strcasecmp( tok[ 2 ], "onelevel" ) == 0 ) {
nextfip->lfi_scope = LDAP_SCOPE_ONELEVEL;
} else if ( strcasecmp( tok[ 2 ], "base" ) == 0 ) {
nextfip->lfi_scope = LDAP_SCOPE_BASE;
} else {
LDAP_VFREE( tok );
ldap_getfilter_free( lfdp );
errno = EINVAL;
return( NULL );
}
LDAP_FREE( tok[ 2 ] );
tok[ 2 ] = NULL;
} else {
nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;
}
nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL &&
strchr( tok[ 0 ], '~' ) == NULL );
LDAP_FREE( tok );
}
break;
default:
LDAP_VFREE( tok );
ldap_getfilter_free( lfdp );
errno = EINVAL;
return( NULL );
}
}
if ( tag != NULL ) {
LDAP_FREE( tag );
}
return( lfdp );
}
LDAPFiltDesc *
ldap_init_getfilter( LDAP_CONST char *fname )
{
FILE *fp;
char *buf;
long rlen, len;
int eof;
LDAPFiltDesc *lfdp;
if (( fp = fopen( fname, "r" )) == NULL ) {
return( NULL );
}
if ( fseek( fp, 0L, SEEK_END ) != 0 ) {
fclose( fp );
return( NULL );
}
len = ftell( fp );
if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {
fclose( fp );
return( NULL );
}
if (( buf = LDAP_MALLOC( (size_t)len )) == NULL ) {
fclose( fp );
return( NULL );
}
rlen = fread( buf, 1, (size_t)len, fp );
eof = feof( fp );
fclose( fp );
if ( rlen != len && !eof ) {
LDAP_FREE( buf );
return( NULL );
}
lfdp = ldap_init_getfilter_buf( buf, rlen );
LDAP_FREE( buf );
return( lfdp );
}
LDAPFiltInfo *
ldap_getfirstfilter(
LDAPFiltDesc *lfdp,
char *tagpat,
char *value )
{
LDAPFiltList *flp;
int rc;
regex_t re;
if ( lfdp->lfd_curvalcopy != NULL ) {
LDAP_FREE( lfdp->lfd_curvalcopy );
LDAP_FREE( lfdp->lfd_curvalwords );
}
lfdp->lfd_curval = value;
lfdp->lfd_curfip = NULL;
for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) {
if (regcomp(&re, tagpat, REG_EXTENDED|REG_NOSUB) != 0)
continue;
rc = regexec(&re, flp->lfl_tag, 0, NULL, 0);
regfree(&re);
if (rc != 0)
continue;
if (regcomp(&re, flp->lfl_pattern, REG_EXTENDED|REG_NOSUB) != 0)
continue;
rc = regexec(&re, lfdp->lfd_curval, 0, NULL, 0);
regfree(&re);
if (rc != 0)
continue;
lfdp->lfd_curfip = flp->lfl_ilist;
break;
}
if ( lfdp->lfd_curfip == NULL ) {
return( NULL );
}
if (( lfdp->lfd_curvalcopy = LDAP_STRDUP( value )) == NULL ) {
return( NULL );
}
if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims,
&lfdp->lfd_curvalwords ) < 0 ) {
LDAP_FREE( lfdp->lfd_curvalcopy );
lfdp->lfd_curvalcopy = NULL;
return( NULL );
}
return( ldap_getnextfilter( lfdp ));
}
static void
ldap_build_filter(
char *filtbuf,
ber_len_t buflen,
LDAP_CONST char *pattern,
LDAP_CONST char *prefix,
LDAP_CONST char *suffix,
LDAP_CONST char *attr,
LDAP_CONST char *value,
char **valwords );
LDAPFiltInfo *
ldap_getnextfilter( LDAPFiltDesc *lfdp )
{
LDAPFiltInfo *fip;
fip = lfdp->lfd_curfip;
if ( fip == NULL ) {
return( NULL );
}
lfdp->lfd_curfip = fip->lfi_next;
ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter,
lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL,
lfdp->lfd_curval, lfdp->lfd_curvalwords );
lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter;
lfdp->lfd_retfi.lfi_desc = fip->lfi_desc;
lfdp->lfd_retfi.lfi_scope = fip->lfi_scope;
lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact;
return( &lfdp->lfd_retfi );
}
static void
ldap_build_filter(
char *filtbuf,
ber_len_t buflen,
LDAP_CONST char *pattern,
LDAP_CONST char *prefix,
LDAP_CONST char *suffix,
LDAP_CONST char *attr,
LDAP_CONST char *value,
char **valwords )
{
const char *p;
char *f;
size_t slen;
int i, wordcount, wordnum, endwordnum;
if ( valwords == NULL ) {
wordcount = 0;
} else {
for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) {
;
}
}
f = filtbuf;
if ( prefix != NULL ) {
strcpy( f, prefix );
f += strlen( prefix );
}
for ( p = pattern; *p != '\0'; ++p ) {
if ( *p == '%' ) {
++p;
if ( *p == 'v' ) {
if ( LDAP_DIGIT( (unsigned char) p[1] )) {
++p;
wordnum = *p - '1';
if ( *(p+1) == '-' ) {
++p;
if ( LDAP_DIGIT( (unsigned char) p[1] )) {
++p;
endwordnum = *p - '1';
if ( endwordnum > wordcount - 1 ) {
endwordnum = wordcount - 1;
}
} else {
endwordnum = wordcount - 1;
}
} else {
endwordnum = wordnum;
}
if ( wordcount > 0 ) {
for ( i = wordnum; i <= endwordnum; ++i ) {
if ( i > wordnum ) {
*f++ = ' ';
}
slen = strlen( valwords[ i ] );
AC_MEMCPY( f, valwords[ i ], slen );
f += slen;
}
}
} else if ( *(p+1) == '$' ) {
++p;
if ( wordcount > 0 ) {
wordnum = wordcount - 1;
slen = strlen( valwords[ wordnum ] );
AC_MEMCPY( f, valwords[ wordnum ], slen );
f += slen;
}
} else if ( value != NULL ) {
slen = strlen( value );
AC_MEMCPY( f, value, slen );
f += slen;
}
} else if ( *p == 'a' && attr != NULL ) {
slen = strlen( attr );
AC_MEMCPY( f, attr, slen );
f += slen;
} else {
*f++ = *p;
}
} else {
*f++ = *p;
}
if ( (size_t) (f - filtbuf) > buflen ) {
--f;
break;
}
}
if ( suffix != NULL && ( (size_t) (f - filtbuf) < buflen ) )
{
strcpy( f, suffix );
} else {
*f = '\0';
}
}
static int
break_into_words( char *str, LDAP_CONST char *delims, char ***wordsp )
{
char *word, **words;
int count;
char *tok_r;
if (( words = (char **)LDAP_CALLOC( 1, sizeof( char * ))) == NULL ) {
return( -1 );
}
count = 0;
words[ count ] = NULL;
word = ldap_pvt_strtok( str, delims, &tok_r );
while ( word != NULL ) {
if (( words = (char **)LDAP_REALLOC( words,
( count + 2 ) * sizeof( char * ))) == NULL ) {
return( -1 );
}
words[ count ] = word;
words[ ++count ] = NULL;
word = ldap_pvt_strtok( NULL, delims, &tok_r );
}
*wordsp = words;
return( count );
}