#include <sys/queue.h>
#include <sys/types.h>
#include <string.h>
#include <stdint.h>
#include "ldapd.h"
#include "log.h"
static int ldap_filt_eq(struct ber_element *root, struct plan *plan);
static int ldap_filt_subs(struct ber_element *root, struct plan *plan);
static int ldap_filt_and(struct ber_element *root, struct plan *plan);
static int ldap_filt_or(struct ber_element *root, struct plan *plan);
static int ldap_filt_not(struct ber_element *root, struct plan *plan);
static int
ldap_filt_eq(struct ber_element *root, struct plan *plan)
{
char *vs;
struct ber_element *a, *vals, *v;
if (plan->undefined)
return -1;
else if (plan->adesc != NULL)
a = ldap_get_attribute(root, plan->adesc);
else
a = ldap_find_attribute(root, plan->at);
if (a == NULL) {
log_debug("no attribute [%s] found",
plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
return -1;
}
vals = a->be_next;
if (vals == NULL)
return -1;
for (v = vals->be_sub; v; v = v->be_next) {
if (ober_get_string(v, &vs) != 0)
continue;
if (strcasecmp(plan->assert.value, vs) == 0)
return 0;
}
return -1;
}
static int
ldap_filt_subs_value(struct ber_element *v, struct ber_element *sub)
{
int class;
unsigned int type;
const char *cmpval;
char *vs, *p, *end;
if (ober_get_string(v, &vs) != 0)
return -1;
for (; sub; sub = sub->be_next) {
if (ober_scanf_elements(sub, "ts", &class, &type, &cmpval) != 0)
return -1;
if (class != BER_CLASS_CONTEXT)
return -1;
switch (type) {
case LDAP_FILT_SUBS_INIT:
if (strncasecmp(cmpval, vs, strlen(cmpval)) == 0)
vs += strlen(cmpval);
else
return 1;
break;
case LDAP_FILT_SUBS_ANY:
if ((p = strcasestr(vs, cmpval)) != NULL)
vs = p + strlen(cmpval);
else
return 1;
break;
case LDAP_FILT_SUBS_FIN:
if (strlen(vs) < strlen(cmpval))
return 1;
end = vs + strlen(vs) - strlen(cmpval);
if (strcasecmp(end, cmpval) == 0)
vs = end + strlen(cmpval);
else
return 1;
break;
default:
log_warnx("invalid subfilter type %u", type);
return -1;
}
}
return 0;
}
static int
ldap_filt_subs(struct ber_element *root, struct plan *plan)
{
const char *attr;
struct ber_element *a, *v;
if (plan->undefined)
return -1;
else if (plan->adesc != NULL)
a = ldap_get_attribute(root, plan->adesc);
else
a = ldap_find_attribute(root, plan->at);
if (a == NULL) {
log_debug("no attribute [%s] found",
plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
return -1;
}
if (ober_scanf_elements(a, "s(e", &attr, &v) != 0)
return -1;
for (; v; v = v->be_next) {
switch (ldap_filt_subs_value(v, plan->assert.substring)) {
case 0:
return 0;
case -1:
return -1;
default:
break;
}
}
return -1;
}
static int
ldap_filt_and(struct ber_element *root, struct plan *plan)
{
struct plan *arg;
TAILQ_FOREACH(arg, &plan->args, next)
if (ldap_matches_filter(root, arg) != 0)
return -1;
return 0;
}
static int
ldap_filt_or(struct ber_element *root, struct plan *plan)
{
struct plan *arg;
TAILQ_FOREACH(arg, &plan->args, next)
if (ldap_matches_filter(root, arg) == 0)
return 0;
return -1;
}
static int
ldap_filt_not(struct ber_element *root, struct plan *plan)
{
struct plan *arg;
TAILQ_FOREACH(arg, &plan->args, next)
if (ldap_matches_filter(root, arg) != 0)
return 0;
return -1;
}
static int
ldap_filt_presence(struct ber_element *root, struct plan *plan)
{
struct ber_element *a;
if (plan->undefined)
return -1;
else if (plan->adesc != NULL)
a = ldap_get_attribute(root, plan->adesc);
else
a = ldap_find_attribute(root, plan->at);
if (a == NULL) {
log_debug("no attribute [%s] found",
plan->adesc ? plan->adesc : ATTR_NAME(plan->at));
return -1;
}
return 0;
}
int
ldap_matches_filter(struct ber_element *root, struct plan *plan)
{
if (plan == NULL)
return 0;
switch (plan->op) {
case LDAP_FILT_EQ:
case LDAP_FILT_APPR:
return ldap_filt_eq(root, plan);
case LDAP_FILT_SUBS:
return ldap_filt_subs(root, plan);
case LDAP_FILT_AND:
return ldap_filt_and(root, plan);
case LDAP_FILT_OR:
return ldap_filt_or(root, plan);
case LDAP_FILT_NOT:
return ldap_filt_not(root, plan);
case LDAP_FILT_PRES:
return ldap_filt_presence(root, plan);
default:
log_warnx("filter type %d not implemented", plan->op);
return -1;
}
}