Chromium Code Reviews| 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..0814370966a7ea8123406b9e1d51db875f872803 100644 |
| --- a/remoting/host/it2me/it2me_native_messaging_host.cc |
| +++ b/remoting/host/it2me/it2me_native_messaging_host.cc |
| @@ -9,22 +9,33 @@ |
| #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 +50,24 @@ 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) |
| + |
| } // namespace |
| It2MeNativeMessagingHost::It2MeNativeMessagingHost( |
| + bool needs_elevation, |
| 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_watcher_(PolicyWatcher::Create(factory_->get_policy_service(), |
| + host_context_->file_task_runner())), |
| weak_factory_(this) { |
| weak_ptr_ = weak_factory_.GetWeakPtr(); |
| @@ -59,6 +80,12 @@ It2MeNativeMessagingHost::It2MeNativeMessagingHost( |
| xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls(); |
| directory_bot_jid_ = service_urls->directory_bot_jid(); |
| + |
| + policy_watcher_->StartWatching( |
| + base::Bind(&It2MeNativeMessagingHost::OnPolicyUpdate, |
| + base::Unretained(this)), |
|
Sergey Ulanov
2016/08/31 23:00:17
I don't think it's safe to use Unretained() here b
joedow
2016/09/02 21:58:59
Done.
|
| + base::Bind(&It2MeNativeMessagingHost::OnPolicyError, |
| + base::Unretained(this))); |
| } |
| It2MeNativeMessagingHost::~It2MeNativeMessagingHost() { |
| @@ -99,11 +126,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 +156,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 +171,26 @@ 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_ && allow_elevated_host_) { |
|
Sergey Ulanov
2016/08/31 23:00:16
Add a comment here to explain what happens here.
joedow
2016/09/02 21:58:59
Done.
|
| + if (!DelegateToElevatedHost(std::move(message))) { |
| + response->SetBoolean("result", false); |
|
Sergey Ulanov
2016/08/31 23:00:16
Does the app support this field right now?
joedow
2016/09/02 21:58:59
I seem to remember testing this in a previous iter
|
| + SendMessageToClient(std::move(response)); |
| + } |
| + return; |
| + } |
| + |
| if (it2me_host_.get()) { |
| SendErrorAndExit(std::move(response), |
| "Connect can be called only when disconnected."); |
| @@ -156,13 +199,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 +227,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 +240,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; |
| @@ -221,9 +264,18 @@ void It2MeNativeMessagingHost::ProcessConnect( |
| } |
| 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_ && allow_elevated_host_) { |
| + if (!DelegateToElevatedHost(std::move(message))) { |
| + response->SetBoolean("result", false); |
| + SendMessageToClient(std::move(response)); |
| + } |
| + return; |
| + } |
| if (it2me_host_.get()) { |
| it2me_host_->Disconnect(); |
| @@ -328,4 +380,77 @@ std::string It2MeNativeMessagingHost::HostStateToString( |
| return ValueToName(kIt2MeHostStates, host_state); |
| } |
| +void It2MeNativeMessagingHost::OnPolicyUpdate( |
| + std::unique_ptr<base::DictionaryValue> policies) { |
| + // The policy watcher runs on the |file_task_runner| but we want to run the |
| + // update code on |task_runner|. |
| + if (!task_runner()->BelongsToCurrentThread()) { |
| + task_runner()->PostTask( |
| + FROM_HERE, base::Bind(&It2MeNativeMessagingHost::OnPolicyUpdate, |
| + weak_ptr_, base::Passed(&policies))); |
| + return; |
| + } |
| + |
| + 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; |
| + } |
| + |
| + if (!policies->GetBoolean( |
| + policy::key::kRemoteAccessHostAllowUiAccessForRemoteAssistance, |
| + &allow_elevated_host_)) { |
| + LOG(WARNING) << "Failed to retrieve elevated host policy value."; |
| + } |
| + |
| + policy_received_ = true; |
| + if (!pending_connect_.is_null()) { |
| + base::ResetAndReturn(&pending_connect_).Run(); |
| + } |
| +} |
| + |
| +void It2MeNativeMessagingHost::OnPolicyError() { |
| + // TODO(joedow): Report the policy error to the user. crbug.com/433009 |
| + NOTIMPLEMENTED(); |
| +} |
| + |
| +#if defined(OS_WIN) |
| + |
| +bool It2MeNativeMessagingHost::DelegateToElevatedHost( |
| + std::unique_ptr<base::DictionaryValue> message) { |
| + DCHECK(task_runner()->BelongsToCurrentThread()); |
| + DCHECK(needs_elevation_); |
| + DCHECK(allow_elevated_host_); |
| + |
| + 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. |
| + elevated_host_.reset(new ElevatedNativeMessagingHost( |
| + binary_path.DirName().Append(kElevatedHostBinaryName), |
| + /*parent_window_handle=*/0, |
|
Sergey Ulanov
2016/08/31 23:00:17
Why is this not parameter passed to the elevated p
joedow
2016/09/02 21:58:59
Done.
|
| + /*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 |