summaryrefslogblamecommitdiffstats
path: root/ldap_match_sre.c
blob: b0e69c1485e82e33abcc2305162d6f8d7af51de5 (plain) (tree)














































                                                                                   
                                                               





















































































































                                                                                                        
#include <unistd.h>
#include "ldap.h"
#include "byte.h"
#include "case.h"
#include <ctype.h>

static int matchcasestr(struct string* a,struct string* b) {
  unsigned long l=a->l;
  unsigned long r;
  if (b->l<l) l=b->l;
  if ((r=case_diffb(a->s,l,b->s))) return r;
  if (a->l>l) return 1;
  if (b->l>l) return -1;
  return 0;
}

static int matchstr(struct string* a,struct string* b) {
  unsigned long l=a->l;
  unsigned long r;
  if (b->l<l) l=b->l;
  if ((r=byte_diff(a->s,l,b->s))) return r;
  if (a->l>l) return 1;
  if (b->l>l) return -1;
  return 0;
}

static int matchstr_sre(struct Filter* f,struct string* s) {
  int r;
  if (f->attrflag&1)
    r=matchcasestr(&f->ava.value,s);
  else
    r=matchstr(&f->ava.value,s);
  if (f->type==EQUAL) return (r==0);
  if (f->type==LESSEQUAL) return (r>0);
  return (r<0);
}

static int ldap_match_present_sre(struct SearchResultEntry* sre,struct string* s) {
  struct PartialAttributeList* p;
  for (p=sre->attributes; p; p=p->next) {
    int r;
    if ((r=matchstr(&p->type,s))) return r;
  }
  return 0;
}

static int substrmatch(struct Substring* x,struct string* s,int ignorecase) {
  int (*diff)(const void* a, unsigned long len, const void* b);
  if (ignorecase)
    diff=case_diffb;
  else
    diff=byte_diff;
  while (x) {
    unsigned long i;
    if (x->s.l>s->l) return 0;
    switch (x->substrtype) {
    case prefix:
      if (diff(x->s.s,x->s.l,s->s)) return 0;
found:
      break;
    case any:
      if (s->l<x->s.l) return 0;
      for (i=0; i<=s->l-x->s.l; ++i)
	if (!diff(x->s.s,x->s.l,s->s+i))
	  goto found;
      return 0;
    case suffix:
      if (diff(x->s.s,x->s.l,s->s+s->l-x->s.l)) return 0;
    }
    x=x->next;
  }
  return 1;
}

extern uint32_t dn_ofs;

int ldap_matchfilter_sre(struct SearchResultEntry* sre,struct Filter* f) {
  struct PartialAttributeList* p;
  struct Filter* y=f->x;
  if (!f) return 1;
  switch (f->type) {
  case AND:
    while (y) {
      if (!ldap_matchfilter_sre(sre,y)) return 0;
      y=y->next;
    }
    return 1;
  case OR:
    while (y) {
      if (ldap_matchfilter_sre(sre,y)) return 1;
      y=y->next;
    }
    return 0;
  case NOT:
    return !ldap_matchfilter_sre(sre,y);
  case PRESENT:
    return ldap_match_present_sre(sre,&f->ava.desc);
  case EQUAL:
  case LESSEQUAL:
  case GREATEQUAL:
    if (f->attrofs==dn_ofs)
      return matchstr_sre(f,&sre->objectName);
    for (p=sre->attributes; p; p=p->next) {
      int r;
      struct AttributeDescriptionList* a;
      if (matchstr(&f->ava.desc,&p->type)) {
	for (a=p->values; a; a=a->next)
	  if ((r=matchstr_sre(f,&a->a))) return r;
	return 0;
      }
    }
    return 0;
  case SUBSTRING:
    if (f->attrofs==dn_ofs)
      return substrmatch(f->substrings,&sre->objectName,f->attrflag&1);
    for (p=sre->attributes; p; p=p->next) {
      if (matchstr(&f->ava.desc,&p->type)) {
	struct AttributeDescriptionList* a;
	int r;
	for (a=p->values; a; a=a->next)
	  if ((r=substrmatch(f->substrings,&a->a,f->attrflag&1))) return r;
	return 0;
      }
    }
    return 0;
  default:
    write(2,"unsupported query type\n",23);
    return 0;
  }
  return 1;
}

/* return 0 if they didn't match, otherwise return length in b */
static int match(const char* a,int len,const char* b,int blen) {
  const char* A=a+len;
  const char* B=b+blen;
  while (len>0 && A>a && B>b) {
    --A; --B; --len;
    while (*A==' ' && A>a) { --A; --len; }
    while (*B==' ' && B>b) --B;
    if (tolower(*A) != tolower(*B))
      return 0;
  }
  return b+blen-B;
}

int ldap_match_sre(struct SearchResultEntry* sre,struct SearchRequest* sr) {
  unsigned long i;
  if (sr->baseObject.l>sre->objectName.l)
    /* baseObject is longer than dn */
    return 0;
  if (sr->baseObject.l && !match(sr->baseObject.s,sr->baseObject.l,sre->objectName.s,sre->objectName.l))
    /* baseObject is not a suffix of dn */
    return 0;
  switch (sr->scope) {
  case wholeSubtree: break;
  case baseObject: if (sre->objectName.l==sr->baseObject.l) break; return 0;
  default:
    for (i=0; i<sre->objectName.l; ++i)
      if (sre->objectName.s[i]==',')
	break;
    if (i+2>=sre->objectName.l-sr->baseObject.l) break;
    return 0;
  }
  return ldap_matchfilter_sre(sre,sr->filter);
}