You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

304 lines
8.1 KiB

#include <string.h>
#include <stdio.h>
#include <fnmatch.h>
#include "slp_predicate.h"
#include "slp_linkedlist.h"
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
/* for those platforms without FNM_CASEFOLD */
#ifndef FNM_CASEFOLD
#define FNM_CASEFOLD 0
#endif
/* the usual */
#define SLP_MIN(a, b) ((a) < (b) ? (a) : (b))
#define SLP_MAX(a, b) ((a) > (b) ? (a) : (b))
#ifdef DEBUG
void dumpAttrList(int level, const SLPAttrList *attrs)
{
int i;
if (SLP_IS_EMPTY(attrs) )
{
return;
}
for ( i = 0; i <= level; i++ )
{
printf("\t");
}
attrs = attrs->next;
while ( !SLP_IS_HEAD(attrs) )
{
switch ( attrs->type )
{
case string:
printf("%s = %s (string) \n", attrs->name, attrs->val.stringVal);
break;
case integer:
printf("%s = %lu (integer) \n", attrs->name, attrs->val.intVal);
break;
case boolean:
printf("%s = %s (boolean) \n",
attrs->name,
(attrs->val.boolVal ? " TRUE " : " FALSE "));
break;
case opaque:
case head:
default:
printf("%s = %s\n", attrs->name, "illegal or unknown attribute type");
break;
}
attrs = attrs->next;
}
return;
}
void printOperator(int op)
{
switch ( op )
{
case ldap_or: printf(" OR ");
break;
case ldap_and: printf( " AND " );
break;
case ldap_not: printf(" NOT ");
break;
case expr_eq: printf(" EQUAL ");
break;
case expr_gt: printf(" GREATER THAN ");
break;
case expr_lt: printf(" LESS THAN ");
break;
case expr_present: printf(" PRESENT ");
break;
case expr_approx: printf(" APPROX ");
break;
case -1: printf(" list head ");
break;
default:
printf(" unknown operator value %i ", op);
break;
}
return;
}
void dumpFilterTree( const SLPLDAPFilter *filter )
{
int i;
for ( i = 0; i < filter->nestingLevel; i++ )
{
printf("\t");
}
printOperator(filter->operator);
printf("%s (level %i) \n",
(filter->logical_value ? " TRUE " : " FALSE "),
filter->nestingLevel );
dumpAttrList(filter->nestingLevel, &(filter->attrs));
if ( !SLP_IS_EMPTY( &(filter->children) ) )
{
dumpFilterTree((SLPLDAPFilter *)filter->children.next ) ;
}
if ( (!SLP_IS_HEAD(filter->next)) && (!SLP_IS_EMPTY(filter->next)) )
{
dumpFilterTree(filter->next);
}
return;
}
#endif /* DEBUG*/
int SLPEvaluateOperation(int compare_result, int operation)
{
switch ( operation )
{
case expr_eq:
if ( compare_result == 0 ) /* a == b */
return(TRUE);
break;
case expr_gt:
if ( compare_result >= 0 ) /* a >= b */
return(TRUE);
break;
case expr_lt: /* a <= b */
if ( compare_result <= 0 )
return(TRUE);
break;
case expr_present:
case expr_approx:
default:
return(TRUE);
break;
}
return(FALSE);
}
/* evaluates attr values, not names */
int SLPEvaluateAttributes(const SLPAttrList *a, const SLPAttrList *b, int op)
{
/* first ensure they are the same type */
if ( a->type == b->type )
{
switch ( a->type )
{
case string:
return( SLPEvaluateOperation(fnmatch(a->val.stringVal, b->val.stringVal, FNM_CASEFOLD), op) );
case integer:
return( SLPEvaluateOperation( a->val.intVal - b->val.intVal, op));
case tag: /* equivalent to a presence test */
return(TRUE);
case boolean:
if ( (a->val.boolVal != 0) && (b->val.boolVal != 0) )
return(TRUE);
if ( (a->val.boolVal == 0) && (b->val.boolVal == 0) )
return(TRUE);
break;
case opaque:
if ( ! memcmp((((char *)(a->val.opaqueVal)) + 4),
(((char *)(b->val.opaqueVal)) + 4),
SLP_MIN((*((int *)a->val.opaqueVal)), (*((int *)a->val.opaqueVal)))) );
return(TRUE);
break;
default:
break;
}
}
return(FALSE);
}
/* filter is a filter tree, attrs is ptr to an attr listhead */
int SLPEvaluateFilterTree(SLPLDAPFilter *filter, const SLPAttrList *attrs)
{
if ( !SLP_IS_EMPTY( &(filter->children) ) )
{
SLPEvaluateFilterTree((SLPLDAPFilter *)filter->children.next, attrs);
}
if ( ! (SLP_IS_HEAD(filter->next)) && (!SLP_IS_EMPTY(filter->next)) )
{
SLPEvaluateFilterTree(filter->next, attrs);
}
if ( filter->operator == ldap_and ||
filter->operator == ldap_or ||
filter->operator == ldap_not )
{
/* evaluate ldap logical operators by evaluating filter->children as a list of filters */
SLPLDAPFilter *child_list = (SLPLDAPFilter *)filter->children.next;
/* initialize the filter's logical value to true */
if ( filter->operator == ldap_or )
{
filter->logical_value = FALSE;
}
else
{
filter->logical_value = TRUE;
}
while ( !SLP_IS_HEAD(child_list) )
{
if ( child_list->logical_value == TRUE )
{
if ( filter->operator == ldap_or )
{
filter->logical_value = TRUE;
break;
}
if ( filter->operator == ldap_not )
{
filter->logical_value = FALSE;
break;
}
/* for an & operator keep going */
}
else
{
/* child is false */
if ( filter->operator == ldap_and )
{
filter->logical_value = FALSE;
break;
}
}
child_list = child_list->next;
}
}
else
{
/* find the first matching attribute and set the logical value */
filter->logical_value = FALSE;
if ( !SLP_IS_HEAD(filter->attrs.next) )
{
attrs = attrs->next;
while ( (!SLP_IS_HEAD(attrs )) &&
( FNM_NOMATCH == fnmatch(filter->attrs.next->name,
attrs->name, FNM_CASEFOLD)) )
{
attrs = attrs->next ;
}
/* either we have traversed the list or found the first matching attribute */
if ( !SLP_IS_HEAD(attrs) )
{
/* we found the first matching attribute, now do the comparison */
if ( filter->operator == expr_present ||
filter->operator == expr_approx )
{
filter->logical_value = TRUE;
}
else
{
filter->logical_value = SLPEvaluateAttributes(filter->attrs.next,
attrs, filter->operator );
}
}
}
}
return(filter->logical_value);
}
/* a is an attribute list, while b is a string representation of an ldap filter */
int SLP_predicate_match(const SLPAttrList *attrlist,
const char *filter)
{
int ccode;
SLPLDAPFilter *ftree;
if ( filter == NULL || ! strlen(filter) )
{
return(TRUE); /* no predicate - aways tests TRUE */
}
if ( NULL != (ftree = SLPDecodeLDAPFilter(filter)) )
{
ccode = SLPEvaluateFilterTree(ftree, attrlist);
SLPFreeFilterTree(ftree);
return(ccode);
}
return(FALSE);
}