Ejemplo n.º 1
0
/***************************************
 * 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) ||
Ejemplo n.º 2
0
Archivo: crypt.c Proyecto: dvdhoo/wine
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;
}
Ejemplo n.º 3
0
/***************************************
 * 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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}