#define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include "mduptab.h" #include "mstorage.h" #include #include "ldif.h" #include "byte.h" #include "textcode.h" #include "stralloc.h" #include "uint32.h" mduptab_t attributes,classes; mstorage_t stringtable; uint32_t dn, objectClass; unsigned long lines; /* this is called after each record. * If it returns -1, ldif_parse will exit immediately. * If it returns 0, ldif_parse will continue parsing and overwrite the * current ldaprec. * If it returns 1, ldif_parse will allocate a new ldaprec and link it * using the next pointer in the current ldaprec. * If the callback is NULL, a callback that always returns 1 is assumed. * */ int (*ldif_parse_callback)(struct ldaprec* l); uint32_t (*ldif_addstring_callback)(const char* s,unsigned long len); unsigned long ldifrecords; static void addattribute(struct ldaprec** l,uint32_t name,uint32_t val) { if (name==dn) (*l)->dn=val; else if ((*l)->na[(*l)->n].name=name; (*l)->a[(*l)->n].value=val; ++(*l)->n; } else { buffer_puts(buffer_2,"\r\n\nLDIF parse error: too many attributes!: "); buffer_puts(buffer_2,attributes.Strings->root+name); buffer_puts(buffer_2," in line "); buffer_putulong(buffer_2,lines); buffer_putnlflush(buffer_2); exit(1); } } static size_t unbase64(char* buf) { size_t destlen; char temp[8192]; size_t l=scan_base64(buf,temp,&destlen); if (buf[l] && buf[l]!='\n') return 0; byte_copy(buf,destlen,temp); return destlen; } uint32_t (*ldif_addstring_callback)(const char* s,unsigned long len); static uint32_t addstring(const char* s,unsigned long len) { return mstorage_add(&stringtable,s,len); } static long commit_string_bin(const char* s,unsigned long n) { unsigned int i; static char zero; uint32_t x; char intbuf[4]; if (n==0 || (n==1 && s[0]==0)) goto encodebinary; for (i=0; idn=-1; (*l)->next=0; (*l)->n=0; ldifrecords=0; do { uint32_t tmp, val; base64=binary=0; buf[ofs]=0; n=ofs+buffer_get_token(b,buf+ofs,8192-ofs,":\n",2); if (n==ofs) { if (buf[ofs]==0) eof=1; break; } if (buf[0]=='#') { /* comment line */ while (n>=8192-ofs || buf[n]==':') { /* if we got a partial line or the comment contained a colon, do over */ ofs=0; n=buffer_get_token(b,buf,8192,"\n",1); } ++lines; continue; } i=scan_whitenskip(buf,n); if (buf[byte_chr(buf+i,n-i,'\n')]=='\n') { buffer_putm(buffer_2,"\r\n\n",filename,":"); buffer_putulong(buffer_2,lines+1); buffer_putsflush(buffer_2,": error: no key:value found\n"); exit(1); } buf[n]=0; if ((i2=str_chr(buf,';'))<(unsigned int)n) { buf[i2]=0; if (str_equal("binary",buf+i2+1)) binary=1; } if ((tmp=mduptab_adds(&attributes,buf+i))==(uint32_t)-1) { // write(2,"a",1); goto nomem; } if (!stralloc_copys(&payload,"")) { // write(2,"b",1); goto nomem; } { char dummy; int res; /* read line, skipping initial whitespace */ for (n=0; (res=buffer_getc(b,&dummy))==1; ) { if (dummy=='\n') { ++lines; break; } if (!n && dummy==':' && base64==0) { base64=1; continue; } if (!n && (dummy==' ' || dummy=='\t')) continue; if (!stralloc_append(&payload,&dummy)) { // write(2,"c",1); goto nomem; } ++n; } if (res==-1) return 1; } 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,8192,"\n",1); if (n==-1) return 1; if (!stralloc_catb(&payload,buf,n)) { // write(2,"d",1); goto nomem; } goto lookagain; } else if (c=='\n') { struct ldaprec* m; ++lines; if (payload.len) { if (!stralloc_0(&payload)) { // write(2,"e",1); goto nomem; } if (base64) { len=unbase64(payload.s); if (len==0) { buffer_putm(buffer_2,"\r\n\n",filename,":"); buffer_putulong(buffer_2,lines+1); buffer_putsflush(buffer_2,": error: base64 decoding failed\n"); exit(1); } if (!binary) { payload.s[len]=0; ++len; } } else { size_t sl; len=n; sl=scan_ldapescape(payload.s,payload.s,&len); if (sl!=payload.len-1) { buffer_putm(buffer_2,"\r\n\n",filename,":"); buffer_putulong(buffer_2,lines+1); buffer_putsflush(buffer_2,": error: LDIF de-escaping failed\n"); exit(1); } payload.s[len]=0; ++len; } } else len=0; #if 0 buffer_puts(buffer_2,"feld \""); buffer_puts(buffer_2,attributes.Strings->root+tmp); buffer_puts(buffer_2,"\", wert \""); buffer_put(buffer_2,payload.s,len); buffer_putsflush(buffer_2,"\".\n"); #endif if (tmp==objectClass) { if ((val=mduptab_add(&classes,payload.s,len-1))==(uint32_t)-1) { // write(2,"f",1); goto nomem; } } else if (tmp==dn) { if ((val=add_normalized(payload.s,len))==(uint32_t)-1) { // write(2,"g",1); goto nomem; } } else if ((val=commit_string_bin(payload.s,len))==(uint32_t)-1) { // write(2,"h",1); goto nomem; } addattribute(l,tmp,val); m=0; if (ldif_parse_callback) { switch (ldif_parse_callback(*l)) { case -1: return -1; case 0: m=*l; break; #if 0 case 1: m=0; break; #endif } } if (!m) if (!(m=malloc(sizeof(struct ldaprec)))) return 2; (*l)->next=m; m->n=0; m->dn=-1; m->next=0; ofs=0; // dumprec(*l); if (*l!=m) l=&((*l)->next); ++ldifrecords; continue; } else { ofs=1; buf[0]=c; } } // buf[n]=0; #if 1 if (payload.len) { if (!stralloc_0(&payload)) { // write(2,"i",1); goto nomem; } if (base64) { len=unbase64(payload.s); if (len==0) { buffer_putm(buffer_2,"\r\n\n",filename,":"); buffer_putulong(buffer_2,lines+1); buffer_putsflush(buffer_2,": error: base64 decoding failed\n"); exit(1); } if (!binary) { payload.s[len]=0; ++len; } } else { len=n; scan_ldapescape(payload.s,payload.s,&len); payload.s[len]=0; ++len; } } else len=0; #if 0 buffer_puts(buffer_2,"feld \""); buffer_puts(buffer_2,attributes.Strings->root+tmp); buffer_puts(buffer_2,"\", wert \""); buffer_put(buffer_2,payload.s,len); buffer_putsflush(buffer_2,"\".\n"); #endif if (tmp==objectClass) { if ((val=mduptab_add(&classes,payload.s,len-1))==(uint32_t)-1) { // write(2,"j",1); goto nomem; } } else if (tmp==dn) { if ((val=add_normalized(payload.s,payload.len))==(uint32_t)-1) { // write(2,"k",1); goto nomem; } } else if ((val=commit_string_bin(payload.s,len))==(uint32_t)-1) { // write(2,"l",1); goto nomem; } addattribute(l,tmp,val); #endif } while (!eof); if (!eof) { buffer_putm(buffer_2,"\r\n\n",filename,":"); buffer_putulong(buffer_2,lines+1); buffer_putsflush(buffer_2,": error: parse error (maybe 2nd empty line?)\n"); exit(1); } 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; free((*l)); (*l)=m; } return 0; } struct ldaprec *first=0; int ldif_parse(const char* filename,off_t fromofs,struct stat* ss) { char buf[4096]; int fd; buffer in; buffer* tmp; mstorage_init(&stringtable); if (ldif_addstring_callback==0) ldif_addstring_callback=addstring; if (filename[0]=='-' && !filename[1]) { tmp=buffer_0; fd=-1; } else { fd=open_read(filename); 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=∈ } dn=mduptab_adds(&attributes,"dn"); objectClass=mduptab_adds(&attributes,"objectClass"); lines=0; { int res=parserec(tmp,&first,filename); 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; } }