Bug 708690 - Updater enhancements for product information blocks. r=rstrong

This commit is contained in:
Brian R. Bondy 2012-02-24 16:29:41 -05:00
Родитель 80084f79ea
Коммит dbab800567
6 изменённых файлов: 135 добавлений и 3 удалений

Просмотреть файл

@ -59,6 +59,10 @@
#define CERT_LOAD_ERROR 17
#define CERT_HANDLING_ERROR 18
#define CERT_VERIFY_ERROR 19
#define ARCHIVE_NOT_OPEN 20
#define COULD_NOT_READ_PRODUCT_INFO_BLOCK_ERROR 21
#define MAR_CHANNEL_MISMATCH_ERROR 22
#define VERSION_DOWNGRADE_ERROR 23
// The following error codes are only used by updater.exe
// when a fallback key exists and XPCShell tests are being run.

Просмотреть файл

@ -112,7 +112,10 @@ endif
include $(topsrcdir)/config/rules.mk
DEFINES += -DNS_NO_XPCOM
DEFINES += -DNS_NO_XPCOM \
-DMAR_CHANNEL_ID='"$(MAR_CHANNEL_ID)"' \
-DMOZ_APP_VERSION='"$(MOZ_APP_VERSION)"' \
$(NULL)
ifdef _MSC_VER
WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup

Просмотреть файл

