From 2d323613808a0a8189cb38d613e84a5658e8b849 Mon Sep 17 00:00:00 2001 From: leitner Date: Mon, 14 Jan 2002 16:14:31 +0000 Subject: [PATCH] check in work in progress. Please see README. --- Makefile | 57 ++++ README | 28 ++ asn1.h | 74 ++++++ bindrequest.c | 12 + fmt_asn1int.c | 11 + fmt_asn1intpayload.c | 19 ++ fmt_asn1length.c | 26 ++ fmt_asn1string.c | 9 + fmt_asn1tag.c | 26 ++ fmt_asn1transparent.c | 10 + fmt_ldapbindrequest.c | 15 ++ fmt_ldapbindresponse.c | 20 ++ fmt_ldapmessage.c | 13 + ldap.h | 56 ++++ ldapclient.c | 74 ++++++ scan_asn1ENUMERATED.c | 12 + scan_asn1INTEGER.c | 12 + scan_asn1SEQUENCE.c | 17 ++ scan_asn1STRING.c | 12 + scan_asn1int.c | 21 ++ scan_asn1length.c | 18 ++ scan_asn1string.c | 13 + scan_asn1tag.c | 19 ++ scan_ldapbindrequest.c | 19 ++ scan_ldapbindresponse.c | 24 ++ scan_ldapmessage.c | 22 ++ strduptab.c | 29 +++ strduptab.h | 13 + strstorage.c | 29 +++ strstorage.h | 5 + t.c | 557 ++++++++++++++++++++++++++++++++++++++++ t1.c | 143 +++++++++++ t2.c | 49 ++++ tinyldap.c | 58 +++++ 34 files changed, 1522 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 asn1.h create mode 100644 bindrequest.c create mode 100644 fmt_asn1int.c create mode 100644 fmt_asn1intpayload.c create mode 100644 fmt_asn1length.c create mode 100644 fmt_asn1string.c create mode 100644 fmt_asn1tag.c create mode 100644 fmt_asn1transparent.c create mode 100644 fmt_ldapbindrequest.c create mode 100644 fmt_ldapbindresponse.c create mode 100644 fmt_ldapmessage.c create mode 100644 ldap.h create mode 100644 ldapclient.c create mode 100644 scan_asn1ENUMERATED.c create mode 100644 scan_asn1INTEGER.c create mode 100644 scan_asn1SEQUENCE.c create mode 100644 scan_asn1STRING.c create mode 100644 scan_asn1int.c create mode 100644 scan_asn1length.c create mode 100644 scan_asn1string.c create mode 100644 scan_asn1tag.c create mode 100644 scan_ldapbindrequest.c create mode 100644 scan_ldapbindresponse.c create mode 100644 scan_ldapmessage.c create mode 100644 strduptab.c create mode 100644 strduptab.h create mode 100644 strstorage.c create mode 100644 strstorage.h create mode 100644 t.c create mode 100644 t1.c create mode 100644 t2.c create mode 100644 tinyldap.c 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