diff options
Diffstat (limited to 'onlineupdate/source/service/serviceinstall.cxx')
-rw-r--r-- | onlineupdate/source/service/serviceinstall.cxx | 206 |
1 files changed, 123 insertions, 83 deletions
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 <lm.h> -#include <nsWindowsHelpers.h> -#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 <memory> #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<char[]> fileVersionInfo(new char[fileVersionInfoSize]); + std::unique_ptr<char[]> 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<VS_FIXEDFILEINFO *>(fileVersionInfo.get()); UINT size; - if (!VerQueryValueW(fileVersionInfo.get(), L"\\", + if (!VerQueryValueW(fileVersionInfo.get(), L"\\", 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())); 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<char[]> serviceConfigBuffer(new char[bytesNeeded]); - if (!QueryServiceConfigW(schService, - reinterpret_cast<QUERY_SERVICE_CONFIGW*>(serviceConfigBuffer.get()), + std::unique_ptr<char[]> serviceConfigBuffer(new char[bytesNeeded]); + if (!QueryServiceConfigW(schService.get(), + reinterpret_cast<QUERY_SERVICE_CONFIGW*>(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<QUERY_SERVICE_CONFIGW*>(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) { |