commit 2d323613808a0a8189cb38d613e84a5658e8b849 Author: leitner Date: Mon Jan 14 16:14:31 2002 +0000 check in work in progress. Please see README. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e0a8c3b --- /dev/null +++ b/Makefile @@ -0,0 +1,57 @@ +#DEBUG=1 + +all: t t1 t2 bindrequest tinyldap ldapclient + +asn1.a: fmt_asn1intpayload.o fmt_asn1length.o fmt_asn1tag.o \ +fmt_asn1int.o fmt_asn1string.o fmt_asn1transparent.o scan_asn1tag.o \ +scan_asn1length.o scan_asn1int.o scan_asn1string.o scan_asn1INTEGER.o \ +scan_asn1STRING.o scan_asn1SEQUENCE.o scan_asn1ENUMERATED.o + +ldap.a: scan_ldapmessage.o fmt_ldapmessage.o fmt_ldapbindrequest.o \ +scan_ldapbindrequest.o fmt_ldapbindresponse.o scan_ldapbindresponse.o + +DIET=diet -Os +CC=gcc +CFLAGS=-pipe -I. -Wall +ifneq ($(DEBUG),) +DIET=diet +CFLAGS=-pipe -I. -Wall -g +endif + +%.o: %.c + $(DIET) $(CC) $(CFLAGS) -c $< + +%.a: + ar cru $@ $^ + +%: %.c + $(DIET) $(CC) $(CFLAGS) -o $@ $^ -lowfat + +t1: strduptab.o strstorage.o +t2: ldap.a asn1.a +bindrequest tinyldap ldapclient: ldap.a asn1.a + +strduptab.o: strduptab.c + gcc $(CFLAGS) -c $^ + +.PHONY: clean tar +clean: + rm -f t t1 t2 *.[ao] bindrequest tinyldap + +tar: clean + cd ..; tar cvvf ldap.tar.bz2 ldap --use=bzip2 --exclude CVS --exclude exp.ldif --exclude polyp* --exclude rfc* + +fmt_asn1int.o: fmt_asn1int.c +fmt_asn1intpayload.o: fmt_asn1intpayload.c +fmt_asn1length.o: fmt_asn1length.c asn1.h +fmt_asn1string.o: fmt_asn1string.c asn1.h +fmt_asn1tag.o: fmt_asn1tag.c asn1.h +fmt_asn1transparent.o: fmt_asn1transparent.c asn1.h +scan_asn1int.o: scan_asn1int.c asn1.h +scan_asn1length.o: scan_asn1length.c asn1.h +scan_asn1string.o: scan_asn1string.c asn1.h +scan_asn1tag.o: scan_asn1tag.c asn1.h +scan_asn1INTEGER.o: scan_asn1INTEGER.c asn1.h +scan_asn1STRING.o: scan_asn1STRING.c asn1.h +scan_asn1SEQUENCE.o: scan_asn1SEQUENCE.c asn1.h +scan_ldapmessage.o: scan_ldapmessage.c asn1.h ldap.h diff --git a/README b/README new file mode 100644 index 0000000..c0b0d25 --- /dev/null +++ b/README @@ -0,0 +1,28 @@ +polyp-00 ist der ASN.1-Code, der mir gemailt wurde. +Leider half er mir nicht sonderlich beim Verständnis von LDAP, daher hab +ich das nochmal selber angefangen. + +Nachdem mir der Parser beim Verständnis geholfen hat, weiß ich jetzt, +wie der Parser wirklich aussehen muß, und habe ihn in Form von scan_* +Routinen neugehackt. Er ist dadurch viel übersichtlicher geworden. +Die Routinen auf dem höchsten Level sind scan_ldapmessage und +scan_ldapbindrequest, und damit erschöpft sich der Parser im Moment auch +schon. Ich habe auch gleich angefangen, einen LDAP Formatter zu +schreiben, der in Form der fmt_* Routinen vorliegt, und er ist genau so +weit wie der Parser, nämlich kann er eine BindResponse mit der gleichen +Message-ID wie der BindRequest formatieren, in eine LDAPMessage +einpacken und das auf file handle 1 ausgeben. Das Ergebnis entspricht +den Paketen von openldap, d.h. scheint zu funktionieren. + +bindrequest ist die Client-Testanwendung. Er stellt einen BindRequest +und gibt ihn auf stdout aus. + +-rwxr-xr-x 1 leitner users 1676 Jan 14 02:58 bindrequest + +tinyldap ist die Server-Testanwendung. Er list eine LDAPMessage von +stdin, schaut ob es ein BindRequest ist, und wenn ja, dann generiert er +eine passende BindResponse. + +-rwxr-xr-x 1 leitner users 4084 Jan 14 03:13 tinyldap + +diet libc und libowfat rulen! ;) diff --git a/asn1.h b/asn1.h new file mode 100644 index 0000000..ea3d6f4 --- /dev/null +++ b/asn1.h @@ -0,0 +1,74 @@ +enum asn1_tagclass { + UNIVERSAL=(0<<6), + APPLICATION=(1<<6), + PRIVATE=(2<<6), + CONTEXT_SPECIFIC=(3<<6) +}; + +enum asn1_tagtype { + PRIMITIVE=(0<<5), + CONSTRUCTED=(1<<5) +}; + +enum asn1_tag { + INTEGER=2, + OCTET_STRING=4, + ENUMERATED=10, + SEQUENCE_OF=16, +}; + +/* write int in least amount of bytes, return number of bytes */ +/* as used in ASN.1 tag */ +int fmt_asn1tag(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,unsigned long tag); + +/* write int in least amount of bytes, return number of bytes */ +/* as used in ASN.1 length */ +int fmt_asn1length(char* dest,unsigned long l); + +/* write int in least amount of bytes, return number of bytes */ +/* as used in ASN.1 INTEGER. This only does the payload, not the tag + * and length headers! */ +int fmt_asn1intpayload(char* dest,unsigned long l); + +/* write int in least amount of bytes, return number of bytes */ +/* as used in ASN.1 INTEGER or ENUMERATED. */ +int fmt_asn1int(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,enum asn1_tag tag,unsigned long l); + +/* write any data type that does not require transformation in the least + * amount of bytes, return number of bytes */ +/* as used in ASN.1 OCTET STRING, SEQUENCE etc. */ +/* does not wrote the payload itself, just the header! First construct + * the sequence/octet string so you know the length, then use + * fmt_asn1transparent to write the header before it */ +int fmt_asn1transparent(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,enum asn1_tag tag,unsigned long l); + +/* write string in least amount of bytes, return number of bytes */ +/* as used in ASN.1 OCTET STRING. */ +int fmt_asn1string(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,enum asn1_tag tag,const char* c,unsigned long l); + +/* write ASN.1 OCTET STRING */ +#define fmt_asn1OCTETSTRING(dest,c,l) fmt_asn1string(dest,UNIVERSAL,PRIMITIVE,OCTET_STRING,c,l); + +/* write ASN.1 INTEGER */ +#define fmt_asn1INTEGER(dest,l) fmt_asn1int(dest,UNIVERSAL,PRIMITIVE,INTEGER,l); + +/* write ASN.1 ENUMERATED */ +#define fmt_asn1ENUMERATED(dest,l) fmt_asn1int(dest,UNIVERSAL,PRIMITIVE,ENUMERATED,l); + +/* write ASN.1 SEQUENCE */ +#define fmt_asn1SEQUENCE(dest,l) fmt_asn1transparent(dest,UNIVERSAL,CONSTRUCTED,SEQUENCE_OF,l); + +int scan_asn1tag(const char* src,const char* max, + enum asn1_tagclass* tc,enum asn1_tagtype* tt, unsigned long* tag); +int scan_asn1length(const char* src,const char* max,unsigned long* length); +int scan_asn1int(const char* src,const char* max, + enum asn1_tagclass* tc,enum asn1_tagtype* tt, unsigned long* tag, + unsigned long* l); +int scan_asn1string(const char* src,const char* max, + enum asn1_tagclass* tc,enum asn1_tagtype* tt,unsigned long* tag, + const char** s,unsigned long* l); + +int scan_asn1SEQUENCE(const char* src,const char* max,unsigned long* len); +int scan_asn1INTEGER(const char* src,const char* max,unsigned long* l); +int scan_asn1ENUMERATED(const char* src,const char* max,unsigned long* l); +int scan_asn1STRING(const char* src,const char* max,const char** s,unsigned long* l); diff --git a/bindrequest.c b/bindrequest.c new file mode 100644 index 0000000..77ede5e --- /dev/null +++ b/bindrequest.c @@ -0,0 +1,12 @@ +#include +#include "ldap.h" + +int main() { + char buf[1024]; + int s=100; + int len=fmt_ldapbindrequest(buf+s,3,"",""); + int hlen=fmt_ldapmessage(0,1,0,len); + fmt_ldapmessage(buf+s-hlen,1,0,len); + write(1,buf+s-hlen,len+hlen); + return 0; +} diff --git a/fmt_asn1int.c b/fmt_asn1int.c new file mode 100644 index 0000000..caed0d3 --- /dev/null +++ b/fmt_asn1int.c @@ -0,0 +1,11 @@ +#include + +int fmt_asn1int(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,enum asn1_tag tag,unsigned long l) { + int len,tmp; + /* first the tag */ + if (!dest) return 2+fmt_asn1intpayload(0,l); + len=fmt_asn1tag(dest,tc,tt,tag); + tmp=fmt_asn1intpayload(dest+len+1,l); + if (fmt_asn1length(dest+len,tmp)!=1) return 0; + return len+tmp+1; +} diff --git a/fmt_asn1intpayload.c b/fmt_asn1intpayload.c new file mode 100644 index 0000000..57f6b25 --- /dev/null +++ b/fmt_asn1intpayload.c @@ -0,0 +1,19 @@ +#include + +int fmt_asn1intpayload(char* dest,unsigned long l) { + int needed=sizeof l; + int i; + for (i=1; i>(i*8))) + break; + } + if (dest) { + int j=i; + while (j) { + --j; + *dest=(l>>(j*8))&0xff; + ++dest; + } + } + return i; +} diff --git a/fmt_asn1length.c b/fmt_asn1length.c new file mode 100644 index 0000000..2ebe9a6 --- /dev/null +++ b/fmt_asn1length.c @@ -0,0 +1,26 @@ +#include "asn1.h" + +/* write int in least amount of bytes, return number of bytes */ +/* as used in ASN.1 length */ +int fmt_asn1length(char* dest,unsigned long l) { + /* encoding is either l%128 or (0x80+number of bytes,bytes) */ + int needed=(sizeof l); + int i; + if (l<128) { + if (dest) *dest=l&0x7f; + return 1; + } + for (i=1; i>(i*8))) + break; + if (dest) { + int j=i; + *dest=0x80+i; ++dest; + while (j) { + --j; + *dest=((l>>(j*8))&0xff); + ++dest; + } + } + return i+1; +} diff --git a/fmt_asn1string.c b/fmt_asn1string.c new file mode 100644 index 0000000..f6885df --- /dev/null +++ b/fmt_asn1string.c @@ -0,0 +1,9 @@ +#include "asn1.h" +#include "byte.h" + +int fmt_asn1string(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,enum asn1_tag tag,const char* c,unsigned long l) { + int len; + len=fmt_asn1transparent(dest,tc,tt,tag,l); + if (dest) byte_copy(dest+len,l,c); + return len+l; +} diff --git a/fmt_asn1tag.c b/fmt_asn1tag.c new file mode 100644 index 0000000..de147e6 --- /dev/null +++ b/fmt_asn1tag.c @@ -0,0 +1,26 @@ +#include "asn1.h" + +/* write int in least amount of bytes, return number of bytes */ +/* as used in ASN.1 tags */ +int fmt_asn1tag(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,unsigned long l) { + /* encoding is either l%128 or (0x80+number of bytes,bytes) */ + int needed=(sizeof l)+1; + int i; + if (l<0x1f) { + if (dest) *dest=(int)tc+(int)tt+(l&0x1f); + return 1; + } + for (i=1; i>(i*7))) + break; + if (dest) { + int j=i; + *dest=(int)tc+(int)tt+0x1f; ++dest; + while (j) { + --j; + *dest=((l>>(j*7))&0x7f); + ++dest; + } + } + return i+1; +} diff --git a/fmt_asn1transparent.c b/fmt_asn1transparent.c new file mode 100644 index 0000000..d7576c5 --- /dev/null +++ b/fmt_asn1transparent.c @@ -0,0 +1,10 @@ +#include "asn1.h" +#include "byte.h" + +int fmt_asn1transparent(char* dest,enum asn1_tagclass tc,enum asn1_tagtype tt,enum asn1_tag tag,unsigned long l) { + int len,tmp; + /* first the tag */ + len=fmt_asn1tag(dest,tc,tt,tag); + tmp=fmt_asn1length(dest?dest+len:dest,l); + return tmp+len; +} diff --git a/fmt_ldapbindrequest.c b/fmt_ldapbindrequest.c new file mode 100644 index 0000000..4a0afeb --- /dev/null +++ b/fmt_ldapbindrequest.c @@ -0,0 +1,15 @@ +#include "asn1.h" +#include "ldap.h" + +int fmt_ldapbindrequest(char* dest,long version,char* name,char* simple) { + int l,sum=0; + int nlen=strlen(name); + sum=l=fmt_asn1INTEGER(dest,version); + if (dest) dest+=l; + l=fmt_asn1OCTETSTRING(dest,name,nlen); + sum+=l+nlen; if (dest) dest+=l+nlen; + nlen=strlen(simple); + l=fmt_asn1string(dest,PRIVATE,PRIMITIVE,0,simple,nlen); + if (dest) dest+=l+nlen; + return sum+l+nlen; +} diff --git a/fmt_ldapbindresponse.c b/fmt_ldapbindresponse.c new file mode 100644 index 0000000..31ed400 --- /dev/null +++ b/fmt_ldapbindresponse.c @@ -0,0 +1,20 @@ + +#include "asn1.h" +#include "ldap.h" + +int fmt_ldapbindresponse(char* dest,long result,char* matcheddn,char* errormessage,char* referral) { + int l,sum=0; + int nlen; + sum=l=fmt_asn1ENUMERATED(dest,result); + if (dest) dest+=l; + nlen=strlen(matcheddn); + l=fmt_asn1OCTETSTRING(dest,matcheddn,nlen); + sum+=l+nlen; if (dest) dest+=l+nlen; + nlen=strlen(errormessage); + l=fmt_asn1OCTETSTRING(dest,errormessage,nlen); + sum+=l+nlen; if (dest) dest+=l+nlen; + nlen=strlen(referral); + l=fmt_asn1OCTETSTRING(dest,referral,nlen); + if (dest) dest+=l+nlen; + return sum+l+nlen; +} diff --git a/fmt_ldapmessage.c b/fmt_ldapmessage.c new file mode 100644 index 0000000..be87a39 --- /dev/null +++ b/fmt_ldapmessage.c @@ -0,0 +1,13 @@ +#include "asn1.h" +#include "ldap.h" + +int fmt_ldapmessage(char* dest,long messageid,long op,long len) { + int l,l2,l3; + l2=fmt_asn1INTEGER(0,messageid); + l3=fmt_asn1transparent(0,APPLICATION,CONSTRUCTED,op,len); + l=fmt_asn1SEQUENCE(dest,len+l2+l3); + if (!dest) return l+l2+l3; + l+=fmt_asn1INTEGER(dest+l,messageid); + l+=fmt_asn1transparent(dest+l,APPLICATION,CONSTRUCTED,op,len); + return l; +} diff --git a/ldap.h b/ldap.h new file mode 100644 index 0000000..f86f41e --- /dev/null +++ b/ldap.h @@ -0,0 +1,56 @@ + +struct attributevalueassertion { + unsigned char* desc,* value; + long dlen, vlen; +}; + +struct attributelist { + unsigned char* a; + long alen; + struct attributelist* next; +}; + +struct filter { + enum { + AND=0, OR=1, NOT=2, EQUAL=3, SUBSTRING=4, GREATEQUAL=5, LESSEQUAL=6, PRESENT=7, APPROX=8, EXTENSIBLE=9 + } type; + struct attributevalueassertion ava; + struct attributelist *a; + enum { + PREFIX=0, ANY=1, SUFFIX=2 + } substrtype; + struct filter* x,*next; +}; + +struct string { + long l; + const char* s; +}; + +enum ldapops { + BindRequest=0, BindResponse=1, + UnbindRequest=2, + SearchRequest=3, SearchResultEntry=4, SearchResultDone=5, + ModifyRequest=6, ModifyResponse=7, + AddRequest=8, AddResponse=9, + DelRequest=10, DelResponse=11, + ModifyDNRequest=12, ModifyDNResponse=13, + CompareRequest=14, CompareResponse=15, + AbandonRequest=16, + ExtendedRequest=23 /* das ist doch kein Zufall?! */, ExtendedResponse=24 +}; + +void freefilter(struct filter* f); + +int scan_ldapmessage(const char* src,const char* max, + long* messageid,long* op,long* len); +int scan_ldapbindrequest(const char* src,const char* max, + long* version,struct string* name,long* method); +int scan_ldapbindresponse(const char* src,const char* max, + long* result,struct string* matcheddn, + struct string* errormessage,struct string* referral); + +int fmt_ldapmessage(char* dest,long messageid,long op,long len); +int fmt_ldapbindrequest(char* dest,long version,char* name,char* simple); +int fmt_ldapbindresponse(char* dest,long result,char* matcheddn, + char* errormessage,char* referral); diff --git a/ldapclient.c b/ldapclient.c new file mode 100644 index 0000000..c2bb770 --- /dev/null +++ b/ldapclient.c @@ -0,0 +1,74 @@ +#include +#include "byte.h" +#include "buffer.h" +#include "ldap.h" +#include "socket.h" +#include "ip4.h" + +#define BUFSIZE 8192 + +int main() { + int sock; + char buf[BUFSIZE]; + int len=0; + long messageid=1; + + sock=socket_tcp4(); + { + char ip[4]; + scan_ip4(ip,"127.0.0.1"); + if (socket_connect4(sock,ip,389)) { + buffer_putsflush(buffer_2,"could not connect to ldap server!\n"); + return 1; + } + } + { + char outbuf[1024]; + int s=100; + int len=fmt_ldapbindrequest(outbuf+s,3,"",""); + int hlen=fmt_ldapmessage(0,messageid,BindRequest,len); + fmt_ldapmessage(outbuf+s-hlen,messageid,BindRequest,len); + write(sock,outbuf+s-hlen,len+hlen); + } + for (;;) { + int tmp=read(sock,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; } + len+=tmp; + res=scan_ldapmessage(buf,buf+len,&messageid,&op,&Len); + if (res>0) { + buffer_puts(buffer_2,"got message of length "); + buffer_putulong(buffer_2,Len); + buffer_puts(buffer_2," with id "); + buffer_putulong(buffer_2,messageid); + buffer_puts(buffer_2,": op "); + buffer_putulong(buffer_2,op); + buffer_putsflush(buffer_2,".\n"); + switch (op) { + case BindResponse: + { + long result; + struct string matcheddn,errormessage,referral; + res=scan_ldapbindresponse(buf+res,buf+res+len,&result,&matcheddn,&errormessage,&referral); + if (res>=0) { + buffer_puts(buffer_2,"bind response: result "); + buffer_putulong(buffer_2,result); + buffer_puts(buffer_2,", matched dn \""); + buffer_put(buffer_2,matcheddn.s,matcheddn.l); + buffer_puts(buffer_2,"\", error message \""); + buffer_put(buffer_2,errormessage.s,errormessage.l); + buffer_puts(buffer_2,"\", referral \""); + buffer_put(buffer_2,referral.s,referral.l); + buffer_putsflush(buffer_2,"\".\n"); + } + } + } + if (Lenmax) return 0; + *len=res+tlen; + if (tc==UNIVERSAL || tt==CONSTRUCTED || tag==SEQUENCE_OF) + return res; + return 0; +} diff --git a/scan_asn1STRING.c b/scan_asn1STRING.c new file mode 100644 index 0000000..b91cc46 --- /dev/null +++ b/scan_asn1STRING.c @@ -0,0 +1,12 @@ +#include "asn1.h" + +int scan_asn1STRING(const char* src,const char* max,const char** s,unsigned long* l) { + int tmp; + long tag; + enum asn1_tagclass tc; + enum asn1_tagtype tt; + if ((tmp=scan_asn1string(src,max,&tc,&tt,&tag,s,l))) + if (tc==UNIVERSAL || tt==PRIMITIVE || tag==OCTET_STRING) + return tmp; + return 0; +} diff --git a/scan_asn1int.c b/scan_asn1int.c new file mode 100644 index 0000000..0847286 --- /dev/null +++ b/scan_asn1int.c @@ -0,0 +1,21 @@ +#include "asn1.h" + +static long int handleint(const unsigned char* c,int len) { + long l=0; + while (len) { + l=l*256+*c; + --len; ++c; + } + return l; +} + +int scan_asn1int(const char* src,const char* max,enum asn1_tagclass* tc,enum asn1_tagtype* tt,unsigned long* tag,unsigned long* l) { + int len,tmp; + long tlen; + if (!(len=scan_asn1tag(src,max,tc,tt,tag))) return 0; + if (!(tmp=scan_asn1length(src+len,max,&tlen))) return 0; + len+=tmp; + if (src+len+tlen>max) return 0; + *l=handleint(src+len,tlen); + return len+tlen; +} diff --git a/scan_asn1length.c b/scan_asn1length.c new file mode 100644 index 0000000..478f5c1 --- /dev/null +++ b/scan_asn1length.c @@ -0,0 +1,18 @@ +#include "asn1.h" + +int scan_asn1length(const char* src,const char* max,unsigned long* length) { + const char* orig=src; + if (src>max) return 0; + if (*src&0x80) { + int chars=*src&0x7f; + long l=0; + while (chars>0) { + if (++src>=max) return 0; + l=l*256+*src; + --chars; + } + *length=l; + } else + *length=*src&0x7f; + return src-orig+1; +} diff --git a/scan_asn1string.c b/scan_asn1string.c new file mode 100644 index 0000000..fb9d2ca --- /dev/null +++ b/scan_asn1string.c @@ -0,0 +1,13 @@ +#include "asn1.h" + +int scan_asn1string(const char* src,const char* max, + enum asn1_tagclass* tc,enum asn1_tagtype* tt,unsigned long* tag, + const char** s,unsigned long* l) { + int len,tmp; + if (!(len=scan_asn1tag(src,max,tc,tt,tag))) return 0; + if (!(tmp=scan_asn1length(src+len,max,l))) return 0; + len+=tmp; + if (src+len+*l>max) return 0; + *s=src+len; + return len+*l; +} diff --git a/scan_asn1tag.c b/scan_asn1tag.c new file mode 100644 index 0000000..3057a34 --- /dev/null +++ b/scan_asn1tag.c @@ -0,0 +1,19 @@ +#include "asn1.h" + +int scan_asn1tag(const char* src,const char* max,enum asn1_tagclass* tc,enum asn1_tagtype* tt,unsigned long* tag) { + const char* orig=src; + *tc=(*src&0xC0); + *tt=(*src&0x20); + if (maxmax) return 0; + *tag=*tag*128+(*src&0x7F); + if (!(*src&0x80)) break; + } + return (src-orig+1); + } else { + *tag=*src&0x1f; + return 1; + } +} diff --git a/scan_ldapbindrequest.c b/scan_ldapbindrequest.c new file mode 100644 index 0000000..1068bec --- /dev/null +++ b/scan_ldapbindrequest.c @@ -0,0 +1,19 @@ +#include "asn1.h" +#include "ldap.h" + +int scan_ldapbindrequest(const char* src,const char* max, + long* version,struct string* name,long* method) { + int res,tmp; + if (!(res=scan_asn1INTEGER(src,max,version))) return 0; + if (!(tmp=scan_asn1STRING(src+res,max,&name->s,&name->l))) return 0; + res+=tmp; + { + enum asn1_tagclass tc; + enum asn1_tagtype tt; + long method; + if (!(tmp=scan_asn1tag(src+res,max,&tc,&tt,&method))) return 0; + if (tc!=PRIVATE || tt!=PRIMITIVE) return 0; + res+=tmp; + } + return res; +} diff --git a/scan_ldapbindresponse.c b/scan_ldapbindresponse.c new file mode 100644 index 0000000..488ad16 --- /dev/null +++ b/scan_ldapbindresponse.c @@ -0,0 +1,24 @@ +#include "asn1.h" +#include "ldap.h" + +int scan_ldapbindresponse(const char* src,const char* max, + long* result,struct string* matcheddn, + struct string* errormessage,struct string* referral) { + int res,tmp; + if (!(res=scan_asn1ENUMERATED(src,max,result))) return 0; + if (!(tmp=scan_asn1STRING(src+res,max,&matcheddn->s,&matcheddn->l))) return 0; + res+=tmp; + if (src+ress,&errormessage->l))) return 0; + res+=tmp; + } else { + errormessage->s=0; errormessage->l=0; + } + if (src+ress,&referral->l))) return 0; + res+=tmp; + } else { + referral->s=0; referral->l=0; + } + return res; +} diff --git a/scan_ldapmessage.c b/scan_ldapmessage.c new file mode 100644 index 0000000..12dec56 --- /dev/null +++ b/scan_ldapmessage.c @@ -0,0 +1,22 @@ +#include "asn1.h" +#include "ldap.h" + +int scan_ldapmessage(const char* src,const char* max, + long* messageid,long* op,long* len) { + int res,tmp; + if (!(res=scan_asn1SEQUENCE(src,max,len))) goto error; + if (!(tmp=scan_asn1INTEGER(src+res,max,messageid))) goto error; + res+=tmp; + { + enum asn1_tagclass tc; + enum asn1_tagtype tt; + if (!(tmp=scan_asn1tag(src+res,max,&tc,&tt,op))) goto error; + if (tc!=APPLICATION || tt!=CONSTRUCTED) goto error; + res+=tmp; + if (!(tmp=scan_asn1length(src+res,max,len))) goto error; + res+=tmp; + } + return res; +error: + return 0; +} diff --git a/strduptab.c b/strduptab.c new file mode 100644 index 0000000..5653fa4 --- /dev/null +++ b/strduptab.c @@ -0,0 +1,29 @@ +#include +#include "str.h" +#include "strduptab.h" +#include "strstorage.h" + +#define PAGESIZE 4096 + +const char* strduptab_add(struct stringduptable* t,const char* s) { + int i; + for (i=0; in; ++i) + if (str_equal(t->s[i],s)) + return t->s[i]; + if (t->n>=t->a) { + const char** x; + int a=t->a*2; + if (!a) a=1024; + if (!(x=realloc((char**)t->s,a*sizeof(char*)))) + return 0; + t->a=a; + t->s=x; + } + { + const char* x=strstorage_add(s,strlen(s)+1); + if (!x) return 0; + s=x; + } + t->s[t->n]=s; ++t->n; + return s; +} diff --git a/strduptab.h b/strduptab.h new file mode 100644 index 0000000..48097b6 --- /dev/null +++ b/strduptab.h @@ -0,0 +1,13 @@ +/* save memory for constant strings by keeping a list of the ones that + * we already saw and not allocating memory for each new one. The only + * API is "add string and return pointer". Will try to insert the + * string in the table. If the same string was already there, it will + * return a pointer to that string, otherwise it will insert a copy of + * the new string. */ + +struct stringduptable { + int n,a; + const char** s; +}; + +const char* strduptab_add(struct stringduptable* t,const char* s); diff --git a/strstorage.c b/strstorage.c new file mode 100644 index 0000000..309049b --- /dev/null +++ b/strstorage.c @@ -0,0 +1,29 @@ +#include +#include "byte.h" +#include "strstorage.h" + +#define PAGESIZE 4096 + +const char* strstorage_add(const char* s,int n) { + static char* page=0; + static int leftonpage=0; + if (leftonpage>=n) { +copyit: + byte_copy(page,n,s); + s=page; + page+=n; + leftonpage-=n; + } else { + if (n>=PAGESIZE/2) { + char* tmp=malloc(n); + if (!tmp) return 0; + byte_copy(tmp,n,s); + s=tmp; + } else { + if (!(page=malloc(PAGESIZE))) return 0; + leftonpage=PAGESIZE; + goto copyit; + } + } + return s; +} diff --git a/strstorage.h b/strstorage.h new file mode 100644 index 0000000..58a8663 --- /dev/null +++ b/strstorage.h @@ -0,0 +1,5 @@ +/* provide a string allocator. It is add-only, you can't free a string + * later. On the plus side, the allocation overhead is close to zero. + * Will a stored copy of the string. */ + +const char* strstorage_add(const char* s,int n); diff --git a/t.c b/t.c new file mode 100644 index 0000000..dbb4921 --- /dev/null +++ b/t.c @@ -0,0 +1,557 @@ +#include "open.h" +#include "buffer.h" +#include +#include +#include +#include + +#if 0 + LDAPMessage ::= SEQUENCE { + messageID MessageID, + protocolOp CHOICE { + bindRequest BindRequest, + bindResponse BindResponse, + unbindRequest UnbindRequest, + searchRequest SearchRequest, + searchResEntry SearchResultEntry, + searchResDone SearchResultDone, + searchResRef SearchResultReference, + modifyRequest ModifyRequest, + modifyResponse ModifyResponse, + addRequest AddRequest, + addResponse AddResponse, + delRequest DelRequest, + delResponse DelResponse, + modDNRequest ModifyDNRequest, + modDNResponse ModifyDNResponse, + compareRequest CompareRequest, + compareResponse CompareResponse, + abandonRequest AbandonRequest, + extendedReq ExtendedRequest, + extendedResp ExtendedResponse }, + controls [0] Controls OPTIONAL } + + MessageID ::= INTEGER (0 .. maxInt) + + maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) -- + + LDAPString ::= OCTET STRING + + LDAPOID ::= OCTET STRING + + LDAPDN ::= LDAPString + + RelativeLDAPDN ::= LDAPString +#endif + +static long int handleint(unsigned char* c,int len) { + long l=0; + while (len) { + l=l*256+*c; + --len; ++c; + } + return l; +} + +static int gethibitlen(unsigned char* c,unsigned char* max,unsigned long* len) { + unsigned char* orig=c; + if (*c&0x80) { + int chars=*c&0x7f; + *len=0; + while (chars>0) { + if (++c>=max) return 0; + *len=*len*256+*c; + --chars; + } + } else + *len=*c&0x7f; + return c-orig+1; +} + +static int parsetag(unsigned char* c,unsigned char* max,unsigned long* tag,unsigned long* len) { + unsigned char* orig=c; + if (max=max) return 0; + *tag=*tag*128+(*c&0x7F); + if (!(*c&0x80)) break; + } + else + *tag=*c&0x1f; + ++c; + c+=gethibitlen(c,max,len); + return c-orig; +} + +static void interpret(unsigned char* c,int dlen) { +// unsigned char *max=c+dlen; +// enum { PRIMITIVE, CONSTRUCTED } type; + unsigned long tag=0; + unsigned long len=0; + switch (*c>>6) { + case 0: puts("universal"); break; + case 1: puts("application"); break; + case 2: puts("context-specific"); break; + case 3: puts("private"); break; + } + if (!(*c & 0x20)) { /* primitive encoding */ + puts("primitive, definite-length"); + } else { + puts("constructed, definite-length"); + } + if ((*c&0x1f) == 0x1f) { /* high-tag-number form */ + for (;;) { + ++c; + tag=tag*128+(*c&0x7F); + if (!(*c&0x80)) break; + } + } else + tag=*c&0x1f; + ++c; + if (*c&0x80) { + int chars=*c&0x7f; + while (chars>0) { + ++c; + len=len*256+*c; + --chars; + } + } else + len=*c&0x7f; + ++c; + switch (tag) { + case 2: + printf(" -> INTEGER: %ld\n",handleint(c,len)); + break; + case 4: + printf(" -> OCTET STRING: "); fwrite(c,len,1,stdout); printf("\n"); + break; + case 10: + printf(" -> ENUMERATED: %ld\n",handleint(c,len)); + break; + case 16: + puts("SEQUENCE OF"); + break; + default: + printf("unknown tag %lu (%lx)\n",tag,tag); + } + if (tag!=16) c+=len; +// if (csizeof(long)) { + if (*buf) return 0; /* number larger than native int size */ + ++buf; --len; + } + while (len) { + *l=*l*256+*buf; + ++buf; --len; + } + return buf-orig; + } + return 0; +} + +static unsigned int parseint(unsigned char* buf,unsigned char* max,long int* l) { + return parseintlike(buf,max,2,l); +} + +static unsigned int parseenum(unsigned char* buf,unsigned char* max,long int* l) { + return parseintlike(buf,max,10,l); +} + +static unsigned int parsebool(unsigned char* buf,unsigned char* max,long int* l) { + return parseintlike(buf,max,1,l); +} + +/* parse ASN.1 OCTET STRING, return length or 0 on parse error */ +static unsigned int parseoctetstring(unsigned char* buf,unsigned char* max,unsigned char** s,unsigned long* slen) { + int res; + unsigned long tag; + unsigned char* orig=buf; + if ((res=parsetag(buf,max,&tag,slen))) { + if (tag!=4) return 0; + buf+=res; + *s=buf; + buf+=*slen; + return buf-orig; + } + return 0; +} + +static int handlebind(unsigned char* buf,unsigned char* max,long messageid,int answerfd) { + int res; + long bindversion; + unsigned char* s; + unsigned long slen; + /* int version */ + if (!(res=parseint(buf,max,&bindversion))) return -1; + buf+=res; + printf("bind version %ld\n",bindversion); +#if 0 + if (bindversion>3) { + char buf[100]; + int b=8,e=8; + } +#endif + /* ldapdn name */ + if (!(res=parseoctetstring(buf,max,&s,&slen))) return -1; + buf+=res; + printf("name \""); fwrite(s,slen,1,stdout); printf("\"\n"); + /* authentication authenticationchoice */ + /* since we are such a trivial LDAP server, we discard bind requests */ + return 0; +} + +struct attributevalueassertion { + unsigned char* desc,* value; + long dlen, vlen; +}; + +struct attributelist { + unsigned char* a; + long alen; + struct attributelist* next; +}; + +static int parseava(unsigned char* buf,unsigned char* max, struct attributevalueassertion* ava) { + /* SEQUENCE { desc: OCTET STRING, value: OCTET STRING } */ + int res; + unsigned char* orig=buf; + if (!(res=parseoctetstring(buf,max,&ava->desc,&ava->dlen))) return 0; + buf+=res; + if (!(res=parseoctetstring(buf,max,&ava->value,&ava->vlen))) return 0; + buf+=res; + printf("attribute value assertion: \""); + fwrite(ava->desc,ava->dlen,1,stdout); + printf("\" \""); + fwrite(ava->value,ava->vlen,1,stdout); + printf("\"\n"); + return buf-orig; +} + +struct filter { + enum { + AND=0, OR=1, NOT=2, EQUAL=3, SUBSTRING=4, GREATEQUAL=5, LESSEQUAL=6, PRESENT=7, APPROX=8, EXTENSIBLE=9 + } type; + struct attributevalueassertion ava; + struct attributelist *a; + enum { + PREFIX=0, ANY=1, SUFFIX=2 + } substrtype; + struct filter* x,*next; +}; + +static int parsefilter(unsigned char* buf,unsigned char* max,struct filter** f) { +/* + Filter ::= CHOICE { + and [0] SET OF Filter, + or [1] SET OF Filter, + not [2] Filter, + equalityMatch [3] AttributeValueAssertion, + substrings [4] SubstringFilter, + greaterOrEqual [5] AttributeValueAssertion, + lessOrEqual [6] AttributeValueAssertion, + present [7] AttributeDescription, + approxMatch [8] AttributeValueAssertion, + extensibleMatch [9] MatchingRuleAssertion } + + SubstringFilter ::= SEQUENCE { + type AttributeDescription, + -- at least one must be present + substrings SEQUENCE OF CHOICE { + initial [0] LDAPString, + any [1] LDAPString, + final [2] LDAPString } } + + MatchingRuleAssertion ::= SEQUENCE { + matchingRule [1] MatchingRuleId OPTIONAL, + type [2] AttributeDescription OPTIONAL, + matchValue [3] AssertionValue, + dnAttributes [4] BOOLEAN DEFAULT FALSE } +*/ + unsigned char* orig=buf; + unsigned long slen,tag; + int res; + *f=0; + if ((buf[0]>>6)!=2) goto error; /* context-specific */ + if (!(res=parsetag(buf,max,&tag,&slen))) goto error; + if (tag<0 || tag>9) goto error; + *f=malloc(sizeof(struct filter)); + (*f)->x=(*f)->next=0; + (*f)->type=tag; + buf+=res; + switch (tag) { + case 3: case 5: case 6: case 8: + if (!(res=parseava(buf,buf+slen,&(*f)->ava))) goto error; + buf+=res; + break; + case 0: puts("AND"); return 0; + case 1: + puts("OR"); + (*f)->x=0; + while (bufx; + int res; + if (!(res=parsefilter(buf,max,&(*f)->x))) { + if (F) { /* OK, end of sequence */ + (*f)->x=F; + return buf-orig; + } +// interpret(buf,max-buf); + (*f)->x=F; + goto error; + } + (*f)->x->next=F; + buf+=res; + } +// interpret(buf,max-buf); + return 0; + case 2: puts("NOT"); return 0; + case 4: + { + unsigned char* nmax=buf+slen; + long l,tlen; + if (!(res=parseoctetstring(buf,nmax,&(*f)->ava.desc,&(*f)->ava.dlen))) goto error; + buf+=res; + printf("substr in attribute \""); fwrite((*f)->ava.desc,(*f)->ava.dlen,1,stdout); printf("\"\n"); + if (!(res=parsetag(buf,nmax,&l,&tlen))) goto error; + buf+=res; + if (l != 16) goto error; /* sequence of */ + if (buf+tlen != nmax) goto error; /* no more tags after the sequence */ + while (bufava.value=buf; (*f)->ava.vlen=tlen; + buf+=tlen; + if (l<0 || l>2) goto error; + (*f)->substrtype=l; + switch (l) { + case 0: printf("prefix \""); break; + case 1: printf("substr \""); break; + case 2: printf("suffix \""); break; + } + fwrite((*f)->ava.value,(*f)->ava.vlen,1,stdout); printf("\"\n"); + } + break; + } + case 7: puts("PRESENT"); return 0; + case 9: puts("EXTENSIBLE"); return 0; + default: goto error; + } + return buf-orig; +error: + if (*f) { free(*f); *f=0; } + return 0; +} + +static void freefilter(struct filter* f) { + if (f) { + while (f->a) { + struct attributelist* a=f->a->next; + free(f->a); + f->a=a; + } + if (f->x) freefilter(f->x); + if (f->next) freefilter(f->next); + free(f); + } +} + +static int handlesearch(unsigned char* buf,unsigned char* max) { + int res; + unsigned char* s; + unsigned long slen,scope,deref,sizelimit,timelimit,typesonly; + struct filter* f; + f=0; + /* int version */ + if (!(res=parseoctetstring(buf,max,&s,&slen))) goto error; + buf+=res; + printf("baseObject \""); fwrite(s,slen,1,stdout); printf("\"\n"); + /* scope enumerated; 0=baseObject, 1=singleLevel, 2=wholeSubtree */ + if (!(res=parseenum(buf,max,&scope))) goto error; + buf+=res; + printf("scope: "); + switch (scope) { + case 0: puts("baseObject"); break; + case 1: puts("singleLevel"); break; + case 2: puts("wholeSubtree"); break; + default: goto error; + } + /* derefaliases enumerated; 0=never, 1=in searching, 2=baseobject, * 3=always */ + if (!(res=parseenum(buf,max,&deref))) goto error; + buf+=res; + printf("derefaliases: "); + switch (scope) { + case 0: puts("never"); break; + case 1: puts("in searching"); break; + case 2: puts("baseobject"); break; + case 3: puts("always"); break; + default: goto error; + } + /* int sizelimit */ + if (!(res=parseint(buf,max,&sizelimit))) goto error; + buf+=res; + printf("size limit %lu\n",sizelimit); + /* int timelimit */ + if (!(res=parseint(buf,max,&timelimit))) goto error; + buf+=res; + printf("time limit %lu\n",timelimit); + /* bool typesonly */ + if (!(res=parsebool(buf,max,&typesonly))) goto error; + buf+=res; + printf("typesonly %lu\n",typesonly); + /* filter */ + if (!(res=parsefilter(buf,max,&f))) goto error; + buf+=res; + /* attributes */ + { + unsigned char* nmax; + long seqlen; + struct attributelist** a=&f->a; + if (buf[0]!='0') goto error; + ++buf; + buf+=gethibitlen(buf,max,&seqlen); + nmax=buf+seqlen; + if (nmax>max) goto error; + for (;;) { + if (buf>max) goto error; + if (buf==max) break; + if (!*a) *a=malloc(sizeof(struct attributelist)); + (*a)->next=0; + if (!(res=parseoctetstring(buf,max,&(*a)->a,&(*a)->alen))) goto error; + buf+=res; + printf("attribute \""); fwrite((*a)->a,(*a)->alen,1,stdout); printf("\"\n"); + a=&(*a)->next; + } + } + puts("ok"); + return 0; +error: + freefilter(f); + return -1; +} + +#define TEST + +/* return length of query that was parsed OK or 0 on parse error */ +static unsigned int parseldapquery(unsigned char* buf,unsigned char* max,int answerfd) { + long seqlen; + int res; + long messageid; + unsigned long tag,len; + unsigned char* orig=buf; +// interpret(buf,max-buf); + /* SEQUENCE OF */ + if (buf[0]!='0') goto error; + ++buf; + buf+=gethibitlen(buf,max,&seqlen); + /* INTEGER message id */ + if (!(res=parseint(buf,max,&messageid))) goto error; + buf+=res; + printf("message id %ld\n",messageid); + /* CHOICE */ + if ((buf[0]>>6)!=1) return 0; /* application */ + if (!(res=parsetag(buf,max,&tag,&len))) goto error; + buf+=res; + switch (tag) { + case 0: + puts("bind"); + if (handlebind(buf,max,messageid,answerfd)) goto error; + break; + case 2: + puts("unbind"); + break; + case 3: + puts("search"); + if (handlesearch(buf,buf+len)) goto error; + break; + case 16: + printf("abandon %lu\n",handleint(buf,len)); + break; +#ifdef TEST + case 1: + puts("bindreply"); + /* + BindResponse ::= [APPLICATION 1] SEQUENCE { + COMPONENTS OF LDAPResult, + serverSaslCreds [7] OCTET STRING OPTIONAL } + */ + { + long code,alen; + int res; + unsigned char* a; + len+=(buf-orig); + if (!(res=parseenum(buf,orig+len,&code))) goto error; + printf("code %ld\n",code); + buf+=res; + if (!(res=parseoctetstring(buf,max,&a,&alen))) goto error; + buf+=res; + printf("matchedDN \""); fwrite(a,alen,1,stdout); printf("\"\n"); + if (!(res=parseoctetstring(buf,max,&a,&alen))) goto error; + buf+=res; + printf("errorMessage \""); fwrite(a,alen,1,stdout); printf("\"\n"); + return len; + } + break; + case 4: + puts("searchResult"); + { + int res; + long tag,alen; + unsigned char* a; + if (!(res=parseoctetstring(buf,max,&a,&alen))) goto error; + buf+=res; + printf("objectName \""); fwrite(a,alen,1,stdout); printf("\"\n"); + + if (!(res=parsetag(buf,max,&tag,&alen))) goto error; + if (tag != 16) goto error; + printf("sequence length %ld\n",alen); + buf+=res; + } + return 0; +#endif + default: + printf("unknown op %ld\n",tag); + return 0; + } + printf("skipping len %ld\n",len); + buf+=len; + return buf-orig; +error: + return 0; +} + +int main() { + char buf[8192]; + char* max; + int l,fd,res; +// fd=open_read("/tmp/ldap/127.000.000.001.32875-127.000.000.001.00389"); +// fd=open_read("/tmp/ldap/127.000.000.001.32779-127.000.000.001.00389"); +// fd=open_read("/tmp/ldap/127.000.000.001.38433-127.000.000.001.00389"); +// fd=open_read("/tmp/ldap/127.000.000.001.00389-127.000.000.001.32779"); + fd=open_read("answer"); + l=read(fd,buf,8192); + max=buf+l; + close(fd); + l=0; + for (;;) { + res=parseldapquery(buf+l,max,1); + printf("res= %d\n",res); + if (res==0) break; + l+=res; + } +// interpret(buf,l); + return 0; +} diff --git a/t1.c b/t1.c new file mode 100644 index 0000000..77ba030 --- /dev/null +++ b/t1.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include "strduptab.h" +#include "strstorage.h" +#include "str.h" + +/* how many attributes do we allow per record? */ +#define ATTRIBS 8 + +struct attribute { + const char* name,* value; +}; + +struct ldaprec { + const char* dn,* mail,* sn,* cn; /* most often encountered records */ + int n; /* number of attributes */ + struct attribute a[ATTRIBS]; + struct ldaprec* next; +}; + +static struct stringduptable tags; +static struct stringduptable classes; + +const char* dn,* mail,* sn,* cn,* objectClass; + +int parserec(buffer* b, struct ldaprec** l) { + char buf[8192]; + int n,i,eof=0,ofs=0; + if (!(*l=malloc(sizeof(struct ldaprec)))) return 2; + do { + const char* tmp,* val; + n=ofs+buffer_get_token(b,buf+ofs,8192-ofs,":",1); + i=scan_whitenskip(buf,n); + buf[n]=0; + if (!(tmp=strduptab_add(&tags,buf+i))) { +nomem: + buffer_putsflush(buffer_2,"out of memory!\n"); + return 1; + } +#if 0 + buffer_puts(buffer_1,"found tag "); + buffer_put(buffer_1,buf+i,n-i); + buffer_putsflush(buffer_1,".\n"); +#endif + n=buffer_get_token(b,buf,8192,"\n",1); + if (n==0) break; + i=scan_whitenskip(buf,n); +lookagain: + { + char c; + switch (buffer_getc(b,&c)) { + case 0: eof=1; break; + case -1: buffer_putsflush(buffer_2,"read error!\n"); return 1; + } + if (c==' ') { /* continuation */ +// puts("continuation!"); + n+=buffer_get_token(b,buf+n,8192-n,"\n",1); + goto lookagain; + } else if (c=='\n') { +#if 1 + struct ldaprec* m=malloc(sizeof(struct ldaprec)); + if (!m) return 2; + (*l)->next=m; + m->n=0; m->dn=m->mail=m->sn=m->cn=0; m->next=0; + ofs=0; + l=&((*l)->next); +#else + struct ldaprec* m=malloc(sizeof(struct ldaprec)); + if (!m) return 2; + m->next=*l; + *l=m; + m->n=0; m->dn=m->mail=m->sn=m->cn=0; + ofs=0; +#endif + } else { + ofs=1; + buf[0]=c; + } + } + buf[n]=0; + if (tmp==objectClass) { + if (!(val=strduptab_add(&classes,buf+i))) goto nomem; + } else + if (!(val=strstorage_add(buf+i,n-i+1))) goto nomem; + if (tmp==dn) (*l)->dn=val; else + if (tmp==mail) (*l)->mail=val; else + if (tmp==sn) (*l)->sn=val; else + if (tmp==cn) (*l)->cn=val; else { + if ((*l)->na[(*l)->n].name=tmp; + (*l)->a[(*l)->n].value=val; + ++(*l)->n; + } + } +#if 0 + buffer_puts(buffer_1,"found value \""); + buffer_put(buffer_1,buf+i,n-i); + buffer_putsflush(buffer_1,"\".\n"); +#endif +// write(2,".",1); + } while (!eof); + if (!(*l)->dn) { + struct ldaprec* m=(*l)->next; + free((*l)); + (*l)=m; + } + return 0; +} + +struct ldaprec *first=0; + +int parse_ldif(const char* filename) { + char buf[4096]; + int fd=open_read(filename); + buffer in=BUFFER_INIT(read,fd,buf,sizeof buf); + if (fd<0) return 1; + dn=strduptab_add(&tags,"dn"); + mail=strduptab_add(&tags,"mail"); + sn=strduptab_add(&tags,"sn"); + cn=strduptab_add(&tags,"cn"); + objectClass=strduptab_add(&tags,"objectClass"); + parserec(&in,&first); + close(fd); + return 0; +} + +#ifndef INCLUDE +int main() { + parse_ldif("exp.ldif"); +// read(0,buf,1); +#if 0 + /* dump structure */ + while (first) { + printf("dn= %s\n",first->dn); + first=first->next; + } +#endif + return 0; +} +#endif diff --git a/t2.c b/t2.c new file mode 100644 index 0000000..89dfe86 --- /dev/null +++ b/t2.c @@ -0,0 +1,49 @@ +#include +#include +#include "mmap.h" +#include "asn1.h" +#include "ldap.h" + +int main(int argc,char* argv[]) { +#if 0 + unsigned long size; +// char* ldapsequence=mmap_read("req",&size); + char* ldapsequence=mmap_read(argc>1?argv[1]:"capture/127.000.000.001.32779-127.000.000.001.00389",&size); + long messageid, op, len; + int res; + printf("%d\n",res=scan_ldapmessage(ldapsequence,ldapsequence+size,&messageid,&op,&len)); + printf("message id %lu, op %lu, len %lu\n",messageid,op,len); + if (op==0) { + long version,namelen,method; + const char* name; + printf("%d\n",res=scan_ldapbindrequest(ldapsequence+res,ldapsequence+size,&version,&name,&namelen,&method)); + printf("version %lu, name \"%*s\", method %lu\n",version,namelen,name,method); + if (method==0) { + printf("%d\n",scan_asn1STRING(ldapsequence+res,ldapsequence+size,&name,&namelen)); + printf("simple \"%*s\"\n",namelen,name); + } + } +#else + char buf[1024]; + int s=100; + int len=fmt_ldapbindrequest(buf+s,3,"",""); + int hlen=fmt_ldapmessage(0,1,0,len); + fmt_ldapmessage(buf+s-hlen,1,0,len); + write(1,buf+s-hlen,len+hlen); +#endif +#if 0 + char buf[1024]; + enum asn1_tagtype tt; + enum asn1_tagclass tc; + long tag,len; + int res; + const char* c; + printf("%d\n",res=fmt_asn1int(buf,UNIVERSAL,PRIMITIVE,INTEGER,0x01020304)); + printf("%d\n",scan_asn1int(buf,buf+res,&tc,&tt,&tag,&len)); + printf("got %lx\n",len); + printf("%d\n",res=fmt_asn1string(buf,UNIVERSAL,PRIMITIVE,OCTET_STRING,"fnord",5)); + printf("%d\n",scan_asn1string(buf,buf+res,&tc,&tt,&tag,&c,&len)); + printf("got %*s\n",(int)len,c); +#endif + return 0; +} diff --git a/tinyldap.c b/tinyldap.c new file mode 100644 index 0000000..b501d84 --- /dev/null +++ b/tinyldap.c @@ -0,0 +1,58 @@ +#include +#include "byte.h" +#include "buffer.h" +#include "ldap.h" + +#define BUFSIZE 8192 + +int main() { + char buf[BUFSIZE]; + int len=0; + 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; } + len+=tmp; + res=scan_ldapmessage(buf,buf+len,&messageid,&op,&Len); + if (res>0) { + buffer_puts(buffer_2,"got message of length "); + buffer_putulong(buffer_2,Len); + buffer_puts(buffer_2," with id "); + buffer_putulong(buffer_2,messageid); + buffer_puts(buffer_2,": op "); + buffer_putulong(buffer_2,op); + buffer_putsflush(buffer_2,".\n"); + switch (op) { + case 0: + { + long version,method; + struct string name; + res=scan_ldapbindrequest(buf+res,buf+res+len,&version,&name,&method); + if (res>=0) { + buffer_puts(buffer_2,"bind request: version "); + buffer_putulong(buffer_2,version); + buffer_puts(buffer_2," for name \""); + buffer_put(buffer_2,name.s,name.l); + buffer_puts(buffer_2,"\" with method "); + buffer_putulong(buffer_2,method); + buffer_putsflush(buffer_2,".\n"); + { + char outbuf[1024]; + int s=100; + int len=fmt_ldapbindresponse(outbuf+s,0,"","go ahead",""); + int hlen=fmt_ldapmessage(0,messageid,BindResponse,len); + fmt_ldapmessage(outbuf+s-hlen,messageid,BindResponse,len); + write(1,outbuf+s-hlen,len+hlen); + } + } + } + } + if (Len