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

Side by Side 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: Fixing some comments 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 unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/it2me/it2me_native_messaging_host.h" 5 #include "remoting/host/it2me/it2me_native_messaging_host.h"
6 6
7 #include <string> 7 #include <string>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #include "base/callback_helpers.h"
12 #include "base/json/json_reader.h" 13 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h" 14 #include "base/json/json_writer.h"
14 #include "base/strings/string_number_conversions.h" 15 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
16 #include "base/strings/stringize_macros.h" 17 #include "base/strings/stringize_macros.h"
17 #include "base/threading/thread.h" 18 #include "base/threading/thread.h"
19 #include "base/time/time.h"
18 #include "base/values.h" 20 #include "base/values.h"
19 #include "build/build_config.h" 21 #include "build/build_config.h"
22 #include "components/policy/policy_constants.h"
20 #include "net/base/url_util.h" 23 #include "net/base/url_util.h"
21 #include "net/url_request/url_request_context_getter.h" 24 #include "net/url_request/url_request_context_getter.h"
22 #include "remoting/base/auto_thread_task_runner.h" 25 #include "remoting/base/auto_thread_task_runner.h"
23 #include "remoting/host/chromoting_host_context.h" 26 #include "remoting/host/chromoting_host_context.h"
24 #include "remoting/host/host_exit_codes.h" 27 #include "remoting/host/host_exit_codes.h"
28 #include "remoting/host/policy_watcher.h"
25 #include "remoting/host/service_urls.h" 29 #include "remoting/host/service_urls.h"
26 #include "remoting/protocol/name_value_map.h" 30 #include "remoting/protocol/name_value_map.h"
27 31
32 #if defined(OS_WIN)
33 #include "base/command_line.h"
34 #include "base/files/file_path.h"
35
36 #include "remoting/host/win/elevated_native_messaging_host.h"
37 #endif // defined(OS_WIN)
38
28 namespace remoting { 39 namespace remoting {
29 40
30 namespace { 41 namespace {
31 42
32 const remoting::protocol::NameMapElement<It2MeHostState> kIt2MeHostStates[] = { 43 const remoting::protocol::NameMapElement<It2MeHostState> kIt2MeHostStates[] = {
33 {kDisconnected, "DISCONNECTED"}, 44 {kDisconnected, "DISCONNECTED"},
34 {kStarting, "STARTING"}, 45 {kStarting, "STARTING"},
35 {kRequestedAccessCode, "REQUESTED_ACCESS_CODE"}, 46 {kRequestedAccessCode, "REQUESTED_ACCESS_CODE"},
36 {kReceivedAccessCode, "RECEIVED_ACCESS_CODE"}, 47 {kReceivedAccessCode, "RECEIVED_ACCESS_CODE"},
37 {kConnected, "CONNECTED"}, 48 {kConnected, "CONNECTED"},
38 {kError, "ERROR"}, 49 {kError, "ERROR"},
39 {kInvalidDomainError, "INVALID_DOMAIN_ERROR"}, 50 {kInvalidDomainError, "INVALID_DOMAIN_ERROR"},
40 }; 51 };
41 52
53 #if defined(OS_WIN)
54 const base::FilePath::CharType kBaseHostBinaryName[] =
55 FILE_PATH_LITERAL("remote_assistance_host.exe");
56 const base::FilePath::CharType kElevatedHostBinaryName[] =
57 FILE_PATH_LITERAL("remote_assistance_host_uiaccess.exe");
58 #endif // defined(OS_WIN)
59
42 } // namespace 60 } // namespace
43 61
44 It2MeNativeMessagingHost::It2MeNativeMessagingHost( 62 It2MeNativeMessagingHost::It2MeNativeMessagingHost(
63 bool needs_elevation,
45 std::unique_ptr<ChromotingHostContext> context, 64 std::unique_ptr<ChromotingHostContext> context,
46 std::unique_ptr<It2MeHostFactory> factory) 65 std::unique_ptr<It2MeHostFactory> factory)
47 : client_(nullptr), 66 : needs_elevation_(needs_elevation),
48 host_context_(std::move(context)), 67 host_context_(std::move(context)),
49 factory_(std::move(factory)), 68 factory_(std::move(factory)),
69 policy_watcher_(PolicyWatcher::Create(factory_->get_policy_service(),
70 host_context_->file_task_runner())),
50 weak_factory_(this) { 71 weak_factory_(this) {
51 weak_ptr_ = weak_factory_.GetWeakPtr(); 72 weak_ptr_ = weak_factory_.GetWeakPtr();
52 73
53 const ServiceUrls* service_urls = ServiceUrls::GetInstance(); 74 const ServiceUrls* service_urls = ServiceUrls::GetInstance();
54 const bool xmpp_server_valid = 75 const bool xmpp_server_valid =
55 net::ParseHostAndPort(service_urls->xmpp_server_address(), 76 net::ParseHostAndPort(service_urls->xmpp_server_address(),
56 &xmpp_server_config_.host, 77 &xmpp_server_config_.host,
57 &xmpp_server_config_.port); 78 &xmpp_server_config_.port);
58 DCHECK(xmpp_server_valid); 79 DCHECK(xmpp_server_valid);
59 80
60 xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls(); 81 xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls();
61 directory_bot_jid_ = service_urls->directory_bot_jid(); 82 directory_bot_jid_ = service_urls->directory_bot_jid();
83
84 policy_watcher_->StartWatching(
85 base::Bind(&It2MeNativeMessagingHost::OnPolicyUpdate,
86 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.
87 base::Bind(&It2MeNativeMessagingHost::OnPolicyError,
88 base::Unretained(this)));
62 } 89 }
63 90
64 It2MeNativeMessagingHost::~It2MeNativeMessagingHost() { 91 It2MeNativeMessagingHost::~It2MeNativeMessagingHost() {
65 DCHECK(task_runner()->BelongsToCurrentThread()); 92 DCHECK(task_runner()->BelongsToCurrentThread());
66 93
67 if (it2me_host_.get()) { 94 if (it2me_host_.get()) {
68 it2me_host_->Disconnect(); 95 it2me_host_->Disconnect();
69 it2me_host_ = nullptr; 96 it2me_host_ = nullptr;
70 } 97 }
71 } 98 }
(...skipping 20 matching lines...) Expand all
92 119
93 std::string type; 120 std::string type;
94 if (!message_dict->GetString("type", &type)) { 121 if (!message_dict->GetString("type", &type)) {
95 SendErrorAndExit(std::move(response), "'type' not found in request."); 122 SendErrorAndExit(std::move(response), "'type' not found in request.");
96 return; 123 return;
97 } 124 }
98 125
99 response->SetString("type", type + "Response"); 126 response->SetString("type", type + "Response");
100 127
101 if (type == "hello") { 128 if (type == "hello") {
102 ProcessHello(*message_dict, std::move(response)); 129 ProcessHello(std::move(message_dict), std::move(response));
103 } else if (type == "connect") { 130 } else if (type == "connect") {
104 ProcessConnect(*message_dict, std::move(response)); 131 ProcessConnect(std::move(message_dict), std::move(response));
105 } else if (type == "disconnect") { 132 } else if (type == "disconnect") {
106 ProcessDisconnect(*message_dict, std::move(response)); 133 ProcessDisconnect(std::move(message_dict), std::move(response));
107 } else { 134 } else {
108 SendErrorAndExit(std::move(response), "Unsupported request type: " + type); 135 SendErrorAndExit(std::move(response), "Unsupported request type: " + type);
109 } 136 }
110 } 137 }
111 138
112 void It2MeNativeMessagingHost::Start(Client* client) { 139 void It2MeNativeMessagingHost::Start(Client* client) {
113 DCHECK(task_runner()->BelongsToCurrentThread()); 140 DCHECK(task_runner()->BelongsToCurrentThread());
114 client_ = client; 141 client_ = client;
115 #if !defined(OS_CHROMEOS) 142 #if !defined(OS_CHROMEOS)
116 log_message_handler_.reset( 143 log_message_handler_.reset(
117 new LogMessageHandler( 144 new LogMessageHandler(
118 base::Bind(&It2MeNativeMessagingHost::SendMessageToClient, 145 base::Bind(&It2MeNativeMessagingHost::SendMessageToClient,
119 base::Unretained(this)))); 146 base::Unretained(this))));
120 #endif // !defined(OS_CHROMEOS) 147 #endif // !defined(OS_CHROMEOS)
121 } 148 }
122 149
123 void It2MeNativeMessagingHost::SendMessageToClient( 150 void It2MeNativeMessagingHost::SendMessageToClient(
124 std::unique_ptr<base::Value> message) const { 151 std::unique_ptr<base::Value> message) const {
125 DCHECK(task_runner()->BelongsToCurrentThread()); 152 DCHECK(task_runner()->BelongsToCurrentThread());
126 std::string message_json; 153 std::string message_json;
127 base::JSONWriter::Write(*message, &message_json); 154 base::JSONWriter::Write(*message, &message_json);
128 client_->PostMessageFromNativeHost(message_json); 155 client_->PostMessageFromNativeHost(message_json);
129 } 156 }
130 157
131 void It2MeNativeMessagingHost::ProcessHello( 158 void It2MeNativeMessagingHost::ProcessHello(
132 const base::DictionaryValue& message, 159 std::unique_ptr<base::DictionaryValue> message,
133 std::unique_ptr<base::DictionaryValue> response) const { 160 std::unique_ptr<base::DictionaryValue> response) const {
134 DCHECK(task_runner()->BelongsToCurrentThread()); 161 DCHECK(task_runner()->BelongsToCurrentThread());
135 162
136 response->SetString("version", STRINGIZE(VERSION)); 163 response->SetString("version", STRINGIZE(VERSION));
137 164
138 // This list will be populated when new features are added. 165 // This list will be populated when new features are added.
139 std::unique_ptr<base::ListValue> supported_features_list( 166 std::unique_ptr<base::ListValue> supported_features_list(
140 new base::ListValue()); 167 new base::ListValue());
141 response->Set("supportedFeatures", supported_features_list.release()); 168 response->Set("supportedFeatures", supported_features_list.release());
142 169
143 SendMessageToClient(std::move(response)); 170 SendMessageToClient(std::move(response));
144 } 171 }
145 172
146 void It2MeNativeMessagingHost::ProcessConnect( 173 void It2MeNativeMessagingHost::ProcessConnect(
147 const base::DictionaryValue& message, 174 std::unique_ptr<base::DictionaryValue> message,
148 std::unique_ptr<base::DictionaryValue> response) { 175 std::unique_ptr<base::DictionaryValue> response) {
149 DCHECK(task_runner()->BelongsToCurrentThread()); 176 DCHECK(task_runner()->BelongsToCurrentThread());
150 177
178 if (!policy_received_) {
179 DCHECK(pending_connect_.is_null());
180 pending_connect_ =
181 base::Bind(&It2MeNativeMessagingHost::ProcessConnect, weak_ptr_,
182 base::Passed(&message), base::Passed(&response));
183 return;
184 }
185
186 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.
187 if (!DelegateToElevatedHost(std::move(message))) {
188 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
189 SendMessageToClient(std::move(response));
190 }
191 return;
192 }
193
151 if (it2me_host_.get()) { 194 if (it2me_host_.get()) {
152 SendErrorAndExit(std::move(response), 195 SendErrorAndExit(std::move(response),
153 "Connect can be called only when disconnected."); 196 "Connect can be called only when disconnected.");
154 return; 197 return;
155 } 198 }
156 199
157 XmppSignalStrategy::XmppServerConfig xmpp_config = xmpp_server_config_; 200 XmppSignalStrategy::XmppServerConfig xmpp_config = xmpp_server_config_;
158 201
159 if (!message.GetString("userName", &xmpp_config.username)) { 202 if (!message->GetString("userName", &xmpp_config.username)) {
160 SendErrorAndExit(std::move(response), "'userName' not found in request."); 203 SendErrorAndExit(std::move(response), "'userName' not found in request.");
161 return; 204 return;
162 } 205 }
163 206
164 std::string auth_service_with_token; 207 std::string auth_service_with_token;
165 if (!message.GetString("authServiceWithToken", &auth_service_with_token)) { 208 if (!message->GetString("authServiceWithToken", &auth_service_with_token)) {
166 SendErrorAndExit(std::move(response), 209 SendErrorAndExit(std::move(response),
167 "'authServiceWithToken' not found in request."); 210 "'authServiceWithToken' not found in request.");
168 return; 211 return;
169 } 212 }
170 213
171 // For backward compatibility the webapp still passes OAuth service as part of 214 // For backward compatibility the webapp still passes OAuth service as part of
172 // the authServiceWithToken field. But auth service part is always expected to 215 // the authServiceWithToken field. But auth service part is always expected to
173 // be set to oauth2. 216 // be set to oauth2.
174 const char kOAuth2ServicePrefix[] = "oauth2:"; 217 const char kOAuth2ServicePrefix[] = "oauth2:";
175 if (!base::StartsWith(auth_service_with_token, kOAuth2ServicePrefix, 218 if (!base::StartsWith(auth_service_with_token, kOAuth2ServicePrefix,
176 base::CompareCase::SENSITIVE)) { 219 base::CompareCase::SENSITIVE)) {
177 SendErrorAndExit(std::move(response), "Invalid 'authServiceWithToken': " + 220 SendErrorAndExit(std::move(response), "Invalid 'authServiceWithToken': " +
178 auth_service_with_token); 221 auth_service_with_token);
179 return; 222 return;
180 } 223 }
181 224
182 xmpp_config.auth_token = 225 xmpp_config.auth_token =
183 auth_service_with_token.substr(strlen(kOAuth2ServicePrefix)); 226 auth_service_with_token.substr(strlen(kOAuth2ServicePrefix));
184 227
185 #if !defined(NDEBUG) 228 #if !defined(NDEBUG)
186 std::string address; 229 std::string address;
187 if (!message.GetString("xmppServerAddress", &address)) { 230 if (!message->GetString("xmppServerAddress", &address)) {
188 SendErrorAndExit(std::move(response), 231 SendErrorAndExit(std::move(response),
189 "'xmppServerAddress' not found in request."); 232 "'xmppServerAddress' not found in request.");
190 return; 233 return;
191 } 234 }
192 235
193 if (!net::ParseHostAndPort(address, &xmpp_config.host, 236 if (!net::ParseHostAndPort(address, &xmpp_config.host,
194 &xmpp_config.port)) { 237 &xmpp_config.port)) {
195 SendErrorAndExit(std::move(response), 238 SendErrorAndExit(std::move(response),
196 "Invalid 'xmppServerAddress': " + address); 239 "Invalid 'xmppServerAddress': " + address);
197 return; 240 return;
198 } 241 }
199 242
200 if (!message.GetBoolean("xmppServerUseTls", &xmpp_config.use_tls)) { 243 if (!message->GetBoolean("xmppServerUseTls", &xmpp_config.use_tls)) {
201 SendErrorAndExit(std::move(response), 244 SendErrorAndExit(std::move(response),
202 "'xmppServerUseTls' not found in request."); 245 "'xmppServerUseTls' not found in request.");
203 return; 246 return;
204 } 247 }
205 248
206 if (!message.GetString("directoryBotJid", &directory_bot_jid_)) { 249 if (!message->GetString("directoryBotJid", &directory_bot_jid_)) {
207 SendErrorAndExit(std::move(response), 250 SendErrorAndExit(std::move(response),
208 "'directoryBotJid' not found in request."); 251 "'directoryBotJid' not found in request.");
209 return; 252 return;
210 } 253 }
211 #endif // !defined(NDEBUG) 254 #endif // !defined(NDEBUG)
212 255
213 // Create the It2Me host and start connecting. 256 // Create the It2Me host and start connecting.
214 it2me_host_ = factory_->CreateIt2MeHost(host_context_->Copy(), 257 it2me_host_ = factory_->CreateIt2MeHost(host_context_->Copy(),
215 weak_ptr_, 258 weak_ptr_,
216 xmpp_config, 259 xmpp_config,
217 directory_bot_jid_); 260 directory_bot_jid_);
218 it2me_host_->Connect(); 261 it2me_host_->Connect();
219 262
220 SendMessageToClient(std::move(response)); 263 SendMessageToClient(std::move(response));
221 } 264 }
222 265
223 void It2MeNativeMessagingHost::ProcessDisconnect( 266 void It2MeNativeMessagingHost::ProcessDisconnect(
224 const base::DictionaryValue& message, 267 std::unique_ptr<base::DictionaryValue> message,
225 std::unique_ptr<base::DictionaryValue> response) { 268 std::unique_ptr<base::DictionaryValue> response) {
226 DCHECK(task_runner()->BelongsToCurrentThread()); 269 DCHECK(task_runner()->BelongsToCurrentThread());
270 DCHECK(policy_received_);
271
272 if (needs_elevation_ && allow_elevated_host_) {
273 if (!DelegateToElevatedHost(std::move(message))) {
274 response->SetBoolean("result", false);
275 SendMessageToClient(std::move(response));
276 }
277 return;
278 }
227 279
228 if (it2me_host_.get()) { 280 if (it2me_host_.get()) {
229 it2me_host_->Disconnect(); 281 it2me_host_->Disconnect();
230 it2me_host_ = nullptr; 282 it2me_host_ = nullptr;
231 } 283 }
232 SendMessageToClient(std::move(response)); 284 SendMessageToClient(std::move(response));
233 } 285 }
234 286
235 void It2MeNativeMessagingHost::SendErrorAndExit( 287 void It2MeNativeMessagingHost::SendErrorAndExit(
236 std::unique_ptr<base::DictionaryValue> response, 288 std::unique_ptr<base::DictionaryValue> response,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 It2MeNativeMessagingHost::task_runner() const { 373 It2MeNativeMessagingHost::task_runner() const {
322 return host_context_->ui_task_runner(); 374 return host_context_->ui_task_runner();
323 } 375 }
324 376
325 /* static */ 377 /* static */
326 std::string It2MeNativeMessagingHost::HostStateToString( 378 std::string It2MeNativeMessagingHost::HostStateToString(
327 It2MeHostState host_state) { 379 It2MeHostState host_state) {
328 return ValueToName(kIt2MeHostStates, host_state); 380 return ValueToName(kIt2MeHostStates, host_state);
329 } 381 }
330 382
383 void It2MeNativeMessagingHost::OnPolicyUpdate(
384 std::unique_ptr<base::DictionaryValue> policies) {
385 // The policy watcher runs on the |file_task_runner| but we want to run the
386 // update code on |task_runner|.
387 if (!task_runner()->BelongsToCurrentThread()) {
388 task_runner()->PostTask(
389 FROM_HERE, base::Bind(&It2MeNativeMessagingHost::OnPolicyUpdate,
390 weak_ptr_, base::Passed(&policies)));
391 return;
392 }
393
394 if (policy_received_) {
395 // Don't dynamically change how the host operates since we don't have a good
396 // way to communicate changes to the user.
397 return;
398 }
399
400 if (!policies->GetBoolean(
401 policy::key::kRemoteAccessHostAllowUiAccessForRemoteAssistance,
402 &allow_elevated_host_)) {
403 LOG(WARNING) << "Failed to retrieve elevated host policy value.";
404 }
405
406 policy_received_ = true;
407 if (!pending_connect_.is_null()) {
408 base::ResetAndReturn(&pending_connect_).Run();
409 }
410 }
411
412 void It2MeNativeMessagingHost::OnPolicyError() {
413 // TODO(joedow): Report the policy error to the user. crbug.com/433009
414 NOTIMPLEMENTED();
415 }
416
417 #if defined(OS_WIN)
418
419 bool It2MeNativeMessagingHost::DelegateToElevatedHost(
420 std::unique_ptr<base::DictionaryValue> message) {
421 DCHECK(task_runner()->BelongsToCurrentThread());
422 DCHECK(needs_elevation_);
423 DCHECK(allow_elevated_host_);
424
425 if (!elevated_host_) {
426 base::FilePath binary_path =
427 base::CommandLine::ForCurrentProcess()->GetProgram();
428 CHECK(binary_path.BaseName() == base::FilePath(kBaseHostBinaryName));
429
430 // The new process runs at an elevated level due to being granted uiAccess.
431 elevated_host_.reset(new ElevatedNativeMessagingHost(
432 binary_path.DirName().Append(kElevatedHostBinaryName),
433 /*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.
434 /*elevate_process=*/false,
435 /*host_timeout=*/base::TimeDelta(), client_));
436 }
437
438 if (elevated_host_->EnsureElevatedHostCreated()) {
439 elevated_host_->SendMessage(std::move(message));
440 return true;
441 }
442
443 return false;
444 }
445
446 #else // !defined(OS_WIN)
447
448 bool It2MeNativeMessagingHost::DelegateToElevatedHost(
449 std::unique_ptr<base::DictionaryValue> message) {
450 NOTREACHED();
451 return false;
452 }
453
454 #endif // !defined(OS_WIN)
455
331 } // namespace remoting 456 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698