toolkit/mozapps/update/updater/archivereader.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include <string.h>
     8 #include <stdlib.h>
     9 #include <fcntl.h>
    10 #include "bzlib.h"
    11 #include "archivereader.h"
    12 #include "errors.h"
    13 #ifdef XP_WIN
    14 #include "nsAlgorithm.h" // Needed by nsVersionComparator.cpp
    15 #include "updatehelper.h"
    16 #endif
    18 #define UPDATER_NO_STRING_GLUE_STL
    19 #include "nsVersionComparator.cpp"
    20 #undef UPDATER_NO_STRING_GLUE_STL
    22 #if defined(XP_UNIX)
    23 # include <sys/types.h>
    24 #elif defined(XP_WIN)
    25 # include <io.h>
    26 #endif
    28 static int inbuf_size  = 262144;
    29 static int outbuf_size = 262144;
    30 static char *inbuf  = nullptr;
    31 static char *outbuf = nullptr;
    33 #ifdef XP_WIN
    34 #include "resource.h"
    36 /**
    37  * Obtains the data of the specified resource name and type.
    38  *
    39  * @param  name The name ID of the resource
    40  * @param  type The type ID of the resource
    41  * @param  data Out parameter which sets the pointer to a buffer containing
    42  *                  the needed data.
    43  * @param  size Out parameter which sets the size of the returned data buffer 
    44  * @return TRUE on success
    45 */
    46 BOOL
    47 LoadFileInResource(int name, int type, const uint8_t *&data, uint32_t& size)
    48 {
    49   HMODULE handle = GetModuleHandle(nullptr);
    50   if (!handle) {
    51     return FALSE;
    52   }
    54   HRSRC resourceInfoBlockHandle = FindResource(handle, 
    55                                                MAKEINTRESOURCE(name),
    56                                                MAKEINTRESOURCE(type));
    57   if (!resourceInfoBlockHandle) {
    58     FreeLibrary(handle);
    59     return FALSE;
    60   }
    62   HGLOBAL resourceHandle = LoadResource(handle, resourceInfoBlockHandle);
    63   if (!resourceHandle) {
    64     FreeLibrary(handle);
    65     return FALSE;
    66   }
    68   size = SizeofResource(handle, resourceInfoBlockHandle);
    69   data = static_cast<const uint8_t*>(::LockResource(resourceHandle));
    70   FreeLibrary(handle);
    71   return TRUE;
    72 }
    74 /**
    75  * Performs a verification on the opened MAR file with the passed in
    76  * certificate name ID and type ID.
    77  *
    78  * @param  archive   The MAR file to verify the signature on
    79  * @param  name      The name ID of the resource
    80  * @param  type      THe type ID of the resource
    81  * @return OK on success, CERT_LOAD_ERROR or CERT_VERIFY_ERROR on failure.
    82 */
    83 int
    84 VerifyLoadedCert(MarFile *archive, int name, int type)
    85 {
    86   uint32_t size = 0;
    87   const uint8_t *data = nullptr;
    88   if (!LoadFileInResource(name, type, data, size) || !data || !size) {
    89     return CERT_LOAD_ERROR;
    90   }
    92   if (mar_verify_signaturesW(archive, &data, &size, 1)) {
    93     return CERT_VERIFY_ERROR;
    94   }
    96   return OK;
    97 }
    98 #endif
   101 /**
   102  * Performs a verification on the opened MAR file.  Both the primary and backup 
   103  * keys stored are stored in the current process and at least the primary key 
   104  * will be tried.  Success will be returned as long as one of the two 
   105  * signatures verify.
   106  *
   107  * @return OK on success
   108 */
   109 int
   110 ArchiveReader::VerifySignature()
   111 {
   112   if (!mArchive) {
   113     return ARCHIVE_NOT_OPEN;
   114   }
   116 #ifdef XP_WIN
   117   // If the fallback key exists we're running an XPCShell test and we should
   118   // use the XPCShell specific cert for the signed MAR.
   119   int rv;
   120   if (DoesFallbackKeyExist()) {
   121     rv = VerifyLoadedCert(mArchive, IDR_XPCSHELL_CERT, TYPE_CERT);
   122   } else {
   123     rv = VerifyLoadedCert(mArchive, IDR_PRIMARY_CERT, TYPE_CERT);
   124     if (rv != OK) {
   125       rv = VerifyLoadedCert(mArchive, IDR_BACKUP_CERT, TYPE_CERT);
   126     }
   127   }
   128   return rv;
   129 #else
   130   return OK;
   131 #endif
   132 }
   134 /**
   135  * Verifies that the MAR file matches the current product, channel, and version
   136  * 
   137  * @param MARChannelID   The MAR channel name to use, only updates from MARs
   138  *                       with a matching MAR channel name will succeed.
   139  *                       If an empty string is passed, no check will be done
   140  *                       for the channel name in the product information block.
   141  *                       If a comma separated list of values is passed then
   142  *                       one value must match.
   143  * @param appVersion     The application version to use, only MARs with an
   144  *                       application version >= to appVersion will be applied.
   145  * @return OK on success
   146  *         COULD_NOT_READ_PRODUCT_INFO_BLOCK if the product info block 
   147  *                                           could not be read.
   148  *         MARCHANNEL_MISMATCH_ERROR         if update-settings.ini's MAR 
   149  *                                           channel ID doesn't match the MAR
   150  *                                           file's MAR channel ID. 
   151  *         VERSION_DOWNGRADE_ERROR           if the application version for
   152  *                                           this updater is newer than the
   153  *                                           one in the MAR.
   154  */
   155 int
   156 ArchiveReader::VerifyProductInformation(const char *MARChannelID, 
   157                                         const char *appVersion)
   158 {
   159   if (!mArchive) {
   160     return ARCHIVE_NOT_OPEN;
   161   }
   163   ProductInformationBlock productInfoBlock;
   164   int rv = mar_read_product_info_block(mArchive, 
   165                                        &productInfoBlock);
   166   if (rv != OK) {
   167     return COULD_NOT_READ_PRODUCT_INFO_BLOCK_ERROR;
   168   }
   170   // Only check the MAR channel name if specified, it should be passed in from
   171   // the update-settings.ini file.
   172   if (MARChannelID && strlen(MARChannelID)) {
   173     // Check for at least one match in the comma separated list of values.
   174     const char *delimiter = " ,\t";
   175     // Make a copy of the string in case a read only memory buffer 
   176     // was specified.  strtok modifies the input buffer.
   177     char channelCopy[512] = { 0 };
   178     strncpy(channelCopy, MARChannelID, sizeof(channelCopy) - 1);
   179     char *channel = strtok(channelCopy, delimiter);
   180     rv = MAR_CHANNEL_MISMATCH_ERROR;
   181     while(channel) {
   182       if (!strcmp(channel, productInfoBlock.MARChannelID)) {
   183         rv = OK;
   184         break;
   185       }
   186       channel = strtok(nullptr, delimiter);
   187     }
   188   }
   190   if (rv == OK) {
   191     /* Compare both versions to ensure we don't have a downgrade
   192         -1 if appVersion is older than productInfoBlock.productVersion
   193         1 if appVersion is newer than productInfoBlock.productVersion
   194         0 if appVersion is the same as productInfoBlock.productVersion
   195        This even works with strings like:
   196         - 12.0a1 being older than 12.0a2
   197         - 12.0a2 being older than 12.0b1
   198         - 12.0a1 being older than 12.0
   199         - 12.0 being older than 12.1a1 */
   200     int versionCompareResult = 
   201       mozilla::CompareVersions(appVersion, productInfoBlock.productVersion);
   202     if (1 == versionCompareResult) {
   203       rv = VERSION_DOWNGRADE_ERROR;
   204     }
   205   }
   207   free((void *)productInfoBlock.MARChannelID);
   208   free((void *)productInfoBlock.productVersion);
   209   return rv;
   210 }
   212 int
   213 ArchiveReader::Open(const NS_tchar *path)
   214 {
   215   if (mArchive)
   216     Close();
   218   if (!inbuf) {
   219     inbuf = (char *)malloc(inbuf_size);
   220     if (!inbuf) {
   221       // Try again with a smaller buffer.
   222       inbuf_size = 1024;
   223       inbuf = (char *)malloc(inbuf_size);
   224       if (!inbuf)
   225         return ARCHIVE_READER_MEM_ERROR;
   226     }
   227   }
   229   if (!outbuf) {
   230     outbuf = (char *)malloc(outbuf_size);
   231     if (!outbuf) {
   232       // Try again with a smaller buffer.
   233       outbuf_size = 1024;
   234       outbuf = (char *)malloc(outbuf_size);
   235       if (!outbuf)
   236         return ARCHIVE_READER_MEM_ERROR;
   237     }
   238   }
   240 #ifdef XP_WIN
   241   mArchive = mar_wopen(path);
   242 #else
   243   mArchive = mar_open(path);
   244 #endif
   245   if (!mArchive)
   246     return READ_ERROR;
   248   return OK;
   249 }
   251 void
   252 ArchiveReader::Close()
   253 {
   254   if (mArchive) {
   255     mar_close(mArchive);
   256     mArchive = nullptr;
   257   }
   259   if (inbuf) {
   260     free(inbuf);
   261     inbuf = nullptr;
   262   }
   264   if (outbuf) {
   265     free(outbuf);
   266     outbuf = nullptr;
   267   }
   268 }
   270 int
   271 ArchiveReader::ExtractFile(const char *name, const NS_tchar *dest)
   272 {
   273   const MarItem *item = mar_find_item(mArchive, name);
   274   if (!item)
   275     return READ_ERROR;
   277 #ifdef XP_WIN
   278   FILE* fp = _wfopen(dest, L"wb+");
   279 #else
   280   int fd = creat(dest, item->flags);
   281   if (fd == -1)
   282     return WRITE_ERROR;
   284   FILE *fp = fdopen(fd, "wb");
   285 #endif
   286   if (!fp)
   287     return WRITE_ERROR;
   289   int rv = ExtractItemToStream(item, fp);
   291   fclose(fp);
   292   return rv;
   293 }
   295 int
   296 ArchiveReader::ExtractFileToStream(const char *name, FILE *fp)
   297 {
   298   const MarItem *item = mar_find_item(mArchive, name);
   299   if (!item)
   300     return READ_ERROR;
   302   return ExtractItemToStream(item, fp);
   303 }
   305 int
   306 ArchiveReader::ExtractItemToStream(const MarItem *item, FILE *fp)
   307 {
   308   /* decompress the data chunk by chunk */
   310   bz_stream strm;
   311   int offset, inlen, outlen, ret = OK;
   313   memset(&strm, 0, sizeof(strm));
   314   if (BZ2_bzDecompressInit(&strm, 0, 0) != BZ_OK)
   315     return UNEXPECTED_BZIP_ERROR;
   317   offset = 0;
   318   for (;;) {
   319     if (!item->length) {
   320       ret = UNEXPECTED_MAR_ERROR;
   321       break;
   322     }
   324     if (offset < (int) item->length && strm.avail_in == 0) {
   325       inlen = mar_read(mArchive, item, offset, inbuf, inbuf_size);
   326       if (inlen <= 0)
   327         return READ_ERROR;
   328       offset += inlen;
   329       strm.next_in = inbuf;
   330       strm.avail_in = inlen;
   331     }
   333     strm.next_out = outbuf;
   334     strm.avail_out = outbuf_size;
   336     ret = BZ2_bzDecompress(&strm);
   337     if (ret != BZ_OK && ret != BZ_STREAM_END) {
   338       ret = UNEXPECTED_BZIP_ERROR;
   339       break;
   340     }
   342     outlen = outbuf_size - strm.avail_out;
   343     if (outlen) {
   344       if (fwrite(outbuf, outlen, 1, fp) != 1) {
   345         ret = WRITE_ERROR;
   346         break;
   347       }
   348     }
   350     if (ret == BZ_STREAM_END) {
   351       ret = OK;
   352       break;
   353     }
   354   }
   356   BZ2_bzDecompressEnd(&strm);
   357   return ret;
   358 }

mercurial