From 05d388f122681a94e71f5a3089a9e67be81e359a Mon Sep 17 00:00:00 2001 From: leitner Date: Sun, 20 Apr 2008 06:59:11 +0000 Subject: [PATCH] add journal rereading add DelRequest support add little delete test tool ldapdelete --- Makefile | 12 +- dumpacls.c | 9 -- fmt_ldapdeleterequest.c | 8 + idx2ldif.c | 2 +- ldap.h | 14 ++ ldapclient.c | 15 ++ ldapdelete.c | 127 +++++++++++++++ ldif.h | 4 +- ldif_parse.c | 44 ++---- mduptab.h | 1 + mstorage_add.c | 2 +- mstorage_unmap.c | 10 ++ parse.c | 2 +- scan_asn1ENUMERATED.c | 1 - scan_ldapdeleterequest.c | 10 ++ tinyldap.c | 324 ++++++++++++++++++++++++++++----------- 16 files changed, 448 insertions(+), 137 deletions(-) create mode 100644 fmt_ldapdeleterequest.c create mode 100644 ldapdelete.c create mode 100644 scan_ldapdeleterequest.c diff --git a/Makefile b/Makefile index c27edf1..57cda08 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ all: t1 t2 parse dumpidx idx2ldif addindex bindrequest tinyldap \ tinyldap_standalone tinyldap_debug ldapclient ldapclient_str \ -md5password mysql2ldif acl dumpacls # t6 # t +md5password mysql2ldif acl dumpacls ldapdelete # t6 # t asn1.a: fmt_asn1intpayload.o fmt_asn1length.o fmt_asn1tag.o \ fmt_asn1int.o fmt_asn1string.o fmt_asn1transparent.o scan_asn1tag.o \ @@ -23,20 +23,21 @@ matchprefix.o matchcasestring.o matchcaseprefix.o \ scan_ldapmodifyrequest.o scan_ldapaddrequest.o bstrlen.o bstrfirst.o \ bstrstart.o free_ldapadl.o free_ldappal.o free_ldapsearchfilter.o \ scan_ldapsearchfilterstring.o free_ldapsearchresultentry.o \ -fmt_ldapsearchfilterstring.o ldap_match_sre.o +fmt_ldapsearchfilterstring.o ldap_match_sre.o \ +fmt_ldapdeleterequest.o scan_ldapdeleterequest.o normalize_dn.o ldif.a: ldif_parse.o ldap_match_mapped.o storage.a: strstorage.o strduptab.o mstorage_add.o mduptab_add.o \ bstr_diff.o mduptab_adds.o bstr_diff2.o mstorage_add_bin.o \ mstorage_init.o mstorage_init_persistent.o mstorage_unmap.o \ -mduptab_init.o mduptab_init_reuse.o +mduptab_init.o mduptab_init_reuse.o mduptab_reset.o auth.a: auth.o DIET=/opt/diet/bin/diet -Os CC=gcc -CFLAGS=-pipe -I. -Wall -W +CFLAGS=-pipe -I. -Wall -W -Wextra ifneq ($(DEBUG),) DIET=/opt/diet/bin/diet CFLAGS=-pipe -I. -Wall -W -g -fstack-protector @@ -66,9 +67,10 @@ t2: ldap.a asn1.a t3 t4 t5 addindex: storage.a t6: storage.a tinyldap tinyldap_standalone tinyldap_debug: ldif.a storage.a auth.a -bindrequest tinyldap tinyldap_standalone tinyldap_debug ldapclient ldapclient_str: ldap.a asn1.a +bindrequest tinyldap tinyldap_standalone tinyldap_debug ldapclient ldapclient_str ldapdelete: ldap.a asn1.a idx2ldif: ldap.a dumpacls: ldap.a asn1.a +parse: normalize_dn.o tinyldap_standalone: tinyldap.c $(DIET) $(CC) $(CFLAGS) -DSTANDALONE -o $@ $^ $(LDFLAGS) -lowfat $(LIBS) diff --git a/dumpacls.c b/dumpacls.c index f44eabb..ce44a9e 100644 --- a/dumpacls.c +++ b/dumpacls.c @@ -66,15 +66,6 @@ kaputt: if (!buf) goto kaputt; buf[l2=fmt_ldapsearchfilterstring(buf,f)]=0; buffer_puts(buffer_1,buf); - if (l!=l2) { - buffer_puts(buffer_1,"\n\n\n"); - buffer_putulong(buffer_1,l); - buffer_puts(buffer_1," != "); - buffer_putulong(buffer_1,l2); - buffer_puts(buffer_1,"\n"); - buffer_flush(buffer_1); - assert(l==l2); - } free_ldapsearchfilter(f); free(f); } diff --git a/fmt_ldapdeleterequest.c b/fmt_ldapdeleterequest.c new file mode 100644 index 0000000..ffddc3a --- /dev/null +++ b/fmt_ldapdeleterequest.c @@ -0,0 +1,8 @@ +#include +#include "ldap.h" +#include "byte.h" + +size_t fmt_ldapdeleterequest(char* dest,struct string* s) { + if (dest) byte_copy(dest,s->l,s->s); + return s->l; +} diff --git a/idx2ldif.c b/idx2ldif.c index 5e25c67..c78f22f 100644 --- a/idx2ldif.c +++ b/idx2ldif.c @@ -14,7 +14,7 @@ static void dumpbstr(const char* c) { l=bstrlen(c); d=bstrfirst(c); up=fmt_ldapescape(0,d,l); - assert(up>=l); +// assert(up>=l); if (up==l) { buffer_puts(buffer_1," "); if (*c) diff --git a/ldap.h b/ldap.h index 35d82a8..0755d23 100644 --- a/ldap.h +++ b/ldap.h @@ -14,6 +14,10 @@ int matchcasestring(struct string* s,const char* c); int matchprefix(struct string* s,const char* c); int matchcaseprefix(struct string* s,const char* c); +/* "ou=fnord; O=fefe; c=de" -> "ou=fnord,o=fefe,c=de" */ +/* returns the length of the new string */ +size_t normalize_dn(char* dest,const char* src,int len); + struct AttributeValueAssertion { struct string desc, value; }; @@ -94,6 +98,12 @@ struct AddRequest { struct Addition a; }; +struct ModifyDNRequest { + struct string entry, newrdn; + int deleteoldrdn; + struct string newsuperior; +}; + enum ldapops { BindRequest=0, BindResponse=1, UnbindRequest=2, @@ -173,6 +183,8 @@ size_t scan_ldapresult(const char* src,const char* max,unsigned long* result, size_t scan_ldapmodifyrequest(const char* src,const char* max,struct ModifyRequest* m); size_t scan_ldapaddrequest(const char* src, const char * max, struct AddRequest * a); size_t scan_ldapsearchfilterstring(const char* src,struct Filter** f); +size_t scan_ldapdeleterequest(const char* src,const char* max,struct string* s); +size_t scan_ldapmodifydnrequest(const char* src,const char* max,struct ModifyDNRequest* mdr); size_t fmt_ldapstring(char* dest,struct string* s); size_t fmt_ldapmessage(char* dest,long messageid,long op,size_t len); @@ -187,6 +199,8 @@ size_t fmt_ldapadl(char* dest,struct AttributeDescriptionList* adl); size_t fmt_ldapavl(char* dest,struct AttributeDescriptionList* adl); size_t fmt_ldapmodifyrequest(char* dest,struct ModifyRequest* m); size_t fmt_ldapsearchfilterstring(char* dest,struct Filter* f); +size_t fmt_ldapdeleterequest(char* dest,struct string* s); +size_t fmt_ldapmodifydnrequest(char* dest,struct ModifyDNRequest* mdr); #define fmt_ldapbindresponse(a,b,c,d,e) fmt_ldapresult(a,b,c,d,e) #define fmt_ldapsearchresultdone(a,b,c,d,e) fmt_ldapresult(a,b,c,d,e) diff --git a/ldapclient.c b/ldapclient.c index 2a596f4..5c97f7d 100644 --- a/ldapclient.c +++ b/ldapclient.c @@ -195,6 +195,21 @@ nextmessage: goto copypartialandcontinue; } } else if (op==SearchResultDone) { + unsigned long result; + struct string matcheddn,errormessage,referral; + if (scan_ldapresult(buf+cur+tmp2,max,&result,&matcheddn,&errormessage,&referral)>0) { + if (result!=0) { + buffer_puts(buffer_2,"fail, code "); + buffer_putulong(buffer_2,result); + if (errormessage.l) { + buffer_puts(buffer_2,", error message \""); + buffer_put(buffer_2,errormessage.s,errormessage.l); + buffer_puts(buffer_2,"\n"); + } + buffer_putsflush(buffer_2,".\n"); + } + } else + buffer_putsflush(buffer_2,"scan_ldapresult failed!\n"); if (!matches) buffer_putsflush(buffer_2,"no matches.\n"); if (bench && durchlauf!=0) diff --git a/ldapdelete.c b/ldapdelete.c new file mode 100644 index 0000000..8b956b4 --- /dev/null +++ b/ldapdelete.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include "byte.h" +#include "buffer.h" +#include "asn1.h" +#include "ldap.h" +#include "socket.h" +#include "ip4.h" +#include "str.h" +#include "textcode.h" + +#include +#include + +#define BUFSIZE 8192 + +static unsigned long messageid=1; + +static int ldapbind(int sock) { + char outbuf[1024]; + int s=100; + size_t len=fmt_ldapbindrequest(outbuf+s,3,"",""); + size_t hlen=fmt_ldapmessage(0,messageid,BindRequest,len); + size_t res,Len; + unsigned long op,result; + struct string matcheddn,errormessage,referral; + fmt_ldapmessage(outbuf+s-hlen,messageid,BindRequest,len); + if ((size_t)write(sock,outbuf+s-hlen,len+hlen)!=len+hlen) return 0;; + len=read(sock,outbuf,1024); + res=scan_ldapmessage(outbuf,outbuf+len,&messageid,&op,&Len); + if (!res) return 0; + if (op!=BindResponse) return 0; + res=scan_ldapbindresponse(outbuf+res,outbuf+res+Len,&result,&matcheddn,&errormessage,&referral); + if (!res) return 0; + if (result) return 0; + return 1; +} + +int main(int argc,char* argv[]) { + int sock; + char buf[BUFSIZE]; + int len=0; + char* me; + if ((me=strrchr(argv[0],'/'))) + ++me; + else + me=argv[0]; + + if (argc<2) { +usage: + buffer_putsflush(buffer_2,"usage: ldapdelete ip dn\n"); + return 0; + } + + sock=socket_tcp4b(); + { + char ip[4]; + if (argv[1][scan_ip4(argv[1],ip)]) goto usage; + if (socket_connect4(sock,ip,389)) { + buffer_putsflush(buffer_2,"could not connect to ldap server!\n"); + return 1; + } + } + if (ldapbind(sock)) { + struct string s; + + s.l=strlen(argv[2]); + s.s=argv[2]; + + len=fmt_ldapdeleterequest(buf+100,&s); + { + int tmp=fmt_ldapmessage(0,++messageid,DelRequest,len); + fmt_ldapmessage(buf+100-tmp,messageid,DelRequest,len); + write(sock,buf+100-tmp,len+tmp); + } + shutdown(sock,SHUT_WR); + { + char buf[32*1024]; /* arbitrary limit, bad! */ + int len=0,tmp,tmp2; + char* max; + + unsigned long mid,op; + size_t slen; + int cur=0; + + tmp=read(sock,buf+len,sizeof(buf)-len); + + if (tmp<=0) { + buffer_putsflush(buffer_2,"read error.\n"); + return 2; + } + len+=tmp; + if ((tmp2=scan_ldapmessage(buf+cur,buf+len,&mid,&op,&slen))) { + max=buf+cur+slen+tmp2; + if (op==DelResponse) { + unsigned long result; + struct string matcheddn, errormessage, referral; + if (scan_ldapresult(buf+cur+tmp2,max,&result,&matcheddn,&errormessage,&referral)>0) { + if (result==success) { + buffer_putsflush(buffer_2,"ok\n"); + } else { + buffer_puts(buffer_2,"fail, code "); + buffer_putulong(buffer_2,result); + if (errormessage.l) { + buffer_puts(buffer_2,", error message \""); + buffer_put(buffer_2,errormessage.s,errormessage.l); + buffer_puts(buffer_2,"\n"); + } + buffer_putsflush(buffer_2,".\n"); + } + } else + buffer_putsflush(buffer_2,"failed to parse result message.\n"); + } else + buffer_putsflush(buffer_2,"unexpected response.\n"); + } else + buffer_putsflush(buffer_2,"failed to parse ldap message.\n"); + } + } else { + buffer_putsflush(buffer_2,"ldapbind failed\n"); + return 2; + } + close(sock); + + return 0; +} diff --git a/ldif.h b/ldif.h index 21d7417..cb69bd1 100644 --- a/ldif.h +++ b/ldif.h @@ -1,3 +1,5 @@ +#define _FILE_OFFSET_BITS 64 +#include #include #include @@ -19,7 +21,7 @@ extern uint32_t dn, mail, sn, cn, objectClass; extern struct ldaprec *first; extern unsigned long ldifrecords; -int ldif_parse(const char* filename); +int ldif_parse(const char* filename,off_t fromofs,struct stat* ss); /* return non-zero if the record matches the search request */ int ldap_match(struct ldaprec* r,struct SearchRequest* sr); diff --git a/ldif_parse.c b/ldif_parse.c index b9a540c..0ea49e5 100644 --- a/ldif_parse.c +++ b/ldif_parse.c @@ -1,3 +1,4 @@ +#define _FILE_OFFSET_BITS 64 #include #include #include @@ -48,34 +49,10 @@ static void addattribute(struct ldaprec** l,uint32_t name,uint32_t val) { } } -/* "ou=fnord; O=fefe; c=de" -> "ou=fnord,o=fefe,c=de" */ -/* returns the length of the new string */ -static int normalize_dn(char* dest,const char* src,int len) { - int makelower=1; - char* orig=dest; - while (len) { - if (*src==';' || *src==',') { - *dest=','; - while (len>1 && src[1]==' ') { ++src; --len; } - makelower=1; - } else { - if (makelower) - *dest=tolower(*src); - else - *dest=*src; - if (*dest=='=') makelower=0; - } - ++dest; - ++src; - --len; - } - return dest-orig; -} - -static int unbase64(char* buf) { - unsigned long destlen; +static size_t unbase64(char* buf) { + size_t destlen; char temp[8192]; - long l=scan_base64(buf,temp,&destlen); + size_t l=scan_base64(buf,temp,&destlen); if (buf[l] && buf[l]!='\n') return 0; byte_copy(buf,destlen,temp); return destlen; @@ -302,6 +279,7 @@ lookagain: addattribute(l,tmp,val); #endif } while (!eof); + if ((*l)->dn==(uint32_t)-1) return 0; if (ldif_parse_callback && ldif_parse_callback(*l)==-1) return -1; if ((*l)->dn==(uint32_t)-1 && ((*l)->next)) { struct ldaprec* m=(*l)->next; @@ -313,7 +291,7 @@ lookagain: struct ldaprec *first=0; -int ldif_parse(const char* filename) { +int ldif_parse(const char* filename,off_t fromofs,struct stat* ss) { char buf[4096]; int fd; buffer in; @@ -325,7 +303,8 @@ int ldif_parse(const char* filename) { fd=-1; } else { fd=open_read(filename); - if (fd<0) return 1; + if (fd<0) return 0; // no journal file is permissible + if (fromofs) lseek(fd,fromofs,SEEK_SET); buffer_init(&in,(void*)read,fd,buf,sizeof buf); tmp=∈ } @@ -334,6 +313,13 @@ int ldif_parse(const char* filename) { lines=0; { int res=parserec(tmp,&first); + if (ss) { + fstat(fd,ss); + /* the file size may have changed between parserec hitting EOF and + * us calling lstat, we we write the current file pointer position + * to st_size */ + ss->st_size=lseek(fd,0,SEEK_CUR); + } if (fd!=-1) close(fd); return res; } diff --git a/mduptab.h b/mduptab.h index cb6198a..5704e87 100644 --- a/mduptab.h +++ b/mduptab.h @@ -16,3 +16,4 @@ void mduptab_init(mduptab_t* t); void mduptab_init_reuse(mduptab_t* t,mstorage_t* s); long mduptab_add(mduptab_t* t,const char* s,size_t len); long mduptab_adds(mduptab_t* t,const char* s); +void mduptab_reset(mduptab_t* t); diff --git a/mstorage_add.c b/mstorage_add.c index 3431af6..14feff4 100644 --- a/mstorage_add.c +++ b/mstorage_add.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include "byte.h" diff --git a/mstorage_unmap.c b/mstorage_unmap.c index 15253ed..32b66a4 100644 --- a/mstorage_unmap.c +++ b/mstorage_unmap.c @@ -1,12 +1,22 @@ #include "mstorage.h" #include #include +#include +#include #include +#include +#include void mstorage_unmap(mstorage_t* p) { +#ifdef MREMAP_MAYMOVE munmap(p->root,p->mapped); +#else + free(p->root); +#endif if (p->fd!=-1) { ftruncate(p->fd,p->used); close(p->fd); } + p->mapped=p->used=0; + p->root=0; } diff --git a/parse.c b/parse.c index 2da9d50..cbfaf5b 100644 --- a/parse.c +++ b/parse.c @@ -193,7 +193,7 @@ writeerror: // if ((mduptab_adds(&attributes,"*"))<0) // die(1,"out of memory"); - ldif_parse(argc<2?"exp.ldif":argv[1]); + ldif_parse(argc<2?"exp.ldif":argv[1],0,0); if (!first) die(1,"usage: parse [src-ldif-filename] [dest-bin-filename]\n"); diff --git a/scan_asn1ENUMERATED.c b/scan_asn1ENUMERATED.c index 799d1e7..36347cc 100644 --- a/scan_asn1ENUMERATED.c +++ b/scan_asn1ENUMERATED.c @@ -8,7 +8,6 @@ size_t scan_asn1ENUMERATED(const char* src,const char* max,unsigned long* val) { long ltmp; if ((tmp=scan_asn1int(src,max,&tc,&tt,&tag,<mp))) if (tc==UNIVERSAL && tt==PRIMITIVE && tag==ENUMERATED) { - if (ltmp<0 || src+tmp+ltmp>max) return 0; *val=(unsigned long)ltmp; return tmp; } diff --git a/scan_ldapdeleterequest.c b/scan_ldapdeleterequest.c new file mode 100644 index 0000000..38d2af4 --- /dev/null +++ b/scan_ldapdeleterequest.c @@ -0,0 +1,10 @@ +#include "asn1.h" +#include "ldap.h" + +size_t scan_ldapdeleterequest(const char* src,const char* max, + struct string* s) { + if (src>=max) return 0; + s->l=max-src; + s->s=src; + return s->l; +} diff --git a/tinyldap.c b/tinyldap.c index fb241ee..2bd9816 100644 --- a/tinyldap.c +++ b/tinyldap.c @@ -1,3 +1,4 @@ +#define _FILE_OFFSET_BITS 64 #include #include #include @@ -196,6 +197,8 @@ struct acl { struct acl** Acls; static void load_acls() { + struct acl** oldAcls=Acls; + size_t oldacls=acls; uint32 ofs; uint32 acl_ofs; acl_ofs=0; @@ -281,11 +284,56 @@ kaputt: for (i=0; iattrs; ++k) { -/* if (Acls[j]->Attrs[k]==any_ofs || !matchstring(&adl->a,map+Acls[j]->Attrs[k])) { */ if (Acls[j]->Attrs[k]==any_ofs || attrofs==Acls[j]->Attrs[k]) { if (Acls[j]->may&operation) return 1; @@ -1087,7 +1134,7 @@ add_attribute: |___/ |_| */ -int copystring(struct string* dest,struct string* src) { +static int copystring(struct string* dest,struct string* src) { dest->s=malloc(src->l+1); if (!dest->s) return -1; byte_copy((char*)dest->s,src->l,src->s); @@ -1340,7 +1387,7 @@ static int lookupdn(struct string* dn,size_t* index, struct hashnode** hn) { useindex(&f,&result); if (result.first>result.last) return 0; - assert(result.last<=record_count); +// assert(result.last<=record_count); for (i=result.first; i<=result.last; ) { if (!result.bits[i/(8*sizeof(long))]) { i+=8*sizeof(long); @@ -1357,6 +1404,17 @@ static int lookupdn(struct string* dn,size_t* index, struct hashnode** hn) { return 0; } +static void normalize_string_dn(struct string* s) { + /* OK this is a kludge. s->s is supposed to be read-only because it points into the + * buffer where we read it into from the network. + * Since normalize_dn ends up using less or equal space, and we are not interested in + * the non-normalized dn, we do the read-write cast and normalize in-place. + * Kids, don't do this at home. */ + s->l=normalize_dn((char*)s->s,s->s,s->l); +} + +static void update(); + /* a standard LDAP session looks like this: * 1. connect to server * 2. send a BindRequest @@ -1368,7 +1426,7 @@ static int lookupdn(struct string* dn,size_t* index, struct hashnode** hn) { * 5. close * tinyldap does not complain if you don't unbind before hanging up. */ -int handle(int in,int out) { +static int handle(int in,int out) { size_t len; char buf[BUFSIZE]; for (len=0;;) { @@ -1395,14 +1453,15 @@ int handle(int in,int out) { buffer_putulong(buffer_2,op); buffer_putsflush(buffer_2,".\n"); } + update(); switch (op) { case BindRequest: { unsigned long version,method; struct string name; - int tmp; - tmp=scan_ldapbindrequest(buf+res,buf+res+len,&version,&name,&method); - if (tmp>=0) { + size_t tmp; + tmp=scan_ldapbindrequest(buf+res,buf+len,&version,&name,&method); + if (tmp>0) { if (verbose) { buffer_puts(buffer_2,"bind request: version "); buffer_putulong(buffer_2,version); @@ -1418,8 +1477,9 @@ int handle(int in,int out) { struct hashnode* hn; int err=success; - scan_ldapstring(buf+res+tmp,buf+res+len,&password); + scan_ldapstring(buf+res+tmp,buf+len,&password); + normalize_string_dn(&name); switch (lookupdn(&name,&idx,&hn)) { case -1: err=operationsError; break; case 1: break; @@ -1430,7 +1490,7 @@ int handle(int in,int out) { goto authfailure; else { char* c=0; - uint32 authdn; + uint32 authdn=0; char* authdn_str=0; if (idx==(size_t)-1) { // found in journal size_t i; @@ -1485,9 +1545,9 @@ authfailure: } { char outbuf[1024]; - int s=100; - int len=fmt_ldapbindresponse(outbuf+s,0,"","go ahead",""); - int hlen=fmt_ldapmessage(0,messageid,BindResponse,len); + size_t s=100; + size_t len=fmt_ldapbindresponse(outbuf+s,0,"","go ahead",""); + size_t hlen=fmt_ldapmessage(0,messageid,BindResponse,len); fmt_ldapmessage(outbuf+s-hlen,messageid,BindResponse,len); write(out,outbuf+s-hlen,len+hlen); } @@ -1497,7 +1557,7 @@ authfailure: case SearchRequest: { struct SearchRequest sr; - int tmp; + size_t tmp; #if 0 { int fd=open_write("request"); @@ -1505,7 +1565,7 @@ authfailure: close(fd); } #endif - if ((tmp=scan_ldapsearchrequest(buf+res,buf+res+len,&sr))) { + if ((tmp=scan_ldapsearchrequest(buf+res,buf+len,&sr))) { size_t returned=0; #if (debug != 0) @@ -1542,7 +1602,7 @@ authfailure: * of the matches in a table. Use findrec to locate * the records that point to the data. */ useindex(sr.filter,&result); - assert(result.last<=record_count); +// assert(result.last<=record_count); for (i=result.first; i<=result.last; ) { size_t ni=i+8*sizeof(long); if (!result.bits[i/(8*sizeof(long))]) { @@ -1589,8 +1649,8 @@ authfailure: } { char buf[1000]; - long l=fmt_ldapsearchresultdone(buf+100,0,"","",""); - int hlen=fmt_ldapmessage(0,messageid,SearchResultDone,l); + size_t l=fmt_ldapsearchresultdone(buf+100,0,"","",""); + size_t hlen=fmt_ldapmessage(0,messageid,SearchResultDone,l); fmt_ldapmessage(buf+100-hlen,messageid,SearchResultDone,l); write(out,buf+100-hlen,l+hlen); } @@ -1602,30 +1662,34 @@ authfailure: case ModifyRequest: { struct ModifyRequest mr; - int tmp,err=success; + size_t tmp,err=success; buffer_putsflush(buffer_2,"modifyrequest!\n"); - if ((tmp=scan_ldapmodifyrequest(buf+res,buf+res+len,&mr))) { + if ((tmp=scan_ldapmodifyrequest(buf+res,buf+len,&mr))) { struct SearchResultEntry sre; - buffer_puts(buffer_1,"modify request: dn \""); - buffer_put(buffer_1,mr.object.s,mr.object.l); - buffer_putsflush(buffer_1,"\"\n"); - switch (mr.m.operation) { - case 0: buffer_puts(buffer_1,"Add\n"); break; - case 1: buffer_puts(buffer_1,"Delete\n"); break; - case 2: buffer_puts(buffer_1,"Replace\n"); break; + if (verbose) { + buffer_puts(buffer_1,"modify request: dn \""); + buffer_put(buffer_1,mr.object.s,mr.object.l); + buffer_putsflush(buffer_1,"\"\n"); + switch (mr.m.operation) { + case 0: buffer_puts(buffer_1,"Add\n"); break; + case 1: buffer_puts(buffer_1,"Delete\n"); break; + case 2: buffer_puts(buffer_1,"Replace\n"); break; + } + buffer_put(buffer_1,mr.m.AttributeDescription.s,mr.m.AttributeDescription.l); + buffer_puts(buffer_1,"\n"); + { + struct AttributeDescriptionList* x=mr.m.vals; + do { + buffer_puts(buffer_1," -> \""); + buffer_put(buffer_1,x->a.s,x->a.l); + buffer_putsflush(buffer_1,"\"\n"); + x=x->next; + } while (x); + } } - buffer_put(buffer_1,mr.m.AttributeDescription.s,mr.m.AttributeDescription.l); - buffer_puts(buffer_1,"\n"); - { - struct AttributeDescriptionList* x=mr.m.vals; - do { - buffer_puts(buffer_1," -> \""); - buffer_put(buffer_1,x->a.s,x->a.l); - buffer_putsflush(buffer_1,"\"\n"); - x=x->next; - } while (x); - } - /* TODO: do something with the modify request ;-) */ + + normalize_string_dn(&mr.object); + if (acls) { /* convert modifyrequest to searchresultentry */ modreq2sre(&sre,&mr); @@ -1648,7 +1712,7 @@ authfailure: #if 1 /* 3. apply modifications to record to get new record */ if (!applymodreq(hn,&mr,&sre)) { - /* 4. write record to "data.upd" */ + /* 4. write record to journal */ int fd=open("journal",O_WRONLY|O_APPEND|O_CREAT,0600); if (fd==-1) err=operationsError; @@ -1665,8 +1729,10 @@ authfailure: #endif } } - } else + } else { + buffer_putsflush(buffer_2,"could not parse modifyRequest!\n"); err=protocolError; + } { char outbuf[1024]; @@ -1681,7 +1747,7 @@ authfailure: } break; case AbandonRequest: - buffer_putsflush(buffer_2,"AbandonRequest!\n"); + if (verbose) buffer_putsflush(buffer_2,"AbandonRequest!\n"); /* do nothing */ break; case AddRequest: @@ -1689,11 +1755,12 @@ authfailure: int err=success; struct AddRequest ar; // buffer_putsflush(buffer_2,"AddRequest!\n"); - if ((tmp=scan_ldapaddrequest(buf+res,buf+res+len,&ar))) { + if ((tmp=scan_ldapaddrequest(buf+res,buf+len,&ar))) { struct SearchResultEntry sre; + normalize_string_dn(&ar.entry); /* convert addrequest to searchresultentry */ addreq2sre(&sre,&ar); - /* TODO: do something with the add request ;-) */ + /* 1. check ACLs */ if (!acls || checkacl(0,0,acl_add,&sre)==1) { /* 2. check if there already is a record with this dn */ @@ -1706,7 +1773,7 @@ authfailure: default: err=operationsError; } if (err==success) { - /* 3. write record to "data.upd" */ + /* 3. write record to journal */ int fd=open("journal",O_WRONLY|O_APPEND|O_CREAT,0600); if (fd==-1) err=operationsError; @@ -1740,14 +1807,70 @@ authfailure: { char outbuf[1024]; - int s=100; - int len=fmt_ldapresult(outbuf+s,err,"","",""); - int hlen=fmt_ldapmessage(0,messageid,AddResponse,len); + size_t s=100; + size_t len=fmt_ldapresult(outbuf+s,err,"","",""); + size_t hlen=fmt_ldapmessage(0,messageid,AddResponse,len); fmt_ldapmessage(outbuf+s-hlen,messageid,AddResponse,len); write(out,outbuf+s-hlen,len+hlen); } } break; + case DelRequest: + { + struct string s; + size_t l=scan_ldapdeleterequest(buf+res,buf+len,&s); + if (l>0) { + struct SearchResultEntry sre; + int err=success; + if (verbose) { + buffer_puts(buffer_2,"Delete Request for DN \""); + buffer_put(buffer_2,s.s,s.l); + buffer_putsflush(buffer_2,"\".\n"); + } + normalize_string_dn(&s); + /* convert modifyrequest to searchresultentry */ + sre.objectName=s; + sre.attributes=0; + if (acls) { + /* 1. check ACLs */ + if (checkacl(0,0,acl_delete,&sre)!=1) + err=insufficientAccessRights; + } + if (err==success) { + /* 2. check if there already is a record with this dn */ + struct hashnode* hn; + size_t idx; + switch (lookupdn(&s,&idx,&hn)) { + case -1: err=operationsError; break; + case 1: break; + case 0: err=noSuchObject; break; + default: err=operationsError; + } + if (err==success) { + /* 3. write record to journal */ + int fd=open("journal",O_WRONLY|O_APPEND|O_CREAT,0600); + if (fd==-1) + err=operationsError; + else { + if (writesretofd(fd,&sre)==-1) + err=operationsError; + close(fd); + } + } + } + { + char outbuf[1024]; + size_t s=100; + size_t len=fmt_ldapresult(outbuf+s,err,"","",""); + size_t hlen=fmt_ldapmessage(0,messageid,DelResponse,len); + fmt_ldapmessage(outbuf+s-hlen,messageid,DelResponse,len); + write(out,outbuf+s-hlen,len+hlen); + } + } + } + break; + case ModifyDNRequest: + /* TODO */ default: buffer_puts(buffer_2,"unknown request type "); buffer_putulong(buffer_2,op); @@ -1781,7 +1904,7 @@ extern int (*ldif_parse_callback)(struct ldaprec* l); extern mstorage_t stringtable; extern mduptab_t attributes,classes; -unsigned long hash2(const unsigned char* c) { +static unsigned long hash2(const unsigned char* c) { unsigned long h=0; if (*c==0) { uint32 len=uint32_read((char*)c+1); @@ -1798,7 +1921,7 @@ unsigned long hash2(const unsigned char* c) { #define HASHTABSIZE 8191 -unsigned char* bstrdup(unsigned char* c) { +static unsigned char* bstrdup(unsigned char* c) { size_t len; unsigned char* x; if (*c) @@ -1812,7 +1935,7 @@ unsigned char* bstrdup(unsigned char* c) { return x; } -unsigned char* bstrdup_attrib(unsigned char* c) { +static unsigned char* bstrdup_attrib(unsigned char* c) { char* x=map+5*4+size_of_string_table; size_t i,l; if (*c) @@ -1865,12 +1988,13 @@ static struct hashnode** dn_in_journal2(const char* dn,size_t dnlen) { struct hashnode* root; -int parse_callback(struct ldaprec* l) { +static int parse_callback(struct ldaprec* l) { static struct hashnode** nextinlinearlist=&root; size_t i; unsigned long hashval; struct hashnode** hn; - if (l->dn==(uint32)-1) return -1; + if (l->dn==(uint32)-1) + return -1; hashval=hash2((unsigned char*)stringtable.root+l->dn); // printf("journal: \"%s\" -> %lu\n",stringtable.root+l->dn,hashval); hn=hashtab+(hashval%HASHTABSIZE); @@ -1912,11 +2036,64 @@ int parse_callback(struct ldaprec* l) { return 0; } -int readjournal() { +static void readjournal() { ldif_parse_callback=parse_callback; mduptab_init(&attributes); mduptab_init(&classes); - return ldif_parse("journal"); + if (ldif_parse("journal",0,&ss_journal)) { + buffer_putsflush(buffer_2,"Failed to parse journal!\n"); + exit(1); + } +} + +static void update() { + struct stat new_data,new_journal; + if (stat(datafilename,&new_data)==-1) { + /* no data file?! There is no way to salvage the situation. */ + buffer_putsflush(buffer_2,"ABEND: data file suddenly gone.\n"); + exit(1); + } + /* now see if the data file changed. If it did, map it anew. */ + if (new_data.st_size!=ss_data.st_size || + new_data.st_mtime!=ss_data.st_mtime || + new_data.st_ino!=ss_data.st_ino) { + buffer_putsflush(buffer_2,"Data file changed, reloading.\n"); + mmap_unmap(map,filelen); + /* If the new data file is corrupt, map_datafile calls exit. + * I don't believe in limping on. If something is broken on such a fundamental level, + * it's better to bail so that the problem does not go unnoticed and things get even + * worse. */ + map_datafile(datafilename); + /* OK, now that we have the datafile reloaded, we need to clean our idea of a journal + * and reload the journal from scratch. */ + mduptab_reset(&attributes); + mduptab_reset(&classes); + readjournal(); + ss_data=new_data; + return; + } + /* the data file did not change. Maybe the journal did. */ + if (stat("journal",&new_journal)==-1) { + /* no journal; that means: + * a) there never was one, totaly read-only data + * b) there was one, but it has now been incorporated into the main database + * in this case: delete journal data + */ + mduptab_reset(&attributes); + mduptab_reset(&classes); + return; + } + if (new_journal.st_size!=ss_journal.st_size || + new_journal.st_mtime!=ss_journal.st_mtime || + new_journal.st_ino!=ss_journal.st_ino) { + /* Journal changed. Since all we ever do is append, we just read the part from how + * far we got last time, which happens to be ss_journal.st_size. */ + if (ldif_parse("journal",ss_journal.st_size,&ss_journal)) { + buffer_putsflush(buffer_2,"Failed to parse journal!\n"); + exit(1); + } + ss_data=new_data; + } } static int ldap_matchfilter_hn(struct hashnode* hn,struct Filter* f) { @@ -2010,6 +2187,7 @@ static void answerwith_hn(struct hashnode* hn,struct SearchRequest* sr,long mess struct SearchResultEntry sre; struct PartialAttributeList** pal=&sre.attributes; + if (!hn->n) return; if (acls) byte_zero(acl_ec_subjects+filters,filters); @@ -2134,39 +2312,7 @@ int main(int argc,char* argv[]) { signal(SIGPIPE,SIG_IGN); - map=mmap_read(argc>1?argv[1]:"data",&filelen); - if (!map) { - buffer_putsflush(buffer_2,"could not open data!\n"); - return 1; - } - uint32_unpack(map,&magic); - uint32_unpack(map+4,&attribute_count); - uint32_unpack(map+2*4,&record_count); - uint32_unpack(map+3*4,&indices_offset); - uint32_unpack(map+4*4,&size_of_string_table); - record_set_length=(record_count+sizeof(unsigned long)*8-1) / (sizeof(long)*8); - - /* look up "dn" and "objectClass" */ - { - char* x=map+5*4+size_of_string_table; - size_t i; - dn_ofs=objectClass_ofs=userPassword_ofs=any_ofs=0; - for (i=0; i1?argv[1]:"data"); load_acls();