]> www.wagner.pp.ru Git - oss/catdoc.git/blobdiff - src/ole.c
Fix couple of errors from coverity scan
[oss/catdoc.git] / src / ole.c
index ff21a30e587c4d5f735fec4ba548b07ced0c1d46..819ad33eded3a86271b6507c34d7855cd7e69a55 100644 (file)
--- a/src/ole.c
+++ b/src/ole.c
@@ -2,14 +2,14 @@
  * @file   ole.c
  * @author Alex Ott, Victor B Wagner
  * @date   Wed Jun 11 12:33:01 2003
- * Version: $Id: ole.c,v 1.1 2006-02-24 17:44:06 vitus Exp $
+ * Version: $Id: ole.c,v 1.2 2006-02-25 15:28:14 vitus Exp $
  * Copyright: Victor B Wagner, 1996-2003 Alex Ott, 2003
- * 
+ *
  * @brief  Parsing structure of MS Office compound document
- * 
+ *
  * This file is part of catdoc project
  * and distributed under GNU Public License
- * 
+ *
  */
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -37,31 +37,32 @@ long propCurNumber, propLen, propNumber, propStart;
 unsigned char *properties=NULL;
 long int fileLength=0;
 
-static unsigned char ole_sign[]={0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1,0};
+char ole_sign[]={0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1,0};
+char zip_sign[]="PK\003\004";
 
-
-/** 
+/**
  * Initializes ole structure
- * 
+ *
  * @param f (FILE *) compound document file, positioned at bufSize
- *           byte. Might be pipe or socket 
+ *           byte. Might be pipe or socket
  * @param buffer (void *) bytes already read from f
  * @param bufSize number of bytes already read from f should be less
- *                than 512 
- * 
- * @return 
+ *                than 512
+ *
+ * @return
  */
 FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
        unsigned char oleBuf[BBD_BLOCK_SIZE];
        unsigned char *tmpBuf;
        FILE *newfile;
        int ret=0, i;
+       long int bbdSize;
        long int sbdMaxLen, sbdCurrent, propMaxLen, propCurrent, mblock, msat_size;
        oleEntry *tEntry;
 
        /* deleting old data (if it was allocated) */
        ole_finish();
-       
+
        if (fseek(f,0,SEEK_SET) == -1) {
                if ( errno == ESPIPE ) {
                        /* We got non-seekable file, create temp file */
@@ -76,7 +77,7 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
                                        return NULL;
                                }
                        }
-                       
+
                        while(!feof(f)){
                                ret=fread(oleBuf,1,BBD_BLOCK_SIZE,f);
                                fwrite(oleBuf, 1, ret, newfile);
@@ -88,7 +89,7 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
                }
        } else {
                newfile=f;
-       }       
+       }
        fseek(newfile,0,SEEK_END);
        fileLength=ftell(newfile);
 /*     fprintf(stderr, "fileLength=%ld\n", fileLength); */
@@ -97,25 +98,38 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
        if ( ret != BBD_BLOCK_SIZE ) {
                return NULL;
        }
-       if (strncmp(oleBuf,ole_sign,8) != 0) {
+       if (strncmp((char *)&oleBuf,zip_sign,4) == 0) {
+               fprintf(stderr,"Looks like ZIP archive or Office 2007 or later. Not supported\n");
+               return NULL;
+       } else if (strncmp((char *)&oleBuf,ole_sign,8) != 0) {
                return NULL;
        }
        sectorSize = 1<<getshort(oleBuf,0x1e);
        shortSectorSize=1<<getshort(oleBuf,0x20);
-       
+
 /* Read BBD into memory */
        bbdNumBlocks = getulong(oleBuf,0x2c);
+       bbdSize = bbdNumBlocks * sectorSize;
+       if (bbdSize > fileLength) {
+               /* broken file, BBD size greater than entire file*/
+               return NULL;
+       }
+
        if((BBD=malloc(bbdNumBlocks*sectorSize)) == NULL ) {
                return NULL;
        }
-       
+
        if((tmpBuf=malloc(MSAT_ORIG_SIZE)) == NULL ) {
                return NULL;
        }
        memcpy(tmpBuf,oleBuf+0x4c,MSAT_ORIG_SIZE);
        mblock=getlong(oleBuf,0x44);
        msat_size=getlong(oleBuf,0x48);
-
+       if (msat_size * sectorSize > fileLength) {
+               free(tmpBuf);
+               return NULL;
+       }
+               
 /*     fprintf(stderr, "msat_size=%ld\n", msat_size); */
 
        i=0;
@@ -130,7 +144,7 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
                        ole_finish();
                        return NULL;
                }