@ -42,6 +42,12 @@
#include "bzlib.h"
#include "archivereader.h"
#include "errors.h"
#include "nsAlgorithm.h"
#include "updatehelper.h"
#define UPDATER_NO_STRING_GLUE_STL
#include "../../../../xpcom/build/nsVersionComparator.cpp"
#undef UPDATER_NO_STRING_GLUE_STL
#if defined(XP_UNIX)
# include <sys/types.h>
@ -113,7 +119,7 @@ VerifyLoadedCert(MarFile *archive, int name, int type)
return CERT_LOAD_ERROR;
}
if (!archive || mar_verify_signatureW(archive, data, size)) {
if (mar_verify_signatureW(archive, data, size)) {
return CERT_VERIFY_ERROR;
}
@ -133,6 +139,10 @@ VerifyLoadedCert(MarFile *archive, int name, int type)
int
ArchiveReader::VerifySignature()
{
if (!mArchive) {
return ARCHIVE_NOT_OPEN;
}
#ifdef XP_WIN
int rv = VerifyLoadedCert(mArchive, IDR_PRIMARY_CERT, TYPE_CERT);
if (rv != OK) {
@ -144,6 +154,70 @@ ArchiveReader::VerifySignature()
#endif
}
/**
* Verifies that the MAR file matches the current product, channel, and version
*
* @param MARChannelID The MAR channel name to use, only updates from MARs
* with a matching MAR channel name will succeed.
* If an empty string is passed, no check will be done
* for the channel name in the product information block.
* @param appVersion The application version to use, only MARs with an
* application version >= to appVersion will be applied.
* @return OK on success
* COULD_NOT_READ_PRODUCT_INFO_BLOCK if the product info block
* could not be read.
* MARCHANNEL_MISMATCH_ERROR if update-settings.ini's MAR
* channel ID doesn't match the MAR
* file's MAR channel ID.
* VERSION_DOWNGRADE_ERROR if the application version for
* this updater is newer than the
* one in the MAR.
*/
int
ArchiveReader::VerifyProductInformation(const char *MARChannelID,
const char *appVersion)
{
if (!mArchive) {
return ARCHIVE_NOT_OPEN;
}
ProductInformationBlock productInfoBlock;
int rv = mar_read_product_info_block(mArchive,
&productInfoBlock);
if (rv != OK) {
return COULD_NOT_READ_PRODUCT_INFO_BLOCK_ERROR;
}
// Only check the MAR channel name if specified, it should be passed in from
// the update-settings.ini file.
if (MARChannelID && strlen(MARChannelID)) {
if (rv == OK && strcmp(MARChannelID, productInfoBlock.MARChannelID)) {
rv = MAR_CHANNEL_MISMATCH_ERROR;
}
}
if (rv == OK) {
/* Compare both versions to ensure we don't have a downgrade
1 if appVersion is older than productInfoBlock.productVersion
-1 if appVersion is newer than productInfoBlock.productVersion
0 if appVersion is the same as productInfoBlock.productVersion
This even works with strings like:
- 12.0a1 being older than 12.0a2
- 12.0a2 being older than 12.0b1
- 12.0a1 being older than 12.0
- 12.0 being older than 12.1a1 */
int versionCompareResult =
NS_CompareVersions(appVersion, productInfoBlock.productVersion);
if (-1 == versionCompareResult) {
rv = VERSION_DOWNGRADE_ERROR;
}
}
free((void *)productInfoBlock.MARChannelID);
free((void *)productInfoBlock.productVersion);
return rv;
}
int
ArchiveReader::Open(const NS_tchar *path)
{

Просмотреть файл

@ -57,6 +57,8 @@ public:
int Open(const NS_tchar *path);
int VerifySignature();
int VerifyProductInformation(const char *MARChannelID,
const char *appVersion);
void Close();
int ExtractFile(const char *item, const NS_tchar *destination);

Просмотреть файл

@ -68,6 +68,7 @@
#include "bspatch.h"
#include "progressui.h"
#include "archivereader.h"
#include "readstrings.h"
#include "errors.h"
#include "bzlib.h"
@ -191,6 +192,15 @@ private:
FILE* mFile;
};
struct MARChannelStringTable {
MARChannelStringTable()
{
MARChannelID[0] = '\0';
}
char MARChannelID[MAX_TEXT_LEN];
};
//-----------------------------------------------------------------------------
typedef void (* ThreadFunc)(void *param);
@ -1530,6 +1540,29 @@ WaitForServiceFinishThread(void *param)
}
#endif
/**
* This function reads in the MAR_CHANNEL_ID from update-settings.ini
*
* @param path The path to the ini file that is to be read
* @param results A pointer to the location to store the read strings
* @return OK on success
*/
static int
ReadMARChannelIDs(const NS_tchar *path, MARChannelStringTable *results)
{
const unsigned int kNumStrings = 1;
const char *kUpdaterKeys = "MAR_CHANNEL_ID\0";
char updater_strings[kNumStrings][MAX_TEXT_LEN];
int result = ReadStrings(path, kUpdaterKeys, kNumStrings,
updater_strings, "Settings");
strncpy(results->MARChannelID, updater_strings[0], MAX_TEXT_LEN - 1);
results->MARChannelID[MAX_TEXT_LEN - 1] = 0;
return result;
}
static void
UpdateThreadFunc(void *param)
{
@ -1548,6 +1581,22 @@ UpdateThreadFunc(void *param)
}
#endif
if (rv == OK) {
NS_tchar updateSettingsPath[MAX_TEXT_LEN];
NS_tsnprintf(updateSettingsPath,
sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]),
NS_T("%supdate-settings.ini"), gDestPath);
MARChannelStringTable MARStrings;
if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) {
// If we can't read from update-settings.ini then we shouldn't impose
// a MAR restriction. Some installatins won't even include this file.
MARStrings.MARChannelID[0] = '\0';
}
rv = gArchiveReader.VerifyProductInformation(MARStrings.MARChannelID,
MOZ_APP_VERSION);
}
if (rv == OK) {
rv = DoUpdate();
gArchiveReader.Close();

Просмотреть файл

@ -39,7 +39,7 @@
#include <stdlib.h>
#include <string.h>
#ifdef XP_WIN
#if defined(XP_WIN) && !defined(UPDATER_NO_STRING_GLUE_STL)
#include <wchar.h>
#include "nsStringGlue.h"
#endif