123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- // This macro is used in <wrl/module.h>. Since only the COM functionality is
- // used here (while WinRT isn't being used), define this macro to optimize
- // compilation of <wrl/module.h> for COM-only.
- #ifndef __WRL_CLASSIC_COM_STRICT__
- #define __WRL_CLASSIC_COM_STRICT__
- #endif // __WRL_CLASSIC_COM_STRICT__
- #include "chrome/elevation_service/service_main.h"
- #include <atlsecurity.h>
- #include <sddl.h>
- #include <wrl/module.h>
- #include <type_traits>
- #include "base/command_line.h"
- #include "base/logging.h"
- #include "base/no_destructor.h"
- #include "base/win/scoped_com_initializer.h"
- #include "chrome/elevation_service/elevated_recovery_impl.h"
- #include "chrome/elevation_service/elevator.h"
- #include "chrome/install_static/install_util.h"
- namespace elevation_service {
- namespace {
- // Command line switch "--console" runs the service interactively for
- // debugging purposes.
- constexpr char kConsoleSwitchName[] = "console";
- constexpr wchar_t kWindowsServiceName[] = L"ChromeElevationService";
- } // namespace
- ServiceMain* ServiceMain::GetInstance() {
- static base::NoDestructor<ServiceMain> instance;
- return instance.get();
- }
- bool ServiceMain::InitWithCommandLine(const base::CommandLine* command_line) {
- const base::CommandLine::StringVector args = command_line->GetArgs();
- if (!args.empty()) {
- LOG(ERROR) << "No positional parameters expected.";
- return false;
- }
- // Run interactively if needed.
- if (command_line->HasSwitch(kConsoleSwitchName))
- run_routine_ = &ServiceMain::RunInteractive;
- return true;
- }
- // Start() is the entry point called by WinMain.
- int ServiceMain::Start() {
- return (this->*run_routine_)();
- }
- void ServiceMain::CreateWRLModule() {
- Microsoft::WRL::Module<Microsoft::WRL::OutOfProc>::Create(
- this, &ServiceMain::SignalExit);
- }
- // When _ServiceMain gets called, it initializes COM, and then calls Run().
- // Run() initializes security, then calls RegisterClassObject().
- HRESULT ServiceMain::RegisterClassObject() {
- auto& module = Microsoft::WRL::Module<Microsoft::WRL::OutOfProc>::GetModule();
- // We hand-register a unique CLSID for each Chrome channel.
- Microsoft::WRL::ComPtr<IUnknown> factory;
- unsigned int flags = Microsoft::WRL::ModuleType::OutOfProc;
- HRESULT hr = Microsoft::WRL::Details::CreateClassFactory<
- Microsoft::WRL::SimpleClassFactory<Elevator>>(
- &flags, nullptr, __uuidof(IClassFactory), &factory);
- if (FAILED(hr)) {
- LOG(ERROR) << "Factory creation failed; hr: " << hr;
- return hr;
- }
- Microsoft::WRL::ComPtr<IClassFactory> class_factory;
- hr = factory.As(&class_factory);
- if (FAILED(hr)) {
- LOG(ERROR) << "IClassFactory object creation failed; hr: " << hr;
- return hr;
- }
- // The pointer in this array is unowned. Do not release it.
- IClassFactory* class_factories[] = {class_factory.Get()};
- static_assert(std::extent<decltype(cookies_)>() == std::size(class_factories),
- "Arrays cookies_ and class_factories must be the same size.");
- IID class_ids[] = {install_static::GetElevatorClsid()};
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kElevatorClsIdForTestingSwitch)) {
- class_ids[0] = {kTestElevatorClsid};
- }
- DCHECK_EQ(std::size(cookies_), std::size(class_ids));
- static_assert(std::extent<decltype(cookies_)>() == std::size(class_ids),
- "Arrays cookies_ and class_ids must be the same size.");
- hr = module.RegisterCOMObject(nullptr, class_ids, class_factories, cookies_,
- std::size(cookies_));
- if (FAILED(hr)) {
- LOG(ERROR) << "RegisterCOMObject failed; hr: " << hr;
- return hr;
- }
- return hr;
- }
- void ServiceMain::UnregisterClassObject() {
- auto& module = Microsoft::WRL::Module<Microsoft::WRL::OutOfProc>::GetModule();
- const HRESULT hr =
- module.UnregisterCOMObject(nullptr, cookies_, std::size(cookies_));
- if (FAILED(hr))
- LOG(ERROR) << "UnregisterCOMObject failed; hr: " << hr;
- }
- bool ServiceMain::IsExitSignaled() {
- return exit_signal_.IsSignaled();
- }
- void ServiceMain::ResetExitSignaled() {
- exit_signal_.Reset();
- }
- ServiceMain::ServiceMain()
- : run_routine_(&ServiceMain::RunAsService),
- service_status_handle_(nullptr),
- service_status_(),
- cookies_(),
- exit_signal_(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED) {
- service_status_.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- service_status_.dwCurrentState = SERVICE_STOPPED;
- service_status_.dwControlsAccepted = SERVICE_ACCEPT_STOP;
- }
- ServiceMain::~ServiceMain() = default;
- int ServiceMain::RunAsService() {
- static constexpr SERVICE_TABLE_ENTRY dispatch_table[] = {
- {const_cast<LPTSTR>(kWindowsServiceName), &ServiceMain::ServiceMainEntry},
- {nullptr, nullptr}};
- if (!::StartServiceCtrlDispatcher(dispatch_table)) {
- service_status_.dwWin32ExitCode = ::GetLastError();
- PLOG(ERROR) << "Failed to connect to the service control manager";
- }
- return service_status_.dwWin32ExitCode;
- }
- void ServiceMain::ServiceMainImpl() {
- service_status_handle_ = ::RegisterServiceCtrlHandler(
- kWindowsServiceName, &ServiceMain::ServiceControlHandler);
- if (service_status_handle_ == nullptr) {
- PLOG(ERROR) << "RegisterServiceCtrlHandler failed";
- return;
- }
- SetServiceStatus(SERVICE_RUNNING);
- service_status_.dwWin32ExitCode = ERROR_SUCCESS;
- service_status_.dwCheckPoint = 0;
- service_status_.dwWaitHint = 0;
- // Initialize COM for the current thread.
- base::win::ScopedCOMInitializer com_initializer(
- base::win::ScopedCOMInitializer::kMTA);
- if (!com_initializer.Succeeded()) {
- PLOG(ERROR) << "Failed to initialize COM";
- SetServiceStatus(SERVICE_STOPPED);
- return;
- }
- // When the Run function returns, the service has stopped.
- const HRESULT hr = Run();
- if (FAILED(hr)) {
- service_status_.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
- service_status_.dwServiceSpecificExitCode = hr;
- }
- SetServiceStatus(SERVICE_STOPPED);
- }
- int ServiceMain::RunInteractive() {
- return Run();
- }
- // static
- void ServiceMain::ServiceControlHandler(DWORD control) {
- ServiceMain* self = ServiceMain::GetInstance();
- switch (control) {
- case SERVICE_CONTROL_STOP:
- self->SetServiceStatus(SERVICE_STOP_PENDING);
- self->SignalExit();
- break;
- default:
- break;
- }
- }
- // static
- void WINAPI ServiceMain::ServiceMainEntry(DWORD argc, wchar_t* argv[]) {
- ServiceMain::GetInstance()->ServiceMainImpl();
- }
- void ServiceMain::SetServiceStatus(DWORD state) {
- ::InterlockedExchange(&service_status_.dwCurrentState, state);
- ::SetServiceStatus(service_status_handle_, &service_status_);
- }
- HRESULT ServiceMain::Run() {
- LOG_IF(WARNING, FAILED(CleanupChromeRecoveryDirectory()));
- HRESULT hr = InitializeComSecurity();
- if (FAILED(hr))
- return hr;
- CreateWRLModule();
- hr = RegisterClassObject();
- if (SUCCEEDED(hr)) {
- WaitForExitSignal();
- UnregisterClassObject();
- }
- return hr;
- }
- // static
- HRESULT ServiceMain::InitializeComSecurity() {
- CDacl dacl;
- constexpr BYTE com_rights_execute_local =
- COM_RIGHTS_EXECUTE | COM_RIGHTS_EXECUTE_LOCAL;
- dacl.AddAllowedAce(Sids::System(), com_rights_execute_local);
- dacl.AddAllowedAce(Sids::Admins(), com_rights_execute_local);
- dacl.AddAllowedAce(Sids::Interactive(), com_rights_execute_local);
- CSecurityDesc sd;
- sd.SetDacl(dacl);
- sd.MakeAbsolute();
- sd.SetOwner(Sids::Admins());
- sd.SetGroup(Sids::Admins());
- return ::CoInitializeSecurity(
- const_cast<SECURITY_DESCRIPTOR*>(sd.GetPSECURITY_DESCRIPTOR()), -1,
- nullptr, nullptr, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY,
- nullptr, EOAC_DYNAMIC_CLOAKING | EOAC_NO_CUSTOM_MARSHAL, nullptr);
- }
- void ServiceMain::WaitForExitSignal() {
- exit_signal_.Wait();
- }
- void ServiceMain::SignalExit() {
- exit_signal_.Signal();
- }
- } // namespace elevation_service
|