static int szddd_read_headers(struct mspack_system *sys, struct mspack_file *fh, struct msszddd_header *hdr) { unsigned char buf[8]; /* read and check signature */ if (sys->read(fh, buf, 8) != 8) return MSPACK_ERR_READ; if ((mspack_memcmp(buf, szdd_signature_expand, 8) == 0)) { /* common SZDD */ hdr->format = MSSZDD_FMT_NORMAL; /* read the rest of the header */ if (sys->read(fh, buf, 6) != 6) return MSPACK_ERR_READ; if (buf[0] != 0x41) return MSPACK_ERR_DATAFORMAT; hdr->missing_char = buf[1]; hdr->length = EndGetI32(&buf[2]); } else if ((mspack_memcmp(buf, szdd_signature_qbasic, 8) == 0)) { /* special QBasic SZDD */ hdr->format = MSSZDD_FMT_QBASIC; if (sys->read(fh, buf, 4) != 4) return MSPACK_ERR_READ; hdr->missing_char = '\0'; hdr->length = EndGetI32(buf); } else { return MSPACK_ERR_SIGNATURE; } return MSPACK_ERR_OK; }
static int szddd_read_headers(struct mspack_system *sys, struct mspack_file *fh, struct msszddd_header *szdd) { unsigned char buf[szddhead_SIZEOF]; szdd->length = 0; szdd->missing_char = '\0'; /* read header */ if (sys->read(fh, &buf[0], szddhead_SIZEOF) != szddhead_SIZEOF) { return MSPACK_ERR_READ; } /* check signature */ if ((mspack_memcmp(&buf[szddhead_Signature], &szdd_signature[0], 8) != 0)) { return MSPACK_ERR_SIGNATURE; } /* check compression method */ if (buf[szddhead_CompType] != SZDD_COMPTYPE_A) { return MSPACK_ERR_DATAFORMAT; } /* read missing character from filename */ szdd->missing_char = buf[szddhead_FileChar]; /* read decompressed length of file */ szdd->length = EndGetI32(&buf[szddhead_FileLength]); return MSPACK_ERR_OK; }
static gboolean read_uint32 (FILE *input, guint32 *val) { gchar buf[4]; if (fread (buf, 1, 4, input) == 4) { *val = EndGetI32 (buf); return TRUE; } else return FALSE; }
static int oabd_decompress(struct msoab_decompressor *_self, const char *input, const char *output) { struct msoab_decompressor_p *self = (struct msoab_decompressor_p *) _self; struct mspack_system *sys; struct mspack_file *infh = NULL; struct mspack_file *outfh = NULL; unsigned char *buf = NULL; unsigned char hdrbuf[oabhead_SIZEOF]; unsigned int block_max, target_size; struct lzxd_stream *lzx = NULL; struct mspack_system oabd_sys; struct oabd_file in_ofh, out_ofh; unsigned int window_bits; int ret = MSPACK_ERR_OK; if (!self) return MSPACK_ERR_ARGS; sys = self->system; infh = sys->open(sys, input, MSPACK_SYS_OPEN_READ); if (!infh) { ret = MSPACK_ERR_OPEN; goto out; } if (sys->read(infh, hdrbuf, oabhead_SIZEOF) != oabhead_SIZEOF) { ret = MSPACK_ERR_READ; goto out; } if (EndGetI32(&hdrbuf[oabhead_VersionHi]) != 3 || EndGetI32(&hdrbuf[oabhead_VersionLo]) != 1) { ret = MSPACK_ERR_SIGNATURE; goto out; } block_max = EndGetI32(&hdrbuf[oabhead_BlockMax]); target_size = EndGetI32(&hdrbuf[oabhead_TargetSize]); /* We use it for reading block headers too */ if (block_max < oabblk_SIZEOF) block_max = oabblk_SIZEOF; outfh = sys->open(sys, output, MSPACK_SYS_OPEN_WRITE); if (!outfh) { ret = MSPACK_ERR_OPEN; goto out; } buf = sys->alloc(sys, block_max); if (!buf) { ret = MSPACK_ERR_NOMEMORY; goto out; } oabd_sys = *sys; oabd_sys.read = oabd_sys_read; oabd_sys.write = oabd_sys_write; in_ofh.orig_sys = sys; in_ofh.orig_file = infh; out_ofh.orig_sys = sys; out_ofh.orig_file = outfh; while (target_size) { unsigned int blk_csize, blk_dsize, blk_crc, blk_flags; if (sys->read(infh, buf, oabblk_SIZEOF) != oabblk_SIZEOF) { ret = MSPACK_ERR_READ; goto out; } blk_flags = EndGetI32(&buf[oabblk_Flags]); blk_csize = EndGetI32(&buf[oabblk_CompSize]); blk_dsize = EndGetI32(&buf[oabblk_UncompSize]); blk_crc = EndGetI32(&buf[oabblk_CRC]); if (blk_dsize > block_max || blk_dsize > target_size || blk_flags > 1) { ret = MSPACK_ERR_DATAFORMAT; goto out; } if (!blk_flags) { /* Uncompressed block */ if (blk_dsize != blk_csize) { ret = MSPACK_ERR_DATAFORMAT; goto out; } if (sys->read(infh, buf, blk_dsize) != (int)blk_dsize) { ret = MSPACK_ERR_READ; goto out; } if (sys->write(outfh, buf, blk_dsize) != (int)blk_dsize) { ret = MSPACK_ERR_WRITE; goto out; } } else { /* LZX compressed block */ window_bits = 17; while (window_bits < 25 && (1U << window_bits) < blk_dsize) window_bits++; in_ofh.available = blk_csize; out_ofh.crc = 0xffffffff; lzx = lzxd_init(&oabd_sys, (void *)&in_ofh, (void *)&out_ofh, window_bits, 0, 4096, blk_dsize, 1); if (!lzx) { ret = MSPACK_ERR_NOMEMORY; goto out; } ret = lzxd_decompress(lzx, blk_dsize); if (ret != MSPACK_ERR_OK) goto out; lzxd_free(lzx); lzx = NULL; /* Consume any trailing padding bytes before the next block */ while (in_ofh.available) { int count = block_max; if ((size_t)count > in_ofh.available) count = in_ofh.available; count = sys->read(infh, buf, count); if (count < 0) { ret = MSPACK_ERR_READ; goto out; } in_ofh.available -= count; } if (out_ofh.crc != blk_crc) { ret = MSPACK_ERR_CHECKSUM; goto out; } } target_size -= blk_dsize; } out: if (lzx) lzxd_free(lzx); if (buf) sys->free(buf); if (outfh) sys->close(outfh); if (infh) sys->close(infh); return ret; }
/*************************************** * CABD_READ_HEADERS *************************************** * reads the cabinet file header, folder list and file list. * fills out a pre-existing mscabd_cabinet structure, allocates memory * for folders and files as necessary */ static int cabd_read_headers(struct mspack_system *sys, struct mspack_file *fh, struct mscabd_cabinet_p *cab, off_t offset, int quiet) { int num_folders, num_files, folder_resv, i, x; struct mscabd_folder_p *fol, *linkfol = NULL; struct mscabd_file *file, *linkfile = NULL; unsigned char buf[64]; /* initialise pointers */ cab->base.next = NULL; cab->base.files = NULL; cab->base.folders = NULL; cab->base.prevcab = cab->base.nextcab = NULL; cab->base.prevname = cab->base.nextname = NULL; cab->base.previnfo = cab->base.nextinfo = NULL; cab->base.base_offset = offset; /* seek to CFHEADER */ if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) { return MSPACK_ERR_SEEK; } /* read in the CFHEADER */ if (sys->read(fh, &buf[0], cfhead_SIZEOF) != cfhead_SIZEOF) { return MSPACK_ERR_READ; } /* check for "MSCF" signature */ if (EndGetI32(&buf[cfhead_Signature]) != 0x4643534D) { return MSPACK_ERR_SIGNATURE; } /* some basic header fields */ cab->base.length = EndGetI32(&buf[cfhead_CabinetSize]); cab->base.set_id = EndGetI16(&buf[cfhead_SetID]); cab->base.set_index = EndGetI16(&buf[cfhead_CabinetIndex]); /* get the number of folders */ num_folders = EndGetI16(&buf[cfhead_NumFolders]); if (num_folders == 0) { if (!quiet) sys->message(fh, "no folders in cabinet."); return MSPACK_ERR_DATAFORMAT; } /* get the number of files */ num_files = EndGetI16(&buf[cfhead_NumFiles]); if (num_files == 0) { if (!quiet) sys->message(fh, "no files in cabinet."); return MSPACK_ERR_DATAFORMAT; } /* check cabinet version */ if ((buf[cfhead_MajorVersion] != 1) && (buf[cfhead_MinorVersion] != 3)) { if (!quiet) sys->message(fh, "WARNING; cabinet version is not 1.3"); } /* read the reserved-sizes part of header, if present */ cab->base.flags = EndGetI16(&buf[cfhead_Flags]); if (cab->base.flags & cfheadRESERVE_PRESENT) { if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) { return MSPACK_ERR_READ; } cab->base.header_resv = EndGetI16(&buf[cfheadext_HeaderReserved]); folder_resv = buf[cfheadext_FolderReserved]; cab->block_resv = buf[cfheadext_DataReserved]; if (cab->base.header_resv > 60000) { if (!quiet) sys->message(fh, "WARNING; reserved header > 60000."); } /* skip the reserved header */ if (cab->base.header_resv) { if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) { return MSPACK_ERR_SEEK; } } } else { cab->base.header_resv = 0; folder_resv = 0; cab->block_resv = 0; } /* read name and info of preceeding cabinet in set, if present */ if (cab->base.flags & cfheadPREV_CABINET) { cab->base.prevname = cabd_read_string(sys, fh, cab, &x); if (x) return x; cab->base.previnfo = cabd_read_string(sys, fh, cab, &x); if (x) return x; } /* read name and info of next cabinet in set, if present */ if (cab->base.flags & cfheadNEXT_CABINET) { cab->base.nextname = cabd_read_string(sys, fh, cab, &x); if (x) return x; cab->base.nextinfo = cabd_read_string(sys, fh, cab, &x); if (x) return x; } /* read folders */ for (i = 0; i < num_folders; i++) { if (sys->read(fh, &buf[0], cffold_SIZEOF) != cffold_SIZEOF) { return MSPACK_ERR_READ; } if (folder_resv) { if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) { return MSPACK_ERR_SEEK; } } if (!(fol = sys->alloc(sys, sizeof(struct mscabd_folder_p)))) { return MSPACK_ERR_NOMEMORY; } fol->base.next = NULL; fol->base.comp_type = EndGetI16(&buf[cffold_CompType]); fol->base.num_blocks = EndGetI16(&buf[cffold_NumBlocks]); fol->data.next = NULL; fol->data.cab = (struct mscabd_cabinet_p *) cab; fol->data.offset = offset + (off_t) ( (unsigned int) EndGetI32(&buf[cffold_DataOffset]) ); fol->merge_prev = NULL; fol->merge_next = NULL; /* link folder into list of folders */ if (!linkfol) cab->base.folders = (struct mscabd_folder *) fol; else linkfol->base.next = (struct mscabd_folder *) fol; linkfol = fol; } /* read files */ for (i = 0; i < num_files; i++) { if (sys->read(fh, &buf[0], cffile_SIZEOF) != cffile_SIZEOF) { return MSPACK_ERR_READ; } if (!(file = sys->alloc(sys, sizeof(struct mscabd_file)))) { return MSPACK_ERR_NOMEMORY; } file->next = NULL; file->length = EndGetI32(&buf[cffile_UncompressedSize]); file->attribs = EndGetI16(&buf[cffile_Attribs]); file->offset = EndGetI32(&buf[cffile_FolderOffset]); /* set folder pointer */ x = EndGetI16(&buf[cffile_FolderIndex]); if (x < cffileCONTINUED_FROM_PREV) { /* normal folder index; count up to the correct folder. the folder * pointer will be NULL if folder index is invalid */ struct mscabd_folder *ifol = cab->base.folders; while (x--) if (ifol) ifol = ifol->next; file->folder = ifol; if (!ifol) { sys->free(file); D(("invalid folder index")) return MSPACK_ERR_DATAFORMAT; } } else { /* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or * CONTINUED_PREV_AND_NEXT */ if ((x == cffileCONTINUED_TO_NEXT) ||
static BOOL WINTRUST_GetSignedMsgFromCabFile(SIP_SUBJECTINFO *pSubjectInfo, DWORD *pdwEncodingType, DWORD dwIndex, DWORD *pcbSignedDataMsg, BYTE *pbSignedDataMsg) { int header_resv; LONG base_offset, cabsize; USHORT flags; BYTE buf[64]; DWORD cert_offset, cert_size, dwRead; TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex, pcbSignedDataMsg, pbSignedDataMsg); /* get basic offset & size info */ base_offset = SetFilePointer(pSubjectInfo->hFile, 0L, NULL, SEEK_CUR); if (SetFilePointer(pSubjectInfo->hFile, 0, NULL, SEEK_END) == INVALID_SET_FILE_POINTER) { TRACE("seek error\n"); return FALSE; } cabsize = SetFilePointer(pSubjectInfo->hFile, 0L, NULL, SEEK_CUR); if ((cabsize == -1) || (base_offset == -1) || (SetFilePointer(pSubjectInfo->hFile, 0, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER)) { TRACE("seek error\n"); return FALSE; } /* read in the CFHEADER */ if (!ReadFile(pSubjectInfo->hFile, buf, cfhead_SIZEOF, &dwRead, NULL) || dwRead != cfhead_SIZEOF) { TRACE("reading header failed\n"); return FALSE; } /* check basic MSCF signature */ if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) { WARN("cabinet signature not present\n"); return FALSE; } /* Ignore the number of folders and files and the set and cabinet IDs */ /* check the header revision */ if ((buf[cfhead_MajorVersion] > 1) || (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3)) { WARN("cabinet format version > 1.3\n"); return FALSE; } /* pull the flags out */ flags = EndGetI16(buf+cfhead_Flags); if (!(flags & cfheadRESERVE_PRESENT)) { TRACE("no header present, not signed\n"); return FALSE; } if (!ReadFile(pSubjectInfo->hFile, buf, cfheadext_SIZEOF, &dwRead, NULL) || dwRead != cfheadext_SIZEOF) { ERR("bunk reserve-sizes?\n"); return FALSE; } header_resv = EndGetI16(buf+cfheadext_HeaderReserved); if (!header_resv) { TRACE("no header_resv, not signed\n"); return FALSE; } else if (header_resv < cfsigninfo_SIZEOF) { TRACE("header_resv too small, not signed\n"); return FALSE; } if (header_resv > 60000) { WARN("WARNING; header reserved space > 60000\n"); } if (!ReadFile(pSubjectInfo->hFile, buf, cfsigninfo_SIZEOF, &dwRead, NULL) || dwRead != cfsigninfo_SIZEOF) { ERR("couldn't read reserve\n"); return FALSE; } cert_offset = EndGetI32(buf+cfsigninfo_CertOffset); TRACE("cert_offset: %d\n", cert_offset); cert_size = EndGetI32(buf+cfsigninfo_CertSize); TRACE("cert_size: %d\n", cert_size); /* The redundant checks are to avoid wraparound */ if (cert_offset > cabsize || cert_size > cabsize || cert_offset + cert_size > cabsize) { WARN("offset beyond file, not attempting to read\n"); return FALSE; } SetFilePointer(pSubjectInfo->hFile, base_offset, NULL, SEEK_SET); if (!pbSignedDataMsg) { *pcbSignedDataMsg = cert_size; return TRUE; } if (*pcbSignedDataMsg < cert_size) { *pcbSignedDataMsg = cert_size; SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } if (SetFilePointer(pSubjectInfo->hFile, cert_offset, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER) { ERR("couldn't seek to cert location\n"); return FALSE; } if (!ReadFile(pSubjectInfo->hFile, pbSignedDataMsg, cert_size, &dwRead, NULL) || dwRead != cert_size) { ERR("couldn't read cert\n"); SetFilePointer(pSubjectInfo->hFile, base_offset, NULL, SEEK_SET); return FALSE; } /* The encoding of the files I've seen appears to be in ASN.1 * format, and there isn't a field indicating the type, so assume it * always is. */ *pdwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; /* Restore base offset */ SetFilePointer(pSubjectInfo->hFile, base_offset, NULL, SEEK_SET); return TRUE; }
/*************************************** * KWAJD_READ_HEADERS *************************************** * reads the headers of a KWAJ format file */ static int kwajd_read_headers(struct mspack_system *sys, struct mspack_file *fh, struct mskwajd_header *hdr) { unsigned char buf[16]; int i; /* read in the header */ if (sys->read(fh, &buf[0], kwajh_SIZEOF) != kwajh_SIZEOF) { return MSPACK_ERR_READ; } /* check for "KWAJ" signature */ if (((unsigned int) EndGetI32(&buf[kwajh_Signature1]) != 0x4A41574B) || ((unsigned int) EndGetI32(&buf[kwajh_Signature2]) != 0xD127F088)) { return MSPACK_ERR_SIGNATURE; } /* basic header fields */ hdr->comp_type = EndGetI16(&buf[kwajh_CompMethod]); hdr->data_offset = EndGetI16(&buf[kwajh_DataOffset]); hdr->headers = EndGetI16(&buf[kwajh_Flags]); hdr->length = 0; hdr->filename = NULL; hdr->extra = NULL; hdr->extra_length = 0; /* optional headers */ /* 4 bytes: length of unpacked file */ if (hdr->headers & MSKWAJ_HDR_HASLENGTH) { if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ; hdr->length = EndGetI32(&buf[0]); } /* 2 bytes: unknown purpose */ if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN1) { if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ; } /* 2 bytes: length of section, then [length] bytes: unknown purpose */ if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN2) { if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ; i = EndGetI16(&buf[0]); if (sys->seek(fh, (off_t)i, MSPACK_SYS_SEEK_CUR)) return MSPACK_ERR_SEEK; } /* filename and extension */ if (hdr->headers & (MSKWAJ_HDR_HASFILENAME | MSKWAJ_HDR_HASFILEEXT)) { off_t pos = sys->tell(fh); char *fn = (char *) sys->alloc(sys, (size_t) 13); /* allocate memory for maximum length filename */ if (! fn) return MSPACK_ERR_NOMEMORY; hdr->filename = fn; /* copy filename if present */ if (hdr->headers & MSKWAJ_HDR_HASFILENAME) { if (sys->read(fh, &buf[0], 9) != 9) return MSPACK_ERR_READ; for (i = 0; i < 9; i++, fn++) if (!(*fn = buf[i])) break; pos += (i < 9) ? i+1 : 9; if (sys->seek(fh, pos, MSPACK_SYS_SEEK_START)) return MSPACK_ERR_SEEK; } /* copy extension if present */ if (hdr->headers & MSKWAJ_HDR_HASFILEEXT) { *fn++ = '.'; if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ; for (i = 0; i < 4; i++, fn++) if (!(*fn = buf[i])) break; pos += (i < 4) ? i+1 : 4; if (sys->seek(fh, pos, MSPACK_SYS_SEEK_START)) return MSPACK_ERR_SEEK; } *fn = '\0'; } /* 2 bytes: extra text length then [length] bytes of extra text data */ if (hdr->headers & MSKWAJ_HDR_HASEXTRATEXT) { if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ; i = EndGetI16(&buf[0]); hdr->extra = (char *) sys->alloc(sys, (size_t)i+1); if (! hdr->extra) return MSPACK_ERR_NOMEMORY; if (sys->read(fh, hdr->extra, i) != i) return MSPACK_ERR_READ; hdr->extra[i] = '\0'; hdr->extra_length = i; } return MSPACK_ERR_OK; }
static int cabd_sys_read_block(struct mspack_system *sys, struct mscabd_decompress_state *d, int *out, int ignore_cksum) { unsigned char hdr[cfdata_SIZEOF]; unsigned int cksum; int len; d->i_ptr = d->i_end = &d->input[0]; do { if (sys->read(d->infh, &hdr[0], cfdata_SIZEOF) != cfdata_SIZEOF) { return MSPACK_ERR_READ; } if (d->data->cab->block_resv && sys->seek(d->infh, (off_t) d->data->cab->block_resv, MSPACK_SYS_SEEK_CUR)) { return MSPACK_ERR_SEEK; } len = EndGetI16(&hdr[cfdata_CompressedSize]); if (((d->i_end - d->i_ptr) + len) > CAB_INPUTMAX) { return MSPACK_ERR_DATAFORMAT; } if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) { return MSPACK_ERR_DATAFORMAT; } if (sys->read(d->infh, d->i_end, len) != len) { return MSPACK_ERR_READ; } if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) { unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0); if (cabd_checksum(&hdr[4], 4, sum2) != cksum) { if (!ignore_cksum) return MSPACK_ERR_CHECKSUM; sys->message(d->infh, "WARNING; bad block checksum found"); } } d->i_end += len; if ((*out = EndGetI16(&hdr[cfdata_UncompressedSize]))) { return MSPACK_ERR_OK; } sys->close(d->infh); d->infh = NULL; if (!(d->data = d->data->next)) { return MSPACK_ERR_DATAFORMAT; } d->incab = d->data->cab; if (!(d->infh = sys->open(sys, d->incab->base.filename, MSPACK_SYS_OPEN_READ))) { return MSPACK_ERR_OPEN; } if (sys->seek(d->infh, d->data->offset, MSPACK_SYS_SEEK_START)) { return MSPACK_ERR_SEEK; } } while (1); return MSPACK_ERR_OK; }
static int cabd_read_headers(struct mspack_system *sys, struct mspack_file *fh, struct mscabd_cabinet_p *cab, off_t offset, int quiet) { int num_folders, num_files, folder_resv, i, x; struct mscabd_folder_p *fol, *linkfol = NULL; struct mscabd_file *file, *linkfile = NULL; unsigned char buf[64]; cab->base.next = NULL; cab->base.files = NULL; cab->base.folders = NULL; cab->base.prevcab = cab->base.nextcab = NULL; cab->base.prevname = cab->base.nextname = NULL; cab->base.previnfo = cab->base.nextinfo = NULL; cab->base.base_offset = offset; if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) { return MSPACK_ERR_SEEK; } if (sys->read(fh, &buf[0], cfhead_SIZEOF) != cfhead_SIZEOF) { return MSPACK_ERR_READ; } if (EndGetI32(&buf[cfhead_Signature]) != 0x4643534D) { return MSPACK_ERR_SIGNATURE; } cab->base.length = EndGetI32(&buf[cfhead_CabinetSize]); cab->base.set_id = EndGetI16(&buf[cfhead_SetID]); cab->base.set_index = EndGetI16(&buf[cfhead_CabinetIndex]); num_folders = EndGetI16(&buf[cfhead_NumFolders]); if (num_folders == 0) { if (!quiet) sys->message(fh, "no folders in cabinet."); return MSPACK_ERR_DATAFORMAT; } num_files = EndGetI16(&buf[cfhead_NumFiles]); if (num_files == 0) { if (!quiet) sys->message(fh, "no files in cabinet."); return MSPACK_ERR_DATAFORMAT; } if ((buf[cfhead_MajorVersion] != 1) && (buf[cfhead_MinorVersion] != 3)) { if (!quiet) sys->message(fh, "WARNING; cabinet version is not 1.3"); } cab->base.flags = EndGetI16(&buf[cfhead_Flags]); if (cab->base.flags & cfheadRESERVE_PRESENT) { if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) { return MSPACK_ERR_READ; } cab->base.header_resv = EndGetI16(&buf[cfheadext_HeaderReserved]); folder_resv = buf[cfheadext_FolderReserved]; cab->block_resv = buf[cfheadext_DataReserved]; if (cab->base.header_resv > 60000) { if (!quiet) sys->message(fh, "WARNING; reserved header > 60000."); } if (cab->base.header_resv) { if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) { return MSPACK_ERR_SEEK; } } } else { cab->base.header_resv = 0; folder_resv = 0; cab->block_resv = 0; } if (cab->base.flags & cfheadPREV_CABINET) { cab->base.prevname = cabd_read_string(sys, fh, cab, &x); if (x) return x; cab->base.previnfo = cabd_read_string(sys, fh, cab, &x); if (x) return x; } if (cab->base.flags & cfheadNEXT_CABINET) { cab->base.nextname = cabd_read_string(sys, fh, cab, &x); if (x) return x; cab->base.nextinfo = cabd_read_string(sys, fh, cab, &x); if (x) return x; } for (i = 0; i < num_folders; i++) { if (sys->read(fh, &buf[0], cffold_SIZEOF) != cffold_SIZEOF) { return MSPACK_ERR_READ; } if (folder_resv) { if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) { return MSPACK_ERR_SEEK; } } if (!(fol = (struct mscabd_folder_p *)sys->alloc(sys, sizeof(struct mscabd_folder_p)))) { return MSPACK_ERR_NOMEMORY; } fol->base.next = NULL; fol->base.comp_type = EndGetI16(&buf[cffold_CompType]); fol->base.num_blocks = EndGetI16(&buf[cffold_NumBlocks]); fol->data.next = NULL; fol->data.cab = (struct mscabd_cabinet_p *) cab; fol->data.offset = offset + (off_t) ( (unsigned int) EndGetI32(&buf[cffold_DataOffset]) ); fol->merge_prev = NULL; fol->merge_next = NULL; if (!linkfol) cab->base.folders = (struct mscabd_folder *) fol; else linkfol->base.next = (struct mscabd_folder *) fol; linkfol = fol; } for (i = 0; i < num_files; i++) { if (sys->read(fh, &buf[0], cffile_SIZEOF) != cffile_SIZEOF) { return MSPACK_ERR_READ; } if (!(file = (struct mscabd_file *)sys->alloc(sys, sizeof(struct mscabd_file)))) { return MSPACK_ERR_NOMEMORY; } file->next = NULL; file->length = EndGetI32(&buf[cffile_UncompressedSize]); file->attribs = EndGetI16(&buf[cffile_Attribs]); file->offset = EndGetI32(&buf[cffile_FolderOffset]); x = EndGetI16(&buf[cffile_FolderIndex]); if (x < cffileCONTINUED_FROM_PREV) { struct mscabd_folder *ifol = cab->base.folders; while (x--) if (ifol) ifol = ifol->next; file->folder = ifol; if (!ifol) { sys->free(file); return MSPACK_ERR_DATAFORMAT; } } else { if ((x == cffileCONTINUED_TO_NEXT) || (x == cffileCONTINUED_PREV_AND_NEXT)) { struct mscabd_folder *ifol = cab->base.folders; while (ifol->next) ifol = ifol->next; file->folder = ifol; fol = (struct mscabd_folder_p *) ifol; if (!fol->merge_next) fol->merge_next = file; } if ((x == cffileCONTINUED_FROM_PREV) || (x == cffileCONTINUED_PREV_AND_NEXT)) { file->folder = cab->base.folders; fol = (struct mscabd_folder_p *) file->folder; if (!fol->merge_prev) fol->merge_prev = file; } } x = EndGetI16(&buf[cffile_Time]); file->time_h = x >> 11; file->time_m = (x >> 5) & 0x3F; file->time_s = (x << 1) & 0x3E; x = EndGetI16(&buf[cffile_Date]); file->date_d = x & 0x1F; file->date_m = (x >> 5) & 0xF; file->date_y = (x >> 9) + 1980; file->filename = cabd_read_string(sys, fh, cab, &x); if (x) { sys->free(file); return x; } if (!linkfile) cab->base.files = file; else linkfile->next = file; linkfile = file; } return MSPACK_ERR_OK; }
static BOOL WINTRUST_GetSignedMsgFromCabFile(SIP_SUBJECTINFO *pSubjectInfo, DWORD *pdwEncodingType, DWORD dwIndex, DWORD *pcbSignedDataMsg, BYTE *pbSignedDataMsg) { int header_resv; LONG base_offset, cabsize; USHORT flags; BYTE buf[64]; DWORD cert_offset, cert_size, dwRead; TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex, pcbSignedDataMsg, pbSignedDataMsg); /* * FIXME: I just noticed that I am memorizing the initial file pointer * offset and restoring it before reading in the rest of the header * information in the cabinet. Perhaps that's correct -- that is, perhaps * this API is supposed to support "streaming" cabinets which are embedded * in other files, or cabinets which begin at file offsets other than zero. * Otherwise, I should instead go to the absolute beginning of the file. * (Either way, the semantics of wine's FDICopy require me to leave the * file pointer where it is afterwards -- If Windows does not do so, we * ought to duplicate the native behavior in the FDIIsCabinet API, not here. * * So, the answer lies in Windows; will native cabinet.dll recognize a * cabinet "file" embedded in another file? Note that cabextract.c does * support this, which implies that Microsoft's might. I haven't tried it * yet so I don't know. ATM, most of wine's FDI cabinet routines (except * this one) would not work in this way. To fix it, we could just make the * various references to absolute file positions in the code relative to an * initial "beginning" offset. Because the FDICopy API doesn't take a * file-handle like this one, we would therein need to search through the * file for the beginning of the cabinet (as we also do in cabextract.c). * Note that this limits us to a maximum of one cabinet per. file: the first. * * So, in summary: either the code below is wrong, or the rest of fdi.c is * wrong... I cannot imagine that both are correct ;) One of these flaws * should be fixed after determining the behavior on Windows. We ought * to check both FDIIsCabinet and FDICopy for the right behavior. * * -gmt */ /* get basic offset & size info */ base_offset = SetFilePointer(pSubjectInfo->hFile, 0L, NULL, SEEK_CUR); if (SetFilePointer(pSubjectInfo->hFile, 0, NULL, SEEK_END) == INVALID_SET_FILE_POINTER) { TRACE("seek error\n"); return FALSE; } cabsize = SetFilePointer(pSubjectInfo->hFile, 0L, NULL, SEEK_CUR); if ((cabsize == -1) || (base_offset == -1) || (SetFilePointer(pSubjectInfo->hFile, base_offset, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER)) { TRACE("seek error\n"); return FALSE; } /* read in the CFHEADER */ if (!ReadFile(pSubjectInfo->hFile, buf, cfhead_SIZEOF, &dwRead, NULL) || dwRead != cfhead_SIZEOF) { TRACE("reading header failed\n"); return FALSE; } /* check basic MSCF signature */ if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) { WARN("cabinet signature not present\n"); return FALSE; } /* Ignore the number of folders and files and the set and cabinet IDs */ /* check the header revision */ if ((buf[cfhead_MajorVersion] > 1) || (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3)) { WARN("cabinet format version > 1.3\n"); return FALSE; } /* pull the flags out */ flags = EndGetI16(buf+cfhead_Flags); if (!(flags & cfheadRESERVE_PRESENT)) { TRACE("no header present, not signed\n"); return FALSE; } if (!ReadFile(pSubjectInfo->hFile, buf, cfheadext_SIZEOF, &dwRead, NULL) || dwRead != cfheadext_SIZEOF) { ERR("bunk reserve-sizes?\n"); return FALSE; } header_resv = EndGetI16(buf+cfheadext_HeaderReserved); if (!header_resv) { TRACE("no header_resv, not signed\n"); return FALSE; } else if (header_resv < cfsigninfo_SIZEOF) { TRACE("header_resv too small, not signed\n"); return FALSE; } if (header_resv > 60000) { WARN("WARNING; header reserved space > 60000\n"); } if (!ReadFile(pSubjectInfo->hFile, buf, cfsigninfo_SIZEOF, &dwRead, NULL) || dwRead != cfsigninfo_SIZEOF) { ERR("couldn't read reserve\n"); return FALSE; } cert_offset = EndGetI32(buf+cfsigninfo_CertOffset); TRACE("cert_offset: %d\n", cert_offset); cert_size = EndGetI32(buf+cfsigninfo_CertSize); TRACE("cert_size: %d\n", cert_size); /* The redundant checks are to avoid wraparound */ if (cert_offset > cabsize || cert_size > cabsize || cert_offset + cert_size > cabsize) { WARN("offset beyond file, not attempting to read\n"); return FALSE; } SetFilePointer(pSubjectInfo->hFile, base_offset, NULL, SEEK_SET); if (!pbSignedDataMsg) { *pcbSignedDataMsg = cert_size; return TRUE; } if (*pcbSignedDataMsg < cert_size) { *pcbSignedDataMsg = cert_size; SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } if (SetFilePointer(pSubjectInfo->hFile, cert_offset, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER) { ERR("couldn't seek to cert location\n"); return FALSE; } if (!ReadFile(pSubjectInfo->hFile, pbSignedDataMsg, cert_size, &dwRead, NULL) || dwRead != cert_size) { ERR("couldn't read cert\n"); return FALSE; } /* The encoding of the files I've seen appears to be in ASN.1 * format, and there isn't a field indicating the type, so assume it * always is. */ *pdwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; return TRUE; }