Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(917)

Unified Diff: remoting/host/it2me/it2me_native_messaging_host.cc

Issue 2179353004: Update Windows It2Me to allow remote users to interact with elevated windows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@it2me_uiaccess
Patch Set: Removing the CHECK assertion and replacing it with LOG(ERROR) instead. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
« no previous file with comments | « remoting/host/it2me/it2me_native_messaging_host.h ('k') | remoting/host/it2me/it2me_native_messaging_host_main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698