Kaydet (Commit) 7eca4fa0 authored tarafından Markus Mohrhard's avatar Markus Mohrhard

get the update service working

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