diff options
Diffstat (limited to 'toolkit/components/maintenanceservice/workmonitor.cpp')
-rw-r--r-- | toolkit/components/maintenanceservice/workmonitor.cpp | 758 |
1 files changed, 0 insertions, 758 deletions
diff --git a/toolkit/components/maintenanceservice/workmonitor.cpp b/toolkit/components/maintenanceservice/workmonitor.cpp deleted file mode 100644 index d06db3ca2..000000000 --- a/toolkit/components/maintenanceservice/workmonitor.cpp +++ /dev/null @@ -1,758 +0,0 @@ -/* 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/. */ - -#include <shlobj.h> -#include <shlwapi.h> -#include <wtsapi32.h> -#include <userenv.h> -#include <shellapi.h> - -#pragma comment(lib, "wtsapi32.lib") -#pragma comment(lib, "userenv.lib") -#pragma comment(lib, "shlwapi.lib") -#pragma comment(lib, "ole32.lib") -#pragma comment(lib, "rpcrt4.lib") - -#include "nsWindowsHelpers.h" - -#include "workmonitor.h" -#include "serviceinstall.h" -#include "servicebase.h" -#include "registrycertificates.h" -#include "uachelper.h" -#include "updatehelper.h" -#include "pathhash.h" -#include "errors.h" - -// Wait 15 minutes for an update operation to run at most. -// Updates usually take less than a minute so this seems like a -// significantly large and safe amount of time to wait. -static const int TIME_TO_WAIT_ON_UPDATER = 15 * 60 * 1000; -wchar_t* MakeCommandLine(int argc, wchar_t** argv); -BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode); -BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath, - LPCWSTR newFileName); -BOOL DoesFallbackKeyExist(); - -/* - * Read the update.status file and sets isApplying to true if - * the status is set to applying. - * - * @param updateDirPath The directory where update.status is stored - * @param isApplying Out parameter for specifying if the status - * is set to applying or not. - * @return TRUE if the information was filled. -*/ -static BOOL -IsStatusApplying(LPCWSTR updateDirPath, BOOL &isApplying) -{ - isApplying = FALSE; - WCHAR updateStatusFilePath[MAX_PATH + 1] = {L'\0'}; - wcsncpy(updateStatusFilePath, updateDirPath, MAX_PATH); - if (!PathAppendSafe(updateStatusFilePath, L"update.status")) { - LOG_WARN(("Could not append path for update.status file")); - return FALSE; - } - - nsAutoHandle statusFile(CreateFileW(updateStatusFilePath, GENERIC_READ, - FILE_SHARE_READ | - FILE_SHARE_WRITE | - FILE_SHARE_DELETE, - nullptr, OPEN_EXISTING, 0, nullptr)); - - if (INVALID_HANDLE_VALUE == statusFile) { - LOG_WARN(("Could not open update.status file")); - return FALSE; - } - - char buf[32] = { 0 }; - DWORD read; - if (!ReadFile(statusFile, buf, sizeof(buf), &read, nullptr)) { - LOG_WARN(("Could not read from update.status file")); - return FALSE; - } - - const char kApplying[] = "applying"; - isApplying = strncmp(buf, kApplying, - sizeof(kApplying) - 1) == 0; - return TRUE; -} - -/** - * Determines whether we're staging an update. - * - * @param argc The argc value normally sent to updater.exe - * @param argv The argv value normally sent to updater.exe - * @return boolean True if we're staging an update - */ -static bool -IsUpdateBeingStaged(int argc, LPWSTR *argv) -{ - // PID will be set to -1 if we're supposed to stage an update. - return argc == 4 && !wcscmp(argv[3], L"-1") || - argc == 5 && !wcscmp(argv[4], L"-1"); -} - -/** - * Determines whether the param only contains digits. - * - * @param str The string to check - * @param boolean True if the param only contains digits - */ -static bool -IsDigits(WCHAR *str) -{ - while (*str) { - if (!iswdigit(*str++)) { - return FALSE; - } - } - return TRUE; -} - -/** - * Determines whether the command line contains just the directory to apply the - * update to (old command line) or if it contains the installation directory and - * the directory to apply the update to. - * - * @param argc The argc value normally sent to updater.exe - * @param argv The argv value normally sent to updater.exe - * @param boolean True if the command line contains just the directory to apply - * the update to - */ -static bool -IsOldCommandline(int argc, LPWSTR *argv) -{ - return argc == 4 && !wcscmp(argv[3], L"-1") || - argc >= 4 && (wcsstr(argv[3], L"/replace") || IsDigits(argv[3])); -} - -/** - * Gets the installation directory from the arguments passed to updater.exe. - * - * @param argcTmp The argc value normally sent to updater.exe - * @param argvTmp The argv value normally sent to updater.exe - * @param aResultDir Buffer to hold the installation directory. - */ -static BOOL -GetInstallationDir(int argcTmp, LPWSTR *argvTmp, WCHAR aResultDir[MAX_PATH + 1]) -{ - int index = 3; - if (IsOldCommandline(argcTmp, argvTmp)) { - index = 2; - } - - if (argcTmp < index) { - return FALSE; - } - - wcsncpy(aResultDir, argvTmp[2], MAX_PATH); - WCHAR* backSlash = wcsrchr(aResultDir, L'\\'); - // Make sure that the path does not include trailing backslashes - if (backSlash && (backSlash[1] == L'\0')) { - *backSlash = L'\0'; - } - - // The new command line's argv[2] is always the installation directory. - if (index == 2) { - bool backgroundUpdate = IsUpdateBeingStaged(argcTmp, argvTmp); - bool replaceRequest = (argcTmp >= 4 && wcsstr(argvTmp[3], L"/replace")); - if (backgroundUpdate || replaceRequest) { - return PathRemoveFileSpecW(aResultDir); - } - } - return TRUE; -} - -/** - * Runs an update process as the service using the SYSTEM account. - * - * @param argc The number of arguments in argv - * @param argv The arguments normally passed to updater.exe - * argv[0] must be the path to updater.exe - * @param processStarted Set to TRUE if the process was started. - * @return TRUE if the update process was run had a return code of 0. - */ -BOOL -StartUpdateProcess(int argc, - LPWSTR *argv, - LPCWSTR installDir, - BOOL &processStarted) -{ - LOG(("Starting update process as the service in session 0.")); - STARTUPINFO si = {0}; - si.cb = sizeof(STARTUPINFO); - si.lpDesktop = L"winsta0\\Default"; - PROCESS_INFORMATION pi = {0}; - - // The updater command line is of the form: - // updater.exe update-dir apply [wait-pid [callback-dir callback-path args]] - LPWSTR cmdLine = MakeCommandLine(argc, argv); - - int index = 3; - if (IsOldCommandline(argc, argv)) { - index = 2; - } - - // If we're about to start the update process from session 0, - // then we should not show a GUI. This only really needs to be done - // on Vista and higher, but it's better to keep everything consistent - // 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; - } - - // 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, - nullptr, - nullptr, &si, &pi); - - BOOL updateWasSuccessful = FALSE; - if (processStarted) { - BOOL processTerminated = FALSE; - BOOL noProcessExitCode = FALSE; - // Wait for the updater process to finish - LOG(("Process was started... waiting on result.")); - DWORD waitRes = WaitForSingleObject(pi.hProcess, TIME_TO_WAIT_ON_UPDATER); - if (WAIT_TIMEOUT == waitRes) { - // We waited a long period of time for updater.exe and it never finished - // so kill it. - TerminateProcess(pi.hProcess, 1); - processTerminated = TRUE; - } else { - // Check the return code of updater.exe to make sure we get 0 - DWORD returnCode; - if (GetExitCodeProcess(pi.hProcess, &returnCode)) { - LOG(("Process finished with return code %d.", returnCode)); - // updater returns 0 if successful. - updateWasSuccessful = (returnCode == 0); - } else { - LOG_WARN(("Process finished but could not obtain return code.")); - noProcessExitCode = TRUE; - } - } - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - // Check just in case updater.exe didn't change the status from - // applying. If this is the case we report an error. - BOOL isApplying = FALSE; - if (IsStatusApplying(argv[1], isApplying) && isApplying) { - if (updateWasSuccessful) { - LOG(("update.status is still applying even though update was " - "successful.")); - if (!WriteStatusFailure(argv[1], - SERVICE_STILL_APPLYING_ON_SUCCESS)) { - LOG_WARN(("Could not write update.status still applying on " - "success error.")); - } - // Since we still had applying we know updater.exe didn't do its - // job correctly. - updateWasSuccessful = FALSE; - } else { - LOG_WARN(("update.status is still applying and update was not successful.")); - int failcode = SERVICE_STILL_APPLYING_ON_FAILURE; - if (noProcessExitCode) { - failcode = SERVICE_STILL_APPLYING_NO_EXIT_CODE; - } else if (processTerminated) { - failcode = SERVICE_STILL_APPLYING_TERMINATED; - } - if (!WriteStatusFailure(argv[1], failcode)) { - LOG_WARN(("Could not write update.status still applying on " - "failure error.")); - } - } - } - } else { - DWORD lastError = GetLastError(); - LOG_WARN(("Could not create process as current user, " - "updaterPath: %ls; cmdLine: %ls. (%d)", - argv[0], cmdLine, lastError)); - } - - // Empty value on putenv is how you remove an env variable in Windows - putenv(const_cast<char*>("MOZ_USING_SERVICE=")); - - free(cmdLine); - return updateWasSuccessful; -} - -/** - * Validates a file as an official updater. - * - * @param updater Path to the updater to validate - * @param installDir Path to the application installation - * being updated - * @param updateDir Update applyTo direcotry, - * where logs will be written - * - * @return true if updater is the path to a valid updater - */ -static bool -UpdaterIsValid(LPWSTR updater, LPWSTR installDir, LPWSTR updateDir) -{ - // Make sure the path to the updater to use for the update is local. - // We do this check to make sure that file locking is available for - // race condition security checks. - BOOL isLocal = FALSE; - if (!IsLocalFile(updater, isLocal) || !isLocal) { - LOG_WARN(("Filesystem in path %ls is not supported (%d)", - updater, GetLastError())); - if (!WriteStatusFailure(updateDir, SERVICE_UPDATER_NOT_FIXED_DRIVE)) { - LOG_WARN(("Could not write update.status service update failure. (%d)", - GetLastError())); - } - return false; - } - - nsAutoHandle noWriteLock(CreateFileW(updater, GENERIC_READ, FILE_SHARE_READ, - nullptr, OPEN_EXISTING, 0, nullptr)); - if (INVALID_HANDLE_VALUE == noWriteLock) { - LOG_WARN(("Could not set no write sharing access on file. (%d)", - GetLastError())); - if (!WriteStatusFailure(updateDir, SERVICE_COULD_NOT_LOCK_UPDATER)) { - LOG_WARN(("Could not write update.status service update failure. (%d)", - GetLastError())); - } - return false; - } - - // Verify that the updater.exe that we are executing is the same - // as the one in the installation directory which we are updating. - // The installation dir that we are installing to is installDir. - WCHAR installDirUpdater[MAX_PATH + 1] = { L'\0' }; - wcsncpy(installDirUpdater, installDir, MAX_PATH); - if (!PathAppendSafe(installDirUpdater, L"updater.exe")) { - LOG_WARN(("Install directory updater could not be determined.")); - return false; - } - - BOOL updaterIsCorrect; - if (!VerifySameFiles(updater, installDirUpdater, updaterIsCorrect)) { - LOG_WARN(("Error checking if the updaters are the same.\n" - "Path 1: %ls\nPath 2: %ls", updater, installDirUpdater)); - return false; - } - - if (!updaterIsCorrect) { - LOG_WARN(("The updaters do not match, updater will not run.\n" - "Path 1: %ls\nPath 2: %ls", updater, installDirUpdater)); - if (!WriteStatusFailure(updateDir, SERVICE_UPDATER_COMPARE_ERROR)) { - LOG_WARN(("Could not write update.status updater compare failure.")); - } - return false; - } - - LOG(("updater.exe was compared successfully to the installation directory" - " updater.exe.")); - - // Check to make sure the updater.exe module has the unique updater identity. - // This is a security measure to make sure that the signed executable that - // we will run is actually an updater. - bool result = true; - HMODULE updaterModule = LoadLibraryEx(updater, nullptr, - LOAD_LIBRARY_AS_DATAFILE); - if (!updaterModule) { - LOG_WARN(("updater.exe module could not be loaded. (%d)", GetLastError())); - result = false; - } else { - char updaterIdentity[64]; - if (!LoadStringA(updaterModule, IDS_UPDATER_IDENTITY, - updaterIdentity, sizeof(updaterIdentity))) { - LOG_WARN(("The updater.exe application does not contain the Mozilla" - " updater identity.")); - result = false; - } - - if (strcmp(updaterIdentity, UPDATER_IDENTITY_STRING)) { - LOG_WARN(("The updater.exe identity string is not valid.")); - result = false; - } - FreeLibrary(updaterModule); - } - - if (result) { - LOG(("The updater.exe application contains the Mozilla" - " updater identity.")); - } else { - if (!WriteStatusFailure(updateDir, SERVICE_UPDATER_IDENTITY_ERROR)) { - LOG_WARN(("Could not write update.status no updater identity.")); - } - return false; - } - -#ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK - return DoesBinaryMatchAllowedCertificates(installDir, updater); -#else - return true; -#endif -} - -/** - * Processes a software update command - * - * @param argc The number of arguments in argv - * @param argv The arguments normally passed to updater.exe - * argv[0] must be the path to updater.exe - * @return TRUE if the update was successful. - */ -BOOL -ProcessSoftwareUpdateCommand(DWORD argc, LPWSTR *argv) -{ - BOOL result = TRUE; - if (argc < 3) { - LOG_WARN(("Not enough command line parameters specified. " - "Updating update.status.")); - - // We can only update update.status if argv[1] exists. argv[1] is - // the directory where the update.status file exists. - if (argc < 2 || - !WriteStatusFailure(argv[1], SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS)) { - LOG_WARN(("Could not write update.status service update failure. (%d)", - GetLastError())); - } - return FALSE; - } - - WCHAR installDir[MAX_PATH + 1] = {L'\0'}; - if (!GetInstallationDir(argc, argv, installDir)) { - LOG_WARN(("Could not get the installation directory")); - if (!WriteStatusFailure(argv[1], SERVICE_INSTALLDIR_ERROR)) { - LOG_WARN(("Could not write update.status for GetInstallationDir failure.")); - } - return FALSE; - } - - if (UpdaterIsValid(argv[0], installDir, argv[1])) { - BOOL updateProcessWasStarted = FALSE; - if (StartUpdateProcess(argc, argv, installDir, - updateProcessWasStarted)) { - LOG(("updater.exe was launched and run successfully!")); - LogFlush(); - - // Don't attempt to update the service when the update is being staged. - if (!IsUpdateBeingStaged(argc, argv)) { - // We might not execute code after StartServiceUpdate because - // the service installer will stop the service if it is running. - StartServiceUpdate(installDir); - } - } else { - result = FALSE; - LOG_WARN(("Error running update process. Updating update.status (%d)", - GetLastError())); - LogFlush(); - - // If the update process was started, then updater.exe is responsible for - // setting the failure code. If it could not be started then we do the - // work. We set an error instead of directly setting status pending - // so that the app.update.service.errors pref can be updated when - // the callback app restarts. - if (!updateProcessWasStarted) { - if (!WriteStatusFailure(argv[1], - SERVICE_UPDATER_COULD_NOT_BE_STARTED)) { - LOG_WARN(("Could not write update.status service update failure. (%d)", - GetLastError())); - } - } - } - } else { - result = FALSE; - LOG_WARN(("Could not start process due to certificate check error on " - "updater.exe. Updating update.status. (%d)", GetLastError())); - - // When there is a certificate check error on the updater.exe application, - // we want to write out the error. - if (!WriteStatusFailure(argv[1], - SERVICE_UPDATER_SIGN_ERROR)) { - LOG_WARN(("Could not write pending state to update.status. (%d)", - GetLastError())); - } - } - - return result; -} - -/** - * Obtains the updater path alongside a subdir of the service binary. - * The purpose of this function is to return a path that is likely high - * integrity and therefore more safe to execute code from. - * - * @param serviceUpdaterPath Out parameter for the path where the updater - * should be copied to. - * @return TRUE if a file path was obtained. - */ -BOOL -GetSecureUpdaterPath(WCHAR serviceUpdaterPath[MAX_PATH + 1]) -{ - if (!GetModuleFileNameW(nullptr, serviceUpdaterPath, MAX_PATH)) { - LOG_WARN(("Could not obtain module filename when attempting to " - "use a secure updater path. (%d)", GetLastError())); - return FALSE; - } - - if (!PathRemoveFileSpecW(serviceUpdaterPath)) { - LOG_WARN(("Couldn't remove file spec when attempting to use a secure " - "updater path. (%d)", GetLastError())); - return FALSE; - } - - if (!PathAppendSafe(serviceUpdaterPath, L"update")) { - LOG_WARN(("Couldn't append file spec when attempting to use a secure " - "updater path. (%d)", GetLastError())); - return FALSE; - } - - CreateDirectoryW(serviceUpdaterPath, nullptr); - - if (!PathAppendSafe(serviceUpdaterPath, L"updater.exe")) { - LOG_WARN(("Couldn't append file spec when attempting to use a secure " - "updater path. (%d)", GetLastError())); - return FALSE; - } - - return TRUE; -} - -/** - * Deletes the passed in updater path and the associated updater.ini file. - * - * @param serviceUpdaterPath The path to delete. - * @return TRUE if a file was deleted. - */ -BOOL -DeleteSecureUpdater(WCHAR serviceUpdaterPath[MAX_PATH + 1]) -{ - BOOL result = FALSE; - if (serviceUpdaterPath[0]) { - result = DeleteFileW(serviceUpdaterPath); - if (!result && GetLastError() != ERROR_PATH_NOT_FOUND && - GetLastError() != ERROR_FILE_NOT_FOUND) { - LOG_WARN(("Could not delete service updater path: '%ls'.", - serviceUpdaterPath)); - } - - WCHAR updaterINIPath[MAX_PATH + 1] = { L'\0' }; - if (PathGetSiblingFilePath(updaterINIPath, serviceUpdaterPath, - L"updater.ini")) { - result = DeleteFileW(updaterINIPath); - if (!result && GetLastError() != ERROR_PATH_NOT_FOUND && - GetLastError() != ERROR_FILE_NOT_FOUND) { - LOG_WARN(("Could not delete service updater INI path: '%ls'.", - updaterINIPath)); - } - } - } - return result; -} - -/** - * Executes a service command. - * - * @param argc The number of arguments in argv - * @param argv The service command line arguments, argv[0] and argv[1] - * and automatically included by Windows. argv[2] is the - * service command. - * - * @return FALSE if there was an error executing the service command. - */ -BOOL -ExecuteServiceCommand(int argc, LPWSTR *argv) -{ - if (argc < 3) { - LOG_WARN(("Not enough command line arguments to execute a service command")); - return FALSE; - } - - // The tests work by making sure the log has changed, so we put a - // unique ID in the log. - RPC_WSTR guidString = RPC_WSTR(L""); - GUID guid; - HRESULT hr = CoCreateGuid(&guid); - if (SUCCEEDED(hr)) { - UuidToString(&guid, &guidString); - } - LOG(("Executing service command %ls, ID: %ls", - argv[2], reinterpret_cast<LPCWSTR>(guidString))); - RpcStringFree(&guidString); - - BOOL result = FALSE; - if (!lstrcmpi(argv[2], L"software-update")) { - // This check is also performed in updater.cpp and is performed here - // as well since the maintenance service can be called directly. - if (argc < 4 || !IsValidFullPath(argv[4])) { - // Since the status file is written to the patch directory and the patch - // directory is invalid don't write the status file. - LOG_WARN(("The patch directory path is not valid for this application.")); - return FALSE; - } - - // This check is also performed in updater.cpp and is performed here - // as well since the maintenance service can be called directly. - if (argc < 5 || !IsValidFullPath(argv[5])) { - LOG_WARN(("The install directory path is not valid for this application.")); - if (!WriteStatusFailure(argv[4], SERVICE_INVALID_INSTALL_DIR_PATH_ERROR)) { - LOG_WARN(("Could not write update.status for previous failure.")); - } - return FALSE; - } - - if (!IsOldCommandline(argc - 3, argv + 3)) { - // This check is also performed in updater.cpp and is performed here - // as well since the maintenance service can be called directly. - if (argc < 6 || !IsValidFullPath(argv[6])) { - LOG_WARN(("The working directory path is not valid for this application.")); - if (!WriteStatusFailure(argv[4], SERVICE_INVALID_WORKING_DIR_PATH_ERROR)) { - LOG_WARN(("Could not write update.status for previous failure.")); - } - return FALSE; - } - - // These checks are also performed in updater.cpp and is performed here - // as well since the maintenance service can be called directly. - if (_wcsnicmp(argv[6], argv[5], MAX_PATH) != 0) { - if (wcscmp(argv[7], L"-1") != 0 && !wcsstr(argv[7], L"/replace")) { - LOG_WARN(("Installation directory and working directory must be the " - "same for non-staged updates. Exiting.")); - if (!WriteStatusFailure(argv[4], SERVICE_INVALID_APPLYTO_DIR_ERROR)) { - LOG_WARN(("Could not write update.status for previous failure.")); - } - return FALSE; - } - - NS_tchar workingDirParent[MAX_PATH]; - NS_tsnprintf(workingDirParent, - sizeof(workingDirParent) / sizeof(workingDirParent[0]), - NS_T("%s"), argv[6]); - if (!PathRemoveFileSpecW(workingDirParent)) { - LOG_WARN(("Couldn't remove file spec when attempting to verify the " - "working directory path. (%d)", GetLastError())); - if (!WriteStatusFailure(argv[4], REMOVE_FILE_SPEC_ERROR)) { - LOG_WARN(("Could not write update.status for previous failure.")); - } - return FALSE; - } - - if (_wcsnicmp(workingDirParent, argv[5], MAX_PATH) != 0) { - LOG_WARN(("The apply-to directory must be the same as or " - "a child of the installation directory! Exiting.")); - if (!WriteStatusFailure(argv[4], SERVICE_INVALID_APPLYTO_DIR_STAGED_ERROR)) { - LOG_WARN(("Could not write update.status for previous failure.")); - } - return FALSE; - } - } - - } - - // Use the passed in command line arguments for the update, except for the - // path to updater.exe. We always look for updater.exe in the installation - // directory, then we copy updater.exe to a the directory of the - // MozillaMaintenance service so that a low integrity process cannot - // replace the updater.exe at any point and use that for the update. - // It also makes DLL injection attacks harder. - WCHAR installDir[MAX_PATH + 1] = { L'\0' }; - if (!GetInstallationDir(argc - 3, argv + 3, installDir)) { - LOG_WARN(("Could not get the installation directory")); - if (!WriteStatusFailure(argv[4], SERVICE_INSTALLDIR_ERROR)) { - LOG_WARN(("Could not write update.status for previous failure.")); - } - return FALSE; - } - - if (!DoesFallbackKeyExist()) { - WCHAR maintenanceServiceKey[MAX_PATH + 1]; - if (CalculateRegistryPathFromFilePath(installDir, maintenanceServiceKey)) { - LOG(("Checking for Maintenance Service registry. key: '%ls'", - maintenanceServiceKey)); - HKEY baseKey = nullptr; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, - maintenanceServiceKey, 0, - KEY_READ | KEY_WOW64_64KEY, - &baseKey) != ERROR_SUCCESS) { - LOG_WARN(("The maintenance service registry key does not exist.")); - if (!WriteStatusFailure(argv[4], SERVICE_INSTALL_DIR_REG_ERROR)) { - LOG_WARN(("Could not write update.status for previous failure.")); - } - return FALSE; - } - RegCloseKey(baseKey); - } else { - if (!WriteStatusFailure(argv[4], SERVICE_CALC_REG_PATH_ERROR)) { - LOG_WARN(("Could not write update.status for previous failure.")); - } - return FALSE; - } - } - - WCHAR installDirUpdater[MAX_PATH + 1] = { L'\0' }; - wcsncpy(installDirUpdater, installDir, MAX_PATH); - if (!PathAppendSafe(installDirUpdater, L"updater.exe")) { - LOG_WARN(("Install directory updater could not be determined.")); - result = FALSE; - } - - result = UpdaterIsValid(installDirUpdater, installDir, argv[4]); - - WCHAR secureUpdaterPath[MAX_PATH + 1] = { L'\0' }; - if (result) { - result = GetSecureUpdaterPath(secureUpdaterPath); // Does its own logging - } - if (result) { - LOG(("Passed in path: '%ls'; Using this path for updating: '%ls'.", - installDirUpdater, secureUpdaterPath)); - DeleteSecureUpdater(secureUpdaterPath); - result = CopyFileW(installDirUpdater, secureUpdaterPath, FALSE); - } - - if (!result) { - LOG_WARN(("Could not copy path to secure location. (%d)", - GetLastError())); - if (!WriteStatusFailure(argv[4], SERVICE_COULD_NOT_COPY_UPDATER)) { - LOG_WARN(("Could not write update.status could not copy updater error")); - } - } else { - - // We obtained the path and copied it successfully, update the path to - // use for the service update. - argv[3] = secureUpdaterPath; - - WCHAR installDirUpdaterINIPath[MAX_PATH + 1] = { L'\0' }; - WCHAR secureUpdaterINIPath[MAX_PATH + 1] = { L'\0' }; - if (PathGetSiblingFilePath(secureUpdaterINIPath, secureUpdaterPath, - L"updater.ini") && - PathGetSiblingFilePath(installDirUpdaterINIPath, installDirUpdater, - L"updater.ini")) { - // This is non fatal if it fails there is no real harm - if (!CopyFileW(installDirUpdaterINIPath, secureUpdaterINIPath, FALSE)) { - LOG_WARN(("Could not copy updater.ini from: '%ls' to '%ls'. (%d)", - installDirUpdaterINIPath, secureUpdaterINIPath, GetLastError())); - } - } - - result = ProcessSoftwareUpdateCommand(argc - 3, argv + 3); - DeleteSecureUpdater(secureUpdaterPath); - } - - // We might not reach here if the service install succeeded - // because the service self updates itself and the service - // installer will stop the service. - LOG(("Service command %ls complete.", argv[2])); - } else { - LOG_WARN(("Service command not recognized: %ls.", argv[2])); - // result is already set to FALSE - } - - LOG(("service command %ls complete with result: %ls.", - argv[1], (result ? L"Success" : L"Failure"))); - return TRUE; -} |