Bug 1177861 - remove remaining unused declarations and cleanup update staging. r=spohl
authorRobert Strong <robert.bugzilla@gmail.com>
Tue, 11 Aug 2015 14:30:35 -0700
changeset 289944 66bf3e9e71d4d1730c15bbdd0448b91c8c1a15b8
parent 289943 410f6c78d22652c5b977acf211faf8faf8879ca4
child 289945 9b4fa1dc91fd42a5ecc095bcf194ed98f51209d9
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersspohl
bugs1177861
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1177861 - remove remaining unused declarations and cleanup update staging. r=spohl
toolkit/components/maintenanceservice/certificatecheck.cpp
toolkit/components/maintenanceservice/certificatecheck.h
toolkit/components/maintenanceservice/moz.build
toolkit/components/maintenanceservice/registrycertificates.cpp
toolkit/components/maintenanceservice/registrycertificates.h
toolkit/components/maintenanceservice/workmonitor.cpp
toolkit/mozapps/update/common/certificatecheck.cpp
toolkit/mozapps/update/common/certificatecheck.h
toolkit/mozapps/update/common/errors.h
toolkit/mozapps/update/common/moz.build
toolkit/mozapps/update/common/registrycertificates.cpp
toolkit/mozapps/update/common/registrycertificates.h
toolkit/mozapps/update/common/sources.mozbuild
toolkit/mozapps/update/common/updatehelper.cpp
toolkit/mozapps/update/common/updatehelper.h
toolkit/mozapps/update/nsUpdateService.js
toolkit/mozapps/update/tests/TestAUSHelper.cpp
toolkit/mozapps/update/updater/updater.cpp
--- a/toolkit/components/maintenanceservice/moz.build
+++ b/toolkit/components/maintenanceservice/moz.build
@@ -2,19 +2,17 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # 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/.
 
 Program('maintenanceservice')
 
 SOURCES += [
-    'certificatecheck.cpp',
     'maintenanceservice.cpp',
-    'registrycertificates.cpp',
     'servicebase.cpp',
     'serviceinstall.cpp',
     'workmonitor.cpp',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     USE_LIBS += [
         'updatecommon-standalone',
--- a/toolkit/components/maintenanceservice/workmonitor.cpp
+++ b/toolkit/components/maintenanceservice/workmonitor.cpp
@@ -201,33 +201,16 @@ StartUpdateProcess(int argc,
   // across all OS if it's of no harm.
   if (argc >= index) {
     // Setting the desktop to blank will ensure no GUI is displayed
     si.lpDesktop = L"";
     si.dwFlags |= STARTF_USESHOWWINDOW;
     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.
   putenv(const_cast<char*>("MOZ_USING_SERVICE=1"));
   LOG(("Starting service with cmdline: %ls", cmdLine));
   processStarted = CreateProcessW(argv[0], cmdLine,
                                   nullptr, nullptr, FALSE,
                                   CREATE_DEFAULT_ERROR_MODE,
@@ -292,47 +275,16 @@ StartUpdateProcess(int argc,
     }
   } else {
     DWORD lastError = GetLastError();
     LOG_WARN(("Could not create process as current user, "
               "updaterPath: %ls; cmdLine: %ls.  (%d)",
               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="));
 
   free(cmdLine);
   return updateWasSuccessful;
 }
 
 /**
rename from toolkit/components/maintenanceservice/certificatecheck.cpp
rename to toolkit/mozapps/update/common/certificatecheck.cpp
--- a/toolkit/components/maintenanceservice/certificatecheck.cpp
+++ b/toolkit/mozapps/update/common/certificatecheck.cpp
@@ -4,17 +4,17 @@
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <windows.h>
 #include <softpub.h>
 #include <wintrust.h>
 
 #include "certificatecheck.h"
-#include "servicebase.h"
+#include "updatelogging.h"
 
 #pragma comment(lib, "wintrust.lib")
 #pragma comment(lib, "crypt32.lib")
 
 static const int ENCODING = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
 
 /**
  * Checks to see if a file stored at filePath matches the specified info.
@@ -118,40 +118,40 @@ cleanup:
  * @param  infoToMatch  The acceptable information to match
  * @return FALSE if the info does not match or if any error occurs in the check
  */
 BOOL 
 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.
     dwData = CertGetNameString(certContext, 
                                CERT_NAME_SIMPLE_DISPLAY_TYPE,
                                CERT_NAME_ISSUER_FLAG, nullptr,
                                nullptr, 0);
 
     if (!dwData) {
       LOG_WARN(("CertGetNameString failed.  (%d)", GetLastError()));
       return FALSE;
     }
 
     // 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()));
       return FALSE;
     }
 
     // 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);
       return FALSE;
     }
 
     // If the issuer does not match, return a failure.
     if (!infoToMatch.issuer ||
@@ -169,25 +169,25 @@ DoCertificateAttributesMatch(PCCERT_CONT
     dwData = CertGetNameString(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
                                0, nullptr, nullptr, 0);
     if (!dwData) {
       LOG_WARN(("CertGetNameString failed.  (%d)", GetLastError()));
       return FALSE;
     }
 
     // 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()));
       return FALSE;
     }
 
     // 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);
       return FALSE;
     }
 
     // If the issuer does not match, return a failure.
     if (!infoToMatch.name || 
@@ -200,33 +200,16 @@ DoCertificateAttributesMatch(PCCERT_CONT
     LocalFree(szName);
   }
 
   // If there were any errors we would have aborted by now.
   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.
  *
  * @param  filePath  The file path to check.
  * @return ERROR_SUCCESS if successful, or the last error code otherwise.
  */
 DWORD
 VerifyCertificateTrustForFile(LPCWSTR filePath)
 {
rename from toolkit/components/maintenanceservice/certificatecheck.h
rename to toolkit/mozapps/update/common/certificatecheck.h
--- a/toolkit/mozapps/update/common/errors.h
+++ b/toolkit/mozapps/update/common/errors.h
@@ -77,16 +77,18 @@
 #define WRITE_ERROR_OPEN_PATCH_FILE 63
 #define WRITE_ERROR_PATCH_FILE 64
 #define WRITE_ERROR_APPLY_DIR_PATH 65
 #define WRITE_ERROR_CALLBACK_PATH 66
 #define WRITE_ERROR_FILE_ACCESS_DENIED 67
 #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
 
 // The following error codes are only used by updater.exe
 // when a fallback key exists for tests.
 #define FALLBACKKEY_UNKNOWN_ERROR 100
 #define FALLBACKKEY_REGPATH_ERROR 101
 #define FALLBACKKEY_NOKEY_ERROR 102
--- a/toolkit/mozapps/update/common/moz.build
+++ b/toolkit/mozapps/update/common/moz.build
@@ -7,23 +7,25 @@
 EXPORTS += [
     'readstrings.h',
     'updatedefines.h',
     'updatelogging.h',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXPORTS += [
+        'certificatecheck.h',
         'pathhash.h',
+        'registrycertificates.h',
         'uachelper.h',
         'updatehelper.cpp',
         'updatehelper.h',
     ]
 
 Library('updatecommon')
 
+DEFINES['NS_NO_XPCOM'] = True
+
 srcdir = '.'
 
 include('sources.mozbuild')
 
-FINAL_LIBRARY = 'xul'
-
 FAIL_ON_WARNINGS = True
rename from toolkit/components/maintenanceservice/registrycertificates.cpp
rename to toolkit/mozapps/update/common/registrycertificates.cpp
--- a/toolkit/components/maintenanceservice/registrycertificates.cpp
+++ b/toolkit/mozapps/update/common/registrycertificates.cpp
@@ -3,18 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <windows.h>
 
 #include "registrycertificates.h"
 #include "pathhash.h"
-#include "nsWindowsHelpers.h"
-#include "servicebase.h"
+#include "updatelogging.h"
 #include "updatehelper.h"
 #define MAX_KEY_LENGTH 255
 
 /**
  * Verifies if the file path matches any certificate stored in the registry.
  *
  * @param  filePath The file path of the application to check if allowed.
  * @param  allowFallbackKeySkip when this is TRUE the fallback registry key will
@@ -36,113 +35,120 @@ DoesBinaryMatchAllowedCertificates(LPCWS
   }
 
   // We use KEY_WOW64_64KEY to always force 64-bit view.
   // The user may have both x86 and x64 applications installed
   // which each register information.  We need a consistent place
   // 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.
     // We use this registry key on our test slaves to store the 
     // 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;
     } else if (allowFallbackKeySkip) {
       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;
   retCode = RegQueryInfoKeyW(baseKey, nullptr, nullptr, nullptr, &subkeyCount,
                              nullptr, nullptr, nullptr, nullptr, nullptr,
                              nullptr, nullptr);
   if (retCode != ERROR_SUCCESS) {
     LOG_WARN(("Could not query info key.  (%d)", retCode));
+    RegCloseKey(baseKey);
     return FALSE;
   }
 
   // Enumerate the subkeys, each subkey represents an allowed certificate.
   for (DWORD i = 0; i < subkeyCount; i++) { 
     WCHAR subkeyBuffer[MAX_KEY_LENGTH];
     DWORD subkeyBufferCount = MAX_KEY_LENGTH;  
     retCode = RegEnumKeyExW(baseKey, i, subkeyBuffer, 
                             &subkeyBufferCount, nullptr, 
                             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
     }
 
     const int MAX_CHAR_COUNT = 256;
     DWORD valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR);
     WCHAR name[MAX_CHAR_COUNT] = { L'\0' };
     WCHAR issuer[MAX_CHAR_COUNT] = { L'\0' };
 
     // Get the name from the registry
     retCode = RegQueryValueExW(subKey, L"name", 0, nullptr, 
                                (LPBYTE)name, &valueBufSize);
     if (retCode != ERROR_SUCCESS) {
       LOG_WARN(("Could not obtain name from registry.  (%d)", retCode));
+      RegCloseKey(subKey);
       continue; // Try the next subkey
     }
 
     // Get the issuer from the registry
     valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR);
     retCode = RegQueryValueExW(subKey, L"issuer", 0, nullptr, 
                                (LPBYTE)issuer, &valueBufSize);
     if (retCode != ERROR_SUCCESS) {
       LOG_WARN(("Could not obtain issuer from registry.  (%d)", retCode));
+      RegCloseKey(subKey);
       continue; // Try the next subkey
     }
 
     CertificateCheckInfo allowedCertificate = {
       name, 
       issuer, 
     };
 
     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;
 }
rename from toolkit/components/maintenanceservice/registrycertificates.h
rename to toolkit/mozapps/update/common/registrycertificates.h
--- a/toolkit/mozapps/update/common/sources.mozbuild
+++ b/toolkit/mozapps/update/common/sources.mozbuild
@@ -1,17 +1,19 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # 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/.
 
 sources = []
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     sources += [
+        'certificatecheck.cpp',
         'pathhash.cpp',
+        'registrycertificates.cpp',
         'uachelper.cpp',
         'updatehelper.cpp',
     ]
 
 sources += [
     'readstrings.cpp',
     'updatelogging.cpp',
 ]
--- a/toolkit/mozapps/update/common/updatehelper.cpp
+++ b/toolkit/mozapps/update/common/updatehelper.cpp
@@ -16,18 +16,20 @@
 #include "mozilla/UniquePtr.h"
 
 // Needed for PathAppendW
 #include <shlwapi.h>
 
 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.
  *
  * @param  destinationBuffer A buffer of size MAX_PATH + 1 to store the result.
  * @param  siblingFIlePath   The path of another file in the same directory
  * @param  newFileName       The filename of another file in the same directory
  * @return TRUE if successful
@@ -49,147 +51,16 @@ PathGetSiblingFilePath(LPWSTR destinatio
   if (wcslen(destinationBuffer) + wcslen(newFileName) >= MAX_PATH) {
     return FALSE;
   }
 
   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.
  *
  * @param  installDir the installation directory where
  *         maintenanceservice_installer.exe is located.
  * @return TRUE if successful
  */
 BOOL
--- a/toolkit/mozapps/update/common/updatehelper.h
+++ b/toolkit/mozapps/update/common/updatehelper.h
@@ -1,18 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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);
 DWORD WaitForProcessExit(LPCWSTR filename, DWORD maxSeconds);
 BOOL DoesFallbackKeyExist();
 BOOL IsLocalFile(LPCWSTR file, BOOL &isLocal);
 DWORD StartServiceCommand(int argc, LPCWSTR* argv);
 BOOL IsUnpromptedElevation(BOOL &isUnpromptedElevation);
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -1074,20 +1074,19 @@ function shouldUseService() {
   if (AppConstants.MOZ_MAINTENANCE_SERVICE && isServiceInstalled()) {
     return getPref("getBoolPref",
                    PREF_APP_UPDATE_SERVICE_ENABLED, false);
   }
   return false;
 }
 
 /**
- * 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") {
     let installed = 0;
     try {
       let wrk = Cc["@mozilla.org/windows-registry-key;1"].
                 createInstance(Ci.nsIWindowsRegKey);
       wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
--- a/toolkit/mozapps/update/tests/TestAUSHelper.cpp
+++ b/toolkit/mozapps/update/tests/TestAUSHelper.cpp
@@ -29,16 +29,17 @@
 # define NS_tfopen _wfopen
 # define NS_tstrcmp wcscmp
 # define NS_ttoi _wtoi
 # define NS_tstat _wstat
 # define NS_tgetcwd _wgetcwd
 # define LOG_S "%S"
 
 #include "../common/updatehelper.h"
+#include "../common/certificatecheck.h"
 
 #else
 # include <unistd.h>
 # define NS_main main
   typedef char NS_tchar;
 # define NS_T(str) str
 # define NS_tsnprintf snprintf
 # define NS_taccess access
@@ -127,71 +128,42 @@ CheckMsg(const NS_tchar *path, const cha
 
   bool isMatch = strcmp(rb, expected) == 0;
   free(mbuf);
   fclose(inFP);
   inFP = nullptr;
   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) {
     if (!NS_tstrcmp(argv[1], NS_T("post-update-async")) ||
         !NS_tstrcmp(argv[1], NS_T("post-update-sync"))) {
       NS_tchar exePath[MAXPATHLEN];
 #ifdef XP_WIN
       if (!::GetModuleFileNameW(0, exePath, MAXPATHLEN)) {
         return 1;
       }
 #else
       strcpy(exePath, argv[0]);
 #endif
       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"))) {
 #ifdef XP_WIN
         Sleep(2000);
 #else
         sleep(2);
 #endif
--- a/toolkit/mozapps/update/updater/updater.cpp
+++ b/toolkit/mozapps/update/updater/updater.cpp
@@ -122,27 +122,33 @@ static bool sUseHardLinks = true;
 
 #if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \
     !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK)
 #include "nss.h"
 #include "prerror.h"
 #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
 // return code specified. This prevents multiple launches of the callback
 // application by preventing the elevated process from launching the callback.
 #define EXIT_WHEN_ELEVATED(path, handle, retCode) \
   { \
       if (handle != INVALID_HANDLE_VALUE) { \
         CloseHandle(handle); \
       } \
       if (_waccess(path, F_OK) == 0 && NS_tremove(path) != 0) { \
+        LogFinish(); \
         return retCode; \
       } \
   }
 #endif
 
 //-----------------------------------------------------------------------------
 
 // This variable lives in libbz2.  It's declared in bzlib_private.h, so we just
@@ -1808,16 +1814,139 @@ PatchIfFile::Finish(int status)
 
 //-----------------------------------------------------------------------------
 
 #ifdef XP_WIN
 #include "nsWindowsRestart.cpp"
 #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
 LaunchCallbackApp(const NS_tchar *workingDir,
                   int argc,
                   NS_tchar **argv,
                   bool usingService)
 {
@@ -2530,16 +2659,38 @@ int NS_main(int argc, NS_tchar **argv)
   } else if (sReplaceRequest) {
     LOG(("Performing a replace request"));
   }
 
   LOG(("PATCH DIRECTORY " LOG_S, gPatchDirPath));
   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) {
     int32_t prioVal;
     int32_t oomScoreAdj;
     int32_t ioprioClass;
     int32_t ioprioLevel;
     if (sscanf(prioEnv, "%d/%d/%d/%d",
@@ -2823,18 +2974,17 @@ int NS_main(int argc, NS_tchar **argv)
       // current user's session of this unelevated updater.exe the
       // current process is running as.
       // Note that we don't need to do this if we're just staging the update,
       // as the PostUpdate step runs when performing the replacing in that case.
       if (useService && !sStagedUpdate) {
         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.");
           }
         }
       }
 
       // If we didn't want to use the service at all, or if an update was
       // already happening, or launching the service command failed, then
@@ -3219,28 +3369,28 @@ int NS_main(int argc, NS_tchar **argv)
   }
 #endif /* XP_MACOSX */
 
   LogFinish();
 
   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
       // because it's possible we are updating with updater.exe without the
       // service if the service failed to apply the update. We want to update
       // 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);
       }
     }
     EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0);
 #endif /* XP_WIN */
 #ifdef XP_MACOSX
     if (gSucceeded) {
       LaunchMacPostProcess(gInstallDirPath);