-               
+
                fseek(newfile, 512+mblock*sectorSize, SEEK_SET);
                if(fread(tmpBuf+MSAT_ORIG_SIZE+(sectorSize-4)*i,
                                                 1, sectorSize, newfile) != sectorSize) {
@@ -142,11 +156,11 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
                i++;
                mblock=getlong(tmpBuf, MSAT_ORIG_SIZE+(sectorSize-4)*i);
        }
-       
+
 /*     fprintf(stderr, "bbdNumBlocks=%ld\n", bbdNumBlocks); */
        for(i=0; i< bbdNumBlocks; i++) {
                long int bbdSector=getlong(tmpBuf,4*i);
-               
+
                if (bbdSector >= fileLength/sectorSize || bbdSector < 0) {
                        fprintf(stderr, "Bad BBD entry!\n");
                        ole_finish();
@@ -161,7 +175,7 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
                }
        }
        free(tmpBuf);
-       
+
 /* Read SBD into memory */
        sbdLen=0;
        sbdMaxLen=10;
@@ -177,7 +191,7 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
                        sbdLen++;
                        if (sbdLen >= sbdMaxLen) {
                                unsigned char *newSBD;
-                               
+
                                sbdMaxLen+=5;
                                if ((newSBD=realloc(SBD, sectorSize*sbdMaxLen)) != NULL) {
                                        SBD=newSBD;
@@ -187,6 +201,10 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
                                        return NULL;
                                }
                        }
+                       if (sbdCurrent * 4 > bbdSize) {
+                               ole_finish();
+                               return NULL;
+                       }
                        sbdCurrent = getlong(BBD, sbdCurrent*4);
                        if(sbdCurrent < 0 ||
                                sbdCurrent >= fileLength/sectorSize)
@@ -209,12 +227,19 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
                while(1) {
 /*                     fprintf(stderr, "propCurrent=%ld\n",propCurrent); */
                        fseek(newfile, 512+propCurrent*sectorSize, SEEK_SET);
-                       fread(properties+propLen*sectorSize,
-                                 1, sectorSize, newfile);
+                       errno=0;
+                       if (fread(properties+propLen*sectorSize,
+                                 1, sectorSize, newfile)!=sectorSize) {
+                                 if (errno != 0) {
+                                       perror("reading properties catalog");
+                                 }
+                                 ole_finish();
+                                 return NULL;
+                       }
                        propLen++;
                        if (propLen >= propMaxLen) {
                                unsigned char *newProp;
-                               
+
                                propMaxLen+=5;
                                if ((newProp=realloc(properties, propMaxLen*sectorSize)) != NULL)
                                        properties=newProp;
@@ -224,11 +249,11 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
                                        return NULL;
                                }
                        }
-                       
+
                        propCurrent = getlong(BBD, propCurrent*4);
                        if(propCurrent < 0 ||
-                          propCurrent >= fileLength/sectorSize ) {
-                               break;
+                          propCurrent >= bbdSize/4 ) {
+                          break;
                        }
                }
 /*             fprintf(stderr, "propLen=%ld\n",propLen); */
@@ -239,11 +264,11 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
                properties = NULL;
                return NULL;
        }
-       
-       
+
+
 /* Find Root Entry */
        while((tEntry=(oleEntry*)ole_readdir(newfile)) != NULL) {
-               if (!tEntry->name[0]||strcmp(tEntry->name,"Root Entry") == 0) {
+               if (tEntry->type == oleRootDir ) {
                        rootEntry=tEntry;
                        break;
                }
@@ -252,42 +277,41 @@ FILE* ole_init(FILE *f, void *buffer, size_t bufSize)  {
        propCurNumber = 0;
        fseek(newfile, 0, SEEK_SET);
        if (!rootEntry) {
-               fprintf(stderr,"Cannot find root entry in this file!\n");
-               ole_finish();
+               fprintf(stderr,"Broken OLE structure. Cannot find root entry in this file!\n");         ole_finish();
                return NULL;
-       }       
+       }
        return newfile;
 }
 
-/** 
- * 
- * 
- * @param oleBuf 
- * 
- * @return 
+/**
+ *
+ *
+ * @param oleBuf
+ *
+ * @return
  */
 int rightOleType(unsigned char *oleBuf) {
        return (oleBuf[0x42] == 1 || oleBuf[0x42] == 2 ||
                        oleBuf[0x42] == 3 || oleBuf[0x42] == 5 );
 }
 
-/** 
- * 
- * 
- * @param oleBuf 
- * 
- * @return 
+/**
+ *
+ *
+ * @param oleBuf
+ *
+ * @return
  */
 oleType getOleType(unsigned char *oleBuf) {
        return (oleType)((unsigned char)oleBuf[0x42]);
 }
 
-/** 
+/**
  * Reads next directory entry from file
- * 
+ *
  * @param name buffer for name converted to us-ascii should be at least 33 chars long
- * @param size size of file 
- * 
+ * @param size size of file
+ *
  * @return 0 if everything is ok -1 on error
  */
 FILE *ole_readdir(FILE *f) {
@@ -295,13 +319,13 @@ FILE *ole_readdir(FILE *f) {
        unsigned char *oleBuf;
        oleEntry *e=NULL;
        long int chainMaxLen, chainCurrent;
-       
+
        if ( properties == NULL || propCurNumber >= propNumber || f == NULL )
                return NULL;
        oleBuf=properties + propCurNumber*PROP_BLOCK_SIZE;
        if( !rightOleType(oleBuf))
                return NULL;
-       if ((e = (oleEntry*)malloc(sizeof(oleEntry))) == NULL) {
+       if ((e = (oleEntry*) calloc(sizeof(oleEntry),1)) == NULL) {
                perror("Can\'t allocate memory");
                return NULL;
        }
@@ -310,8 +334,12 @@ FILE *ole_readdir(FILE *f) {
        e->file=f;
        e->startBlock=getlong(oleBuf,0x74);
        e->blocks=NULL;
-       
+
        nLen=getshort(oleBuf,0x40);
+       if (nLen > OLENAMELENGTH) {
+               free(e);
+               return NULL;
+       }
        for (i=0 ; i < nLen /2; i++)
                e->name[i]=(char)oleBuf[i*2];
        e->name[i]='\0';
@@ -329,18 +357,36 @@ FILE *ole_readdir(FILE *f) {
                (e->startBlock <=
                 fileLength/(e->isBigBlock ? sectorSize : shortSectorSize))) {
                if((e->blocks=malloc(chainMaxLen*sizeof(long int))) == NULL ) {
+                       free(e);
                        return NULL;
                }
                while(1) {
+                       if(chainCurrent < 0 ||
+                          chainCurrent >= (
+                               e->isBigBlock ?
+                               ((bbdNumBlocks*sectorSize)/4) :
+                               ((sbdNumber*shortSectorSize)/4)
+                               ) ||
+                          (e->numOfBlocks >
+                               e->length/(
+                                    e->isBigBlock ?
+                                    sectorSize :
+                                    shortSectorSize
+                                    )
+                                )
+                           ) {
+/*                             fprintf(stderr, "chain End=%ld\n", chainCurrent);   */
+                               break;
+                       }
 /*                     fprintf(stderr, "chainCurrent=%ld\n", chainCurrent); */
                        e->blocks[e->numOfBlocks++] = chainCurrent;
                        if (e->numOfBlocks >= chainMaxLen) {
                                long int *newChain;
                                chainMaxLen+=25;
                                if ((newChain=realloc(e->blocks,
-                                                                         chainMaxLen*sizeof(long int))) != NULL)
+                                                                         chainMaxLen*sizeof(long int))) != NULL) {
                                        e->blocks=newChain;
-                               else {
+                               else {
                                        perror("Properties realloc error");
                                        free(e->blocks);
                                        e->blocks=NULL;
@@ -354,50 +400,41 @@ FILE *ole_readdir(FILE *f) {
                        } else {
                                chainCurrent=-1;
                        }
-                       if(chainCurrent <= 0 ||
-                          chainCurrent >= ( e->isBigBlock ?
-                                                                ((bbdNumBlocks*sectorSize)/4)
-                                                                : ((sbdNumber*shortSectorSize)/4) ) ||
-                          (e->numOfBlocks >
-                               e->length/(e->isBigBlock ? sectorSize : shortSectorSize))) {
-/*                             fprintf(stderr, "chain End=%ld\n", chainCurrent);   */
-                               break;
-                       }
                }
        }
-       
+
        if(e->length > (e->isBigBlock ? sectorSize : shortSectorSize)*e->numOfBlocks)
                e->length = (e->isBigBlock ? sectorSize : shortSectorSize)*e->numOfBlocks;
 /*     fprintf(stderr, "READDIR: e->name=%s e->numOfBlocks=%ld length=%ld\n", */
 /*                                     e->name, e->numOfBlocks, e->length); */
-       
+
        return (FILE*)e;
 }
 
-/** 
+/**
  * Open stream, which correspond to directory entry last read by
- * ole_readdir 
- * 
- * 
+ * ole_readdir
+ *
+ *
  * @return opaque pointer to pass to ole_read, casted to (FILE *)
  */
 int ole_open(FILE *stream) {
        oleEntry *e=(oleEntry *)stream;
        if ( e->type != oleStream)
                return -2;
-       
+
        e->ole_offset=0;
        e->file_offset= ftell(e->file);
        return 0;
 }
 
-/** 
- * 
- * 
- * @param e 
- * @param blk 
- * 
- * @return 
+/**
+ *
+ *
+ * @param e
+ * @param blk
+ *
+ * @return
  */
 long int calcFileBlockOffset(oleEntry *e, long int blk) {
        long int res;
@@ -407,7 +444,7 @@ long int calcFileBlockOffset(oleEntry *e, long int blk) {
                long int sbdPerSector=sectorSize/shortSectorSize;
                long int sbdSecNum=e->blocks[blk]/sbdPerSector;
                long int sbdSecMod=e->blocks[blk]%sbdPerSector;
-/*             fprintf(stderr, "calcoffset: e->name=%s e->numOfBlocks=%ld length=%ld sbdSecNum=%ld rootEntry->blocks=%p\n", 
+/*             fprintf(stderr, "calcoffset: e->name=%s e->numOfBlocks=%ld length=%ld sbdSecNum=%ld rootEntry->blocks=%p\n",
                                                e->name, e->numOfBlocks, e->length, sbdSecNum, rootEntry->blocks);*/
                res=512 + rootEntry->blocks[sbdSecNum]*sectorSize + sbdSecMod*shortSectorSize;
        }
@@ -415,14 +452,14 @@ long int calcFileBlockOffset(oleEntry *e, long int blk) {
 }
 
 
-/** 
+/**
  * Reads block from open ole stream interface-compatible with fread
- * 
+ *
  * @param ptr pointer to buffer for read to
  * @param size size of block
- * @param nmemb size in blocks 
+ * @param nmemb size in blocks
  * @param stream pointer to FILE* structure
- * 
+ *
  * @return number of readed blocks
  */
 size_t ole_read(void *ptr, size_t size, size_t nmemb, FILE *stream) {
@@ -431,22 +468,22 @@ size_t ole_read(void *ptr, size_t size, size_t nmemb, FILE *stream) {
        long int blockNumber, modBlock, toReadBlocks, toReadBytes, bytesInBlock;
        long int ssize;                         /**< Size of block */
        long int newoffset;
-       unsigned char *cptr = ptr;      
+       unsigned char *cptr = ptr;
        if( e->ole_offset+llen > e->length )
                llen= e->length - e->ole_offset;
-       
+
        ssize = (e->isBigBlock ? sectorSize : shortSectorSize);
        blockNumber=e->ole_offset/ssize;
 /*     fprintf(stderr, "blockNumber=%ld e->numOfBlocks=%ld llen=%ld\n", */
 /*                     blockNumber, e->numOfBlocks, llen); */
        if ( blockNumber >= e->numOfBlocks || llen <=0 )
                return 0;
-       
+
        modBlock=e->ole_offset%ssize;
        bytesInBlock = ssize - modBlock;
        if(bytesInBlock < llen) {
                toReadBlocks = (llen-bytesInBlock)/ssize;
-               toReadBytes = (llen-bytesInBlock)%ssize; 
+               toReadBytes = (llen-bytesInBlock)%ssize;
        } else {
                toReadBlocks = toReadBytes = 0;
        }
@@ -462,8 +499,8 @@ size_t ole_read(void *ptr, size_t size, size_t nmemb, FILE *stream) {
                int readbytes;
                blockNumber++;
                newoffset = calcFileBlockOffset(e,blockNumber);
-               if (newoffset != e->file_offset);
-               fseek(e->file, e->file_offset=newoffset , SEEK_SET);
+               if (newoffset != e->file_offset)
+                       fseek(e->file, e->file_offset=newoffset , SEEK_SET);
                readbytes=fread(cptr+rread, 1, min(llen-rread, ssize), e->file);
                rread +=readbytes;
                e->file_offset +=readbytes;
@@ -481,14 +518,14 @@ size_t ole_read(void *ptr, size_t size, size_t nmemb, FILE *stream) {
        e->ole_offset, rread, llen);*/
        e->ole_offset+=rread;
        return rread;
-}      
-
-/** 
- * 
- * 
- * @param stream 
- * 
- * @return 
+}
+
+/**
+ *
+ *
+ * @param stream
+ *
+ * @return
  */
 int ole_eof(FILE *stream) {
        oleEntry *e=(oleEntry*)stream;
@@ -497,9 +534,9 @@ int ole_eof(FILE *stream) {
        return (e->ole_offset >=  e->length);
 }
 
-/** 
- * 
- * 
+/**
+ *
+ *
  */
 void ole_finish(void) {
        if ( BBD != NULL ) free(BBD);
@@ -510,12 +547,12 @@ void ole_finish(void) {
        rootEntry = NULL;
 }
 
-/** 
- * 
- * 
- * @param stream 
- * 
- * @return 
+/**
+ *
+ *
+ * @param stream
+ *
+ * @return
  */
 int ole_close(FILE *stream) {
        oleEntry *e=(oleEntry*)stream;
@@ -528,32 +565,32 @@ int ole_close(FILE *stream) {
 }
 
 /**
- * 
- * 
+ *
+ *
  * @param stream pointer to OLE stream structure
- * @param offset 
- * @param whence 
- * 
- * @return 
+ * @param offset
+ * @param whence
+ *
+ * @return
  */
 int ole_seek(FILE *stream, long offset, int whence) {
        oleEntry *e=(oleEntry*)stream;
        long int new_ole_offset=0, new_file_offset;
        int ssize, modBlock, blockNumber;
-       
+
        switch(whence) {
        case SEEK_SET:
                new_ole_offset=offset;
                break;
-               
+
        case SEEK_CUR:
                new_ole_offset=e->ole_offset+offset;
                break;
-               
+
        case SEEK_END:
                new_ole_offset=e->length+offset;
                break;
-               
+
        default:
                errno=EINVAL;
                return -1;
@@ -567,20 +604,20 @@ int ole_seek(FILE *stream, long offset, int whence) {
        blockNumber=new_ole_offset/ssize;
        if ( blockNumber >= e->numOfBlocks )
                return -1;
-       
+
        modBlock=new_ole_offset%ssize;
        new_file_offset = calcFileBlockOffset(e,blockNumber)+modBlock;
        fseek(e->file, e->file_offset=new_file_offset, SEEK_SET);
        e->ole_offset=new_ole_offset;
-       
+
        return 0;
 }
 
-/** 
+/**
  * Tell position inside OLE stream
- * 
+ *
  * @param stream pointer to OLE stream
- * 
+ *
  * @return current position inside OLE stream
  */
 long ole_tell(FILE *stream) {
@@ -590,8 +627,8 @@ long ole_tell(FILE *stream) {
 
 
 /**
- * 
- * 
+ *
+ *
  */
 size_t (*catdoc_read)(void *ptr, size_t size, size_t nmemb, FILE *stream);
 int (*catdoc_eof)(FILE *stream);
@@ -608,10 +645,10 @@ void set_ole_func(void) {
 #ifdef feof
 /* feof is macro in Turbo C, so we need a real function to assign to
  * pointer
- */ 
+ */
 int my_feof(FILE *f) {
     return feof(f);
-}    
+}
 #define FEOF my_feof
 #else
 #define FEOF feof