diff --git a/FORMAT b/FORMAT index 2d2aff8..6f27c94 100644 --- a/FORMAT +++ b/FORMAT @@ -37,11 +37,17 @@ All integers are stored LITTLE ENDIAN. faster but twice as large; this is actually saved as two arrays, one for the pointers and one for the numbers, for cache performance reasons. + 2 == ACL data rest reserved */ uint32_t next; /* offset of next index */ /* for index_type==0: */ uint32_t indexed_attribute; /* offset of attribute name */ uint32_t record_offsets[record_count]; + /* for index_type==1: */ + uint32_t indexed_attribute; + uint32_t record_offsets[record_count]; + uint32_t record_number[record_count]; + /* for index_type==2 see file "ACL" */ } The indices are at the end to make it possible to add more indices. diff --git a/Makefile b/Makefile index b5b1fd3..11e42e2 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ DEBUG=1 all: t1 t2 parse dumpidx idx2ldif addindex bindrequest tinyldap \ tinyldap_standalone tinyldap_debug ldapclient ldapclient_str \ -md5password mysql2ldif acl # t6 # t +md5password mysql2ldif acl dumpacls # 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 \ @@ -21,7 +21,8 @@ fmt_ldapsearchfilter.o fmt_ldapsearchrequest.o matchstring.o \ 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 +scan_ldapsearchfilterstring.o free_ldapsearchresultentry.o \ +fmt_ldapsearchfilterstring.o ldif.a: ldif_parse.o ldap_match_mapped.o @@ -61,6 +62,7 @@ t6: storage.a tinyldap tinyldap_standalone tinyldap_debug: ldif.a auth.a bindrequest tinyldap tinyldap_standalone tinyldap_debug ldapclient ldapclient_str: ldap.a asn1.a idx2ldif: ldap.a +dumpacls: ldap.a asn1.a tinyldap_standalone: tinyldap.c $(DIET) $(CC) $(CFLAGS) -DSTANDALONE -o $@ $^ $(LDFLAGS) -lowfat $(LIBS) diff --git a/acl.c b/acl.c index cf59151..02a4b03 100644 --- a/acl.c +++ b/acl.c @@ -1,3 +1,4 @@ +#define _FILE_OFFSET_BITS 64 #define MAIN #include @@ -11,11 +12,15 @@ #include #include #include +#include #include +#include +#include const char Any[]="*"; const char Self[]="self"; const char Dn[]="dn"; +uint32 any_ofs; enum { acl_read = 1, @@ -28,6 +33,7 @@ enum { struct assertion { const char* filterstring; struct Filter* f; + uint32 idx; struct assertion* sameas; }; @@ -128,7 +134,7 @@ int parseaclattrib(buffer* in,struct acl* a) { { char c=*buffer_peek(in); if (c=='+' || c=='-') { - a->attrib=Any; + a->attrib=(char*)Any; a->anum=1; return 1; } @@ -139,7 +145,7 @@ int parseaclattrib(buffer* in,struct acl* a) { stralloc_chop(&x); if (!stralloc_0(&x)) return -1; if (str_equal(x.s,"*")) { - a->attrib=Any; + a->attrib=(char*)Any; a->anum=1; return 1; } @@ -195,6 +201,7 @@ static int parseacl(buffer* in,struct acl* a) { } static void fold(struct assertion* a,struct assertion* b) { + if (a==b) return; if (a->sameas || b->sameas) return; if (!strcmp(a->filterstring,b->filterstring)) b->sameas=a; @@ -221,7 +228,7 @@ int readacls(const char* filename) { int r; root=0; next=&root; if (buffer_mmapread(&b,filename)==-1) return -1; - while ((r=parseacl(&b,&a))!=-1) { + while ((r=parseacl(&b,&a))==1) { *next=malloc(sizeof(struct acl)); if (!*next) diesys(1,"malloc"); **next=a; @@ -251,21 +258,39 @@ int marshalfilter(stralloc* x,struct assertion* a) { } } -int marshal(char* map,unsigned long filelen) { +int marshal(char* map,unsigned long filelen,const char* filename) { unsigned long filters,acls,i,j,k; unsigned long filter_offset,acl_offset; struct acl* a; uint32* F,* A; uint32 attribute_count; uint32 attrtab; - static stralloc x; + static stralloc x,y; + int fd=open_append(filename); + + if (fd==-1) + diesys(1,"could not open file `",filename,"' for writing"); + stralloc_copys(&x,""); + stralloc_copys(&y,""); filters=acls=0; for (a=root; a; a=a->next) { ++acls; - if (!a->subject.sameas) ++filters; - if (!a->object.sameas) ++filters; + if (!a->subject.sameas) { + a->subject.idx=filters; + ++filters; + } + if (!a->object.sameas) { + a->object.idx=filters; + ++filters; + } } + + buffer_putulong(buffer_1,acls); + buffer_puts(buffer_1," ACLs with "); + buffer_putulong(buffer_1,filters); + buffer_putsflush(buffer_1," filters.\n"); + F=malloc(sizeof(*F)*(filters+1)); filter_offset=filelen+(filters+4)*sizeof(*F); /* 2 uints for index header, 1 uint filters_count, then filter_count+1 uint32 in F */ @@ -297,38 +322,49 @@ nomem: * the ACLs. To make it possible to skip over it, the offset table of * the filters has one more element, which points to the start of the * ACLs. */ - for (a=root; a; a=a->next) { - unsigned int l=0; - if (!(a->attrs=malloc(a->anum*sizeof(*a->attrs)))) - goto nomem; - a->attrs[l]=a->attrib; ++l; - for (k=0; a->attrib[k]; ++k) - if (a->attrib[k]==',') { - a->attrib[k]=0; - a->attrs[l]=a->attrib+k+1; - } - if (a->attrib!=Self && a->attrib!=Any) - for (k=0; kanum; ++k) { - int found=0; - for (j=0; jattrs[k])) { - a->attrs[k]=map+uint32_read(map+attrtab+j*4); - found=1; - break; + { + int anyused=0; + + for (a=root; a; a=a->next) { + unsigned int l=0; + if (!(a->attrs=malloc(a->anum*sizeof(*a->attrs)))) + goto nomem; + a->attrs[l]=a->attrib; ++l; + if (a->attrib!=Any) { + for (k=0; a->attrib[k]; ++k) + if (a->attrib[k]==',') { + a->attrib[k]=0; + a->attrs[l]=a->attrib+k+1; + } + for (k=0; kanum; ++k) { + int found=0; + for (j=0; jattrs[k])) { + a->attrs[k]=map+uint32_read(map+attrtab+j*4); + found=1; + break; + } + } + if (!found) { + /* warning: evil kludge ahead! We assume that the sum of the + * lengths of the new attributes plus the ACLs is smaller than + * the address where mmap mapped the file. */ + char* tmp=a->attrs[k]; + // buffer_putmflush(buffer_1,"adding attribute ",a->attrs[k],"\n"); + a->attrs[k]=map+filelen+ + 2*4+ /* index_type and next */ + (filters+2)*4+ /* filters_count plus (filter_count+1)*uint32 */ + x.len; + if (!stralloc_catb(&x,tmp,strlen(tmp)+1)) goto nomem; } } - if (!found) { - /* warning: evil kludge ahead! We assume that the sum of the - * lengths of the new attributes plus the ACLs is smaller than - * the address where mmap mapped the file. */ - char* tmp=a->attrs[k]; - a->attrs[k]=map+filelen+ - 2*4+ /* index_type and next */ - (filters+2)*4+ /* filters_count plus (filter_count+1)+uint32 */ - x.len; - if (!stralloc_cats(&x,tmp)) goto nomem; - } - } + } else anyused=1; + } + if (anyused) { + any_ofs=filelen+2*4+(filters+2)*4+x.len; +// printf("filelen is %d, filters is %d, x.len is %d -> anyofs is %d\n",filelen,filters,x.len,any_ofs); + if (!stralloc_catb(&x,Any,2)) goto nomem; + } } /* 32-bit align */ @@ -344,13 +380,98 @@ nomem: if (!A) goto nomem; acl_offset=F[i]+(acls+1)*sizeof(*A); - /* FIXME, TODO */ + i=0; + for (a=root; a; a=a->next) { + char tmp[4]; + unsigned int j; + A[i]=y.len; ++i; + if (!stralloc_readyplus(&y,12)) goto nomem; + if (a->subject.sameas) + uint32_pack(tmp,a->subject.sameas->idx); + else + uint32_pack(tmp,a->subject.idx); + stralloc_catb(&y,tmp,4); + if (a->object.sameas) + uint32_pack(tmp,a->object.sameas->idx); + else + uint32_pack(tmp,a->object.idx); + stralloc_catb(&y,tmp,4); + uint16_pack(tmp,a->may); + stralloc_catb(&y,tmp,2); + uint16_pack(tmp,a->maynot); + stralloc_catb(&y,tmp,2); + if (a->attrib==Any) { + uint32_pack(tmp,any_ofs); + if (!stralloc_catb(&y,tmp,4)) goto nomem; + } else { + for (j=0; janum; ++j) { + if (a->attrs[j]==Any) + buffer_putmflush(buffer_1,a->attrs[j],"\n"); + uint32_pack(tmp,a->attrs[j]-map); + if (!stralloc_catb(&y,tmp,4)) goto nomem; + } + } + uint32_pack(tmp,0); + if (!stralloc_catb(&y,tmp,4)) goto nomem; + } + + /* 32-bit align */ + { + unsigned int align=(-(y.len&3))&3; + if (!stralloc_catb(&y,"\0\0\0",align)) goto nomem; + } + + { + char tmp[8]; + unsigned long i; + uint32 fixup; + /* write index header: + * uint32 index_type (2 in this case); + * uint32 offset_of_next_header; */ + uint32_pack(tmp,2); + uint32_pack(tmp+4,filelen+ + 8+ /* index header */ + 4+ /* uint32 filters_count; */ + 4*(filters+1)+ /* uint32 offsets_to_filters_in_scan_ldapsearchfilter_format[filter_count+1]; */ + x.len+ /* marshalled filters */ + 4+ /* uint32 acl_count */ + 4*acls+ /* uint32 offsets_to_acls[acl_count]; */ + y.len); /* marshalled acls */ + if (write(fd,tmp,8)!=8) { +shortwrite: + ftruncate(fd,filelen); + close(fd); + diesys(1,"short write"); + } + /* uint32 filter_count */ + uint32_pack(tmp,filters); + if (write(fd,tmp,4)!=4) goto shortwrite; + /* uint32 offsets_to_filters_in_scan_ldapsearchfilter_format[filter_count+1]; */ + for (i=0; i1?argv[1]:"data",&filelen); + char* filename=argc>1?argv[1]:"data"; + char* map=mmap_read(filename,&filelen); if (filelen<5*4 || uint32_read(map)!=0xfefe1da9) { buffer_putmflush(buffer_2,"not a valid tinyldap data file!\n"); @@ -360,7 +481,7 @@ int main(int argc,char* argv[]) { if (readacls("acls")==-1) die(1,"readacls failed"); // acl_offsets(map,filelen); - marshal(map,filelen); + marshal(map,filelen,filename); return 0; } #endif diff --git a/dumpacls.c b/dumpacls.c new file mode 100644 index 0000000..a16f0c2 --- /dev/null +++ b/dumpacls.c @@ -0,0 +1,132 @@ +#include +#include +#include "buffer.h" +#include "mmap.h" +#include "uint16.h" +#include "uint32.h" +#include "ldap.h" +#include "byte.h" + +int main(int argc,char* argv[]) { + int verbose=0; + unsigned long filelen; + char* fn=argc<2?"data":argv[1]; + char* map=mmap_read(fn,&filelen); + uint32 magic,attribute_count,record_count,indices_offset,size_of_string_table,acl_ofs; + if (!map) { + buffer_puts(buffer_2,"could not open `"); + buffer_puts(buffer_2,fn); + buffer_puts(buffer_2,"´: "); + buffer_puterror(buffer_2); + buffer_putnlflush(buffer_2); + exit(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); + + { + uint32 ofs,next; + acl_ofs=0; + for (ofs=indices_offset+record_count*4; ofs<(unsigned long)filelen;) { + uint32 index_type,next,indexed_attribute; + uint32_unpack(map+ofs,&index_type); + uint32_unpack(map+ofs+4,&next); + if (index_type==2) { acl_ofs=ofs; break; } + if (nextfilelen) { +kaputt: + buffer_putsflush(buffer_1,"broken file!\n"); + return 1; + } + ofs=next; + } + if (acl_ofs) { + uint32 i,filters,acls,filtertab,acltab; + ofs=acl_ofs+8; + buffer_putulong(buffer_1,filters=uint32_read(map+ofs)); + buffer_puts(buffer_1," Filters:\n\n"); + filtertab=ofs+4; + ofs=filtertab+filters*4; + if (ofsfilelen) goto kaputt; + buffer_putulong(buffer_1,i); + buffer_puts(buffer_1,": "); + if (byte_equal(map+ofs,4,"self")) + buffer_puts(buffer_1,"self"); + else if (byte_equal(map+ofs,3,"any")) + buffer_puts(buffer_1,"any"); + else if (scan_ldapsearchfilter(map+ofs,map+filelen,&f)!=0) { + unsigned long l=fmt_ldapsearchfilterstring(0,f); + unsigned long l2; + char* buf=malloc(l+23); + 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); + } + buffer_putsflush(buffer_1,"\n"); + } + ofs=uint32_read(map+filtertab+filters*4); + if (ofsfilelen-4) goto kaputt; + acls=uint32_read(map+ofs); + buffer_puts(buffer_1,"\n\n"); + buffer_putulong(buffer_1,acls); + buffer_putsflush(buffer_1," ACLs:\n\n"); + acltab=ofs+4; + for (i=0; ifilelen-16) goto kaputt; + buffer_putlong(buffer_1,i); + buffer_puts(buffer_1,": acl ["); + buffer_putulong(buffer_1,uint32_read(map+ofs)); + buffer_puts(buffer_1,"] ["); + buffer_putulong(buffer_1,uint32_read(map+ofs+4)); + buffer_puts(buffer_1,"] "); + may=uint16_read(map+ofs+8); + maynot=uint16_read(map+ofs+10); + for (ofs+=12; ofsofs) goto kaputt; + if (!j) break; + buffer_puts(buffer_1,map+j); + buffer_puts(buffer_1,uint32_read(map+ofs+4)?",":" "); + } + if (may) { + buffer_puts(buffer_1,"+"); + if (may&1) buffer_puts(buffer_1,"r"); + if (may&2) buffer_puts(buffer_1,"w"); + if (may&4) buffer_puts(buffer_1,"a"); + if (may&8) buffer_puts(buffer_1,"d"); + if (may&16) buffer_puts(buffer_1,"R"); + } + if (maynot) { + buffer_puts(buffer_1,"-"); + if (maynot&1) buffer_puts(buffer_1,"r"); + if (maynot&2) buffer_puts(buffer_1,"w"); + if (maynot&4) buffer_puts(buffer_1,"a"); + if (maynot&8) buffer_puts(buffer_1,"d"); + if (maynot&16) buffer_puts(buffer_1,"R"); + } + buffer_putsflush(buffer_1,"\n"); + } + } + } + buffer_flush(buffer_1); + return 0; +} diff --git a/dumpidx.c b/dumpidx.c index f0e3bd9..2af458e 100644 --- a/dumpidx.c +++ b/dumpidx.c @@ -98,6 +98,9 @@ int main(int argc,char* argv[]) { case 1: buffer_puts(buffer_1,"sorted table with record pointer"); break; + case 2: + buffer_puts(buffer_1,"acl data"); + break; default: buffer_puts(buffer_1,"unknown ("); buffer_putulong(buffer_1,index_type); diff --git a/ldap.h b/ldap.h index a1b96a3..9479ac5 100644 --- a/ldap.h +++ b/ldap.h @@ -143,6 +143,7 @@ unsigned int fmt_ldapava(char* dest,struct AttributeValueAssertion* a); unsigned int fmt_ldapadl(char* dest,struct AttributeDescriptionList* adl); unsigned int fmt_ldapavl(char* dest,struct AttributeDescriptionList* adl); unsigned int fmt_ldapmodifyrequest(char* dest,struct ModifyRequest* m); +unsigned int fmt_ldapsearchfilterstring(char* dest,struct Filter* f); #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)