#include #include #include "byte.h" #include "buffer.h" #include "ldap.h" #include "ldif.h" #include "open.h" #include "mmap.h" #include "uint32.h" #ifdef STANDALONE #include "socket.h" #include "ip6.h" #include #endif static int verbose=0; char* map; long filelen; uint32 magic,attribute_count,record_count,indices_offset,size_of_string_table; /* how many longs are needed to have one bit for each record? */ uint32 record_set_length; #define BUFSIZE 8192 static int indexable(struct Filter* f) { struct Filter* y=f->x; if (!f) return 1; switch (f->type) { case AND: while (y) { if (!indexable(y)) return 0; y=y->next; } return 1; case OR: while (y) { if (!indexable(y)) return 0; y=y->next; } return 1; #if 0 /* doesn't make much sense to try to speed up negated queries */ case NOT: return indexable(y); #endif case SUBSTRING: if (f->substrings->substrtype!=prefix) return 0; /* fall through */ case EQUAL: { uint32 ofs; 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); uint32_unpack(map+ofs+8,&indexed_attribute); if (index_type==0) if (!matchstring(&f->ava.desc,map+indexed_attribute)) return 1; ofs=next; } } /* fall through */ default: return 0; } } /* find record given a data pointer */ static uint32 findrec(uint32 dat) { uint32* records=(uint32*)(map+indices_offset); uint32 bottom=0; uint32 top=record_count; while ((top>=bottom)) { uint32 mid=(top+bottom)/2; uint32 k,l; uint32_unpack(&records[mid],&k); uint32_unpack(map+k+8,&l); #if 0 buffer_puts(buffer_2,"findrec: look for "); buffer_putulong(buffer_2,dat); buffer_puts(buffer_2," in record "); buffer_putulong(buffer_2,mid); buffer_puts(buffer_2," @"); buffer_putulong(buffer_2,l); buffer_putsflush(buffer_2,".\n"); #endif if (ldat) return mid; /* found! */ bottom=mid+1; } else if (mid) top=mid-1; else break; } buffer_putsflush(buffer_2,"findrec failed!\n"); return 0; } static inline void emptyset(unsigned long* r) { unsigned long i; for (i=0; i0) buffer_putsflush(buffer_2,"not properly sorted!\n"); } } } #endif while ((top>=bottom)) { uint32 mid=(top+bottom)/2; uint32 k; int l; #if 0 buffer_puts(buffer_2,"bottom="); buffer_putulong(buffer_2,bottom); buffer_puts(buffer_2,", mid="); buffer_putulong(buffer_2,mid); buffer_puts(buffer_2,", top="); buffer_putulong(buffer_2,top); buffer_puts(buffer_2,", elements="); buffer_putulong(buffer_2,elements); buffer_putsflush(buffer_2,".\n"); #endif uint32_unpack(&index[mid],&k); if ((l=matchstring(s,map+k))==0) { /* match! */ uint32 rec; uint32 oldk=k; if ((rec=findrec(k))) setbit(bitfield,rec); /* there may be multiple matches. * Look before and after mid, too */ for (oldk=k; k>0; ) { k-=4; if ((l=matchstring(s,map+k))==0) if ((rec=findrec(k))) setbit(bitfield,rec); } for (k=oldk; ks,s->l); buffer_puts(buffer_2,"\" vs. \""); buffer_puts(buffer_2,map+k); buffer_puts(buffer_2," -> "); buffer_putlong(buffer_2,l); buffer_putsflush(buffer_2,"\n"); #endif if (l<0) { if (mid) top=mid-1; else break; } else bottom=mid+1; } } static int useindex(struct Filter* f,unsigned long* bitfield) { struct Filter* y=f->x; if (!f) return 1; switch (f->type) { case AND: while (y) { if (!indexable(y)) return 0; y=y->next; } return 1; case OR: while (y) { if (!indexable(y)) return 0; y=y->next; } return 1; #if 0 /* doesn't make much sense to try to speed up negated queries */ case NOT: return indexable(y); #endif case SUBSTRING: if (f->substrings->substrtype!=prefix) return 0; /* fall through */ case EQUAL: { uint32 ofs; 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); uint32_unpack(map+ofs+8,&indexed_attribute); if (index_type==0) if (!matchstring(&f->ava.desc,map+indexed_attribute)) { tagmatches((uint32*)(map+ofs+12),(next-ofs-12)/4,&f->ava.value,bitfield); return 1; } ofs=next; } } /* fall through */ default: return 0; } } static void answerwith(uint32 ofs,struct SearchRequest* sr,long messageid,int out) { uint32 k; struct SearchResultEntry sre; struct PartialAttributeList** pal=&sre.attributes; if (0) { char* x=map+ofs; uint32 j,k; uint32_unpack(x,&j); buffer_putulong(buffer_2,j); buffer_puts(buffer_2," attributes:\n"); x+=8; buffer_puts(buffer_2," dn: "); uint32_unpack(x,&k); buffer_puts(buffer_2,map+k); buffer_puts(buffer_2,"\n objectClass: "); x+=4; uint32_unpack(x,&k); buffer_puts(buffer_2,map+k); buffer_puts(buffer_2,"\n"); x+=4; for (; j>2; --j) { uint32_unpack(x,&k); buffer_puts(buffer_2," "); buffer_puts(buffer_2,map+k); buffer_puts(buffer_2,": "); uint32_unpack(x+4,&k); buffer_puts(buffer_2,map+k); buffer_puts(buffer_2,"\n"); x+=8; } buffer_flush(buffer_2); } uint32_unpack(map+ofs+8,&k); sre.objectName.s=map+k; sre.objectName.l=strlen(map+k); sre.attributes=0; /* now go through list of requested attributes */ { struct AttributeDescriptionList* adl=sr->attributes; while (adl) { const char* val=0; uint32 i=2,j; uint32_unpack(map+ofs,&j); #if 0 buffer_puts(buffer_2,"looking for attribute \""); buffer_put(buffer_2,adl->a.s,adl->a.l); buffer_putsflush(buffer_2,"\"\n"); #endif if (!matchstring(&adl->a,"dn")) val=sre.objectName.s; else if (!matchstring(&adl->a,"objectClass")) { uint32_unpack(map+ofs+12,&k); val=map+k; } else { for (; ia,map+k)) { uint32_unpack(map+ofs+i*8+4,&k); val=map+k; break; } } } if (val) { *pal=malloc(sizeof(struct PartialAttributeList)); if (!*pal) { nomem: buffer_putsflush(buffer_2,"out of virtual memory!\n"); exit(1); } (*pal)->type=adl->a; { struct AttributeDescriptionList** a=&(*pal)->values; while (ia.s=val; (*a)->a.l=strlen(val); (*a)->next=0; for (;ia,map+k)) { uint32_unpack(map+ofs+i*8+4,&k); val=map+k; ++i; break; } } } } (*pal)->next=0; pal=&(*pal)->next; } adl=adl->next; } } { long l=fmt_ldapsearchresultentry(0,&sre); char *buf=alloca(l+300); /* you never know ;) */ long tmp; if (verbose) { buffer_puts(buffer_2,"sre len "); buffer_putulong(buffer_2,l); buffer_putsflush(buffer_2,".\n"); } tmp=fmt_ldapmessage(buf,messageid,SearchResultEntry,l); fmt_ldapsearchresultentry(buf+tmp,&sre); write(out,buf,l+tmp); } } int handle(int in,int out) { int len; char buf[BUFSIZE]; for (len=0;;) { int tmp=read(in,buf+len,BUFSIZE-len); int res; long messageid,op,Len; if (tmp==0) if (!len) { return 0; } if (tmp<0) { write(2,"error!\n",7); return 1; } len+=tmp; res=scan_ldapmessage(buf,buf+len,&messageid,&op,&Len); if (res>0) { if (verbose) { 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 BindRequest: { long version,method; struct string name; int tmp; tmp=scan_ldapbindrequest(buf+res,buf+res+len,&version,&name,&method); if (tmp>=0) { if (verbose) { 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(out,outbuf+s-hlen,len+hlen); } } } break; case SearchRequest: { struct SearchRequest sr; int tmp; #if 0 { int fd=open_write("request"); write(fd,buf,res+len); close(fd); } #endif if ((tmp=scan_ldapsearchrequest(buf+res,buf+res+len,&sr))) { if (indexable(sr.filter)) { unsigned long* result; unsigned long i; // buffer_putsflush(buffer_2,"query is indexable!\n"); record_set_length=(record_count+sizeof(unsigned long)*8-1) / (sizeof(long)*8); result=alloca(record_set_length*sizeof(unsigned long)); /* Use the index to find matching data. Put the offsets * of the matches in a table. Use findrec to locate * the records that point to the data. */ useindex(sr.filter,result); for (i=0; i "); { uint32 l; uint32_unpack(map+j+8,&l); buffer_puts(buffer_2,map+l); } buffer_putsflush(buffer_2,"\n"); #endif if (ldap_match_mapped(j,&sr)) answerwith(j,&sr,messageid,out); } } else { char* x=map+5*4+size_of_string_table+attribute_count*8; unsigned long i; for (i=0; i