summaryrefslogtreecommitdiffstats
path: root/remoting/host/setup
diff options
context:
space:
mode:
authorweitaosu <weitaosu@chromium.org>2015-02-06 15:18:29 -0800
committerCommit bot <commit-bot@chromium.org>2015-02-06 23:19:13 +0000
commit69cccfced484ec798815c5804f7b9825c3e5da9e (patch)
tree77b1fcfb56c10e0bb9f259a3449f0d1281b8f34f /remoting/host/setup
parentc2e11810044fe5ff1c1b8588103671925a5b74fe (diff)
downloadchromium_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.cc615
-rw-r--r--remoting/host/setup/daemon_controller_delegate_win.h32
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);
};