diff --git a/Makefile b/Makefile index 8ba146d..3f531dc 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ scan_ldapstring.o scan_ldapsearchfilter.o scan_ldapsearchrequest.o \ freefilter.o freeava.o scan_ldapava.o fmt_ldapsearchresultentry.o \ fmt_ldapstring.o freepal.o scan_ldapsearchresultentry.o \ -ldif.a: ldif_parse.o +ldif.a: ldif_parse.o ldap_match.o strduptab.o strstorage.o DIET=diet -Os CC=gcc @@ -33,7 +33,7 @@ endif %: %.c $(DIET) $(CC) $(CFLAGS) -o $@ $^ -lowfat -t1: strduptab.o strstorage.o +t1: t2: ldap.a asn1.a bindrequest tinyldap ldapclient: ldap.a asn1.a diff --git a/README b/README index 0898c6c..eecafbb 100644 --- a/README +++ b/README @@ -1,14 +1,17 @@ Please read ldap.h and asn1.h for an overview of the API. Example code using the high level API is in tinyldap and ldapclient. -This will be encapsulated some more eventually. The next steps are: +This will be encapsulated some more eventually. + +Tinyldap now not only parses incoming search requests, it also performs +a search on the data structure we parsed from the flat LDIF file! When +I plug in fmt_ldapsearchresultentry and fmt_ldapsearchresultdone, we +have a minimal LDAP server! + +The next steps are: - - integrate the LDIF parser from t1.c - - write fmt_ldapsearchresponse - write fmt_ldapsearchrequest and scan_ldapsearchresponse -Then we will have a minimal LDAP server! - ldapclient is the client test application. It connects to localhost, makes a BindRequest and dumps the BindResponse in human readable form. diff --git a/ldap_match.c b/ldap_match.c new file mode 100644 index 0000000..fdc1ece --- /dev/null +++ b/ldap_match.c @@ -0,0 +1,92 @@ +#include "ldap.h" +#include "ldif.h" +#include "byte.h" +#include "str.h" +#include +#include + +/* behave like strcmp */ +static int matchstring(struct string* s,const char* c) { + int l,l1,i; + if (!c) return -1; + l1=l=strlen(c); + if (s->ll; + i=byte_diff(s->s,l1,c); + if (i) return i; + /* one is a prefix of the other */ + if (l==s->l) return 0; + if (c[l1]) /* is c the longer string? */ + return c[l1]; + return -(int)(s->s[l1]); +} + +/* look up value of an attribute for an LDIF record. + * Return NULL if not found */ +static const char* findattr(struct ldaprec* f,struct string* name) { + int i; + if (!matchstring(name,"dn")) return f->dn; + if (!matchstring(name,"mail")) return f->mail; + if (!matchstring(name,"sn")) return f->sn; + if (!matchstring(name,"cn")) return f->cn; + for (i=0; ia[i].name)) + return f->a[i].value; + return 0; +} + +/* return non-zero if the record matches the search filter */ +int ldap_matchfilter(struct ldaprec* s,struct Filter* f) { + struct Filter* y=f->x; + if (!f) return 1; + switch (f->type) { + case AND: + while (y) { + if (!ldap_matchfilter(s,y)) return 0; + y=y->next; + } + return 1; + case OR: + while (y) { + if (ldap_matchfilter(s,y)) return 1; + y=y->next; + } + return 0; + case NOT: + return !ldap_matchfilter(s,f->x); + case EQUAL: +// printf(" -> \"%s\" vs. \"%.*s\"\n",findattr(s,&f->ava.desc),f->ava.value.l,f->ava.value.s); + if (matchstring(&f->ava.value,findattr(s,&f->ava.desc))) return 0; +// puts("yes!!!"); + break; + default: + write(2,"foo\n",4); + return 0; + } + return 1; +} + +/* return non-zero if the record matches the search request */ +int ldap_match(struct ldaprec* r,struct SearchRequest* sr) { + int l=strlen(r->dn); + int i; +// printf("comparing \"%s\" and \"%.*s\"\n",r->dn,(int)sr->baseObject.l,sr->baseObject.s); + /* first see if baseObject is a suffix of dn */ + if (sr->baseObject.l>l) { +// puts("fail: baseObject longer than dn"); + return 0; + } + if (!byte_equal(sr->baseObject.s,sr->baseObject.l,r->dn+l-sr->baseObject.l)) { +// puts("fail: not suffix"); + return 0; + } + /* it is. If scope==wholeSubtree, the scope check is also done */ + switch (sr->scope) { + case wholeSubtree: break; + case baseObject: if (l==sr->baseObject.l) break; return 0; + default: + i=str_chr(r->dn,','); + if (i+2>=sr->baseObject.l-l) break; + return 0; + } + return ldap_matchfilter(r,sr->filter); +} diff --git a/ldif.h b/ldif.h index efd0d76..5c8ac66 100644 --- a/ldif.h +++ b/ldif.h @@ -17,7 +17,7 @@ struct ldaprec { extern const char* dn,* mail,* sn,* cn,* objectClass; extern struct ldaprec *first; -int parse_ldif(const char* filename); +int ldif_parse(const char* filename); /* return non-zero if the record matches the search request */ int ldap_match(struct ldaprec* r,struct SearchRequest* sr); diff --git a/tinyldap.c b/tinyldap.c index b5615f0..4ccaf66 100644 --- a/tinyldap.c +++ b/tinyldap.c @@ -9,12 +9,14 @@ int main() { char buf[BUFSIZE]; int len=0; + ldif_parse("exp.ldif"); for (;;) { int tmp=read(0,buf+len,BUFSIZE-len); int res; long messageid,op,Len; - if (tmp==0) { write(2,"eof!\n",5); return 0; } - if (tmp<1) { write(2,"error!\n",7); return 1; } + if (tmp==0) + if (!len) { write(2,"eof!\n",5); return 0; } + if (tmp<0) { write(2,"error!\n",7); return 1; } len+=tmp; res=scan_ldapmessage(buf,buf+len,&messageid,&op,&Len); if (res>0) { @@ -30,8 +32,9 @@ int main() { { long version,method; struct string name; - res=scan_ldapbindrequest(buf+res,buf+res+len,&version,&name,&method); - if (res>=0) { + int tmp; + tmp=scan_ldapbindrequest(buf+res,buf+res+len,&version,&name,&method); + if (tmp>=0) { buffer_puts(buffer_2,"bind request: version "); buffer_putulong(buffer_2,version); buffer_puts(buffer_2," for name \""); @@ -49,11 +52,33 @@ int main() { } } } + break; + case SearchRequest: + { + struct SearchRequest br; + int tmp; + if ((tmp=scan_ldapsearchrequest(buf+res,buf+res+len,&br))) { + struct ldaprec* r=first; + while (r) { + if (ldap_match(r,&br)) { + buffer_puts(buffer_2,"found: "); + buffer_puts(buffer_2,r->dn); + buffer_putsflush(buffer_2,"\n"); + } + r=r->next; + } + } + } + break; + default: + exit(1); } + Len+=res; if (Len