diff options
author | weitaosu <weitaosu@chromium.org> | 2015-02-06 15:18:29 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-06 23:19:13 +0000 |
commit | 69cccfced484ec798815c5804f7b9825c3e5da9e (patch) | |
tree | 77b1fcfb56c10e0bb9f259a3449f0d1281b8f34f /remoting/host/setup | |
parent | c2e11810044fe5ff1c1b8588103671925a5b74fe (diff) | |
download | chromium_src-69cccfced484ec798815c5804f7b9825c3e5da9e.zip chromium_src-69cccfced484ec798815c5804f7b9825c3e5da9e.tar.gz chromium_src-69cccfced484ec798815c5804f7b9825c3e5da9e.tar.bz2 |
Move the |ElevatedDaemonController| implementation to |DaemonControllerDelegateWin|
Changes in this CL include:
1. Moved the daemon controller implemetation from |ElevatedDaemonController| to |DaemonControllerDelegateWin|
2. Removed all code related to COM activation in |DaemonControllerDelegateWin|.
3. Removed code related to SetOwnerWindow in |DaemonControllerDelegateWin|.
4. Removed code related to the pin confirmation dialog in |DaemonControllerDelegateWin|
5. Cleaned up the COM-styled code to make it adhere to the chromium coding styles.
BUG=453172
Review URL: https://codereview.chromium.org/877343004
Cr-Commit-Position: refs/heads/master@{#315129}
Diffstat (limited to 'remoting/host/setup')
-rw-r--r-- | remoting/host/setup/daemon_controller_delegate_win.cc | 615 | ||||
-rw-r--r-- | remoting/host/setup/daemon_controller_delegate_win.h | 32 |
2 files changed, 337 insertions, 310 deletions
diff --git a/remoting/host/setup/daemon_controller_delegate_win.cc b/remoting/host/setup/daemon_controller_delegate_win.cc index e174328..c771b15 100644 --- a/remoting/host/setup/daemon_controller_delegate_win.cc +++ b/remoting/host/setup/daemon_controller_delegate_win.cc @@ -5,60 +5,211 @@ #include "remoting/host/setup/daemon_controller_delegate_win.h" #include "base/basictypes.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/logging.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" #include "base/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "base/timer/timer.h" #include "base/values.h" #include "base/win/scoped_bstr.h" -#include "base/win/scoped_comptr.h" #include "base/win/windows_version.h" #include "remoting/base/scoped_sc_handle_win.h" #include "remoting/host/branding.h" -// chromoting_lib.h contains MIDL-generated declarations. -#include "remoting/host/chromoting_lib.h" +#include "remoting/host/host_config.h" #include "remoting/host/usage_stats_consent.h" - -using base::win::ScopedBstr; -using base::win::ScopedComPtr; +#include "remoting/host/win/security_descriptor.h" namespace remoting { namespace { -// ProgID of the daemon controller. -const wchar_t kDaemonController[] = - L"ChromotingElevatedController.ElevatedController"; +// The maximum size of the configuration file. "1MB ought to be enough" for any +// reasonable configuration we will ever need. 1MB is low enough to make +// the probability of out of memory situation fairly low. OOM is still possible +// and we will crash if it occurs. +const size_t kMaxConfigFileSize = 1024 * 1024; + +// The host configuration file name. +const base::FilePath::CharType kConfigFileName[] = + FILE_PATH_LITERAL("host.json"); + +// The unprivileged configuration file name. +const base::FilePath::CharType kUnprivilegedConfigFileName[] = + FILE_PATH_LITERAL("host_unprivileged.json"); + +// The extension for the temporary file. +const base::FilePath::CharType kTempFileExtension[] = + FILE_PATH_LITERAL("json~"); + +// The host configuration file security descriptor that enables full access to +// Local System and built-in administrators only. +const char kConfigFileSecurityDescriptor[] = + "O:BAG:BAD:(A;;GA;;;SY)(A;;GA;;;BA)"; + +const char kUnprivilegedConfigFileSecurityDescriptor[] = + "O:BAG:BAD:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;AU)"; + +// Configuration keys. + +// The configuration keys that cannot be specified in UpdateConfig(). +const char* const kReadonlyKeys[] = { + kHostIdConfigPath, kHostOwnerConfigPath, kHostOwnerEmailConfigPath, + kXmppLoginConfigPath }; + +// The configuration keys whose values may be read by GetConfig(). +const char* const kUnprivilegedConfigKeys[] = { + kHostIdConfigPath, kXmppLoginConfigPath }; + +// Reads and parses the configuration file up to |kMaxConfigFileSize| in +// size. +bool ReadConfig(const base::FilePath& filename, + scoped_ptr<base::DictionaryValue>* config_out) { + std::string file_content; + if (!base::ReadFileToString(filename, &file_content, kMaxConfigFileSize)) { + PLOG(ERROR) << "Failed to read '" << filename.value() << "'."; + return false; + } -// The COM elevation moniker for the Elevated Controller. -const wchar_t kDaemonControllerElevationMoniker[] = - L"Elevation:Administrator!new:" - L"ChromotingElevatedController.ElevatedController"; + // Parse the JSON configuration, expecting it to contain a dictionary. + scoped_ptr<base::Value> value( + base::JSONReader::Read(file_content, base::JSON_ALLOW_TRAILING_COMMAS)); -// The maximum duration of keeping a reference to a privileged instance of -// the Daemon Controller. This effectively reduces number of UAC prompts a user -// sees. -const int kPrivilegedTimeoutSec = 5 * 60; + base::DictionaryValue* dictionary; + if (!value || !value->GetAsDictionary(&dictionary)) { + LOG(ERROR) << "Failed to parse '" << filename.value() << "'."; + return false; + } -// The maximum duration of keeping a reference to an unprivileged instance of -// the Daemon Controller. This interval should not be too long. If upgrade -// happens while there is a live reference to a Daemon Controller instance -// the old binary still can be used. So dropping the references often makes sure -// that the old binary will go away sooner. -const int kUnprivilegedTimeoutSec = 60; + value.release(); + config_out->reset(dictionary); + return true; +} -void ConfigToString(const base::DictionaryValue& config, ScopedBstr* out) { - std::string config_str; - base::JSONWriter::Write(&config, &config_str); - ScopedBstr config_scoped_bstr(base::UTF8ToUTF16(config_str).c_str()); - out->Swap(config_scoped_bstr); +base::FilePath GetTempLocationFor(const base::FilePath& filename) { + return filename.ReplaceExtension(kTempFileExtension); +} + +// Writes a config file to a temporary location. +bool WriteConfigFileToTemp(const base::FilePath& filename, + const char* security_descriptor, + const std::string& content) { + // Create the security descriptor for the configuration file. + ScopedSd sd = ConvertSddlToSd(security_descriptor); + if (!sd) { + PLOG(ERROR) + << "Failed to create a security descriptor for the configuration file"; + return false; + } + + SECURITY_ATTRIBUTES security_attributes = {0}; + security_attributes.nLength = sizeof(security_attributes); + security_attributes.lpSecurityDescriptor = sd.get(); + security_attributes.bInheritHandle = FALSE; + + // Create a temporary file and write configuration to it. + base::FilePath tempname = GetTempLocationFor(filename); + base::win::ScopedHandle file( + CreateFileW(tempname.value().c_str(), + GENERIC_WRITE, + 0, + &security_attributes, + CREATE_ALWAYS, + FILE_FLAG_SEQUENTIAL_SCAN, + nullptr)); + + if (!file.IsValid()) { + PLOG(ERROR) << "Failed to create '" << filename.value() << "'"; + return false; + } + + DWORD written; + if (!::WriteFile(file.Get(), content.c_str(), content.length(), + &written, nullptr)) { + PLOG(ERROR) << "Failed to write to '" << filename.value() << "'"; + return false; + } + + return true; +} + +// Moves a config file from its temporary location to its permanent location. +bool MoveConfigFileFromTemp(const base::FilePath& filename) { + // Now that the configuration is stored successfully replace the actual + // configuration file. + base::FilePath tempname = GetTempLocationFor(filename); + if (!MoveFileExW(tempname.value().c_str(), + filename.value().c_str(), + MOVEFILE_REPLACE_EXISTING)) { + PLOG(ERROR) << "Failed to rename '" << tempname.value() << "' to '" + << filename.value() << "'"; + return false; + } + + return true; +} + +// Writes the configuration file up to |kMaxConfigFileSize| in size. +bool WriteConfig(const std::string& content) { + if (content.length() > kMaxConfigFileSize) { + return false; + } + + // Extract the configuration data that the user will verify. + scoped_ptr<base::Value> config_value(base::JSONReader::Read(content)); + if (!config_value.get()) { + return false; + } + base::DictionaryValue* config_dict = nullptr; + if (!config_value->GetAsDictionary(&config_dict)) { + return false; + } + std::string email; + if (!config_dict->GetString(kHostOwnerEmailConfigPath, &email) && + !config_dict->GetString(kHostOwnerConfigPath, &email) && + !config_dict->GetString(kXmppLoginConfigPath, &email)) { + return false; + } + std::string host_id, host_secret_hash; + if (!config_dict->GetString(kHostIdConfigPath, &host_id) || + !config_dict->GetString(kHostSecretHashConfigPath, &host_secret_hash)) { + return false; + } + + // Extract the unprivileged fields from the configuration. + base::DictionaryValue unprivileged_config_dict; + for (int i = 0; i < arraysize(kUnprivilegedConfigKeys); ++i) { + const char* key = kUnprivilegedConfigKeys[i]; + base::string16 value; + if (config_dict->GetString(key, &value)) { + unprivileged_config_dict.SetString(key, value); + } + } + std::string unprivileged_config_str; + base::JSONWriter::Write(&unprivileged_config_dict, &unprivileged_config_str); + + // Write the full configuration file to a temporary location. + base::FilePath full_config_file_path = + remoting::GetConfigDir().Append(kConfigFileName); + if (!WriteConfigFileToTemp(full_config_file_path, + kConfigFileSecurityDescriptor, + content)) { + return false; + } + + // Write the unprivileged configuration file to a temporary location. + base::FilePath unprivileged_config_file_path = + remoting::GetConfigDir().Append(kUnprivilegedConfigFileName); + if (!WriteConfigFileToTemp(unprivileged_config_file_path, + kUnprivilegedConfigFileSecurityDescriptor, + unprivileged_config_str)) { + return false; + } + + // Move the full and unprivileged configuration files to their permanent + // locations. + return MoveConfigFileFromTemp(full_config_file_path) && + MoveConfigFileFromTemp(unprivileged_config_file_path); } DaemonController::State ConvertToDaemonState(DWORD service_state) { @@ -87,76 +238,123 @@ DaemonController::State ConvertToDaemonState(DWORD service_state) { } } -DWORD OpenService(ScopedScHandle* service_out) { +ScopedScHandle OpenService(DWORD access) { // Open the service and query its current state. ScopedScHandle scmanager( ::OpenSCManagerW(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE)); if (!scmanager.IsValid()) { - DWORD error = GetLastError(); PLOG(ERROR) << "Failed to connect to the service control manager"; - return error; + return ScopedScHandle(); } ScopedScHandle service(::OpenServiceW(scmanager.Get(), kWindowsServiceName, - SERVICE_QUERY_STATUS)); + access)); if (!service.IsValid()) { - DWORD error = GetLastError(); - if (error != ERROR_SERVICE_DOES_NOT_EXIST) { - PLOG(ERROR) << "Failed to open to the '" << kWindowsServiceName - << "' service"; - } - return error; + PLOG(ERROR) << "Failed to open to the '" << kWindowsServiceName + << "' service"; } - service_out->Set(service.Take()); - return ERROR_SUCCESS; + return service.Pass(); } -DaemonController::AsyncResult HResultToAsyncResult( - HRESULT hr) { - if (SUCCEEDED(hr)) { - return DaemonController::RESULT_OK; - } else if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) { - return DaemonController::RESULT_CANCELLED; - } else { - // TODO(sergeyu): Report other errors to the webapp once it knows - // how to handle them. - return DaemonController::RESULT_FAILED; - } +void InvokeCompletionCallback( + const DaemonController::CompletionCallback& done, bool success) { + DaemonController::AsyncResult async_result = + success ? DaemonController::RESULT_OK : DaemonController::RESULT_FAILED; + done.Run(async_result); } -void InvokeCompletionCallback( - const DaemonController::CompletionCallback& done, HRESULT hr) { - done.Run(HResultToAsyncResult(hr)); +bool SetConfig(const std::string& config) { + // Determine the config directory path and create it if necessary. + base::FilePath config_dir = remoting::GetConfigDir(); + if (!base::CreateDirectory(config_dir)) { + PLOG(ERROR) << "Failed to create the config directory."; + return false; + } + + return WriteConfig(config); } -HWND GetTopLevelWindow(HWND window) { - if (window == nullptr) { - return nullptr; +bool StartDaemon() { + DWORD access = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | + SERVICE_START | SERVICE_STOP; + ScopedScHandle service = OpenService(access); + if (!service.IsValid()) + return false; + + // Change the service start type to 'auto'. + if (!::ChangeServiceConfigW(service.Get(), + SERVICE_NO_CHANGE, + SERVICE_AUTO_START, + SERVICE_NO_CHANGE, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr)) { + PLOG(ERROR) << "Failed to change the '" << kWindowsServiceName + << "'service start type to 'auto'"; + return false; } - for (;;) { - LONG style = GetWindowLong(window, GWL_STYLE); - if ((style & WS_OVERLAPPEDWINDOW) == WS_OVERLAPPEDWINDOW || - (style & WS_POPUP) == WS_POPUP) { - return window; - } + // Start the service. + if (!StartService(service.Get(), 0, nullptr)) { + DWORD error = GetLastError(); + if (error != ERROR_SERVICE_ALREADY_RUNNING) { + LOG(ERROR) << "Failed to start the '" << kWindowsServiceName + << "'service: " << error; - HWND parent = GetAncestor(window, GA_PARENT); - if (parent == nullptr) { - return window; + return false; } + } - window = parent; + return true; +} + +bool StopDaemon() { + DWORD access = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | + SERVICE_START | SERVICE_STOP; + ScopedScHandle service = OpenService(access); + if (!service.IsValid()) + return false; + + // Change the service start type to 'manual'. + if (!::ChangeServiceConfigW(service.Get(), + SERVICE_NO_CHANGE, + SERVICE_DEMAND_START, + SERVICE_NO_CHANGE, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr)) { + PLOG(ERROR) << "Failed to change the '" << kWindowsServiceName + << "'service start type to 'manual'"; + return false; + } + + // Stop the service. + SERVICE_STATUS status; + if (!ControlService(service.Get(), SERVICE_CONTROL_STOP, &status)) { + DWORD error = GetLastError(); + if (error != ERROR_SERVICE_NOT_ACTIVE) { + LOG(ERROR) << "Failed to stop the '" << kWindowsServiceName + << "'service: " << error; + return false; + } } + + return true; } } // namespace -DaemonControllerDelegateWin::DaemonControllerDelegateWin() - : control_is_elevated_(false), - window_handle_(nullptr) { +DaemonControllerDelegateWin::DaemonControllerDelegateWin() { } DaemonControllerDelegateWin::~DaemonControllerDelegateWin() { @@ -166,111 +364,78 @@ DaemonController::State DaemonControllerDelegateWin::GetState() { if (base::win::GetVersion() < base::win::VERSION_XP) { return DaemonController::STATE_NOT_IMPLEMENTED; } + // TODO(alexeypa): Make the thread alertable, so we can switch to APC // notifications rather than polling. - ScopedScHandle service; - DWORD error = OpenService(&service); - - switch (error) { - case ERROR_SUCCESS: { - SERVICE_STATUS status; - if (::QueryServiceStatus(service.Get(), &status)) { - return ConvertToDaemonState(status.dwCurrentState); - } else { - PLOG(ERROR) << "Failed to query the state of the '" - << kWindowsServiceName << "' service"; - return DaemonController::STATE_UNKNOWN; - } - break; - } - case ERROR_SERVICE_DOES_NOT_EXIST: - return DaemonController::STATE_NOT_INSTALLED; - default: - return DaemonController::STATE_UNKNOWN; + ScopedScHandle service = OpenService(SERVICE_QUERY_STATUS); + if (!service.IsValid()) + return DaemonController::STATE_UNKNOWN; + + SERVICE_STATUS status; + if (!::QueryServiceStatus(service.Get(), &status)) { + PLOG(ERROR) << "Failed to query the state of the '" + << kWindowsServiceName << "' service"; + return DaemonController::STATE_UNKNOWN; } + + return ConvertToDaemonState(status.dwCurrentState); } scoped_ptr<base::DictionaryValue> DaemonControllerDelegateWin::GetConfig() { - // Configure and start the Daemon Controller if it is installed already. - HRESULT hr = ActivateController(); - if (FAILED(hr)) - return nullptr; - - // Get the host configuration. - ScopedBstr host_config; - hr = control_->GetConfig(host_config.Receive()); - if (FAILED(hr)) - return nullptr; + base::FilePath config_dir = remoting::GetConfigDir(); - // Parse the string into a dictionary. - base::string16 file_content( - static_cast<BSTR>(host_config), host_config.Length()); - scoped_ptr<base::Value> config( - base::JSONReader::Read(base::UTF16ToUTF8(file_content), - base::JSON_ALLOW_TRAILING_COMMAS)); - - if (!config || !config->IsType(base::Value::TYPE_DICTIONARY)) + // Read the unprivileged part of host configuration. + scoped_ptr<base::DictionaryValue> config; + if (!ReadConfig(config_dir.Append(kUnprivilegedConfigFileName), &config)) return nullptr; - return make_scoped_ptr(static_cast<base::DictionaryValue*>(config.release())); + return config; } void DaemonControllerDelegateWin::UpdateConfig( scoped_ptr<base::DictionaryValue> config, const DaemonController::CompletionCallback& done) { - HRESULT hr = ActivateElevatedController(); - if (FAILED(hr)) { - InvokeCompletionCallback(done, hr); - return; + // Check for bad keys. + for (int i = 0; i < arraysize(kReadonlyKeys); ++i) { + if (config->HasKey(kReadonlyKeys[i])) { + LOG(ERROR) << "Cannot update config: '" << kReadonlyKeys[i] + << "' is read only."; + InvokeCompletionCallback(done, false); + return; + } } - - // Update the configuration. - ScopedBstr config_str(nullptr); - ConfigToString(*config, &config_str); - if (config_str == nullptr) { - InvokeCompletionCallback(done, E_OUTOFMEMORY); + // Get the old config. + base::FilePath config_dir = remoting::GetConfigDir(); + scoped_ptr<base::DictionaryValue> config_old; + if (!ReadConfig(config_dir.Append(kConfigFileName), &config_old)) { + InvokeCompletionCallback(done, false); return; } - // Make sure that the PIN confirmation dialog is focused properly. - hr = control_->SetOwnerWindow( - reinterpret_cast<LONG_PTR>(GetTopLevelWindow(window_handle_))); - if (FAILED(hr)) { - InvokeCompletionCallback(done, hr); - return; - } + // Merge items from the given config into the old config. + config_old->MergeDictionary(config.release()); + + // Write the updated config. + std::string config_updated_str; + base::JSONWriter::Write(config_old.get(), &config_updated_str); + bool result = WriteConfig(config_updated_str); - hr = control_->UpdateConfig(config_str); - InvokeCompletionCallback(done, hr); + InvokeCompletionCallback(done, result); } void DaemonControllerDelegateWin::Stop( const DaemonController::CompletionCallback& done) { - HRESULT hr = ActivateElevatedController(); - if (SUCCEEDED(hr)) - hr = control_->StopDaemon(); + bool result = StopDaemon(); - InvokeCompletionCallback(done, hr); + InvokeCompletionCallback(done, result); } void DaemonControllerDelegateWin::SetWindow(void* window_handle) { - window_handle_ = reinterpret_cast<HWND>(window_handle); } std::string DaemonControllerDelegateWin::GetVersion() { - // Configure and start the Daemon Controller if it is installed already. - HRESULT hr = ActivateController(); - if (FAILED(hr)) - return std::string(); - - // Get the version string. - ScopedBstr version; - hr = control_->GetVersion(version.Receive()); - if (FAILED(hr)) - return std::string(); - - return base::UTF16ToUTF8( - base::string16(static_cast<BSTR>(version), version.Length())); + // TODO (weitaosu): Remove this as GetVersion is not used anymore. + return std::string(); } DaemonController::UsageStatsConsent @@ -280,154 +445,48 @@ DaemonControllerDelegateWin::GetUsageStatsConsent() { consent.allowed = false; consent.set_by_policy = false; - // Activate the Daemon Controller and see if it supports |IDaemonControl2|. - HRESULT hr = ActivateController(); - if (FAILED(hr)) { - // The host is not installed yet. Assume that the user didn't consent to - // collecting crash dumps. - return consent; - } - - if (control2_.get() == nullptr) { - // The host is installed and does not support crash dump reporting. - return consent; - } - // Get the recorded user's consent. - BOOL allowed; - BOOL set_by_policy; - hr = control2_->GetUsageStatsConsent(&allowed, &set_by_policy); - if (FAILED(hr)) { - // If the user's consent is not recorded yet, assume that the user didn't - // consent to collecting crash dumps. - return consent; + bool allowed; + bool set_by_policy; + // If the user's consent is not recorded yet, assume that the user didn't + // consent to collecting crash dumps. + if (remoting::GetUsageStatsConsent(&allowed, &set_by_policy)) { + consent.allowed = allowed; + consent.set_by_policy = set_by_policy; } - consent.allowed = !!allowed; - consent.set_by_policy = !!set_by_policy; return consent; } -HRESULT DaemonControllerDelegateWin::ActivateController() { - if (!control_.get()) { - CLSID class_id; - HRESULT hr = CLSIDFromProgID(kDaemonController, &class_id); - if (FAILED(hr)) { - return hr; - } - - hr = CoCreateInstance(class_id, nullptr, CLSCTX_LOCAL_SERVER, - IID_IDaemonControl, control_.ReceiveVoid()); - if (FAILED(hr)) { - return hr; - } - - // Ignore the error. IID_IDaemonControl2 is optional. - control_.QueryInterface(IID_IDaemonControl2, control2_.ReceiveVoid()); - - // Release |control_| upon expiration of the timeout. - release_timer_.reset(new base::OneShotTimer<DaemonControllerDelegateWin>()); - release_timer_->Start(FROM_HERE, - base::TimeDelta::FromSeconds(kUnprivilegedTimeoutSec), - this, - &DaemonControllerDelegateWin::ReleaseController); - } - - return S_OK; -} - -HRESULT DaemonControllerDelegateWin::ActivateElevatedController() { - // The COM elevation is supported on Vista and above. - if (base::win::GetVersion() < base::win::VERSION_VISTA) - return ActivateController(); - - // Release an unprivileged instance of the daemon controller if any. - if (!control_is_elevated_) - ReleaseController(); - - if (!control_.get()) { - BIND_OPTS3 bind_options; - memset(&bind_options, 0, sizeof(bind_options)); - bind_options.cbStruct = sizeof(bind_options); - bind_options.hwnd = GetTopLevelWindow(window_handle_); - bind_options.dwClassContext = CLSCTX_LOCAL_SERVER; - - HRESULT hr = ::CoGetObject( - kDaemonControllerElevationMoniker, - &bind_options, - IID_IDaemonControl, - control_.ReceiveVoid()); - if (FAILED(hr)) { - return hr; - } - - // Ignore the error. IID_IDaemonControl2 is optional. - control_.QueryInterface(IID_IDaemonControl2, control2_.ReceiveVoid()); - - // Note that we hold a reference to an elevated instance now. - control_is_elevated_ = true; - - // Release |control_| upon expiration of the timeout. - release_timer_.reset(new base::OneShotTimer<DaemonControllerDelegateWin>()); - release_timer_->Start(FROM_HERE, - base::TimeDelta::FromSeconds(kPrivilegedTimeoutSec), - this, - &DaemonControllerDelegateWin::ReleaseController); - } - - return S_OK; -} - -void DaemonControllerDelegateWin::ReleaseController() { - control_.Release(); - control2_.Release(); - release_timer_.reset(); - control_is_elevated_ = false; -} - void DaemonControllerDelegateWin::SetConfigAndStart( scoped_ptr<base::DictionaryValue> config, bool consent, const DaemonController::CompletionCallback& done) { - HRESULT hr = ActivateElevatedController(); - if (FAILED(hr)) { - InvokeCompletionCallback(done, hr); - return; - } - // Record the user's consent. - if (control2_.get()) { - hr = control2_->SetUsageStatsConsent(consent); - if (FAILED(hr)) { - InvokeCompletionCallback(done, hr); - return; - } + if (!remoting::SetUsageStatsConsent(consent)) { + InvokeCompletionCallback(done, false); + return; } // Set the configuration. - ScopedBstr config_str(nullptr); - ConfigToString(*config, &config_str); - if (config_str == nullptr) { - InvokeCompletionCallback(done, E_OUTOFMEMORY); - return; - } + std::string config_str; + base::JSONWriter::Write(config.release(), &config_str); - hr = control_->SetOwnerWindow( - reinterpret_cast<LONG_PTR>(GetTopLevelWindow(window_handle_))); - if (FAILED(hr)) { - InvokeCompletionCallback(done, hr); + // Determine the config directory path and create it if necessary. + base::FilePath config_dir = remoting::GetConfigDir(); + if (!base::CreateDirectory(config_dir)) { + PLOG(ERROR) << "Failed to create the config directory."; + InvokeCompletionCallback(done, false); return; } - hr = control_->SetConfig(config_str); - if (FAILED(hr)) { - InvokeCompletionCallback(done, hr); + if (!WriteConfig(config_str)) { + InvokeCompletionCallback(done, false); return; } // Start daemon. - hr = control_->StartDaemon(); - InvokeCompletionCallback(done, hr); + InvokeCompletionCallback(done, StartDaemon()); } scoped_refptr<DaemonController> DaemonController::Create() { diff --git a/remoting/host/setup/daemon_controller_delegate_win.h b/remoting/host/setup/daemon_controller_delegate_win.h index 29ad739..b05a1e2 100644 --- a/remoting/host/setup/daemon_controller_delegate_win.h +++ b/remoting/host/setup/daemon_controller_delegate_win.h @@ -5,11 +5,6 @@ #ifndef REMOTING_HOST_SETUP_DAEMON_CONTROLLER_DELEGATE_WIN_H_ #define REMOTING_HOST_SETUP_DAEMON_CONTROLLER_DELEGATE_WIN_H_ -#include "base/memory/scoped_ptr.h" -#include "base/timer/timer.h" -#include "base/win/scoped_comptr.h" -// chromoting_lib.h contains MIDL-generated declarations. -#include "remoting/host/chromoting_lib.h" #include "remoting/host/setup/daemon_controller.h" namespace remoting { @@ -36,33 +31,6 @@ class DaemonControllerDelegateWin : public DaemonController::Delegate { virtual std::string GetVersion() override; virtual DaemonController::UsageStatsConsent GetUsageStatsConsent() override; - private: - // Activates an unprivileged instance of the daemon controller and caches it. - HRESULT ActivateController(); - - // Activates an instance of the daemon controller and caches it. If COM - // Elevation is supported (Vista+) the activated instance is elevated, - // otherwise it is activated under credentials of the caller. - HRESULT ActivateElevatedController(); - - // Releases the cached instance of the controller. - void ReleaseController(); - - // |control_| and |control2_| hold references to an instance of the daemon - // controller to prevent a UAC prompt on every operation. - base::win::ScopedComPtr<IDaemonControl> control_; - base::win::ScopedComPtr<IDaemonControl2> control2_; - - // True if |control_| holds a reference to an elevated instance of the daemon - // controller. - bool control_is_elevated_; - - // This timer is used to release |control_| after a timeout. - scoped_ptr<base::OneShotTimer<DaemonControllerDelegateWin> > release_timer_; - - // Handle of the plugin window. - HWND window_handle_; - DISALLOW_COPY_AND_ASSIGN(DaemonControllerDelegateWin); }; |