From 7eca4fa00fc383a40b9957ff3c4b038ac02c2eef Mon Sep 17 00:00:00 2001 From: Markus Mohrhard Date: Tue, 27 Dec 2016 02:45:55 +0100 Subject: get the update service working Change-Id: I25921090083f20c4bb416f9cfdd5ec6400a27a21 --- onlineupdate/Executable_update_service.mk | 28 +++ onlineupdate/Module_onlineupdate.mk | 1 + onlineupdate/source/service/certificatecheck.cxx | 36 ++-- onlineupdate/source/service/maintenanceservice.cxx | 70 +++---- .../source/service/registrycertificates.cxx | 87 ++++++--- onlineupdate/source/service/servicebase.cxx | 23 ++- onlineupdate/source/service/servicebase.hxx | 2 +- onlineupdate/source/service/serviceinstall.cxx | 206 ++++++++++++--------- onlineupdate/source/service/windowsHelper.hxx | 48 +++++ onlineupdate/source/service/workmonitor.cxx | 28 +-- 10 files changed, 341 insertions(+), 188 deletions(-) create mode 100644 onlineupdate/source/service/windowsHelper.hxx (limited to 'onlineupdate') diff --git a/onlineupdate/Executable_update_service.mk b/onlineupdate/Executable_update_service.mk index f32133dd05a9..741ee4ee6e4d 100644 --- a/onlineupdate/Executable_update_service.mk +++ b/onlineupdate/Executable_update_service.mk @@ -9,16 +9,44 @@ $(eval $(call gb_Executable_Executable,update_service)) +$(eval $(call gb_Executable_set_targettype_gui,update_service,YES)) + $(eval $(call gb_Executable_set_include,update_service,\ -I$(SRCDIR)/onlineupdate/source/libmar/src/ \ -I$(SRCDIR)/onlineupdate/source/libmar/verify/ \ -I$(SRCDIR)/onlineupdate/source/libmar/sign/ \ + -I$(SRCDIR)/onlineupdate/source/update/common/ \ $$(INCLUDE) \ )) +$(eval $(call gb_Executable_use_static_libraries,update_service,\ + updatehelper \ + winhelper \ +)) + $(eval $(call gb_Executable_add_libs,update_service,\ ws2_32.lib \ Crypt32.lib \ + shell32.lib \ + wintrust.lib \ + version.lib \ + wtsapi32.lib \ + userenv.lib \ + shlwapi.lib \ + ole32.lib \ + rpcrt4.lib \ + comctl32.lib \ + shlwapi.lib \ + kernel32.lib \ + advapi32.lib \ +)) + +$(eval $(call gb_Executable_add_defs,update_service,\ + -DUNICODE \ +)) + +$(eval $(call gb_Executable_add_ldflags,update_service,\ + /ENTRY:wmainCRTStartup \ )) $(eval $(call gb_Executable_add_cxxobjects,update_service,\ diff --git a/onlineupdate/Module_onlineupdate.mk b/onlineupdate/Module_onlineupdate.mk index 91a5ccf2a850..0d2655d97b4b 100644 --- a/onlineupdate/Module_onlineupdate.mk +++ b/onlineupdate/Module_onlineupdate.mk @@ -18,6 +18,7 @@ $(eval $(call gb_Module_add_targets,onlineupdate,\ StaticLibrary_winhelper )\ Executable_mar \ Executable_updater \ + Executable_update_service \ )) endif diff --git a/onlineupdate/source/service/certificatecheck.cxx b/onlineupdate/source/service/certificatecheck.cxx index c756f2c7a945..3a9eba020ccb 100644 --- a/onlineupdate/source/service/certificatecheck.cxx +++ b/onlineupdate/source/service/certificatecheck.cxx @@ -21,15 +21,15 @@ static const int ENCODING = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; * * @param filePath The PE file path to check * @param infoToMatch The acceptable information to match - * @return ERROR_SUCCESS if successful, ERROR_NOT_FOUND if the info + * @return ERROR_SUCCESS if successful, ERROR_NOT_FOUND if the info * does not match, or the last error otherwise. */ DWORD -CheckCertificateForPEFile(LPCWSTR filePath, +CheckCertificateForPEFile(LPCWSTR filePath, CertificateCheckInfo &infoToMatch) { HCERTSTORE certStore = nullptr; - HCRYPTMSG cryptMsg = nullptr; + HCRYPTMSG cryptMsg = nullptr; PCCERT_CONTEXT certContext = nullptr; PCMSG_SIGNER_INFO signerInfo = nullptr; DWORD lastError = ERROR_SUCCESS; @@ -37,9 +37,9 @@ CheckCertificateForPEFile(LPCWSTR filePath, // Get the HCERTSTORE and HCRYPTMSG from the signed file. DWORD encoding, contentType, formatType; BOOL result = CryptQueryObject(CERT_QUERY_OBJECT_FILE, - filePath, + filePath, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, - CERT_QUERY_CONTENT_FLAG_ALL, + CERT_QUERY_CONTENT_FLAG_ALL, 0, &encoding, &contentType, &formatType, &certStore, &cryptMsg, nullptr); if (!result) { @@ -50,7 +50,7 @@ CheckCertificateForPEFile(LPCWSTR filePath, // Pass in nullptr to get the needed signer information size. DWORD signerInfoSize; - result = CryptMsgGetParam(cryptMsg, CMSG_SIGNER_INFO_PARAM, 0, + result = CryptMsgGetParam(cryptMsg, CMSG_SIGNER_INFO_PARAM, 0, nullptr, &signerInfoSize); if (!result) { lastError = GetLastError(); @@ -68,7 +68,7 @@ CheckCertificateForPEFile(LPCWSTR filePath, // Get the signer information (PCMSG_SIGNER_INFO). // In particular we want the issuer and serial number. - result = CryptMsgGetParam(cryptMsg, CMSG_SIGNER_INFO_PARAM, 0, + result = CryptMsgGetParam(cryptMsg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)signerInfo, &signerInfoSize); if (!result) { lastError = GetLastError(); @@ -77,10 +77,10 @@ CheckCertificateForPEFile(LPCWSTR filePath, } // Search for the signer certificate in the certificate store. - CERT_INFO certInfo; + CERT_INFO certInfo; certInfo.Issuer = signerInfo->Issuer; certInfo.SerialNumber = signerInfo->SerialNumber; - certContext = CertFindCertificateInStore(certStore, ENCODING, 0, + certContext = CertFindCertificateInStore(certStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&certInfo, nullptr); if (!certContext) { @@ -102,10 +102,10 @@ cleanup: if (certContext) { CertFreeCertificateContext(certContext); } - if (certStore) { + if (certStore) { CertCloseStore(certStore, 0); } - if (cryptMsg) { + if (cryptMsg) { CryptMsgClose(cryptMsg); } return lastError; @@ -118,8 +118,8 @@ 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, +BOOL +DoCertificateAttributesMatch(PCCERT_CONTEXT certContext, CertificateCheckInfo &infoToMatch) { DWORD dwData; @@ -127,7 +127,7 @@ DoCertificateAttributesMatch(PCCERT_CONTEXT certContext, if (infoToMatch.issuer) { // Pass in nullptr to get the needed size of the issuer buffer. - dwData = CertGetNameString(certContext, + dwData = CertGetNameString(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, nullptr, nullptr, 0); @@ -190,7 +190,7 @@ DoCertificateAttributesMatch(PCCERT_CONTEXT certContext, } // If the issuer does not match, return a failure. - if (!infoToMatch.name || + if (!infoToMatch.name || wcscmp(szName, infoToMatch.name)) { LocalFree(szName); return FALSE; @@ -210,10 +210,10 @@ DoCertificateAttributesMatch(PCCERT_CONTEXT certContext, * @param inputString The string to duplicate * @return The duplicated string which should be freed by the caller. */ -LPWSTR +LPWSTR AllocateAndCopyWideString(LPCWSTR inputString) { - LPWSTR outputString = + LPWSTR outputString = (LPWSTR)LocalAlloc(LPTR, (wcslen(inputString) + 1) * sizeof(WCHAR)); if (outputString) { lstrcpyW(outputString, inputString); @@ -243,7 +243,7 @@ VerifyCertificateTrustForFile(LPCWSTR filePath) trustData.pPolicyCallbackData = nullptr; trustData.pSIPClientData = nullptr; trustData.dwUIChoice = WTD_UI_NONE; - trustData.fdwRevocationChecks = WTD_REVOKE_NONE; + trustData.fdwRevocationChecks = WTD_REVOKE_NONE; trustData.dwUnionChoice = WTD_CHOICE_FILE; trustData.dwStateAction = 0; trustData.hWVTStateData = nullptr; diff --git a/onlineupdate/source/service/maintenanceservice.cxx b/onlineupdate/source/service/maintenanceservice.cxx index be3a8017b0cd..8471bdbd56c5 100644 --- a/onlineupdate/source/service/maintenanceservice.cxx +++ b/onlineupdate/source/service/maintenanceservice.cxx @@ -12,15 +12,15 @@ #include "maintenanceservice.hxx" #include "servicebase.hxx" #include "workmonitor.hxx" -#include "uachelper.hxx" -#include "updatehelper.hxx" +#include "uachelper.h" +#include "updatehelper.h" // Link w/ subsystem window so we don't get a console when executing // this binary through the installer. #pragma comment(linker, "/SUBSYSTEM:windows") -SERVICE_STATUS gSvcStatus = { 0 }; -SERVICE_STATUS_HANDLE gSvcStatusHandle = nullptr; +SERVICE_STATUS gSvcStatus = { 0 }; +SERVICE_STATUS_HANDLE gSvcStatusHandle = nullptr; HANDLE gWorkDoneEvent = nullptr; HANDLE gThread = nullptr; bool gServiceControlStopping = false; @@ -30,9 +30,14 @@ bool gServiceControlStopping = false; BOOL GetLogDirectoryPath(WCHAR *path); -int +int wmain(int argc, WCHAR **argv) { + if (argc < 2) + { + LOG_WARN(("missing mandatory command line argument")); + return 1; + } // If command-line parameter is "install", install the service // or upgrade if already installed // If command line parameter is "forceinstall", install the service @@ -66,7 +71,7 @@ wmain(int argc, WCHAR **argv) LOG(("The service was installed successfully")); LogFinish(); return 0; - } + } if (!lstrcmpi(argv[1], L"upgrade")) { WCHAR updatePath[MAX_PATH + 1]; @@ -102,12 +107,12 @@ wmain(int argc, WCHAR **argv) return 0; } - SERVICE_TABLE_ENTRYW DispatchTable[] = { - { SVC_NAME, (LPSERVICE_MAIN_FUNCTIONW) SvcMain }, - { nullptr, nullptr } - }; + SERVICE_TABLE_ENTRYW DispatchTable[] = { + { SVC_NAME, (LPSERVICE_MAIN_FUNCTIONW) SvcMain }, + { nullptr, nullptr } + }; - // This call returns when the service has stopped. + // This call returns when the service has stopped. // The process should simply terminate when the call returns. if (!StartServiceCtrlDispatcherW(DispatchTable)) { LOG_WARN(("StartServiceCtrlDispatcher failed. (%d)", GetLastError())); @@ -125,7 +130,7 @@ wmain(int argc, WCHAR **argv) BOOL GetLogDirectoryPath(WCHAR *path) { - HRESULT hr = SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA, nullptr, + HRESULT hr = SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA, nullptr, SHGFP_TYPE_CURRENT, path); if (FAILED(hr)) { return FALSE; @@ -175,7 +180,7 @@ GetBackupLogPath(LPWSTR path, LPCWSTR basePath, int logNumber) * updater1.log -> updater2.log * updater.log -> updater1.log * Which clears room for a new updater.log in the basePath directory - * + * * @param basePath The base directory path where log files are stored * @param numLogsToKeep The number of logs to keep */ @@ -203,14 +208,14 @@ BackupOldLogs(LPCWSTR basePath, int numLogsToKeep) * Ensures the service is shutdown once all work is complete. * There is an issue on XP SP2 and below where the service can hang * in a stop pending state even though the SCM is notified of a stopped - * state. Control *should* be returned to StartServiceCtrlDispatcher from the - * call to SetServiceStatus on a stopped state in the wmain thread. + * state. Control *should* be returned to StartServiceCtrlDispatcher from the + * call to SetServiceStatus on a stopped state in the wmain thread. * Sometimes this is not the case though. This thread will terminate the process * if it has been 5 seconds after all work is done and the process is still not * terminated. This thread is only started once a stopped state was sent to the - * SCM. The stop pending hang can be reproduced intermittently even if you set - * a stopped state dirctly and never set a stop pending state. It is safe to - * forcefully terminate the process ourselves since all work is done once we + * SCM. The stop pending hang can be reproduced intermittently even if you set + * a stopped state dirctly and never set a stop pending state. It is safe to + * forcefully terminate the process ourselves since all work is done once we * start this thread. */ DWORD WINAPI @@ -218,13 +223,12 @@ EnsureProcessTerminatedThread(LPVOID) { Sleep(5000); exit(0); - return 0; } void StartTerminationThread() { - // If the process does not self terminate like it should, this thread + // If the process does not self terminate like it should, this thread // will terminate the process after 5 seconds. HANDLE thread = CreateThread(nullptr, 0, EnsureProcessTerminatedThread, nullptr, 0, nullptr); @@ -254,10 +258,10 @@ SvcMain(DWORD argc, LPWSTR *argv) gSvcStatusHandle = RegisterServiceCtrlHandlerW(SVC_NAME, SvcCtrlHandler); if (!gSvcStatusHandle) { LOG_WARN(("RegisterServiceCtrlHandler failed. (%d)", GetLastError())); - ExecuteServiceCommand(argc, argv); + ExecuteServiceCommand(argc, argv); LogFinish(); exit(1); - } + } // These values will be re-used later in calls involving gSvcStatus gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; @@ -282,7 +286,7 @@ SvcMain(DWORD argc, LPWSTR *argv) // The service command was executed, stop logging and set an event // to indicate the work is done in case someone is waiting on a // service stop operation. - ExecuteServiceCommand(argc, argv); + ExecuteServiceCommand(argc, argv); LogFinish(); SetEvent(gWorkDoneEvent); @@ -298,14 +302,14 @@ SvcMain(DWORD argc, LPWSTR *argv) /** * Sets the current service status and reports it to the SCM. - * + * * @param currentState The current state (see SERVICE_STATUS) * @param exitCode The system error code * @param waitHint Estimated time for pending operation in milliseconds */ void -ReportSvcStatus(DWORD currentState, - DWORD exitCode, +ReportSvcStatus(DWORD currentState, + DWORD exitCode, DWORD waitHint) { static DWORD dwCheckPoint = 1; @@ -314,11 +318,11 @@ ReportSvcStatus(DWORD currentState, gSvcStatus.dwWin32ExitCode = exitCode; gSvcStatus.dwWaitHint = waitHint; - if (SERVICE_START_PENDING == currentState || + if (SERVICE_START_PENDING == currentState || SERVICE_STOP_PENDING == currentState) { gSvcStatus.dwControlsAccepted = 0; } else { - gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | + gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; } @@ -334,8 +338,8 @@ ReportSvcStatus(DWORD currentState, } /** - * Since the SvcCtrlHandler should only spend at most 30 seconds before - * returning, this function does the service stop work for the SvcCtrlHandler. + * Since the SvcCtrlHandler should only spend at most 30 seconds before + * returning, this function does the service stop work for the SvcCtrlHandler. */ DWORD WINAPI StopServiceAndWaitForCommandThread(LPVOID) @@ -363,15 +367,15 @@ SvcCtrlHandler(DWORD dwCtrl) return; } - // Handle the requested control code. + // Handle the requested control code. switch(dwCtrl) { case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_STOP: { gServiceControlStopping = true; ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 1000); - // The SvcCtrlHandler thread should not spend more than 30 seconds in - // shutdown so we spawn a new thread for stopping the service + // The SvcCtrlHandler thread should not spend more than 30 seconds in + // shutdown so we spawn a new thread for stopping the service HANDLE thread = CreateThread(nullptr, 0, StopServiceAndWaitForCommandThread, nullptr, 0, nullptr); diff --git a/onlineupdate/source/service/registrycertificates.cxx b/onlineupdate/source/service/registrycertificates.cxx index a07faf9423c3..f44fb3427d00 100644 --- a/onlineupdate/source/service/registrycertificates.cxx +++ b/onlineupdate/source/service/registrycertificates.cxx @@ -6,13 +6,46 @@ #include #include +#include + #include "registrycertificates.hxx" -#include "pathhash.hxx" -#include "nsWindowsHelpers.hxx" +#include "pathhash.h" #include "servicebase.hxx" -#include "updatehelper.hxx" +#include "updatehelper.h" #define MAX_KEY_LENGTH 255 +namespace { + +struct AutoRegKey +{ + AutoRegKey(HKEY key): + mKey(key) + { + } + + ~AutoRegKey() + { + releaseKey(mKey); + } + + void releaseKey(HKEY key) + { + if (key != nullptr) + { + RegCloseKey(key); + } + } + + HKEY mKey; + + HKEY get() + { + return mKey; + } +}; + +} + /** * Verifies if the file path matches any certificate stored in the registry. * @@ -21,9 +54,9 @@ */ BOOL DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) -{ +{ WCHAR maintenanceServiceKey[MAX_PATH + 1]; - if (!CalculateRegistryPathFromFilePath(basePathForUpdate, + if (!CalculateRegistryPathFromFilePath(basePathForUpdate, maintenanceServiceKey)) { return FALSE; } @@ -35,15 +68,15 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) // force the non redirected registry under Wow6432Node. // This flag is ignored on 32bit systems. HKEY baseKeyRaw; - LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - maintenanceServiceKey, 0, + LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + maintenanceServiceKey, 0, KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw); 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 + // We use this registry key on our test slaves to store the // allowed name/issuers. - retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEST_ONLY_FALLBACK_KEY_PATH, 0, KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw); if (retCode != ERROR_SUCCESS) { @@ -51,11 +84,11 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) return FALSE; } } - nsAutoRegKey baseKey(baseKeyRaw); + AutoRegKey baseKey(baseKeyRaw); // Get the number of subkeys. DWORD subkeyCount = 0; - retCode = RegQueryInfoKeyW(baseKey, nullptr, nullptr, nullptr, &subkeyCount, + retCode = RegQueryInfoKeyW(baseKey.get(), nullptr, nullptr, nullptr, &subkeyCount, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (retCode != ERROR_SUCCESS) { @@ -64,12 +97,12 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) } // Enumerate the subkeys, each subkey represents an allowed certificate. - for (DWORD i = 0; i < subkeyCount; i++) { + 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); + DWORD subkeyBufferCount = MAX_KEY_LENGTH; + retCode = RegEnumKeyExW(baseKey.get(), i, subkeyBuffer, + &subkeyBufferCount, nullptr, + nullptr, nullptr, nullptr); if (retCode != ERROR_SUCCESS) { LOG_WARN(("Could not enum certs. (%d)", retCode)); return FALSE; @@ -77,12 +110,12 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) // Open the subkey for the current certificate HKEY subKeyRaw; - retCode = RegOpenKeyExW(baseKey, - subkeyBuffer, - 0, - KEY_READ | KEY_WOW64_64KEY, + retCode = RegOpenKeyExW(baseKey.get(), + subkeyBuffer, + 0, + KEY_READ | KEY_WOW64_64KEY, &subKeyRaw); - nsAutoRegKey subKey(subKeyRaw); + AutoRegKey subKey(subKeyRaw); if (retCode != ERROR_SUCCESS) { LOG_WARN(("Could not open subkey. (%d)", retCode)); continue; // Try the next subkey @@ -94,7 +127,7 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) WCHAR issuer[MAX_CHAR_COUNT] = { L'\0' }; // Get the name from the registry - retCode = RegQueryValueExW(subKey, L"name", 0, nullptr, + retCode = RegQueryValueExW(subKey.get(), L"name", 0, nullptr, (LPBYTE)name, &valueBufSize); if (retCode != ERROR_SUCCESS) { LOG_WARN(("Could not obtain name from registry. (%d)", retCode)); @@ -103,7 +136,7 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) // Get the issuer from the registry valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR); - retCode = RegQueryValueExW(subKey, L"issuer", 0, nullptr, + retCode = RegQueryValueExW(subKey.get(), L"issuer", 0, nullptr, (LPBYTE)issuer, &valueBufSize); if (retCode != ERROR_SUCCESS) { LOG_WARN(("Could not obtain issuer from registry. (%d)", retCode)); @@ -111,8 +144,8 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) } CertificateCheckInfo allowedCertificate = { - name, - issuer, + name, + issuer, }; retCode = CheckCertificateForPEFile(filePath, allowedCertificate); @@ -128,9 +161,9 @@ DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) } // Raise the roof, we found a match! - return TRUE; + return TRUE; } - + // No certificates match, :'( return FALSE; } diff --git a/onlineupdate/source/service/servicebase.cxx b/onlineupdate/source/service/servicebase.cxx index 2bed24be1cdb..1b4f406f431e 100644 --- a/onlineupdate/source/service/servicebase.cxx +++ b/onlineupdate/source/service/servicebase.cxx @@ -3,10 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "servicebase.hxx" -#include "nsWindowsHelpers.hxx" +#include "windowsHelper.hxx" // Shared code between applications and updater.exe -#include "nsWindowsRestart.cpp" /** * Verifies if 2 files are byte for byte equivalent. @@ -20,19 +19,19 @@ BOOL VerifySameFiles(LPCWSTR file1Path, LPCWSTR file2Path, BOOL &sameContent) { sameContent = FALSE; - nsAutoHandle file1(CreateFileW(file1Path, GENERIC_READ, FILE_SHARE_READ, + AutoHandle file1(CreateFileW(file1Path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr)); - if (INVALID_HANDLE_VALUE == file1) { + if (file1 == INVALID_HANDLE_VALUE) { return FALSE; } - nsAutoHandle file2(CreateFileW(file2Path, GENERIC_READ, FILE_SHARE_READ, + AutoHandle file2(CreateFileW(file2Path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr)); - if (INVALID_HANDLE_VALUE == file2) { + if (file2 == INVALID_HANDLE_VALUE) { return FALSE; } - DWORD fileSize1 = GetFileSize(file1, nullptr); - DWORD fileSize2 = GetFileSize(file2, nullptr); + DWORD fileSize1 = GetFileSize(file1.get(), nullptr); + DWORD fileSize2 = GetFileSize(file2.get(), nullptr); if (INVALID_FILE_SIZE == fileSize1 || INVALID_FILE_SIZE == fileSize2) { return FALSE; } @@ -48,12 +47,12 @@ VerifySameFiles(LPCWSTR file1Path, LPCWSTR file2Path, BOOL &sameContent) DWORD leftOver = fileSize1 % COMPARE_BLOCKSIZE; DWORD readAmount; for (DWORD i = 0; i < numBlocks; i++) { - if (!ReadFile(file1, buf1, COMPARE_BLOCKSIZE, &readAmount, nullptr) || + if (!ReadFile(file1.get(), buf1, COMPARE_BLOCKSIZE, &readAmount, nullptr) || readAmount != COMPARE_BLOCKSIZE) { return FALSE; } - if (!ReadFile(file2, buf2, COMPARE_BLOCKSIZE, &readAmount, nullptr) || + if (!ReadFile(file2.get(), buf2, COMPARE_BLOCKSIZE, &readAmount, nullptr) || readAmount != COMPARE_BLOCKSIZE) { return FALSE; } @@ -65,12 +64,12 @@ VerifySameFiles(LPCWSTR file1Path, LPCWSTR file2Path, BOOL &sameContent) } if (leftOver) { - if (!ReadFile(file1, buf1, leftOver, &readAmount, nullptr) || + if (!ReadFile(file1.get(), buf1, leftOver, &readAmount, nullptr) || readAmount != leftOver) { return FALSE; } - if (!ReadFile(file2, buf2, leftOver, &readAmount, nullptr) || + if (!ReadFile(file2.get(), buf2, leftOver, &readAmount, nullptr) || readAmount != leftOver) { return FALSE; } diff --git a/onlineupdate/source/service/servicebase.hxx b/onlineupdate/source/service/servicebase.hxx index bf8ed02f16de..0353f7d329bb 100644 --- a/onlineupdate/source/service/servicebase.hxx +++ b/onlineupdate/source/service/servicebase.hxx @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include -#include "updatelogging.hxx" +#include "updatelogging.h" BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra); BOOL VerifySameFiles(LPCWSTR file1Path, LPCWSTR file2Path, BOOL &sameContent); diff --git a/onlineupdate/source/service/serviceinstall.cxx b/onlineupdate/source/service/serviceinstall.cxx index 6e8a598ee995..cf7fef354186 100644 --- a/onlineupdate/source/service/serviceinstall.cxx +++ b/onlineupdate/source/service/serviceinstall.cxx @@ -10,18 +10,58 @@ // Used for DNLEN and UNLEN #include -#include -#include "mozilla/UniquePtr.h" - #include "serviceinstall.hxx" #include "servicebase.hxx" -#include "updatehelper.hxx" -#include "shellapi.hxx" -#include "readstrings.hxx" -#include "errors.hxx" +#include "updatehelper.h" +#include "shellapi.h" +#include "readstrings.h" +#include "errors.h" + +#include #pragma comment(lib, "version.lib") +namespace { + +struct AutoServiceHandle +{ + AutoServiceHandle(SC_HANDLE handle): + mHandle(handle) + { + } + + ~AutoServiceHandle() + { + releaseHandle(mHandle); + } + + void releaseHandle(SC_HANDLE handle) + { + if (handle != nullptr) + CloseServiceHandle(handle); + } + + SC_HANDLE get() const + { + return mHandle; + } + + operator bool() const + { + return mHandle != nullptr; + } + + void reset(SC_HANDLE handle = nullptr) + { + releaseHandle(mHandle); + mHandle = handle; + } + + SC_HANDLE mHandle; +}; + +} + /** * A wrapper function to read strings for the maintenance service. * @@ -30,19 +70,19 @@ * @return OK on success */ static int -ReadMaintenanceServiceStrings(LPCWSTR path, +ReadMaintenanceServiceStrings(LPCWSTR path, MaintenanceServiceStringTable *results) { // Read in the maintenance service description string if specified. const unsigned int kNumStrings = 1; const char *kServiceKeys = "MozillaMaintenanceDescription\0"; char serviceStrings[kNumStrings][MAX_TEXT_LEN]; - int result = ReadStrings(path, kServiceKeys, + int result = ReadStrings(path, kServiceKeys, kNumStrings, serviceStrings); if (result != OK) { serviceStrings[0][0] = '\0'; } - strncpy(results->serviceDescription, + strncpy(results->serviceDescription, serviceStrings[0], MAX_TEXT_LEN - 1); results->serviceDescription[MAX_TEXT_LEN - 1] = '\0'; return result; @@ -51,7 +91,7 @@ ReadMaintenanceServiceStrings(LPCWSTR path, /** * Obtains the version number from the specified PE file's version information * Version Format: A.B.C.D (Example 10.0.0.300) - * + * * @param path The path of the file to check the version on * @param A The first part of the version number * @param B The second part of the version number @@ -60,27 +100,27 @@ ReadMaintenanceServiceStrings(LPCWSTR path, * @return TRUE if successful */ static BOOL -GetVersionNumberFromPath(LPWSTR path, DWORD &A, DWORD &B, - DWORD &C, DWORD &D) +GetVersionNumberFromPath(LPWSTR path, DWORD &A, DWORD &B, + DWORD &C, DWORD &D) { DWORD fileVersionInfoSize = GetFileVersionInfoSizeW(path, 0); - mozilla::UniquePtr fileVersionInfo(new char[fileVersionInfoSize]); + std::unique_ptr fileVersionInfo(new char[fileVersionInfoSize]); if (!GetFileVersionInfoW(path, 0, fileVersionInfoSize, fileVersionInfo.get())) { - LOG_WARN(("Could not obtain file info of old service. (%d)", + LOG_WARN(("Could not obtain file info of old service. (%d)", GetLastError())); return FALSE; } - VS_FIXEDFILEINFO *fixedFileInfo = + VS_FIXEDFILEINFO *fixedFileInfo = reinterpret_cast(fileVersionInfo.get()); UINT size; - if (!VerQueryValueW(fileVersionInfo.get(), L"\\", + if (!VerQueryValueW(fileVersionInfo.get(), L"\\", reinterpret_cast(&fixedFileInfo), &size)) { - LOG_WARN(("Could not query file version info of old service. (%d)", + LOG_WARN(("Could not query file version info of old service. (%d)", GetLastError())); return FALSE; - } + } A = HIWORD(fixedFileInfo->dwFileVersionMS); B = LOWORD(fixedFileInfo->dwFileVersionMS); @@ -93,7 +133,7 @@ GetVersionNumberFromPath(LPWSTR path, DWORD &A, DWORD &B, * Updates the service description with what is stored in updater.ini * at the same path as the currently executing module binary. * - * @param serviceHandle A handle to an opened service with + * @param serviceHandle A handle to an opened service with * SERVICE_CHANGE_CONFIG access right * @param TRUE on succcess. */ @@ -101,7 +141,7 @@ BOOL UpdateServiceDescription(SC_HANDLE serviceHandle) { WCHAR updaterINIPath[MAX_PATH + 1]; - if (!GetModuleFileNameW(nullptr, updaterINIPath, + if (!GetModuleFileNameW(nullptr, updaterINIPath, sizeof(updaterINIPath) / sizeof(updaterINIPath[0]))) { LOG_WARN(("Could not obtain module filename when attempting to " @@ -126,7 +166,7 @@ UpdateServiceDescription(SC_HANDLE serviceHandle) "service description. (%d)", GetLastError())); return FALSE; } - + MaintenanceServiceStringTable serviceStrings; int rv = ReadMaintenanceServiceStrings(updaterINIPath, &serviceStrings); if (rv != OK || !strlen(serviceStrings.serviceDescription)) { @@ -136,10 +176,10 @@ UpdateServiceDescription(SC_HANDLE serviceHandle) } WCHAR serviceDescription[MAX_TEXT_LEN]; - if (!MultiByteToWideChar(CP_UTF8, 0, + if (!MultiByteToWideChar(CP_UTF8, 0, serviceStrings.serviceDescription, -1, serviceDescription, - sizeof(serviceDescription) / + sizeof(serviceDescription) / sizeof(serviceDescription[0]))) { LOG_WARN(("Could not convert description to wide string format. (%d)", GetLastError())); @@ -148,8 +188,8 @@ UpdateServiceDescription(SC_HANDLE serviceHandle) SERVICE_DESCRIPTIONW descriptionConfig; descriptionConfig.lpDescription = serviceDescription; - if (!ChangeServiceConfig2W(serviceHandle, - SERVICE_CONFIG_DESCRIPTION, + if (!ChangeServiceConfig2W(serviceHandle, + SERVICE_CONFIG_DESCRIPTION, &descriptionConfig)) { LOG_WARN(("Could not change service config. (%d)", GetLastError())); return FALSE; @@ -235,7 +275,7 @@ BOOL SvcInstall(SvcInstallAction action) { // Get a handle to the local computer SCM database with full access rights. - nsAutoServiceHandle schSCManager(OpenSCManager(nullptr, nullptr, + AutoServiceHandle schSCManager(OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS)); if (!schSCManager) { LOG_WARN(("Could not open service manager. (%d)", GetLastError())); @@ -243,8 +283,8 @@ SvcInstall(SvcInstallAction action) } WCHAR newServiceBinaryPath[MAX_PATH + 1]; - if (!GetModuleFileNameW(nullptr, newServiceBinaryPath, - sizeof(newServiceBinaryPath) / + if (!GetModuleFileNameW(nullptr, newServiceBinaryPath, + sizeof(newServiceBinaryPath) / sizeof(newServiceBinaryPath[0]))) { LOG_WARN(("Could not obtain module filename when attempting to " "install service. (%d)", @@ -253,8 +293,8 @@ SvcInstall(SvcInstallAction action) } // Check if we already have the service installed. - nsAutoServiceHandle schService(OpenServiceW(schSCManager, - SVC_NAME, + AutoServiceHandle schService(OpenServiceW(schSCManager.get(), + SVC_NAME, SERVICE_ALL_ACCESS)); DWORD lastError = GetLastError(); if (!schService && ERROR_SERVICE_DOES_NOT_EXIST != lastError) { @@ -262,13 +302,13 @@ SvcInstall(SvcInstallAction action) LOG_WARN(("Could not open service. (%d)", GetLastError())); return FALSE; } - + if (schService) { // The service exists but it may not have the correct permissions. // This could happen if the permissions were not set correctly originally - // or have been changed after the installation. This will reset the + // or have been changed after the installation. This will reset the // permissions back to allow limited user accounts. - if (!SetUserAccessServiceDACL(schService)) { + if (!SetUserAccessServiceDACL(schService.get())) { LOG_WARN(("Could not reset security ACE on service handle. It might not be " "possible to start the service. This error should never " "happen. (%d)", GetLastError())); @@ -276,31 +316,31 @@ SvcInstall(SvcInstallAction action) // The service exists and we opened it DWORD bytesNeeded; - if (!QueryServiceConfigW(schService, nullptr, 0, &bytesNeeded) && + if (!QueryServiceConfigW(schService.get(), nullptr, 0, &bytesNeeded) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) { LOG_WARN(("Could not determine buffer size for query service config. (%d)", GetLastError())); return FALSE; } - // Get the service config information, in particular we want the binary + // Get the service config information, in particular we want the binary // path of the service. - mozilla::UniquePtr serviceConfigBuffer(new char[bytesNeeded]); - if (!QueryServiceConfigW(schService, - reinterpret_cast(serviceConfigBuffer.get()), + std::unique_ptr serviceConfigBuffer(new char[bytesNeeded]); + if (!QueryServiceConfigW(schService.get(), + reinterpret_cast(serviceConfigBuffer.get()), bytesNeeded, &bytesNeeded)) { LOG_WARN(("Could open service but could not query service config. (%d)", GetLastError())); return FALSE; } - QUERY_SERVICE_CONFIGW &serviceConfig = + QUERY_SERVICE_CONFIGW &serviceConfig = *reinterpret_cast(serviceConfigBuffer.get()); // Check if we need to fix the service path BOOL servicePathWasWrong; static BOOL alreadyCheckedFixServicePath = FALSE; if (!alreadyCheckedFixServicePath) { - if (!FixServicePath(schService, serviceConfig.lpBinaryPathName, + if (!FixServicePath(schService.get(), serviceConfig.lpBinaryPathName, servicePathWasWrong)) { LOG_WARN(("Could not fix service path. This should never happen. (%d)", GetLastError())); @@ -329,31 +369,31 @@ SvcInstall(SvcInstallAction action) // the new file's version number. Versions are in the format of // A.B.C.D. DWORD existingA, existingB, existingC, existingD; - DWORD newA, newB, newC, newD; - BOOL obtainedExistingVersionInfo = - GetVersionNumberFromPath(serviceConfig.lpBinaryPathName, - existingA, existingB, + DWORD newA, newB, newC, newD; + BOOL obtainedExistingVersionInfo = + GetVersionNumberFromPath(serviceConfig.lpBinaryPathName, + existingA, existingB, existingC, existingD); - if (!GetVersionNumberFromPath(newServiceBinaryPath, newA, + if (!GetVersionNumberFromPath(newServiceBinaryPath, newA, newB, newC, newD)) { LOG_WARN(("Could not obtain version number from new path")); return FALSE; } // Check if we need to replace the old binary with the new one - // If we couldn't get the old version info then we assume we should + // If we couldn't get the old version info then we assume we should // replace it. if (ForceInstallSvc == action || - !obtainedExistingVersionInfo || + !obtainedExistingVersionInfo || (existingA < newA) || (existingA == newA && existingB < newB) || - (existingA == newA && existingB == newB && + (existingA == newA && existingB == newB && existingC < newC) || - (existingA == newA && existingB == newB && + (existingA == newA && existingB == newB && existingC == newC && existingD < newD)) { // We have a newer updater, so update the description from the INI file. - UpdateServiceDescription(schService); + UpdateServiceDescription(schService.get()); schService.reset(); if (!StopService()) { @@ -371,7 +411,7 @@ SvcInstall(SvcInstallAction action) // Attempt to copy the new binary over top the existing binary. // If there is an error we try to move it out of the way and then // copy it in. First try the safest / easiest way to overwrite the file. - if (!CopyFileW(newServiceBinaryPath, + if (!CopyFileW(newServiceBinaryPath, serviceConfig.lpBinaryPathName, FALSE)) { LOG_WARN(("Could not overwrite old service binary file. " "This should never happen, but if it does the next " @@ -383,9 +423,9 @@ SvcInstall(SvcInstallAction action) // verify there are more than 3 chars for safe failure in MoveFileExW. const size_t len = wcslen(serviceConfig.lpBinaryPathName); if (len > 3) { - // Calculate the temp file path that we're moving the file to. This + // Calculate the temp file path that we're moving the file to. This // is the same as the proper service path but with a .old extension. - LPWSTR oldServiceBinaryTempPath = + LPWSTR oldServiceBinaryTempPath = new WCHAR[len + 1]; memset(oldServiceBinaryTempPath, 0, (len + 1) * sizeof (WCHAR)); wcsncpy(oldServiceBinaryTempPath, serviceConfig.lpBinaryPathName, len); @@ -393,11 +433,11 @@ SvcInstall(SvcInstallAction action) wcsncpy(oldServiceBinaryTempPath + len - 3, L"old", 3); // Move the current (old) service file to the temp path. - if (MoveFileExW(serviceConfig.lpBinaryPathName, - oldServiceBinaryTempPath, + if (MoveFileExW(serviceConfig.lpBinaryPathName, + oldServiceBinaryTempPath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { // The old binary is moved out of the way, copy in the new one. - if (!CopyFileW(newServiceBinaryPath, + if (!CopyFileW(newServiceBinaryPath, serviceConfig.lpBinaryPathName, FALSE)) { // It is best to leave the old service binary in this condition. LOG_WARN(("The new service binary could not be copied in." @@ -447,7 +487,7 @@ SvcInstall(SvcInstallAction action) LOG_WARN(("Call to delete the old file path failed: %ls.", newServiceBinaryPath)); } - + return result; } @@ -455,11 +495,11 @@ SvcInstall(SvcInstallAction action) // The tmp file (the process of which we are executing right now) will be // left over. Attempt to delete the file on the next reboot. MoveFileExW(newServiceBinaryPath, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); - + // nothing to do, we already have a newer service installed - return TRUE; + return TRUE; } - + // If the service does not exist and we are upgrading, don't install it. if (UpgradeSvc == action) { // The service does not exist and we are upgrading, so don't install it @@ -469,7 +509,7 @@ SvcInstall(SvcInstallAction action) // Quote the path only if it contains spaces. PathQuoteSpacesW(newServiceBinaryPath); // The service does not already exist so create the service as on demand - schService.own(CreateServiceW(schSCManager, SVC_NAME, SVC_DISPLAY_NAME, + schService.reset(CreateServiceW(schSCManager.get(), SVC_NAME, SVC_DISPLAY_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, newServiceBinaryPath, nullptr, nullptr, @@ -479,16 +519,16 @@ SvcInstall(SvcInstallAction action) "This error should never happen since a service install " "should only be called when elevated. (%d)", GetLastError())); return FALSE; - } + } - if (!SetUserAccessServiceDACL(schService)) { + if (!SetUserAccessServiceDACL(schService.get())) { LOG_WARN(("Could not set security ACE on service handle, the service will not " "be able to be started from unelevated processes. " "This error should never happen. (%d)", GetLastError())); } - UpdateServiceDescription(schService); + UpdateServiceDescription(schService.get()); return TRUE; } @@ -502,7 +542,7 @@ BOOL StopService() { // Get a handle to the local computer SCM database with full access rights. - nsAutoServiceHandle schSCManager(OpenSCManager(nullptr, nullptr, + AutoServiceHandle schSCManager(OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS)); if (!schSCManager) { LOG_WARN(("Could not open service manager. (%d)", GetLastError())); @@ -510,17 +550,17 @@ StopService() } // Open the service - nsAutoServiceHandle schService(OpenServiceW(schSCManager, SVC_NAME, + AutoServiceHandle schService(OpenServiceW(schSCManager.get(), SVC_NAME, SERVICE_ALL_ACCESS)); if (!schService) { LOG_WARN(("Could not open service. (%d)", GetLastError())); return FALSE; - } + } LOG(("Sending stop request...")); SERVICE_STATUS status; SetLastError(ERROR_SUCCESS); - if (!ControlService(schService, SERVICE_CONTROL_STOP, &status) && + if (!ControlService(schService.get(), SERVICE_CONTROL_STOP, &status) && GetLastError() != ERROR_SERVICE_NOT_ACTIVE) { LOG_WARN(("Error sending stop request. (%d)", GetLastError())); } @@ -548,7 +588,7 @@ BOOL SvcUninstall() { // Get a handle to the local computer SCM database with full access rights. - nsAutoServiceHandle schSCManager(OpenSCManager(nullptr, nullptr, + AutoServiceHandle schSCManager(OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS)); if (!schSCManager) { LOG_WARN(("Could not open service manager. (%d)", GetLastError())); @@ -556,19 +596,19 @@ SvcUninstall() } // Open the service - nsAutoServiceHandle schService(OpenServiceW(schSCManager, SVC_NAME, + AutoServiceHandle schService(OpenServiceW(schSCManager.get(), SVC_NAME, SERVICE_ALL_ACCESS)); if (!schService) { LOG_WARN(("Could not open service. (%d)", GetLastError())); return FALSE; - } + } //Stop the service so it deletes faster and so the uninstaller // can actually delete its EXE. DWORD totalWaitTime = 0; SERVICE_STATUS status; static const int maxWaitTime = 1000 * 60; // Never wait more than a minute - if (ControlService(schService, SERVICE_CONTROL_STOP, &status)) { + if (ControlService(schService.get(), SERVICE_CONTROL_STOP, &status)) { do { Sleep(status.dwWaitHint); totalWaitTime += (status.dwWaitHint + 10); @@ -577,11 +617,11 @@ SvcUninstall() } else if (totalWaitTime > maxWaitTime) { break; } - } while (QueryServiceStatus(schService, &status)); + } while (QueryServiceStatus(schService.get(), &status)); } // Delete the service or mark it for deletion - BOOL deleted = DeleteService(schService); + BOOL deleted = DeleteService(schService.get()); if (!deleted) { deleted = (GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE); } @@ -619,12 +659,12 @@ SetUserAccessServiceDACL(SC_HANDLE hService) * @return ERROR_SUCCESS if successful */ DWORD -SetUserAccessServiceDACL(SC_HANDLE hService, PACL &pNewAcl, +SetUserAccessServiceDACL(SC_HANDLE hService, PACL &pNewAcl, PSECURITY_DESCRIPTOR psd) { // Get the current security descriptor needed size DWORD needed = 0; - if (!QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, + if (!QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, &psd, 0, &needed)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { LOG_WARN(("Could not query service object security size. (%d)", @@ -641,7 +681,7 @@ SetUserAccessServiceDACL(SC_HANDLE hService, PACL &pNewAcl, } // Get the actual security descriptor now - if (!QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, + if (!QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, psd, size, &needed)) { LOG_WARN(("Could not allocate security descriptor. (%d)", GetLastError())); @@ -653,7 +693,7 @@ SetUserAccessServiceDACL(SC_HANDLE hService, PACL &pNewAcl, PACL pacl = nullptr; BOOL bDaclPresent = FALSE; BOOL bDaclDefaulted = FALSE; - if ( !GetSecurityDescriptorDacl(psd, &bDaclPresent, &pacl, + if ( !GetSecurityDescriptorDacl(psd, &bDaclPresent, &pacl, &bDaclDefaulted)) { LOG_WARN(("Could not obtain DACL. (%d)", GetLastError())); return GetLastError(); @@ -682,8 +722,8 @@ SetUserAccessServiceDACL(SC_HANDLE hService, PACL &pNewAcl, WCHAR domainName[DNLEN + 1] = { L'\0' }; DWORD accountNameSize = UNLEN + 1; DWORD domainNameSize = DNLEN + 1; - if (!LookupAccountSidW(nullptr, sid, accountName, - &accountNameSize, + if (!LookupAccountSidW(nullptr, sid, accountName, + &accountNameSize, domainName, &domainNameSize, &accountType)) { LOG_WARN(("Could not lookup account Sid, will try Users. (%d)", GetLastError())); @@ -696,8 +736,8 @@ SetUserAccessServiceDACL(SC_HANDLE hService, PACL &pNewAcl, // Build the ACE, BuildExplicitAccessWithName cannot fail so it is not logged. EXPLICIT_ACCESS ea; - BuildExplicitAccessWithNameW(&ea, accountName, - SERVICE_START | SERVICE_STOP | GENERIC_READ, + BuildExplicitAccessWithNameW(&ea, accountName, + SERVICE_START | SERVICE_STOP | GENERIC_READ, SET_ACCESS, NO_INHERITANCE); DWORD lastError = SetEntriesInAclW(1, (PEXPLICIT_ACCESS)&ea, pacl, &pNewAcl); if (ERROR_SUCCESS != lastError) { diff --git a/onlineupdate/source/service/windowsHelper.hxx b/onlineupdate/source/service/windowsHelper.hxx new file mode 100644 index 000000000000..584fa63f43bf --- /dev/null +++ b/onlineupdate/source/service/windowsHelper.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * 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/. + */ + +#ifndef INCLUDED_ONLINEUPDATE_SERVICE_WINDOWSHELPER_HXX +#define INCLUDED_ONLINEUPDATE_SERVICE_WINDOWSHELPER_HXX + +struct AutoHandle +{ + AutoHandle(HANDLE handle): + mHandle(handle) + { + } + + ~AutoHandle() + { + release(mHandle); + } + + void release(HANDLE handle) + { + if (handle && handle != INVALID_HANDLE_VALUE) + { + CloseHandle(handle); + } + } + + HANDLE get() const + { + return mHandle; + } + + bool operator==(const AutoHandle& rhs) + { + return mHandle == rhs.mHandle; + } + + HANDLE mHandle; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/onlineupdate/source/service/workmonitor.cxx b/onlineupdate/source/service/workmonitor.cxx index 1aa6c7fb1b61..f27a9147f4d6 100644 --- a/onlineupdate/source/service/workmonitor.cxx +++ b/onlineupdate/source/service/workmonitor.cxx @@ -7,6 +7,7 @@ #include #include #include +#include #pragma comment(lib, "wtsapi32.lib") #pragma comment(lib, "userenv.lib") @@ -14,23 +15,22 @@ #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 "workmonitor.hxx" +#include "serviceinstall.hxx" +#include "servicebase.hxx" +#include "registrycertificates.hxx" #include "uachelper.h" #include "updatehelper.h" #include "errors.h" +#include "windowsHelper.hxx" // 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; -char16_t* MakeCommandLine(int argc, char16_t **argv); +wchar_t* MakeCommandLine(int argc, wchar_t **argv); BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode); -BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath, +BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath, LPCWSTR newFileName); /* @@ -53,20 +53,20 @@ IsStatusApplying(LPCWSTR updateDirPath, BOOL &isApplying) return FALSE; } - nsAutoHandle statusFile(CreateFileW(updateStatusFilePath, GENERIC_READ, + AutoHandle statusFile(CreateFileW(updateStatusFilePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, 0, nullptr)); - if (INVALID_HANDLE_VALUE == statusFile) { + if (statusFile == INVALID_HANDLE_VALUE) { LOG_WARN(("Could not open update.status file")); return FALSE; } char buf[32] = { 0 }; DWORD read; - if (!ReadFile(statusFile, buf, sizeof(buf), &read, nullptr)) { + if (!ReadFile(statusFile.get(), buf, sizeof(buf), &read, nullptr)) { LOG_WARN(("Could not read from update.status file")); return FALSE; } @@ -378,9 +378,9 @@ ProcessSoftwareUpdateCommand(DWORD argc, LPWSTR *argv) return FALSE; } - nsAutoHandle noWriteLock(CreateFileW(argv[0], GENERIC_READ, FILE_SHARE_READ, + AutoHandle noWriteLock(CreateFileW(argv[0], GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr)); - if (INVALID_HANDLE_VALUE == noWriteLock) { + if (noWriteLock == INVALID_HANDLE_VALUE) { LOG_WARN(("Could not set no write sharing access on file. (%d)", GetLastError())); if (!WriteStatusFailure(argv[1], @@ -401,7 +401,7 @@ ProcessSoftwareUpdateCommand(DWORD argc, LPWSTR *argv) result = FALSE; } - BOOL updaterIsCorrect; + BOOL updaterIsCorrect = FALSE; if (result && !VerifySameFiles(argv[0], installDirUpdater, updaterIsCorrect)) { LOG_WARN(("Error checking if the updaters are the same.\n" -- cgit