whoops, broke something?
This commit is contained in:
4
Makefile
4
Makefile
@@ -23,7 +23,7 @@ matchprefix.o matchcasestring.o matchcaseprefix.o \
|
||||
scan_ldapmodifyrequest.o scan_ldapaddrequest.o bstrlen.o bstrfirst.o \
|
||||
bstrstart.o free_ldapadl.o free_ldappal.o free_ldapsearchfilter.o \
|
||||
scan_ldapsearchfilterstring.o free_ldapsearchresultentry.o \
|
||||
fmt_ldapsearchfilterstring.o
|
||||
fmt_ldapsearchfilterstring.o ldap_match_sre.o
|
||||
|
||||
ldif.a: ldif_parse.o ldap_match_mapped.o
|
||||
|
||||
@@ -146,3 +146,5 @@ scan_ldapsearchfilterstring.o: scan_ldapsearchfilterstring.c ldap.h
|
||||
scan_ldapsearchrequest.o: scan_ldapsearchrequest.c asn1.h ldap.h
|
||||
scan_ldapsearchresultentry.o: scan_ldapsearchresultentry.c asn1.h ldap.h
|
||||
scan_ldapstring.o: scan_ldapstring.c asn1.h ldap.h
|
||||
|
||||
ldap_match_sre.o: ldap_match_sre.c ldap.h
|
||||
|
||||
2
acl.c
2
acl.c
@@ -167,7 +167,7 @@ int parseaclpermissions(buffer* in,struct acl* a) {
|
||||
case '-': s=&a->maynot; break;
|
||||
case 'r': *s|=acl_read; break;
|
||||
case 'w': *s|=acl_write; break;
|
||||
case 'a': *s|=acl_auth; break;
|
||||
case 'a': *s|=acl_add; break;
|
||||
case 'd': *s|=acl_delete; break;
|
||||
case 'R': *s|=acl_rendn; break;
|
||||
case ' ': case '\t': case '\n': break;
|
||||
|
||||
2
acl.h
2
acl.h
@@ -2,7 +2,7 @@
|
||||
enum {
|
||||
acl_read = 1,
|
||||
acl_write = 2,
|
||||
acl_auth = 4,
|
||||
acl_add = 4,
|
||||
acl_delete = 8,
|
||||
acl_rendn = 16,
|
||||
};
|
||||
|
||||
43
ldap.h
43
ldap.h
@@ -107,6 +107,47 @@ enum ldapops {
|
||||
ExtendedResponse=24
|
||||
};
|
||||
|
||||
enum ldaperrors {
|
||||
success=0,
|
||||
operationsError=1,
|
||||
protocolError=2,
|
||||
timeLimitExceeded=3,
|
||||
sizeLimitExceeded=4,
|
||||
compareFalse=5,
|
||||
compareTrue=6,
|
||||
authMethodNotSupported=7,
|
||||
strongAuthRequired=8,
|
||||
referral=10,
|
||||
adminLimitExceeded=11,
|
||||
unavailableCriticalExtension=12,
|
||||
confidentialityRequired=13,
|
||||
saslBindInProgress=14,
|
||||
noSuchAttribute=16,
|
||||
undefinedAttributeType=17,
|
||||
inappropriateMatching=18,
|
||||
constraintViolation=19,
|
||||
attributeOrValueExists=20,
|
||||
invalidAttributeSyntax=21,
|
||||
noSuchObject=32,
|
||||
aliasProblem=33,
|
||||
invalidDNSyntax=34,
|
||||
aliasDereferencingProblem=36,
|
||||
inappropriateAuthentication=48,
|
||||
invalidCredentials=49,
|
||||
insufficientAccessRights=50,
|
||||
busy=51,
|
||||
unavailable=52,
|
||||
unwillingToPerform=53,
|
||||
loopDetect=54,
|
||||
namingViolation=64,
|
||||
objectClassViolation=65,
|
||||
notAllowedOnNonLeaf=66,
|
||||
notAllowedOnRDN=67,
|
||||
entryAlreadyExists=68,
|
||||
objectClassModsProhibited=69,
|
||||
affectsMultipleDSAs=71,
|
||||
};
|
||||
|
||||
void freefilter(struct Filter* f);
|
||||
void freeava(struct AttributeDescriptionList* a);
|
||||
void freepal(struct PartialAttributeList* a);
|
||||
@@ -161,5 +202,7 @@ void free_ldapaddrequest(struct AddRequest * a);
|
||||
/* does not free e itself */
|
||||
void free_ldapsearchresultentry(struct SearchResultEntry* e);
|
||||
|
||||
int ldap_matchfilter_sre(struct SearchResultEntry* sre,struct Filter* f);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -152,7 +152,7 @@ int ldap_matchfilter_mapped(uint32 ofs,struct Filter* f) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
write(2,"unsupported query type\n",4);
|
||||
write(2,"unsupported query type\n",23);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
166
ldap_match_sre.c
Normal file
166
ldap_match_sre.c
Normal file
@@ -0,0 +1,166 @@
|
||||
#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 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);
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "asn1.h"
|
||||
#include "ldap.h"
|
||||
#include "buffer.h"
|
||||
#include "byte.h"
|
||||
|
||||
#if 0
|
||||
AddRequest ::= [APPLICATION 8] SEQUENCE {
|
||||
@@ -19,7 +20,7 @@ unsigned int scan_ldapaddrequest(const char* src,const char* max,struct AddReque
|
||||
unsigned int res,tmp;
|
||||
unsigned long oslen; /* outer sequence length */
|
||||
struct Addition* last=0;
|
||||
a->a.next=0;
|
||||
byte_zero(a,sizeof(*a));
|
||||
if (!(res=scan_ldapstring(src,max,&a->entry))) goto error;
|
||||
if (!(tmp=scan_asn1SEQUENCE(src+res,max,&oslen))) goto error;
|
||||
res+=tmp;
|
||||
@@ -30,19 +31,19 @@ unsigned int scan_ldapaddrequest(const char* src,const char* max,struct AddReque
|
||||
unsigned long islen;
|
||||
if (last) {
|
||||
struct Addition* cur;
|
||||
if (!(cur=malloc(sizeof(struct Addition))))
|
||||
if (!(cur=malloc(sizeof(struct Addition))))
|
||||
goto error;
|
||||
last->next=cur;
|
||||
last->next=cur;
|
||||
last=cur;
|
||||
} else {
|
||||
last=&a->a;
|
||||
}
|
||||
last->next=0;
|
||||
if (!(tmp=scan_asn1SEQUENCE(src+res,max,&islen)))
|
||||
if (!(tmp=scan_asn1SEQUENCE(src+res,max,&islen)))
|
||||
goto error;
|
||||
res+=tmp;
|
||||
/* scan AttributeDescription: */
|
||||
if (!(tmp=scan_ldapstring(src+res,max,&last->AttributeDescription)))
|
||||
if (!(tmp=scan_ldapstring(src+res,max,&last->AttributeDescription)))
|
||||
goto error;
|
||||
res+=tmp;
|
||||
|
||||
@@ -69,7 +70,7 @@ unsigned int scan_ldapaddrequest(const char* src,const char* max,struct AddReque
|
||||
ilast=&last->vals;
|
||||
}
|
||||
ilast->next=0;
|
||||
if (!(tmp=scan_ldapstring(src+res,max,&ilast->a)))
|
||||
if (!(tmp=scan_ldapstring(src+res,max,&ilast->a)))
|
||||
goto error;
|
||||
res+=tmp;
|
||||
}
|
||||
|
||||
341
tinyldap.c
341
tinyldap.c
@@ -26,6 +26,8 @@
|
||||
#include "uint16.h"
|
||||
#include "acl.h"
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <sys/poll.h>
|
||||
@@ -456,40 +458,71 @@ static long findrec(uint32 dat) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define RANGECHECK 1
|
||||
|
||||
struct bitfield {
|
||||
unsigned long* bits;
|
||||
#ifdef RANGECHECK
|
||||
unsigned long n;
|
||||
#endif
|
||||
unsigned long first,last;
|
||||
};
|
||||
|
||||
/* basic bit-set support: set all bits to 0 */
|
||||
static inline void emptyset(unsigned long* r) {
|
||||
static inline void emptyset(struct bitfield* b) {
|
||||
unsigned long i;
|
||||
for (i=0; i<record_set_length; ++i) r[i]=0;
|
||||
#ifdef RANGECHECK
|
||||
b->n=
|
||||
#endif
|
||||
b->first=record_count;
|
||||
b->last=0;
|
||||
for (i=0; i<record_set_length; ++i) b->bits[i]=0;
|
||||
}
|
||||
|
||||
/* basic bit-set support: set all bits to 1 */
|
||||
static inline void fillset(unsigned long* r) {
|
||||
static inline void fillset(struct bitfield* b) {
|
||||
unsigned long i;
|
||||
for (i=0; i<record_set_length; ++i) r[i]=(unsigned long)-1;
|
||||
b->first=0;
|
||||
#ifdef RANGECHECK
|
||||
b->n=
|
||||
#endif
|
||||
b->last=record_count;
|
||||
for (i=0; i<record_set_length; ++i) b->bits[i]=(unsigned long)-1;
|
||||
}
|
||||
|
||||
/* basic bit-set support: set one bit to 1 */
|
||||
static inline void setbit(unsigned long* r,unsigned long bit) {
|
||||
r[bit/(8*sizeof(long))] |= (1<<(bit&(8*sizeof(long)-1)));
|
||||
static inline void setbit(struct bitfield* b,unsigned long bit) {
|
||||
#ifdef RANGECHECK
|
||||
if (bit<=b->n) {
|
||||
#endif
|
||||
if (bit<b->first) b->first=bit;
|
||||
if (bit>b->last) b->last=bit;
|
||||
b->bits[bit/(8*sizeof(long))] |= (1<<(bit&(8*sizeof(long)-1)));
|
||||
#ifdef RANGECHECK
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* basic bit-set support: see if given bit is set */
|
||||
static inline int isset(unsigned long* r,unsigned long bit) {
|
||||
return r[bit/(8*sizeof(long))] & (1<<(bit&(8*sizeof(long)-1)));
|
||||
static inline int isset(struct bitfield* b,unsigned long bit) {
|
||||
#ifdef RANGECHECK
|
||||
if (bit>b->n) return 0;
|
||||
#endif
|
||||
return b->bits[bit/(8*sizeof(long))] & (1<<(bit&(8*sizeof(long)-1)));
|
||||
}
|
||||
|
||||
/* use index (sorted table of offsets to records) to do a binary search
|
||||
* for all records that match the value in s. Set the corresponding
|
||||
* bits to 1 in bitfield. */
|
||||
static void tagmatches(uint32* index,unsigned int elements,struct string* s,
|
||||
unsigned long* bitfield,int (*match)(struct string* s,const char* c),
|
||||
struct bitfield* b,int (*match)(struct string* s,const char* c),
|
||||
uint32 index_type,enum FilterType ft) {
|
||||
uint32 bottom=0;
|
||||
uint32 top=elements;
|
||||
uint32 mid,k,m;
|
||||
long rec;
|
||||
rec=0;
|
||||
emptyset(bitfield);
|
||||
emptyset(b);
|
||||
|
||||
while ((top>=bottom)) {
|
||||
int l;
|
||||
@@ -523,7 +556,7 @@ static void tagmatches(uint32* index,unsigned int elements,struct string* s,
|
||||
return;
|
||||
}
|
||||
if (rec>=0)
|
||||
setbit(bitfield,rec);
|
||||
setbit(b,rec);
|
||||
/* there may be multiple matches.
|
||||
* Look before and after mid, too */
|
||||
for (k=mid-1; k>0; --k) {
|
||||
@@ -534,7 +567,7 @@ static void tagmatches(uint32* index,unsigned int elements,struct string* s,
|
||||
else if (index_type==1)
|
||||
rec=uint32_read((char*)(&index[k+elements]));
|
||||
if (rec>=0)
|
||||
setbit(bitfield,rec);
|
||||
setbit(b,rec);
|
||||
} else break;
|
||||
}
|
||||
for (k=mid+1; k<elements; ++k) {
|
||||
@@ -545,7 +578,7 @@ static void tagmatches(uint32* index,unsigned int elements,struct string* s,
|
||||
else if (index_type==1)
|
||||
rec=uint32_read((char*)(&index[k+elements]));
|
||||
if (rec>=0)
|
||||
setbit(bitfield,rec);
|
||||
setbit(b,rec);
|
||||
} else break;
|
||||
}
|
||||
return;
|
||||
@@ -575,7 +608,7 @@ static void tagmatches(uint32* index,unsigned int elements,struct string* s,
|
||||
else if (index_type==1)
|
||||
rec=uint32_read((char*)(&index[k+elements]));
|
||||
if (rec>=0)
|
||||
setbit(bitfield,rec);
|
||||
setbit(b,rec);
|
||||
}
|
||||
} else if (ft==LESSEQUAL) {
|
||||
for (k=0; k<=mid; ++k) {
|
||||
@@ -585,7 +618,7 @@ static void tagmatches(uint32* index,unsigned int elements,struct string* s,
|
||||
else if (index_type==1)
|
||||
rec=uint32_read((char*)(&index[k+elements]));
|
||||
if (rec>=0)
|
||||
setbit(bitfield,rec);
|
||||
setbit(b,rec);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -619,7 +652,7 @@ uint32 hash_tolower(const unsigned char* c,unsigned long keylen) {
|
||||
* be used if it only helps eliminate some of the possible matches (for
|
||||
* example an AND query where only one of the involved attributes has an
|
||||
* index). */
|
||||
static int useindex(struct Filter* f,unsigned long* bitfield) {
|
||||
static int useindex(struct Filter* f,struct bitfield* b) {
|
||||
struct Filter* y=f->x;
|
||||
if (!f) return 1;
|
||||
|
||||
@@ -639,12 +672,12 @@ static int useindex(struct Filter* f,unsigned long* bitfield) {
|
||||
if (hashofs==0) return 1;
|
||||
if (hashofs<ofs)
|
||||
/* direct hit */
|
||||
setbit(bitfield,hashofs);
|
||||
setbit(b,hashofs);
|
||||
else {
|
||||
uint32 n=uint32_read(map+hashofs);
|
||||
hashofs+=4;
|
||||
while (n) {
|
||||
setbit(bitfield,uint32_read(map+hashofs));
|
||||
setbit(b,uint32_read(map+hashofs));
|
||||
hashofs+=4;
|
||||
--n;
|
||||
}
|
||||
@@ -658,14 +691,21 @@ static int useindex(struct Filter* f,unsigned long* bitfield) {
|
||||
switch (f->type) {
|
||||
case AND:
|
||||
{
|
||||
unsigned long* tmp=alloca(record_set_length*sizeof(unsigned long));
|
||||
struct bitfield tmp;
|
||||
int ok=0;
|
||||
fillset(bitfield);
|
||||
tmp.bits=alloca(record_set_length*sizeof(unsigned long));
|
||||
if (y) {
|
||||
useindex(y,b);
|
||||
y=y->next;
|
||||
} else
|
||||
fillset(b);
|
||||
while (y) {
|
||||
if (useindex(y,tmp)) {
|
||||
if (useindex(y,&tmp)) {
|
||||
unsigned int i;
|
||||
for (i=0; i<record_set_length; ++i)
|
||||
bitfield[i] &= tmp[i];
|
||||
b->bits[i] &= tmp.bits[i];
|
||||
if (tmp.first>b->first) b->first=tmp.first;
|
||||
if (tmp.last<b->last) b->last=tmp.last;
|
||||
ok=1;
|
||||
}
|
||||
y=y->next;
|
||||
@@ -674,14 +714,21 @@ static int useindex(struct Filter* f,unsigned long* bitfield) {
|
||||
}
|
||||
case OR:
|
||||
{
|
||||
unsigned long* tmp=alloca(record_set_length*sizeof(unsigned long));
|
||||
struct bitfield tmp;
|
||||
int ok=1;
|
||||
emptyset(bitfield);
|
||||
tmp.bits=alloca(record_set_length*sizeof(unsigned long));
|
||||
if (y) {
|
||||
useindex(y,b);
|
||||
y=y->next;
|
||||
} else
|
||||
emptyset(b);
|
||||
while (y) {
|
||||
if (useindex(y,tmp)) {
|
||||
if (useindex(y,&tmp)) {
|
||||
unsigned int i;
|
||||
for (i=0; i<record_set_length; ++i)
|
||||
bitfield[i] |= tmp[i];
|
||||
b->bits[i] |= tmp.bits[i];
|
||||
if (tmp.first<b->first) b->first=tmp.first;
|
||||
if (tmp.last>b->last) b->last=tmp.last;
|
||||
} else
|
||||
ok=0;
|
||||
y=y->next;
|
||||
@@ -704,7 +751,7 @@ static int useindex(struct Filter* f,unsigned long* bitfield) {
|
||||
indexed_attribute=uint32_read(map+ofs+8);
|
||||
if (index_type<=1)
|
||||
if (!matchstring(&f->ava.desc,map+indexed_attribute)) {
|
||||
tagmatches((uint32*)(map+ofs+12),(next-ofs-12)/(4<<index_type),&f->substrings->s,bitfield,
|
||||
tagmatches((uint32*)(map+ofs+12),(next-ofs-12)/(4<<index_type),&f->substrings->s,b,
|
||||
f->attrflag&1?matchcaseprefix:matchprefix,index_type,f->type);
|
||||
return 1;
|
||||
}
|
||||
@@ -719,10 +766,10 @@ static int useindex(struct Filter* f,unsigned long* bitfield) {
|
||||
* we pretend it's indexed */
|
||||
char* x=map+5*4+size_of_string_table+attribute_count*8;
|
||||
unsigned long i;
|
||||
emptyset(bitfield);
|
||||
emptyset(b);
|
||||
for (i=0; i<record_count; ++i) {
|
||||
if (ldap_match_present(x-map,f->attrofs))
|
||||
setbit(bitfield,i);
|
||||
setbit(b,i);
|
||||
x+=uint32_read(x)*8;
|
||||
}
|
||||
return 1;
|
||||
@@ -739,7 +786,7 @@ static int useindex(struct Filter* f,unsigned long* bitfield) {
|
||||
indexed_attribute=uint32_read(map+ofs+8);
|
||||
if (index_type<=1)
|
||||
if (!matchstring(&f->ava.desc,map+indexed_attribute)) {
|
||||
tagmatches((uint32*)(map+ofs+12),(next-ofs-12)/(4<<index_type),&f->ava.value,bitfield,
|
||||
tagmatches((uint32*)(map+ofs+12),(next-ofs-12)/(4<<index_type),&f->ava.value,b,
|
||||
f->attrflag&1?matchcasestring:matchstring,index_type,f->type);
|
||||
return 1;
|
||||
}
|
||||
@@ -763,6 +810,49 @@ static int useindex(struct Filter* f,unsigned long* bitfield) {
|
||||
|_| |___/ |___/
|
||||
#endif
|
||||
|
||||
static int checkacl(uint32 ofs,uint32 attrofs,unsigned long operation,struct SearchResultEntry* sre) {
|
||||
uint32_t j;
|
||||
for (j=0; j<acls; ++j) {
|
||||
/* does the ACL subject apply? */
|
||||
if (!acl_ec_subjects[Acls[j]->subject]) continue;
|
||||
/* does the ACL even apply to the wanted operation? */
|
||||
if ((Acls[j]->may | Acls[j]->maynot) & operation) {
|
||||
uint32 k;
|
||||
if (acl_ec_subjects[filters+Acls[j]->object]==-1) continue;
|
||||
if (acl_ec_subjects[filters+Acls[j]->object]==0) {
|
||||
int match=0;
|
||||
if (Filters[Acls[j]->object]==(struct Filter*)Any)
|
||||
match=1;
|
||||
else if (Filters[Acls[j]->object]==(struct Filter*)Self)
|
||||
match=(ofs==authenticated_as);
|
||||
else if (ofs)
|
||||
match=ldap_matchfilter_mapped(ofs,Filters[Acls[j]->object]);
|
||||
else if (sre)
|
||||
match=ldap_matchfilter_sre(sre,Filters[Acls[j]->object]);
|
||||
else
|
||||
match=-1;
|
||||
if (match)
|
||||
acl_ec_subjects[filters+Acls[j]->object]=1;
|
||||
else {
|
||||
acl_ec_subjects[filters+Acls[j]->object]=-1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (k=0; k<Acls[j]->attrs; ++k) {
|
||||
/* if (Acls[j]->Attrs[k]==any_ofs || !matchstring(&adl->a,map+Acls[j]->Attrs[k])) { */
|
||||
if (Acls[j]->Attrs[k]==any_ofs || attrofs==Acls[j]->Attrs[k]) {
|
||||
if (Acls[j]->may&operation)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this routine is called for each record matched the query. It basically puts together
|
||||
* an answer LDAP message from the record and the list of attributes the other side said
|
||||
* it wanted to have. */
|
||||
@@ -799,8 +889,11 @@ static void answerwith(uint32 ofs,struct SearchRequest* sr,long messageid,int ou
|
||||
if (acls)
|
||||
byte_zero(acl_ec_subjects+filters,filters);
|
||||
|
||||
if (acls && checkacl(ofs,dn_ofs,acl_read,0)!=1) return;
|
||||
|
||||
sre.objectName.l=bstrlen(sre.objectName.s=map+uint32_read(map+ofs+8));
|
||||
sre.attributes=0;
|
||||
|
||||
/* now go through list of requested attributes */
|
||||
{
|
||||
struct AttributeDescriptionList* adl=sr->attributes;
|
||||
@@ -826,52 +919,8 @@ static void answerwith(uint32 ofs,struct SearchRequest* sr,long messageid,int ou
|
||||
while (adl) {
|
||||
const char* val=0;
|
||||
uint32 i=2,j;
|
||||
int ok=acls?0:1;
|
||||
|
||||
for (j=0; j<acls; ++j) {
|
||||
/* does the ACL subject apply? */
|
||||
if (!acl_ec_subjects[Acls[j]->subject]) continue;
|
||||
/* does the ACL even apply to read operations? */
|
||||
if ((Acls[j]->may | Acls[j]->maynot) & acl_read) {
|
||||
uint32 k;
|
||||
if (acl_ec_subjects[filters+Acls[j]->object]==-1) continue;
|
||||
if (acl_ec_subjects[filters+Acls[j]->object]==0) {
|
||||
int match=0;
|
||||
if (Filters[Acls[j]->object]==(struct Filter*)Any)
|
||||
match=1;
|
||||
else if (Filters[Acls[j]->object]==(struct Filter*)Self)
|
||||
match=(ofs==authenticated_as);
|
||||
else
|
||||
match=(ldap_matchfilter_mapped(ofs,Filters[Acls[j]->object]));
|
||||
if (match)
|
||||
acl_ec_subjects[filters+Acls[j]->object]=1;
|
||||
else {
|
||||
acl_ec_subjects[filters+Acls[j]->object]=-1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (k=0; k<Acls[j]->attrs; ++k) {
|
||||
/* if (Acls[j]->Attrs[k]==any_ofs || !matchstring(&adl->a,map+Acls[j]->Attrs[k])) { */
|
||||
if (Acls[j]->Attrs[k]==any_ofs || adl->attrofs==Acls[j]->Attrs[k]) {
|
||||
if (Acls[j]->may&acl_read) {
|
||||
#if 0
|
||||
printf("acl %u allowed serving attribute \"%.*s\"\n",j,(int)adl->a.l,adl->a.s);
|
||||
#endif
|
||||
ok=1;
|
||||
} else {
|
||||
#if 0
|
||||
printf("acl %u disallowed serving attribute \"%.*s\"\n",j,(int)adl->a.l,adl->a.s);
|
||||
#endif
|
||||
ok=-1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ok) break;
|
||||
}
|
||||
|
||||
if (ok==1) {
|
||||
if (!acls || checkacl(ofs,adl->attrofs,acl_read,0)==1) {
|
||||
uint32_unpack(map+ofs,&j);
|
||||
#if 0
|
||||
buffer_puts(buffer_2,"looking for attribute \"");
|
||||
@@ -949,10 +998,79 @@ add_attribute:
|
||||
|___/ |_|
|
||||
#endif
|
||||
|
||||
int copystring(struct string* dest,struct string* src) {
|
||||
dest->s=malloc(src->l+1);
|
||||
if (!dest->s) return -1;
|
||||
byte_copy((char*)dest->s,src->l,src->s);
|
||||
dest->l=src->l;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* deep copy an attribute description list */
|
||||
static int copyadl(struct AttributeDescriptionList** dest,struct AttributeDescriptionList* src) {
|
||||
*dest=0;
|
||||
while (src) {
|
||||
if (!(*dest=malloc(sizeof(*src)))) return -1;
|
||||
byte_zero(*dest,sizeof(*src));
|
||||
if (copystring(&(*dest)->a,&src->a)) return -1;
|
||||
(*dest)->attrofs=src->attrofs;
|
||||
dest=&(*dest)->next;
|
||||
src=src->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* deep copy a partial attribute list */
|
||||
static int copypal(struct PartialAttributeList** dest,struct PartialAttributeList* src) {
|
||||
*dest=0;
|
||||
while (src) {
|
||||
if (!(*dest=malloc(sizeof(**dest)))) return -1;
|
||||
byte_zero(*dest,sizeof(**dest));
|
||||
if (copystring(&(*dest)->type,&src->type) ||
|
||||
copyadl(&(*dest)->values,src->values)) return -1;
|
||||
dest=&(*dest)->next;
|
||||
src=src->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ar2sreh1(struct PartialAttributeList** dest,struct Addition* src) {
|
||||
*dest=0;
|
||||
while (src) {
|
||||
if (!(*dest=malloc(sizeof(**dest)))) return -1;
|
||||
byte_zero(*dest,sizeof(**dest));
|
||||
if (copystring(&(*dest)->type,&src->AttributeDescription) ||
|
||||
copyadl(&(*dest)->values,&src->vals)) return -1;
|
||||
dest=&(*dest)->next;
|
||||
src=src->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addreq2sre(struct SearchResultEntry* sre,struct AddRequest* ar) {
|
||||
byte_zero(sre,sizeof(*sre));
|
||||
if (copystring(&sre->objectName,&ar->entry)) goto allocfailed;
|
||||
if (!(sre->attributes=malloc(sizeof(*sre->attributes)))) goto allocfailed;
|
||||
if (ar2sreh1(&sre->attributes,&ar->a)) goto allocfailed;
|
||||
return 0;
|
||||
allocfailed:
|
||||
free_ldapsearchresultentry(sre);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This is the high level LDAP handling code. It reads queries from the socket at in, and
|
||||
* then writes the answers to out. Normally in == out, but they are separate here so this
|
||||
* can also be called with in=stdin and out=stdout. */
|
||||
|
||||
int writesretofd(int fd,struct SearchResultEntry* sre) {
|
||||
unsigned long l=fmt_ldapsearchresultentry(0,sre);
|
||||
char* c=alloca(l+10); /* you never know */
|
||||
return write(fd,c,l)==l?0:-1;
|
||||
}
|
||||
|
||||
/* a standard LDAP session looks like this:
|
||||
* 1. connect to server
|
||||
* 2. send a BindRequest
|
||||
@@ -1023,33 +1141,31 @@ authfailure:
|
||||
{
|
||||
char outbuf[1024];
|
||||
int s=100;
|
||||
int len=fmt_ldapbindresponse(outbuf+s,48,"","authentication failure","");
|
||||
int len=fmt_ldapbindresponse(outbuf+s,inappropriateAuthentication,"","authentication failure","");
|
||||
int hlen=fmt_ldapmessage(0,messageid,BindResponse,len);
|
||||
fmt_ldapmessage(outbuf+s-hlen,messageid,BindResponse,len);
|
||||
write(out,outbuf+s-hlen,len+hlen);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
unsigned long* result;
|
||||
struct bitfield result;
|
||||
unsigned long i,done;
|
||||
result=alloca(record_set_length*sizeof(unsigned long));
|
||||
useindex(&f,result);
|
||||
result.bits=alloca(record_set_length*sizeof(unsigned long));
|
||||
useindex(&f,&result);
|
||||
done=0;
|
||||
for (i=0; i<record_set_length; ++i)
|
||||
if (result[i])
|
||||
done=1;
|
||||
if (!done) {
|
||||
if (result.first>result.last) {
|
||||
buffer_putsflush(buffer_2,"no matching dn found, bind failed!\n");
|
||||
goto authfailure;
|
||||
}
|
||||
done=0;
|
||||
for (i=0; i<record_count; ) {
|
||||
if (!result[i/(8*sizeof(long))]) {
|
||||
assert(result.last<=record_count);
|
||||
for (i=result.first; i<=result.last; ) {
|
||||
if (!result.bits[i/(8*sizeof(long))]) {
|
||||
i+=8*sizeof(long);
|
||||
continue;
|
||||
}
|
||||
for (; i<record_count; ++i) {
|
||||
if (isset(result,i)) {
|
||||
for (; i<=result.last; ++i) {
|
||||
if (isset(&result,i)) {
|
||||
uint32 j,authdn;
|
||||
const char* c;
|
||||
uint32_unpack(map+indices_offset+4*i,&j);
|
||||
@@ -1130,25 +1246,26 @@ found:
|
||||
fixup(sr.filter);
|
||||
fixupadl(sr.attributes);
|
||||
if (indexable(sr.filter)) {
|
||||
unsigned long* result;
|
||||
struct bitfield result;
|
||||
unsigned long i;
|
||||
#if (debug != 0)
|
||||
if (debug) buffer_putsflush(buffer_2,"query can be answered with index!\n");
|
||||
#endif
|
||||
result=alloca(record_set_length*sizeof(unsigned long));
|
||||
result.bits=alloca(record_set_length*sizeof(unsigned long));
|
||||
/* Use the index to find matching data. Put the offsets
|
||||
* of the matches in a table. Use findrec to locate
|
||||
* the records that point to the data. */
|
||||
useindex(sr.filter,result);
|
||||
for (i=0; i<record_count; ) {
|
||||
useindex(sr.filter,&result);
|
||||
assert(result.last<=record_count);
|
||||
for (i=result.first; i<=result.last; ) {
|
||||
unsigned long ni=i+8*sizeof(long);
|
||||
if (!result[i/(8*sizeof(long))]) {
|
||||
if (!result.bits[i/(8*sizeof(long))]) {
|
||||
i=ni;
|
||||
continue;
|
||||
}
|
||||
if (ni>record_count) ni=record_count;
|
||||
for (; i<ni; ++i) {
|
||||
if (isset(result,i)) {
|
||||
if (isset(&result,i)) {
|
||||
uint32 j;
|
||||
uint32_unpack(map+indices_offset+4*i,&j);
|
||||
if (ldap_match_mapped(j,&sr)) {
|
||||
@@ -1231,14 +1348,32 @@ found:
|
||||
break;
|
||||
case AddRequest:
|
||||
{
|
||||
int err=success;
|
||||
struct AddRequest ar;
|
||||
// buffer_putsflush(buffer_2,"AddRequest!\n");
|
||||
if ((tmp=scan_ldapaddrequest(buf+res,buf+res+len,&ar))) {
|
||||
struct SearchResultEntry sre;
|
||||
addreq2sre(&sre,&ar);
|
||||
/* convert addrequest to searchresultentry */
|
||||
/* TODO: do something with the add request ;-) */
|
||||
} else {
|
||||
buffer_putsflush(buffer_2,"couldn't parse add request!\n");
|
||||
exit(1);
|
||||
}
|
||||
/* 1. check ACLs */
|
||||
if (!acls || checkacl(0,0,acl_add,&sre)==1) {
|
||||
/* 2. check is there already is a record with this dn */
|
||||
/* 3. write record to "data.upd" */
|
||||
{
|
||||
int fd=open("data.upd",O_WRONLY|O_APPEND|O_CREAT,0600);
|
||||
if (fd==-1)
|
||||
err=operationsError;
|
||||
else {
|
||||
if (writesretofd(fd,&sre)==-1)
|
||||
err=operationsError;
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
} else
|
||||
err=insufficientAccessRights;
|
||||
} else
|
||||
err=protocolError;
|
||||
|
||||
buffer_put(buffer_1,ar.entry.s,ar.entry.l);
|
||||
buffer_putsflush(buffer_1,"\n");
|
||||
@@ -1258,12 +1393,12 @@ found:
|
||||
free_ldapaddrequest(&ar);
|
||||
|
||||
{
|
||||
char outbuf[1024];
|
||||
int s=100;
|
||||
int len=fmt_ldapbindresponse(outbuf+s,0,"","","");
|
||||
int hlen=fmt_ldapmessage(0,messageid,AddResponse,len);
|
||||
fmt_ldapmessage(outbuf+s-hlen,messageid,AddResponse,len);
|
||||
write(out,outbuf+s-hlen,len+hlen);
|
||||
char outbuf[1024];
|
||||
int s=100;
|
||||
int len=fmt_ldapresult(outbuf+s,err,"","","");
|
||||
int hlen=fmt_ldapmessage(0,messageid,AddResponse,len);
|
||||
fmt_ldapmessage(outbuf+s-hlen,messageid,AddResponse,len);
|
||||
write(out,outbuf+s-hlen,len+hlen);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user