зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1177861 - remove remaining unused declarations and cleanup update staging. r=spohl
--HG-- rename : toolkit/components/maintenanceservice/certificatecheck.cpp => toolkit/mozapps/update/common/certificatecheck.cpp rename : toolkit/components/maintenanceservice/certificatecheck.h => toolkit/mozapps/update/common/certificatecheck.h rename : toolkit/components/maintenanceservice/registrycertificates.cpp => toolkit/mozapps/update/common/registrycertificates.cpp rename : toolkit/components/maintenanceservice/registrycertificates.h => toolkit/mozapps/update/common/registrycertificates.h
This commit is contained in:
Родитель
ceabbae040
Коммит
b7924a4a24
|
@ -7,9 +7,7 @@
|
|||
Program('maintenanceservice')
|
||||
|
||||
SOURCES += [
|
||||
'certificatecheck.cpp',
|
||||
'maintenanceservice.cpp',
|
||||
'registrycertificates.cpp',
|
||||
'servicebase.cpp',
|
||||
'serviceinstall.cpp',
|
||||
'workmonitor.cpp',
|
||||
|
|
|
@ -206,23 +206,6 @@ StartUpdateProcess(int argc,
|
|||
si.wShowWindow = SW_HIDE;
|
||||
}
|
||||
|
||||
// We move the updater.ini file out of the way because we will handle
|
||||
// executing PostUpdate through the service. We handle PostUpdate from
|
||||
// the service because there are some per user things that happen that
|
||||
// can't run in session 0 which we run updater.exe in.
|
||||
// Once we are done running updater.exe we rename updater.ini back so
|
||||
// that if there were any errors the next updater.exe will run correctly.
|
||||
WCHAR updaterINI[MAX_PATH + 1];
|
||||
WCHAR updaterINITemp[MAX_PATH + 1];
|
||||
BOOL selfHandlePostUpdate = FALSE;
|
||||
// We use the updater.ini from the same directory as the updater.exe
|
||||
// because of background updates.
|
||||
if (PathGetSiblingFilePath(updaterINI, argv[0], L"updater.ini") &&
|
||||
PathGetSiblingFilePath(updaterINITemp, argv[0], L"updater.tmp")) {
|
||||
selfHandlePostUpdate = MoveFileExW(updaterINI, updaterINITemp,
|
||||
MOVEFILE_REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
// Add an env var for MOZ_USING_SERVICE so the updater.exe can
|
||||
// do anything special that it needs to do for service updates.
|
||||
// Search in updater.cpp for more info on MOZ_USING_SERVICE.
|
||||
|
@ -297,37 +280,6 @@ StartUpdateProcess(int argc,
|
|||
argv[0], cmdLine, lastError));
|
||||
}
|
||||
|
||||
// Now that we're done with the update, restore back the updater.ini file
|
||||
// We use it ourselves, and also we want it back in case we had any type
|
||||
// of error so that the normal update process can use it.
|
||||
if (selfHandlePostUpdate) {
|
||||
MoveFileExW(updaterINITemp, updaterINI, MOVEFILE_REPLACE_EXISTING);
|
||||
|
||||
// Only run the PostUpdate if the update was successful
|
||||
if (updateWasSuccessful && argc > index) {
|
||||
LPCWSTR updateInfoDir = argv[1];
|
||||
bool stagingUpdate = IsUpdateBeingStaged(argc, argv);
|
||||
|
||||
// Launch the PostProcess with admin access in session 0. This is
|
||||
// actually launching the post update process but it takes in the
|
||||
// callback app path to figure out where to apply to.
|
||||
// The PostUpdate process with user only access will be done inside
|
||||
// the unelevated updater.exe after the update process is complete
|
||||
// from the service. We don't know here which session to start
|
||||
// the user PostUpdate process from.
|
||||
// Note that we don't need to do this if we're just staging the
|
||||
// update in the background, as the PostUpdate step runs when
|
||||
// performing the replacing in that case.
|
||||
if (!stagingUpdate) {
|
||||
LOG(("Launching post update process as the service in session 0."));
|
||||
if (!LaunchWinPostProcess(installDir, updateInfoDir, true, nullptr)) {
|
||||
LOG_WARN(("The post update process could not be launched."
|
||||
" installDir: %ls, updateInfoDir: %ls",
|
||||
installDir, updateInfoDir));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Empty value on putenv is how you remove an env variable in Windows
|
||||
putenv(const_cast<char*>("MOZ_USING_SERVICE="));
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <wintrust.h>
|
||||
|
||||
#include "certificatecheck.h"
|
||||
#include "servicebase.h"
|
||||
#include "updatelogging.h"
|
||||
|
||||
#pragma comment(lib, "wintrust.lib")
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
|
@ -123,7 +123,7 @@ DoCertificateAttributesMatch(PCCERT_CONTEXT certContext,
|
|||
CertificateCheckInfo &infoToMatch)
|
||||
{
|
||||
DWORD dwData;
|
||||
LPTSTR szName = nullptr;
|
||||
LPWSTR szName = nullptr;
|
||||
|
||||
if (infoToMatch.issuer) {
|
||||
// Pass in nullptr to get the needed size of the issuer buffer.
|
||||
|
@ -138,7 +138,7 @@ DoCertificateAttributesMatch(PCCERT_CONTEXT certContext,
|
|||
}
|
||||
|
||||
// Allocate memory for Issuer name buffer.
|
||||
LPTSTR szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(WCHAR));
|
||||
szName = (LPWSTR)LocalAlloc(LPTR, dwData * sizeof(WCHAR));
|
||||
if (!szName) {
|
||||
LOG_WARN(("Unable to allocate memory for issuer name. (%d)",
|
||||
GetLastError()));
|
||||
|
@ -146,7 +146,7 @@ DoCertificateAttributesMatch(PCCERT_CONTEXT certContext,
|
|||
}
|
||||
|
||||
// Get Issuer name.
|
||||
if (!CertGetNameString(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
|
||||
if (!CertGetNameStringW(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
|
||||
CERT_NAME_ISSUER_FLAG, nullptr, szName, dwData)) {
|
||||
LOG_WARN(("CertGetNameString failed. (%d)", GetLastError()));
|
||||
LocalFree(szName);
|
||||
|
@ -174,7 +174,7 @@ DoCertificateAttributesMatch(PCCERT_CONTEXT certContext,
|
|||
}
|
||||
|
||||
// Allocate memory for the name buffer.
|
||||
szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(WCHAR));
|
||||
szName = (LPWSTR)LocalAlloc(LPTR, dwData * sizeof(WCHAR));
|
||||
if (!szName) {
|
||||
LOG_WARN(("Unable to allocate memory for subject name. (%d)",
|
||||
GetLastError()));
|
||||
|
@ -182,7 +182,7 @@ DoCertificateAttributesMatch(PCCERT_CONTEXT certContext,
|
|||
}
|
||||
|
||||
// Obtain the name.
|
||||
if (!(CertGetNameString(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
|
||||
if (!(CertGetNameStringW(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
|
||||
nullptr, szName, dwData))) {
|
||||
LOG_WARN(("CertGetNameString failed. (%d)", GetLastError()));
|
||||
LocalFree(szName);
|
||||
|
@ -204,23 +204,6 @@ DoCertificateAttributesMatch(PCCERT_CONTEXT certContext,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates the specified string
|
||||
*
|
||||
* @param inputString The string to duplicate
|
||||
* @return The duplicated string which should be freed by the caller.
|
||||
*/
|
||||
LPWSTR
|
||||
AllocateAndCopyWideString(LPCWSTR inputString)
|
||||
{
|
||||
LPWSTR outputString =
|
||||
(LPWSTR)LocalAlloc(LPTR, (wcslen(inputString) + 1) * sizeof(WCHAR));
|
||||
if (outputString) {
|
||||
lstrcpyW(outputString, inputString);
|
||||
}
|
||||
return outputString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the trust of the specified file path.
|
||||
*
|
|
@ -82,6 +82,8 @@
|
|||
#define WRITE_ERROR_DIR_ACCESS_DENIED 68
|
||||
#define WRITE_ERROR_DELETE_BACKUP 69
|
||||
#define WRITE_ERROR_EXTRACT 70
|
||||
#define REMOVE_FILE_SPEC_ERROR 71
|
||||
#define INVALID_STAGED_PARENT_ERROR 72
|
||||
|
||||
// Error codes 80 through 99 are reserved for nsUpdateService.js
|
||||
|
||||
|
|
|
@ -12,7 +12,9 @@ EXPORTS += [
|
|||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
EXPORTS += [
|
||||
'certificatecheck.h',
|
||||
'pathhash.h',
|
||||
'registrycertificates.h',
|
||||
'uachelper.h',
|
||||
'updatehelper.cpp',
|
||||
'updatehelper.h',
|
||||
|
@ -20,10 +22,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||
|
||||
Library('updatecommon')
|
||||
|
||||
DEFINES['NS_NO_XPCOM'] = True
|
||||
|
||||
srcdir = '.'
|
||||
|
||||
include('sources.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
#include "registrycertificates.h"
|
||||
#include "pathhash.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "servicebase.h"
|
||||
#include "updatelogging.h"
|
||||
#include "updatehelper.h"
|
||||
#define MAX_KEY_LENGTH 255
|
||||
|
||||
|
@ -41,10 +40,10 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath,
|
|||
// to put those certificate attributes in and hence why we always
|
||||
// force the non redirected registry under Wow6432Node.
|
||||
// This flag is ignored on 32bit systems.
|
||||
HKEY baseKeyRaw;
|
||||
HKEY baseKey;
|
||||
LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
maintenanceServiceKey, 0,
|
||||
KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw);
|
||||
KEY_READ | KEY_WOW64_64KEY, &baseKey);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG_WARN(("Could not open key. (%d)", retCode));
|
||||
// Our tests run with a different apply directory for each test.
|
||||
|
@ -52,7 +51,7 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath,
|
|||
// allowed name/issuers.
|
||||
retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
TEST_ONLY_FALLBACK_KEY_PATH, 0,
|
||||
KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw);
|
||||
KEY_READ | KEY_WOW64_64KEY, &baseKey);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG_WARN(("Could not open fallback key. (%d)", retCode));
|
||||
return FALSE;
|
||||
|
@ -60,10 +59,10 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath,
|
|||
LOG_WARN(("Fallback key present, skipping VerifyCertificateTrustForFile "
|
||||
"check and the certificate attribute registry matching "
|
||||
"check."));
|
||||
RegCloseKey(baseKey);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
nsAutoRegKey baseKey(baseKeyRaw);
|
||||
|
||||
// Get the number of subkeys.
|
||||
DWORD subkeyCount = 0;
|
||||
|
@ -72,6 +71,7 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath,
|
|||
nullptr, nullptr);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG_WARN(("Could not query info key. (%d)", retCode));
|
||||
RegCloseKey(baseKey);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -84,17 +84,17 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath,
|
|||
nullptr, nullptr, nullptr);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG_WARN(("Could not enum certs. (%d)", retCode));
|
||||
RegCloseKey(baseKey);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Open the subkey for the current certificate
|
||||
HKEY subKeyRaw;
|
||||
HKEY subKey;
|
||||
retCode = RegOpenKeyExW(baseKey,
|
||||
subkeyBuffer,
|
||||
0,
|
||||
KEY_READ | KEY_WOW64_64KEY,
|
||||
&subKeyRaw);
|
||||
nsAutoRegKey subKey(subKeyRaw);
|
||||
&subKey);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG_WARN(("Could not open subkey. (%d)", retCode));
|
||||
continue; // Try the next subkey
|
||||
|
@ -110,6 +110,7 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath,
|
|||
(LPBYTE)name, &valueBufSize);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG_WARN(("Could not obtain name from registry. (%d)", retCode));
|
||||
RegCloseKey(subKey);
|
||||
continue; // Try the next subkey
|
||||
}
|
||||
|
||||
|
@ -119,6 +120,7 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath,
|
|||
(LPBYTE)issuer, &valueBufSize);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG_WARN(("Could not obtain issuer from registry. (%d)", retCode));
|
||||
RegCloseKey(subKey);
|
||||
continue; // Try the next subkey
|
||||
}
|
||||
|
||||
|
@ -130,19 +132,23 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath,
|
|||
retCode = CheckCertificateForPEFile(filePath, allowedCertificate);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG_WARN(("Error on certificate check. (%d)", retCode));
|
||||
RegCloseKey(subKey);
|
||||
continue; // Try the next subkey
|
||||
}
|
||||
|
||||
retCode = VerifyCertificateTrustForFile(filePath);
|
||||
if (retCode != ERROR_SUCCESS) {
|
||||
LOG_WARN(("Error on certificate trust check. (%d)", retCode));
|
||||
RegCloseKey(subKey);
|
||||
continue; // Try the next subkey
|
||||
}
|
||||
|
||||
RegCloseKey(baseKey);
|
||||
// Raise the roof, we found a match!
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
RegCloseKey(baseKey);
|
||||
// No certificates match, :'(
|
||||
return FALSE;
|
||||
}
|
|
@ -6,7 +6,9 @@ sources = []
|
|||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
sources += [
|
||||
'certificatecheck.cpp',
|
||||
'pathhash.cpp',
|
||||
'registrycertificates.cpp',
|
||||
'uachelper.cpp',
|
||||
'updatehelper.cpp',
|
||||
]
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
using mozilla::MakeUnique;
|
||||
using mozilla::UniquePtr;
|
||||
|
||||
WCHAR* MakeCommandLine(int argc, WCHAR **argv);
|
||||
BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra);
|
||||
BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer,
|
||||
LPCWSTR siblingFilePath,
|
||||
LPCWSTR newFileName);
|
||||
|
||||
/**
|
||||
* Obtains the path of a file in the same directory as the specified file.
|
||||
|
@ -53,137 +55,6 @@ PathGetSiblingFilePath(LPWSTR destinationBuffer,
|
|||
return PathAppendSafe(destinationBuffer, newFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the post update application as the specified user (helper.exe).
|
||||
* It takes in the path of the callback application to calculate the path
|
||||
* of helper.exe. For service updates this is called from both the system
|
||||
* account and the current user account.
|
||||
*
|
||||
* @param installationDir The path to the callback application binary.
|
||||
* @param updateInfoDir The directory where update info is stored.
|
||||
* @param forceSync If true even if the ini file specifies async, the
|
||||
* process will wait for termination of PostUpdate.
|
||||
* @param userToken The user token to run as, if nullptr the current
|
||||
* user will be used.
|
||||
* @return TRUE if there was no error starting the process.
|
||||
*/
|
||||
BOOL
|
||||
LaunchWinPostProcess(const WCHAR *installationDir,
|
||||
const WCHAR *updateInfoDir,
|
||||
bool forceSync,
|
||||
HANDLE userToken)
|
||||
{
|
||||
WCHAR workingDirectory[MAX_PATH + 1] = { L'\0' };
|
||||
wcsncpy(workingDirectory, installationDir, MAX_PATH);
|
||||
|
||||
// Launch helper.exe to perform post processing (e.g. registry and log file
|
||||
// modifications) for the update.
|
||||
WCHAR inifile[MAX_PATH + 1] = { L'\0' };
|
||||
wcsncpy(inifile, installationDir, MAX_PATH);
|
||||
if (!PathAppendSafe(inifile, L"updater.ini")) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR exefile[MAX_PATH + 1];
|
||||
WCHAR exearg[MAX_PATH + 1];
|
||||
WCHAR exeasync[10];
|
||||
bool async = true;
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeRelPath", nullptr,
|
||||
exefile, MAX_PATH + 1, inifile)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeArg", nullptr, exearg,
|
||||
MAX_PATH + 1, inifile)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeAsync", L"TRUE",
|
||||
exeasync,
|
||||
sizeof(exeasync)/sizeof(exeasync[0]),
|
||||
inifile)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR exefullpath[MAX_PATH + 1] = { L'\0' };
|
||||
wcsncpy(exefullpath, installationDir, MAX_PATH);
|
||||
if (!PathAppendSafe(exefullpath, exefile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WCHAR dlogFile[MAX_PATH + 1];
|
||||
if (!PathGetSiblingFilePath(dlogFile, exefullpath, L"uninstall.update")) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR slogFile[MAX_PATH + 1] = { L'\0' };
|
||||
wcsncpy(slogFile, updateInfoDir, MAX_PATH);
|
||||
if (!PathAppendSafe(slogFile, L"update.log")) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WCHAR dummyArg[14] = { L'\0' };
|
||||
wcsncpy(dummyArg, L"argv0ignored ", sizeof(dummyArg) / sizeof(dummyArg[0]) - 1);
|
||||
|
||||
size_t len = wcslen(exearg) + wcslen(dummyArg);
|
||||
WCHAR *cmdline = (WCHAR *) malloc((len + 1) * sizeof(WCHAR));
|
||||
if (!cmdline) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wcsncpy(cmdline, dummyArg, len);
|
||||
wcscat(cmdline, exearg);
|
||||
|
||||
if (forceSync ||
|
||||
!_wcsnicmp(exeasync, L"false", 6) ||
|
||||
!_wcsnicmp(exeasync, L"0", 2)) {
|
||||
async = false;
|
||||
}
|
||||
|
||||
// We want to launch the post update helper app to update the Windows
|
||||
// registry even if there is a failure with removing the uninstall.update
|
||||
// file or copying the update.log file.
|
||||
CopyFileW(slogFile, dlogFile, false);
|
||||
|
||||
STARTUPINFOW si = {sizeof(si), 0};
|
||||
si.lpDesktop = L"";
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
bool ok;
|
||||
if (userToken) {
|
||||
ok = CreateProcessAsUserW(userToken,
|
||||
exefullpath,
|
||||
cmdline,
|
||||
nullptr, // no special security attributes
|
||||
nullptr, // no special thread attributes
|
||||
false, // don't inherit filehandles
|
||||
0, // No special process creation flags
|
||||
nullptr, // inherit my environment
|
||||
workingDirectory,
|
||||
&si,
|
||||
&pi);
|
||||
} else {
|
||||
ok = CreateProcessW(exefullpath,
|
||||
cmdline,
|
||||
nullptr, // no special security attributes
|
||||
nullptr, // no special thread attributes
|
||||
false, // don't inherit filehandles
|
||||
0, // No special process creation flags
|
||||
nullptr, // inherit my environment
|
||||
workingDirectory,
|
||||
&si,
|
||||
&pi);
|
||||
}
|
||||
free(cmdline);
|
||||
if (ok) {
|
||||
if (!async)
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the upgrade process for update of the service if it is
|
||||
* already installed.
|
||||
|
|
|
@ -2,12 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
BOOL LaunchWinPostProcess(const WCHAR *installationDir,
|
||||
const WCHAR *updateInfoDir,
|
||||
bool forceSync,
|
||||
HANDLE userToken);
|
||||
BOOL StartServiceUpdate(LPCWSTR installDir);
|
||||
BOOL GetUpdateDirectoryPath(LPWSTR path);
|
||||
DWORD LaunchServiceSoftwareUpdateCommand(int argc, LPCWSTR *argv);
|
||||
BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode);
|
||||
DWORD WaitForServiceStop(LPCWSTR serviceName, DWORD maxWaitSeconds);
|
||||
|
|
|
@ -1079,10 +1079,9 @@ function shouldUseService() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Determines if the service is is installed and enabled or not.
|
||||
* Determines if the service is is installed.
|
||||
*
|
||||
* @return true if the service should be used for updates,
|
||||
* is installed and enabled.
|
||||
* @return true if the service is installed.
|
||||
*/
|
||||
function isServiceInstalled() {
|
||||
if (AppConstants.MOZ_MAINTENANCE_SERVICE && AppConstants.platform == "win") {
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
# define LOG_S "%S"
|
||||
|
||||
#include "../common/updatehelper.h"
|
||||
#include "../common/certificatecheck.h"
|
||||
|
||||
#else
|
||||
# include <unistd.h>
|
||||
|
@ -132,45 +133,6 @@ CheckMsg(const NS_tchar *path, const char *expected)
|
|||
return isMatch;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
/**
|
||||
* Verifies the trust of the specified file path.
|
||||
*
|
||||
* @param filePath The file path to check.
|
||||
* @return ERROR_SUCCESS if successful, or the last error code otherwise.
|
||||
*/
|
||||
DWORD
|
||||
VerifyCertificateTrustForFile(LPCWSTR filePath)
|
||||
{
|
||||
// Setup the file to check.
|
||||
WINTRUST_FILE_INFO fileToCheck;
|
||||
ZeroMemory(&fileToCheck, sizeof(fileToCheck));
|
||||
fileToCheck.cbStruct = sizeof(WINTRUST_FILE_INFO);
|
||||
fileToCheck.pcwszFilePath = filePath;
|
||||
|
||||
// Setup what to check, we want to check it is signed and trusted.
|
||||
WINTRUST_DATA trustData;
|
||||
ZeroMemory(&trustData, sizeof(trustData));
|
||||
trustData.cbStruct = sizeof(trustData);
|
||||
trustData.pPolicyCallbackData = nullptr;
|
||||
trustData.pSIPClientData = nullptr;
|
||||
trustData.dwUIChoice = WTD_UI_NONE;
|
||||
trustData.fdwRevocationChecks = WTD_REVOKE_NONE;
|
||||
trustData.dwUnionChoice = WTD_CHOICE_FILE;
|
||||
trustData.dwStateAction = 0;
|
||||
trustData.hWVTStateData = nullptr;
|
||||
trustData.pwszURLReference = nullptr;
|
||||
// no UI
|
||||
trustData.dwUIContext = 0;
|
||||
trustData.pFile = &fileToCheck;
|
||||
|
||||
GUID policyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
|
||||
// Check if the file is signed by something that is trusted.
|
||||
return WinVerifyTrust(nullptr, &policyGUID, &trustData);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int NS_main(int argc, NS_tchar **argv)
|
||||
{
|
||||
if (argc == 2) {
|
||||
|
@ -187,6 +149,16 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
NS_tchar runFilePath[MAXPATHLEN];
|
||||
NS_tsnprintf(runFilePath, sizeof(runFilePath)/sizeof(runFilePath[0]),
|
||||
NS_T("%s.running"), exePath);
|
||||
#ifdef XP_WIN
|
||||
if (!NS_taccess(runFilePath, F_OK)) {
|
||||
// This makes it possible to check if the post update process was
|
||||
// launched twice which happens when the service performs an update.
|
||||
NS_tchar runFilePathBak[MAXPATHLEN];
|
||||
NS_tsnprintf(runFilePathBak, sizeof(runFilePathBak)/sizeof(runFilePathBak[0]),
|
||||
NS_T("%s.bak"), runFilePath);
|
||||
MoveFileExW(runFilePath, runFilePathBak, MOVEFILE_REPLACE_EXISTING);
|
||||
}
|
||||
#endif
|
||||
WriteMsg(runFilePath, "running");
|
||||
|
||||
if (!NS_tstrcmp(argv[1], NS_T("post-update-sync"))) {
|
||||
|
|
|
@ -127,6 +127,11 @@ static bool sUseHardLinks = true;
|
|||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "registrycertificates.h"
|
||||
BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra);
|
||||
BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer,
|
||||
LPCWSTR siblingFilePath,
|
||||
LPCWSTR newFileName);
|
||||
#include "updatehelper.h"
|
||||
|
||||
// Closes the handle if valid and if the updater is elevated returns with the
|
||||
|
@ -138,6 +143,7 @@ static bool sUseHardLinks = true;
|
|||
CloseHandle(handle); \
|
||||
} \
|
||||
if (_waccess(path, F_OK) == 0 && NS_tremove(path) != 0) { \
|
||||
LogFinish(); \
|
||||
return retCode; \
|
||||
} \
|
||||
}
|
||||
|
@ -1813,6 +1819,129 @@ PatchIfFile::Finish(int status)
|
|||
#include "nsWindowsHelpers.h"
|
||||
#include "uachelper.h"
|
||||
#include "pathhash.h"
|
||||
|
||||
/**
|
||||
* Launch the post update application (helper.exe). It takes in the path of the
|
||||
* callback application to calculate the path of helper.exe. For service updates
|
||||
* this is called from both the system account and the current user account.
|
||||
*
|
||||
* @param installationDir The path to the callback application binary.
|
||||
* @param updateInfoDir The directory where update info is stored.
|
||||
* @return true if there was no error starting the process.
|
||||
*/
|
||||
bool
|
||||
LaunchWinPostProcess(const WCHAR *installationDir,
|
||||
const WCHAR *updateInfoDir)
|
||||
{
|
||||
WCHAR workingDirectory[MAX_PATH + 1] = { L'\0' };
|
||||
wcsncpy(workingDirectory, installationDir, MAX_PATH);
|
||||
|
||||
// Launch helper.exe to perform post processing (e.g. registry and log file
|
||||
// modifications) for the update.
|
||||
WCHAR inifile[MAX_PATH + 1] = { L'\0' };
|
||||
wcsncpy(inifile, installationDir, MAX_PATH);
|
||||
if (!PathAppendSafe(inifile, L"updater.ini")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WCHAR exefile[MAX_PATH + 1];
|
||||
WCHAR exearg[MAX_PATH + 1];
|
||||
WCHAR exeasync[10];
|
||||
bool async = true;
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeRelPath", nullptr,
|
||||
exefile, MAX_PATH + 1, inifile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeArg", nullptr, exearg,
|
||||
MAX_PATH + 1, inifile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeAsync", L"TRUE",
|
||||
exeasync,
|
||||
sizeof(exeasync)/sizeof(exeasync[0]),
|
||||
inifile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify that exeFile doesn't contain relative paths
|
||||
if (wcsstr(exefile, L"..") != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WCHAR exefullpath[MAX_PATH + 1] = { L'\0' };
|
||||
wcsncpy(exefullpath, installationDir, MAX_PATH);
|
||||
if (!PathAppendSafe(exefullpath, exefile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !defined(TEST_UPDATER)
|
||||
if (sUsingService &&
|
||||
!DoesBinaryMatchAllowedCertificates(installationDir, exefullpath)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
WCHAR dlogFile[MAX_PATH + 1];
|
||||
if (!PathGetSiblingFilePath(dlogFile, exefullpath, L"uninstall.update")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WCHAR slogFile[MAX_PATH + 1] = { L'\0' };
|
||||
wcsncpy(slogFile, updateInfoDir, MAX_PATH);
|
||||
if (!PathAppendSafe(slogFile, L"update.log")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WCHAR dummyArg[14] = { L'\0' };
|
||||
wcsncpy(dummyArg, L"argv0ignored ", sizeof(dummyArg) / sizeof(dummyArg[0]) - 1);
|
||||
|
||||
size_t len = wcslen(exearg) + wcslen(dummyArg);
|
||||
WCHAR *cmdline = (WCHAR *) malloc((len + 1) * sizeof(WCHAR));
|
||||
if (!cmdline) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wcsncpy(cmdline, dummyArg, len);
|
||||
wcscat(cmdline, exearg);
|
||||
|
||||
if (sUsingService ||
|
||||
!_wcsnicmp(exeasync, L"false", 6) ||
|
||||
!_wcsnicmp(exeasync, L"0", 2)) {
|
||||
async = false;
|
||||
}
|
||||
|
||||
// We want to launch the post update helper app to update the Windows
|
||||
// registry even if there is a failure with removing the uninstall.update
|
||||
// file or copying the update.log file.
|
||||
CopyFileW(slogFile, dlogFile, false);
|
||||
|
||||
STARTUPINFOW si = {sizeof(si), 0};
|
||||
si.lpDesktop = L"";
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
|
||||
bool ok = CreateProcessW(exefullpath,
|
||||
cmdline,
|
||||
nullptr, // no special security attributes
|
||||
nullptr, // no special thread attributes
|
||||
false, // don't inherit filehandles
|
||||
0, // No special process creation flags
|
||||
nullptr, // inherit my environment
|
||||
workingDirectory,
|
||||
&si,
|
||||
&pi);
|
||||
free(cmdline);
|
||||
if (ok) {
|
||||
if (!async) {
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
}
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
|
@ -2535,6 +2664,28 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
LOG(("INSTALLATION DIRECTORY " LOG_S, gInstallDirPath));
|
||||
LOG(("WORKING DIRECTORY " LOG_S, gWorkingDirPath));
|
||||
|
||||
#if defined(XP_WIN)
|
||||
if (sReplaceRequest || sStagedUpdate) {
|
||||
NS_tchar stagedParent[MAX_PATH];
|
||||
NS_tsnprintf(stagedParent, sizeof(stagedParent)/sizeof(stagedParent[0]),
|
||||
NS_T("%s"), gWorkingDirPath);
|
||||
if (!PathRemoveFileSpecW(stagedParent)) {
|
||||
WriteStatusFile(REMOVE_FILE_SPEC_ERROR);
|
||||
LOG(("Error calling PathRemoveFileSpecW: %d", GetLastError()));
|
||||
LogFinish();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_wcsnicmp(stagedParent, gInstallDirPath, MAX_PATH) != 0) {
|
||||
WriteStatusFile(INVALID_STAGED_PARENT_ERROR);
|
||||
LOG(("Stage and Replace requests require that the working directory " \
|
||||
"is a sub-directory of the installation directory! Exiting"));
|
||||
LogFinish();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
const char *prioEnv = getenv("MOZ_UPDATER_PRIO");
|
||||
if (prioEnv) {
|
||||
|
@ -2828,8 +2979,7 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
bool updateStatusSucceeded = false;
|
||||
if (IsUpdateStatusSucceeded(updateStatusSucceeded) &&
|
||||
updateStatusSucceeded) {
|
||||
if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath, false,
|
||||
nullptr)) {
|
||||
if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath)) {
|
||||
fprintf(stderr, "The post update process which runs as the user"
|
||||
" for service update could not be launched.");
|
||||
}
|
||||
|
@ -3224,6 +3374,10 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
if (argc > callbackIndex) {
|
||||
#if defined(XP_WIN)
|
||||
if (gSucceeded) {
|
||||
if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath)) {
|
||||
fprintf(stderr, "The post update process was not launched");
|
||||
}
|
||||
|
||||
// The service update will only be executed if it is already installed.
|
||||
// For first time installs of the service, the install will happen from
|
||||
// the PostUpdate process. We do the service update process here
|
||||
|
@ -3232,10 +3386,6 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
// the service to a newer version in that case. If we are not running
|
||||
// through the service, then MOZ_USING_SERVICE will not exist.
|
||||
if (!sUsingService) {
|
||||
if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath, false, nullptr)) {
|
||||
LOG(("NS_main: The post update process could not be launched."));
|
||||
}
|
||||
|
||||
StartServiceUpdate(gInstallDirPath);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче