// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_INSTALLER_UTIL_INSTALL_SERVICE_WORK_ITEM_IMPL_H_
#define CHROME_INSTALLER_UTIL_INSTALL_SERVICE_WORK_ITEM_IMPL_H_
#include <windows.h>
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_types.h"
#include "chrome/installer/util/work_item_list.h"
namespace base {
class CommandLine;
} // namespace base
namespace installer {
// Helper class for the implementation of InstallServiceWorkItem.
class InstallServiceWorkItemImpl {
public:
struct ServiceConfig {
ServiceConfig();
ServiceConfig(uint32_t service_type,
uint32_t service_start_type,
uint32_t service_error_control,
const std::wstring& service_cmd_line,
const wchar_t* dependencies_multi_sz,
const std::wstring& service_display_name);
ServiceConfig(const ServiceConfig& rhs);
ServiceConfig& operator=(const ServiceConfig& rhs) = default;
ServiceConfig(ServiceConfig&& rhs);
ServiceConfig& operator=(ServiceConfig&& rhs) = default;
~ServiceConfig();
friend bool operator==(const ServiceConfig& lhs, const ServiceConfig& rhs);
bool is_valid = false;
uint32_t type = SERVICE_NO_CHANGE;
uint32_t start_type = SERVICE_NO_CHANGE;
uint32_t error_control = SERVICE_NO_CHANGE;
std::wstring cmd_line;
std::vector<wchar_t> dependencies;
std::wstring display_name;
};
InstallServiceWorkItemImpl(const std::wstring& service_name,
const std::wstring& display_name,
uint32_t start_type,
const base::CommandLine& service_cmd_line,
const base::CommandLine& com_service_cmd_line_args,
const std::wstring& registry_path,
const std::vector<GUID>& clsids,
const std::vector<GUID>& iids);
InstallServiceWorkItemImpl(const InstallServiceWorkItemImpl&) = delete;
InstallServiceWorkItemImpl& operator=(const InstallServiceWorkItemImpl&) =
delete;
~InstallServiceWorkItemImpl();
bool DoImpl();
void RollbackImpl();
bool DeleteServiceImpl();
// Member functions that help with service installation or upgrades.
// `MakeUpgradeServiceConfig()` returns a differential `ServiceConfig` that
// facilitates passing it with minimal changes subsequently to
// `ChangeServiceConfig()`. This way, `ChangeServiceConfig()` only asks the
// Windows SCM to make changes where they differ from the existing service
// configuration.
ServiceConfig MakeUpgradeServiceConfig(const ServiceConfig& original_config);
// Takes the `new_config` returned by `MakeUpgradeServiceConfig()` and
// returns true if `new_config` does not match the default configuration.
bool IsUpgradeNeeded(const ServiceConfig& new_config);
bool ChangeServiceConfig(const ServiceConfig& config);
bool DeleteCurrentService();
// Helper functions for service install/upgrade/delete/rollback.
bool OpenService();
bool GetServiceConfig(ServiceConfig* config) const;
// Stores in the registry a versioned service name generated by
// GenerateVersionedServiceName().
bool CreateAndSetServiceName() const;
// Returns the versioned service name if one exists in the registry under the
// named value service_name_. In other cases, it returns service_name_.
std::wstring GetCurrentServiceName() const;
// Returns a display name of the following format:
// "Chrome Elevation Service (ChromeElevationService)"
// or:
// "Chrome Elevation Service (ChromeElevationService1d59511c58deaa8)"
//
// The "Chrome Elevation Service" fragment is the display_name_, and the
// "ChromeElevationService1d59511c58deaa8" fragment is the versioned service
// name returned from GetCurrentServiceName().
std::wstring GetCurrentServiceDisplayName() const;
// Copies and returns a vector containing a sequence of C-style strings
// terminated with '\0\0'. Return an empty vector if the input is nullptr.
static std::vector<wchar_t> MultiSzToVector(const wchar_t* multi_sz);
private:
class ScHandleTraits {
public:
using Handle = SC_HANDLE;
ScHandleTraits() = delete;
ScHandleTraits(const ScHandleTraits&) = delete;
ScHandleTraits& operator=(const ScHandleTraits&) = delete;
static bool CloseHandle(SC_HANDLE handle) {
return ::CloseServiceHandle(handle) != FALSE;
}
static bool IsHandleValid(SC_HANDLE handle) { return handle != nullptr; }
static SC_HANDLE NullHandle() { return nullptr; }
};
using ScopedScHandle =
base::win::GenericScopedHandle<ScHandleTraits,
base::win::DummyVerifierTraits>;
// This is the core functionality for installing the Windows Service itself.
bool DoInstallService();
// This is the core functionality for COM registration for the Service.
bool DoComRegistration();
// Member functions that help with service installation or upgrades.
bool InstallNewService();
// Upgrades an existing service's configuration in-place. Returns true if the
// service was already properly configured, or if it was successfully
// upgraded; otherwise, returns false in case of any failure.
// Side-effects of this function:
// * Saves the original service's config in |original_service_config_| if
// the new service configuration will be different.
// |original_service_config_| is used in rollback scenarios, specifically
// in ReinstallOriginalService() and RestoreOriginalServiceConfig().
// * Sets |rollback_existing_service_| to true if the service is
// successfully upgraded, which is used by RollbackImpl().
bool UpgradeService();
// Member functions that help with rollbacks.
bool ReinstallOriginalService();
bool RestoreOriginalServiceConfig();
// Helper functions for service install/upgrade/delete/rollback.
bool InstallService(const ServiceConfig& config);
bool DeleteService(ScopedScHandle service) const;
// Generates a versioned service name prefixed with service_name_ and suffixed
// with the current system time in hexadecimal format.
std::wstring GenerateVersionedServiceName() const;
// Persists the given service name in the registry.
bool SetServiceName(const std::wstring& service_name) const;
// The COM registration is done using a contained WorkItemList.
std::unique_ptr<WorkItemList> com_registration_work_items_;
// The service name, or in the case of a conflict, the prefix for the service
// name.
const std::wstring service_name_;
// The service name displayed to the user.
const std::wstring display_name_;
// The service start options. This parameter is typically SERVICE_AUTO_START
// or SERVICE_DEMAND_START.
const uint32_t start_type_;
// The desired service command line.
const base::CommandLine service_cmd_line_;
// The SCM will pass any switches specified in `com_service_cmd_line_args_` to
// ServiceMain() during COM activation.
const base::CommandLine com_service_cmd_line_args_;
// The path under HKEY_LOCAL_MACHINE where the service persists information,
// such as a versioned service name. For legacy reasons, this path is mapped
// to the 32-bit view of the registry.
const std::wstring registry_path_;
// If COM CLSID/AppId registration is required, |clsids_| would be populated.
const std::vector<GUID> clsids_;
// If COM Interface/Typelib registration is required, |iids_| would be
// populated.
const std::vector<GUID> iids_;
ScopedScHandle scm_;
ScopedScHandle service_;
// Rollback-specific data.
// True if original_service_config_ and service_ are both valid, and the
// former should be applied to the latter on rollback.
bool rollback_existing_service_;
// True if service_ represents a newly-installed service that is to be deleted
// on rollback.
bool rollback_new_service_;
// The configuration of a pre-existing service on the machine that may have
// been modified or deleted.
ServiceConfig original_service_config_;
// The service name prior to any modifications; may be either |service_name_|
// or a value read from the registry.
std::wstring original_service_name_;
// True if a pre-existing service (named |original_service_name_|) could not
// be deleted and still exists on rollback.
bool original_service_still_exists_;
};
} // namespace installer
#endif // CHROME_INSTALLER_UTIL_INSTALL_SERVICE_WORK_ITEM_IMPL_H_