| Index: remoting/host/it2me/it2me_native_messaging_host.cc
|
| diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
|
| index 1ef878bc79515006763a7c3e283a9bc548157acf..e3d0251d8a9648b2eca19c7b8e9d5e935905a60f 100644
|
| --- a/remoting/host/it2me/it2me_native_messaging_host.cc
|
| +++ b/remoting/host/it2me/it2me_native_messaging_host.cc
|
| @@ -4,27 +4,39 @@
|
|
|
| #include "remoting/host/it2me/it2me_native_messaging_host.h"
|
|
|
| +#include <memory>
|
| #include <string>
|
| #include <utility>
|
|
|
| #include "base/bind.h"
|
| #include "base/callback.h"
|
| +#include "base/callback_helpers.h"
|
| #include "base/json/json_reader.h"
|
| #include "base/json/json_writer.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/stringize_macros.h"
|
| #include "base/threading/thread.h"
|
| +#include "base/time/time.h"
|
| #include "base/values.h"
|
| #include "build/build_config.h"
|
| +#include "components/policy/policy_constants.h"
|
| #include "net/base/url_util.h"
|
| #include "net/url_request/url_request_context_getter.h"
|
| #include "remoting/base/auto_thread_task_runner.h"
|
| #include "remoting/host/chromoting_host_context.h"
|
| #include "remoting/host/host_exit_codes.h"
|
| +#include "remoting/host/policy_watcher.h"
|
| #include "remoting/host/service_urls.h"
|
| #include "remoting/protocol/name_value_map.h"
|
|
|
| +#if defined(OS_WIN)
|
| +#include "base/command_line.h"
|
| +#include "base/files/file_path.h"
|
| +
|
| +#include "remoting/host/win/elevated_native_messaging_host.h"
|
| +#endif // defined(OS_WIN)
|
| +
|
| namespace remoting {
|
|
|
| namespace {
|
| @@ -39,14 +51,44 @@ const remoting::protocol::NameMapElement<It2MeHostState> kIt2MeHostStates[] = {
|
| {kInvalidDomainError, "INVALID_DOMAIN_ERROR"},
|
| };
|
|
|
| +#if defined(OS_WIN)
|
| +const base::FilePath::CharType kBaseHostBinaryName[] =
|
| + FILE_PATH_LITERAL("remote_assistance_host.exe");
|
| +const base::FilePath::CharType kElevatedHostBinaryName[] =
|
| + FILE_PATH_LITERAL("remote_assistance_host_uiaccess.exe");
|
| +#endif // defined(OS_WIN)
|
| +
|
| +// Helper function to run |callback| on the correct thread using |task_runner|.
|
| +void PolicyUpdateCallback(
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner,
|
| + remoting::PolicyWatcher::PolicyUpdatedCallback callback,
|
| + std::unique_ptr<base::DictionaryValue> policies) {
|
| + DCHECK(!callback.is_null());
|
| +
|
| + // Always post the task so the execution is consistent (always asynchronous).
|
| + task_runner->PostTask(FROM_HERE,
|
| + base::Bind(callback, base::Passed(&policies)));
|
| +}
|
| +
|
| +// Called when malformed policies are detected.
|
| +void OnPolicyError() {
|
| + // TODO(joedow): Report the policy error to the user. crbug.com/433009
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| } // namespace
|
|
|
| It2MeNativeMessagingHost::It2MeNativeMessagingHost(
|
| + bool needs_elevation,
|
| + policy::PolicyService* policy_service,
|
| std::unique_ptr<ChromotingHostContext> context,
|
| std::unique_ptr<It2MeHostFactory> factory)
|
| - : client_(nullptr),
|
| + : needs_elevation_(needs_elevation),
|
| host_context_(std::move(context)),
|
| factory_(std::move(factory)),
|
| + policy_service_(policy_service),
|
| + policy_watcher_(PolicyWatcher::Create(policy_service_,
|
| + host_context_->file_task_runner())),
|
| weak_factory_(this) {
|
| weak_ptr_ = weak_factory_.GetWeakPtr();
|
|
|
| @@ -59,6 +101,15 @@ It2MeNativeMessagingHost::It2MeNativeMessagingHost(
|
|
|
| xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls();
|
| directory_bot_jid_ = service_urls->directory_bot_jid();
|
| +
|
| + // The policy watcher runs on the |file_task_runner| but we want to run the
|
| + // update code on |task_runner| so we use a shim to post the callback to the
|
| + // preferred task runner.
|
| + PolicyWatcher::PolicyUpdatedCallback update_callback =
|
| + base::Bind(&It2MeNativeMessagingHost::OnPolicyUpdate, weak_ptr_);
|
| + policy_watcher_->StartWatching(
|
| + base::Bind(&PolicyUpdateCallback, task_runner(), update_callback),
|
| + base::Bind(&OnPolicyError));
|
| }
|
|
|
| It2MeNativeMessagingHost::~It2MeNativeMessagingHost() {
|
| @@ -99,11 +150,11 @@ void It2MeNativeMessagingHost::OnMessage(const std::string& message) {
|
| response->SetString("type", type + "Response");
|
|
|
| if (type == "hello") {
|
| - ProcessHello(*message_dict, std::move(response));
|
| + ProcessHello(std::move(message_dict), std::move(response));
|
| } else if (type == "connect") {
|
| - ProcessConnect(*message_dict, std::move(response));
|
| + ProcessConnect(std::move(message_dict), std::move(response));
|
| } else if (type == "disconnect") {
|
| - ProcessDisconnect(*message_dict, std::move(response));
|
| + ProcessDisconnect(std::move(message_dict), std::move(response));
|
| } else {
|
| SendErrorAndExit(std::move(response), "Unsupported request type: " + type);
|
| }
|
| @@ -129,7 +180,7 @@ void It2MeNativeMessagingHost::SendMessageToClient(
|
| }
|
|
|
| void It2MeNativeMessagingHost::ProcessHello(
|
| - const base::DictionaryValue& message,
|
| + std::unique_ptr<base::DictionaryValue> message,
|
| std::unique_ptr<base::DictionaryValue> response) const {
|
| DCHECK(task_runner()->BelongsToCurrentThread());
|
|
|
| @@ -144,10 +195,31 @@ void It2MeNativeMessagingHost::ProcessHello(
|
| }
|
|
|
| void It2MeNativeMessagingHost::ProcessConnect(
|
| - const base::DictionaryValue& message,
|
| + std::unique_ptr<base::DictionaryValue> message,
|
| std::unique_ptr<base::DictionaryValue> response) {
|
| DCHECK(task_runner()->BelongsToCurrentThread());
|
|
|
| + if (!policy_received_) {
|
| + DCHECK(pending_connect_.is_null());
|
| + pending_connect_ =
|
| + base::Bind(&It2MeNativeMessagingHost::ProcessConnect, weak_ptr_,
|
| + base::Passed(&message), base::Passed(&response));
|
| + return;
|
| + }
|
| +
|
| + if (needs_elevation_) {
|
| + // Attempt to pass the current message to the elevated process. This method
|
| + // will spin up the elevated process if it is not already running. On
|
| + // success, the elevated process will process the message and respond.
|
| + // If the process cannot be started or message passing fails, then return an
|
| + // error to the message sender.
|
| + if (!DelegateToElevatedHost(std::move(message))) {
|
| + SendErrorAndExit(std::move(response),
|
| + "Failed to send message to elevated host.");
|
| + }
|
| + return;
|
| + }
|
| +
|
| if (it2me_host_.get()) {
|
| SendErrorAndExit(std::move(response),
|
| "Connect can be called only when disconnected.");
|
| @@ -156,13 +228,13 @@ void It2MeNativeMessagingHost::ProcessConnect(
|
|
|
| XmppSignalStrategy::XmppServerConfig xmpp_config = xmpp_server_config_;
|
|
|
| - if (!message.GetString("userName", &xmpp_config.username)) {
|
| + if (!message->GetString("userName", &xmpp_config.username)) {
|
| SendErrorAndExit(std::move(response), "'userName' not found in request.");
|
| return;
|
| }
|
|
|
| std::string auth_service_with_token;
|
| - if (!message.GetString("authServiceWithToken", &auth_service_with_token)) {
|
| + if (!message->GetString("authServiceWithToken", &auth_service_with_token)) {
|
| SendErrorAndExit(std::move(response),
|
| "'authServiceWithToken' not found in request.");
|
| return;
|
| @@ -184,7 +256,7 @@ void It2MeNativeMessagingHost::ProcessConnect(
|
|
|
| #if !defined(NDEBUG)
|
| std::string address;
|
| - if (!message.GetString("xmppServerAddress", &address)) {
|
| + if (!message->GetString("xmppServerAddress", &address)) {
|
| SendErrorAndExit(std::move(response),
|
| "'xmppServerAddress' not found in request.");
|
| return;
|
| @@ -197,13 +269,13 @@ void It2MeNativeMessagingHost::ProcessConnect(
|
| return;
|
| }
|
|
|
| - if (!message.GetBoolean("xmppServerUseTls", &xmpp_config.use_tls)) {
|
| + if (!message->GetBoolean("xmppServerUseTls", &xmpp_config.use_tls)) {
|
| SendErrorAndExit(std::move(response),
|
| "'xmppServerUseTls' not found in request.");
|
| return;
|
| }
|
|
|
| - if (!message.GetString("directoryBotJid", &directory_bot_jid_)) {
|
| + if (!message->GetString("directoryBotJid", &directory_bot_jid_)) {
|
| SendErrorAndExit(std::move(response),
|
| "'directoryBotJid' not found in request.");
|
| return;
|
| @@ -211,19 +283,32 @@ void It2MeNativeMessagingHost::ProcessConnect(
|
| #endif // !defined(NDEBUG)
|
|
|
| // Create the It2Me host and start connecting.
|
| - it2me_host_ = factory_->CreateIt2MeHost(host_context_->Copy(),
|
| - weak_ptr_,
|
| - xmpp_config,
|
| - directory_bot_jid_);
|
| + it2me_host_ =
|
| + factory_->CreateIt2MeHost(host_context_->Copy(), policy_service_,
|
| + weak_ptr_, xmpp_config, directory_bot_jid_);
|
| it2me_host_->Connect();
|
|
|
| SendMessageToClient(std::move(response));
|
| }
|
|
|
| void It2MeNativeMessagingHost::ProcessDisconnect(
|
| - const base::DictionaryValue& message,
|
| + std::unique_ptr<base::DictionaryValue> message,
|
| std::unique_ptr<base::DictionaryValue> response) {
|
| DCHECK(task_runner()->BelongsToCurrentThread());
|
| + DCHECK(policy_received_);
|
| +
|
| + if (needs_elevation_) {
|
| + // Attempt to pass the current message to the elevated process. This method
|
| + // will spin up the elevated process if it is not already running. On
|
| + // success, the elevated process will process the message and respond.
|
| + // If the process cannot be started or message passing fails, then return an
|
| + // error to the message sender.
|
| + if (!DelegateToElevatedHost(std::move(message))) {
|
| + SendErrorAndExit(std::move(response),
|
| + "Failed to send message to elevated host.");
|
| + }
|
| + return;
|
| + }
|
|
|
| if (it2me_host_.get()) {
|
| it2me_host_->Disconnect();
|
| @@ -328,4 +413,73 @@ std::string It2MeNativeMessagingHost::HostStateToString(
|
| return ValueToName(kIt2MeHostStates, host_state);
|
| }
|
|
|
| +void It2MeNativeMessagingHost::OnPolicyUpdate(
|
| + std::unique_ptr<base::DictionaryValue> policies) {
|
| + if (policy_received_) {
|
| + // Don't dynamically change how the host operates since we don't have a good
|
| + // way to communicate changes to the user.
|
| + return;
|
| + }
|
| +
|
| + bool allow_elevated_host = false;
|
| + if (!policies->GetBoolean(
|
| + policy::key::kRemoteAccessHostAllowUiAccessForRemoteAssistance,
|
| + &allow_elevated_host)) {
|
| + LOG(WARNING) << "Failed to retrieve elevated host policy value.";
|
| + }
|
| +#if defined(OS_WIN)
|
| + LOG(INFO) << "Allow UiAccess for Remote Assistance: " << allow_elevated_host;
|
| +#endif // defined(OS_WIN)
|
| +
|
| + policy_received_ = true;
|
| +
|
| + // If |allow_elevated_host| is false, then we will fall back to using a host
|
| + // running in the current context regardless of the elevation request. This
|
| + // may not be ideal, but is still functional.
|
| + needs_elevation_ = needs_elevation_ && allow_elevated_host;
|
| + if (!pending_connect_.is_null()) {
|
| + base::ResetAndReturn(&pending_connect_).Run();
|
| + }
|
| +}
|
| +
|
| +#if defined(OS_WIN)
|
| +
|
| +bool It2MeNativeMessagingHost::DelegateToElevatedHost(
|
| + std::unique_ptr<base::DictionaryValue> message) {
|
| + DCHECK(task_runner()->BelongsToCurrentThread());
|
| + DCHECK(needs_elevation_);
|
| +
|
| + if (!elevated_host_) {
|
| + base::FilePath binary_path =
|
| + base::CommandLine::ForCurrentProcess()->GetProgram();
|
| + CHECK(binary_path.BaseName() == base::FilePath(kBaseHostBinaryName));
|
| +
|
| + // The new process runs at an elevated level due to being granted uiAccess.
|
| + // |parent_window_handle| can be used to position dialog windows but is not
|
| + // currently used.
|
| + elevated_host_.reset(new ElevatedNativeMessagingHost(
|
| + binary_path.DirName().Append(kElevatedHostBinaryName),
|
| + /*parent_window_handle=*/0,
|
| + /*elevate_process=*/false,
|
| + /*host_timeout=*/base::TimeDelta(), client_));
|
| + }
|
| +
|
| + if (elevated_host_->EnsureElevatedHostCreated()) {
|
| + elevated_host_->SendMessage(std::move(message));
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +#else // !defined(OS_WIN)
|
| +
|
| +bool It2MeNativeMessagingHost::DelegateToElevatedHost(
|
| + std::unique_ptr<base::DictionaryValue> message) {
|
| + NOTREACHED();
|
| + return false;
|
| +}
|
| +
|
| +#endif // !defined(OS_WIN)
|
| +
|
| } // namespace remoting
|
|
|