Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / remoting / host / setup / me2me_native_messaging_host.cc
blob51b77ef574887820a5e37c5b60d58763940dfd51
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
3 // found in the LICENSE file.
5 #include "remoting/host/setup/me2me_native_messaging_host.h"
6 #include <string>
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/callback_helpers.h"
12 #include "base/command_line.h"
13 #include "base/logging.h"
14 #include "base/strings/stringize_macros.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/threading/thread.h"
18 #include "base/values.h"
19 #include "google_apis/gaia/gaia_oauth_client.h"
20 #include "google_apis/google_api_keys.h"
21 #include "ipc/ipc_channel.h"
22 #include "net/base/net_util.h"
23 #include "remoting/base/rsa_key_pair.h"
24 #include "remoting/host/pin_hash.h"
25 #include "remoting/host/setup/oauth_client.h"
26 #include "remoting/protocol/pairing_registry.h"
28 #if defined(OS_WIN)
29 #include <shellapi.h>
30 #include "base/win/win_util.h"
31 #include "remoting/host/win/security_descriptor.h"
32 #endif // defined(OS_WIN)
34 namespace {
36 #if defined(OS_WIN)
37 // Windows will use default buffer size when 0 is passed to CreateNamedPipeW().
38 const DWORD kBufferSize = 0;
39 const int kTimeOutMilliseconds = 2000;
40 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome_remote_desktop.";
41 const int kElevatedHostTimeoutSeconds = 300;
42 #endif // defined(OS_WIN)
44 // redirect_uri to use when authenticating service accounts (service account
45 // codes are obtained "out-of-band", i.e., not through an OAuth redirect).
46 const char* kServiceAccountRedirectUri = "oob";
48 // Features supported in addition to the base protocol.
49 const char* kSupportedFeatures[] = {
50 "pairingRegistry",
51 "oauthClient"
54 // Helper to extract the "config" part of a message as a DictionaryValue.
55 // Returns NULL on failure, and logs an error message.
56 scoped_ptr<base::DictionaryValue> ConfigDictionaryFromMessage(
57 scoped_ptr<base::DictionaryValue> message) {
58 scoped_ptr<base::DictionaryValue> result;
59 const base::DictionaryValue* config_dict;
60 if (message->GetDictionary("config", &config_dict)) {
61 result.reset(config_dict->DeepCopy());
62 } else {
63 LOG(ERROR) << "'config' dictionary not found";
65 return result.Pass();
68 } // namespace
70 namespace remoting {
72 Me2MeNativeMessagingHost::Me2MeNativeMessagingHost(
73 bool needs_elevation,
74 intptr_t parent_window_handle,
75 scoped_ptr<NativeMessagingChannel> channel,
76 scoped_refptr<DaemonController> daemon_controller,
77 scoped_refptr<protocol::PairingRegistry> pairing_registry,
78 scoped_ptr<OAuthClient> oauth_client)
79 : needs_elevation_(needs_elevation),
80 parent_window_handle_(parent_window_handle),
81 channel_(channel.Pass()),
82 daemon_controller_(daemon_controller),
83 pairing_registry_(pairing_registry),
84 oauth_client_(oauth_client.Pass()),
85 weak_factory_(this) {
86 weak_ptr_ = weak_factory_.GetWeakPtr();
89 Me2MeNativeMessagingHost::~Me2MeNativeMessagingHost() {
90 DCHECK(thread_checker_.CalledOnValidThread());
93 void Me2MeNativeMessagingHost::Start(
94 const base::Closure& quit_closure) {
95 DCHECK(thread_checker_.CalledOnValidThread());
97 quit_closure_ = quit_closure;
99 channel_->Start(
100 base::Bind(&Me2MeNativeMessagingHost::ProcessRequest, weak_ptr_),
101 base::Bind(&Me2MeNativeMessagingHost::Stop, weak_ptr_));
104 void Me2MeNativeMessagingHost::ProcessRequest(
105 scoped_ptr<base::DictionaryValue> message) {
106 DCHECK(thread_checker_.CalledOnValidThread());
108 scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue());
110 // If the client supplies an ID, it will expect it in the response. This
111 // might be a string or a number, so cope with both.
112 const base::Value* id;
113 if (message->Get("id", &id))
114 response->Set("id", id->DeepCopy());
116 std::string type;
117 if (!message->GetString("type", &type)) {
118 LOG(ERROR) << "'type' not found";
119 channel_->SendMessage(scoped_ptr<base::DictionaryValue>());
120 return;
123 response->SetString("type", type + "Response");
125 if (type == "hello") {
126 ProcessHello(message.Pass(), response.Pass());
127 } else if (type == "clearPairedClients") {
128 ProcessClearPairedClients(message.Pass(), response.Pass());
129 } else if (type == "deletePairedClient") {
130 ProcessDeletePairedClient(message.Pass(), response.Pass());
131 } else if (type == "getHostName") {
132 ProcessGetHostName(message.Pass(), response.Pass());
133 } else if (type == "getPinHash") {
134 ProcessGetPinHash(message.Pass(), response.Pass());
135 } else if (type == "generateKeyPair") {
136 ProcessGenerateKeyPair(message.Pass(), response.Pass());
137 } else if (type == "updateDaemonConfig") {
138 ProcessUpdateDaemonConfig(message.Pass(), response.Pass());
139 } else if (type == "getDaemonConfig") {
140 ProcessGetDaemonConfig(message.Pass(), response.Pass());
141 } else if (type == "getPairedClients") {
142 ProcessGetPairedClients(message.Pass(), response.Pass());
143 } else if (type == "getUsageStatsConsent") {
144 ProcessGetUsageStatsConsent(message.Pass(), response.Pass());
145 } else if (type == "startDaemon") {
146 ProcessStartDaemon(message.Pass(), response.Pass());
147 } else if (type == "stopDaemon") {
148 ProcessStopDaemon(message.Pass(), response.Pass());
149 } else if (type == "getDaemonState") {
150 ProcessGetDaemonState(message.Pass(), response.Pass());
151 } else if (type == "getHostClientId") {
152 ProcessGetHostClientId(message.Pass(), response.Pass());
153 } else if (type == "getCredentialsFromAuthCode") {
154 ProcessGetCredentialsFromAuthCode(message.Pass(), response.Pass());
155 } else {
156 LOG(ERROR) << "Unsupported request type: " << type;
157 OnError();
161 void Me2MeNativeMessagingHost::ProcessHello(
162 scoped_ptr<base::DictionaryValue> message,
163 scoped_ptr<base::DictionaryValue> response) {
164 DCHECK(thread_checker_.CalledOnValidThread());
166 response->SetString("version", STRINGIZE(VERSION));
167 scoped_ptr<base::ListValue> supported_features_list(new base::ListValue());
168 supported_features_list->AppendStrings(std::vector<std::string>(
169 kSupportedFeatures, kSupportedFeatures + arraysize(kSupportedFeatures)));
170 response->Set("supportedFeatures", supported_features_list.release());
171 channel_->SendMessage(response.Pass());
174 void Me2MeNativeMessagingHost::ProcessClearPairedClients(
175 scoped_ptr<base::DictionaryValue> message,
176 scoped_ptr<base::DictionaryValue> response) {
177 DCHECK(thread_checker_.CalledOnValidThread());
179 if (needs_elevation_) {
180 if (!DelegateToElevatedHost(message.Pass()))
181 SendBooleanResult(response.Pass(), false);
182 return;
185 if (pairing_registry_.get()) {
186 pairing_registry_->ClearAllPairings(
187 base::Bind(&Me2MeNativeMessagingHost::SendBooleanResult, weak_ptr_,
188 base::Passed(&response)));
189 } else {
190 SendBooleanResult(response.Pass(), false);
194 void Me2MeNativeMessagingHost::ProcessDeletePairedClient(
195 scoped_ptr<base::DictionaryValue> message,
196 scoped_ptr<base::DictionaryValue> response) {
197 DCHECK(thread_checker_.CalledOnValidThread());
199 if (needs_elevation_) {
200 if (!DelegateToElevatedHost(message.Pass()))
201 SendBooleanResult(response.Pass(), false);
202 return;
205 std::string client_id;
206 if (!message->GetString(protocol::PairingRegistry::kClientIdKey,
207 &client_id)) {
208 LOG(ERROR) << "'" << protocol::PairingRegistry::kClientIdKey
209 << "' string not found.";
210 OnError();
211 return;
214 if (pairing_registry_.get()) {
215 pairing_registry_->DeletePairing(
216 client_id, base::Bind(&Me2MeNativeMessagingHost::SendBooleanResult,
217 weak_ptr_, base::Passed(&response)));
218 } else {
219 SendBooleanResult(response.Pass(), false);
223 void Me2MeNativeMessagingHost::ProcessGetHostName(
224 scoped_ptr<base::DictionaryValue> message,
225 scoped_ptr<base::DictionaryValue> response) {
226 DCHECK(thread_checker_.CalledOnValidThread());
228 response->SetString("hostname", net::GetHostName());
229 channel_->SendMessage(response.Pass());
232 void Me2MeNativeMessagingHost::ProcessGetPinHash(
233 scoped_ptr<base::DictionaryValue> message,
234 scoped_ptr<base::DictionaryValue> response) {
235 DCHECK(thread_checker_.CalledOnValidThread());
237 std::string host_id;
238 if (!message->GetString("hostId", &host_id)) {
239 LOG(ERROR) << "'hostId' not found: " << message;
240 OnError();
241 return;
243 std::string pin;
244 if (!message->GetString("pin", &pin)) {
245 LOG(ERROR) << "'pin' not found: " << message;
246 OnError();
247 return;
249 response->SetString("hash", MakeHostPinHash(host_id, pin));
250 channel_->SendMessage(response.Pass());
253 void Me2MeNativeMessagingHost::ProcessGenerateKeyPair(
254 scoped_ptr<base::DictionaryValue> message,
255 scoped_ptr<base::DictionaryValue> response) {
256 DCHECK(thread_checker_.CalledOnValidThread());
258 scoped_refptr<RsaKeyPair> key_pair = RsaKeyPair::Generate();
259 response->SetString("privateKey", key_pair->ToString());
260 response->SetString("publicKey", key_pair->GetPublicKey());
261 channel_->SendMessage(response.Pass());
264 void Me2MeNativeMessagingHost::ProcessUpdateDaemonConfig(
265 scoped_ptr<base::DictionaryValue> message,
266 scoped_ptr<base::DictionaryValue> response) {
267 DCHECK(thread_checker_.CalledOnValidThread());
269 scoped_ptr<base::DictionaryValue> config_dict =
270 ConfigDictionaryFromMessage(message.Pass());
271 if (!config_dict) {
272 OnError();
273 return;
276 daemon_controller_->UpdateConfig(
277 config_dict.Pass(),
278 base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
279 base::Passed(&response)));
282 void Me2MeNativeMessagingHost::ProcessGetDaemonConfig(
283 scoped_ptr<base::DictionaryValue> message,
284 scoped_ptr<base::DictionaryValue> response) {
285 DCHECK(thread_checker_.CalledOnValidThread());
287 daemon_controller_->GetConfig(
288 base::Bind(&Me2MeNativeMessagingHost::SendConfigResponse, weak_ptr_,
289 base::Passed(&response)));
292 void Me2MeNativeMessagingHost::ProcessGetPairedClients(
293 scoped_ptr<base::DictionaryValue> message,
294 scoped_ptr<base::DictionaryValue> response) {
295 DCHECK(thread_checker_.CalledOnValidThread());
297 if (pairing_registry_.get()) {
298 pairing_registry_->GetAllPairings(
299 base::Bind(&Me2MeNativeMessagingHost::SendPairedClientsResponse,
300 weak_ptr_, base::Passed(&response)));
301 } else {
302 scoped_ptr<base::ListValue> no_paired_clients(new base::ListValue);
303 SendPairedClientsResponse(response.Pass(), no_paired_clients.Pass());
307 void Me2MeNativeMessagingHost::ProcessGetUsageStatsConsent(
308 scoped_ptr<base::DictionaryValue> message,
309 scoped_ptr<base::DictionaryValue> response) {
310 DCHECK(thread_checker_.CalledOnValidThread());
312 daemon_controller_->GetUsageStatsConsent(
313 base::Bind(&Me2MeNativeMessagingHost::SendUsageStatsConsentResponse,
314 weak_ptr_, base::Passed(&response)));
317 void Me2MeNativeMessagingHost::ProcessStartDaemon(
318 scoped_ptr<base::DictionaryValue> message,
319 scoped_ptr<base::DictionaryValue> response) {
320 DCHECK(thread_checker_.CalledOnValidThread());
322 bool consent;
323 if (!message->GetBoolean("consent", &consent)) {
324 LOG(ERROR) << "'consent' not found.";
325 OnError();
326 return;
329 scoped_ptr<base::DictionaryValue> config_dict =
330 ConfigDictionaryFromMessage(message.Pass());
331 if (!config_dict) {
332 OnError();
333 return;
336 daemon_controller_->SetConfigAndStart(
337 config_dict.Pass(), consent,
338 base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
339 base::Passed(&response)));
342 void Me2MeNativeMessagingHost::ProcessStopDaemon(
343 scoped_ptr<base::DictionaryValue> message,
344 scoped_ptr<base::DictionaryValue> response) {
345 DCHECK(thread_checker_.CalledOnValidThread());
347 daemon_controller_->Stop(
348 base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
349 base::Passed(&response)));
352 void Me2MeNativeMessagingHost::ProcessGetDaemonState(
353 scoped_ptr<base::DictionaryValue> message,
354 scoped_ptr<base::DictionaryValue> response) {
355 DCHECK(thread_checker_.CalledOnValidThread());
357 DaemonController::State state = daemon_controller_->GetState();
358 switch (state) {
359 case DaemonController::STATE_NOT_IMPLEMENTED:
360 response->SetString("state", "NOT_IMPLEMENTED");
361 break;
362 case DaemonController::STATE_NOT_INSTALLED:
363 response->SetString("state", "NOT_INSTALLED");
364 break;
365 case DaemonController::STATE_INSTALLING:
366 response->SetString("state", "INSTALLING");
367 break;
368 case DaemonController::STATE_STOPPED:
369 response->SetString("state", "STOPPED");
370 break;
371 case DaemonController::STATE_STARTING:
372 response->SetString("state", "STARTING");
373 break;
374 case DaemonController::STATE_STARTED:
375 response->SetString("state", "STARTED");
376 break;
377 case DaemonController::STATE_STOPPING:
378 response->SetString("state", "STOPPING");
379 break;
380 case DaemonController::STATE_UNKNOWN:
381 response->SetString("state", "UNKNOWN");
382 break;
384 channel_->SendMessage(response.Pass());
387 void Me2MeNativeMessagingHost::ProcessGetHostClientId(
388 scoped_ptr<base::DictionaryValue> message,
389 scoped_ptr<base::DictionaryValue> response) {
390 DCHECK(thread_checker_.CalledOnValidThread());
392 response->SetString("clientId", google_apis::GetOAuth2ClientID(
393 google_apis::CLIENT_REMOTING_HOST));
394 channel_->SendMessage(response.Pass());
397 void Me2MeNativeMessagingHost::ProcessGetCredentialsFromAuthCode(
398 scoped_ptr<base::DictionaryValue> message,
399 scoped_ptr<base::DictionaryValue> response) {
400 DCHECK(thread_checker_.CalledOnValidThread());
402 std::string auth_code;
403 if (!message->GetString("authorizationCode", &auth_code)) {
404 LOG(ERROR) << "'authorizationCode' string not found.";
405 OnError();
406 return;
409 gaia::OAuthClientInfo oauth_client_info = {
410 google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING_HOST),
411 google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING_HOST),
412 kServiceAccountRedirectUri
415 oauth_client_->GetCredentialsFromAuthCode(
416 oauth_client_info, auth_code, base::Bind(
417 &Me2MeNativeMessagingHost::SendCredentialsResponse, weak_ptr_,
418 base::Passed(&response)));
421 void Me2MeNativeMessagingHost::SendConfigResponse(
422 scoped_ptr<base::DictionaryValue> response,
423 scoped_ptr<base::DictionaryValue> config) {
424 DCHECK(thread_checker_.CalledOnValidThread());
426 if (config) {
427 response->Set("config", config.release());
428 } else {
429 response->Set("config", base::Value::CreateNullValue());
431 channel_->SendMessage(response.Pass());
434 void Me2MeNativeMessagingHost::SendPairedClientsResponse(
435 scoped_ptr<base::DictionaryValue> response,
436 scoped_ptr<base::ListValue> pairings) {
437 DCHECK(thread_checker_.CalledOnValidThread());
439 response->Set("pairedClients", pairings.release());
440 channel_->SendMessage(response.Pass());
443 void Me2MeNativeMessagingHost::SendUsageStatsConsentResponse(
444 scoped_ptr<base::DictionaryValue> response,
445 const DaemonController::UsageStatsConsent& consent) {
446 DCHECK(thread_checker_.CalledOnValidThread());
448 response->SetBoolean("supported", consent.supported);
449 response->SetBoolean("allowed", consent.allowed);
450 response->SetBoolean("setByPolicy", consent.set_by_policy);
451 channel_->SendMessage(response.Pass());
454 void Me2MeNativeMessagingHost::SendAsyncResult(
455 scoped_ptr<base::DictionaryValue> response,
456 DaemonController::AsyncResult result) {
457 DCHECK(thread_checker_.CalledOnValidThread());
459 switch (result) {
460 case DaemonController::RESULT_OK:
461 response->SetString("result", "OK");
462 break;
463 case DaemonController::RESULT_FAILED:
464 response->SetString("result", "FAILED");
465 break;
466 case DaemonController::RESULT_CANCELLED:
467 response->SetString("result", "CANCELLED");
468 break;
469 case DaemonController::RESULT_FAILED_DIRECTORY:
470 response->SetString("result", "FAILED_DIRECTORY");
471 break;
473 channel_->SendMessage(response.Pass());
476 void Me2MeNativeMessagingHost::SendBooleanResult(
477 scoped_ptr<base::DictionaryValue> response, bool result) {
478 DCHECK(thread_checker_.CalledOnValidThread());
480 response->SetBoolean("result", result);
481 channel_->SendMessage(response.Pass());
484 void Me2MeNativeMessagingHost::SendCredentialsResponse(
485 scoped_ptr<base::DictionaryValue> response,
486 const std::string& user_email,
487 const std::string& refresh_token) {
488 DCHECK(thread_checker_.CalledOnValidThread());
490 response->SetString("userEmail", user_email);
491 response->SetString("refreshToken", refresh_token);
492 channel_->SendMessage(response.Pass());
495 void Me2MeNativeMessagingHost::OnError() {
496 // Trigger a host shutdown by sending a NULL message.
497 channel_->SendMessage(scoped_ptr<base::DictionaryValue>());
500 void Me2MeNativeMessagingHost::Stop() {
501 DCHECK(thread_checker_.CalledOnValidThread());
503 if (!quit_closure_.is_null())
504 base::ResetAndReturn(&quit_closure_).Run();
507 #if defined(OS_WIN)
509 bool Me2MeNativeMessagingHost::DelegateToElevatedHost(
510 scoped_ptr<base::DictionaryValue> message) {
511 DCHECK(thread_checker_.CalledOnValidThread());
513 EnsureElevatedHostCreated();
515 // elevated_channel_ will be null if user rejects the UAC request.
516 if (elevated_channel_)
517 elevated_channel_->SendMessage(message.Pass());
519 return elevated_channel_ != NULL;
522 void Me2MeNativeMessagingHost::EnsureElevatedHostCreated() {
523 DCHECK(thread_checker_.CalledOnValidThread());
524 DCHECK(needs_elevation_);
526 if (elevated_channel_)
527 return;
529 // presubmit: allow wstring
530 std::wstring user_sid;
531 if (!base::win::GetUserSidString(&user_sid)) {
532 LOG(ERROR) << "Failed to query the current user SID.";
533 OnError();
534 return;
537 // Create a security descriptor that gives full access to the caller and
538 // denies access by anyone else.
539 std::string security_descriptor = base::StringPrintf(
540 "O:%1$sG:%1$sD:(A;;GA;;;%1$s)", base::UTF16ToASCII(user_sid).c_str());
542 ScopedSd sd = ConvertSddlToSd(security_descriptor);
543 if (!sd) {
544 PLOG(ERROR) << "Failed to create a security descriptor for the"
545 << "Chromoting Me2Me native messaging host.";
546 OnError();
547 return;
550 SECURITY_ATTRIBUTES security_attributes = {0};
551 security_attributes.nLength = sizeof(security_attributes);
552 security_attributes.lpSecurityDescriptor = sd.get();
553 security_attributes.bInheritHandle = FALSE;
555 // Generate a unique name for the input channel.
556 std::string input_pipe_name(kChromePipeNamePrefix);
557 input_pipe_name.append(IPC::Channel::GenerateUniqueRandomChannelID());
559 base::win::ScopedHandle delegate_write_handle(::CreateNamedPipe(
560 base::ASCIIToUTF16(input_pipe_name).c_str(),
561 PIPE_ACCESS_OUTBOUND,
562 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
564 kBufferSize,
565 kBufferSize,
566 kTimeOutMilliseconds,
567 &security_attributes));
569 if (!delegate_write_handle.IsValid()) {
570 PLOG(ERROR) << "Failed to create named pipe '" << input_pipe_name << "'";
571 OnError();
572 return;
575 // Generate a unique name for the input channel.
576 std::string output_pipe_name(kChromePipeNamePrefix);
577 output_pipe_name.append(IPC::Channel::GenerateUniqueRandomChannelID());
579 base::win::ScopedHandle delegate_read_handle(::CreateNamedPipe(
580 base::ASCIIToUTF16(output_pipe_name).c_str(),
581 PIPE_ACCESS_INBOUND,
582 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
584 kBufferSize,
585 kBufferSize,
586 kTimeOutMilliseconds,
587 &security_attributes));
589 if (!delegate_read_handle.IsValid()) {
590 PLOG(ERROR) << "Failed to create named pipe '" << output_pipe_name << "'";
591 OnError();
592 return;
595 const base::CommandLine* current_command_line =
596 base::CommandLine::ForCurrentProcess();
597 const base::CommandLine::SwitchMap& switches =
598 current_command_line->GetSwitches();
599 base::CommandLine::StringVector args = current_command_line->GetArgs();
601 // Create the child process command line by copying switches from the current
602 // command line.
603 base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
604 command_line.AppendSwitch(kElevatingSwitchName);
605 command_line.AppendSwitchASCII(kInputSwitchName, input_pipe_name);
606 command_line.AppendSwitchASCII(kOutputSwitchName, output_pipe_name);
608 DCHECK(!current_command_line->HasSwitch(kElevatingSwitchName));
609 for (base::CommandLine::SwitchMap::const_iterator i = switches.begin();
610 i != switches.end(); ++i) {
611 command_line.AppendSwitchNative(i->first, i->second);
613 for (base::CommandLine::StringVector::const_iterator i = args.begin();
614 i != args.end(); ++i) {
615 command_line.AppendArgNative(*i);
618 // Get the name of the binary to launch.
619 base::FilePath binary = current_command_line->GetProgram();
620 base::CommandLine::StringType parameters =
621 command_line.GetCommandLineString();
623 // Launch the child process requesting elevation.
624 SHELLEXECUTEINFO info;
625 memset(&info, 0, sizeof(info));
626 info.cbSize = sizeof(info);
627 info.hwnd = reinterpret_cast<HWND>(parent_window_handle_);
628 info.lpVerb = L"runas";
629 info.lpFile = binary.value().c_str();
630 info.lpParameters = parameters.c_str();
631 info.nShow = SW_HIDE;
633 if (!ShellExecuteEx(&info)) {
634 DWORD error = ::GetLastError();
635 PLOG(ERROR) << "Unable to launch '" << binary.value() << "'";
636 if (error != ERROR_CANCELLED) {
637 OnError();
639 return;
642 if (!::ConnectNamedPipe(delegate_write_handle.Get(), NULL)) {
643 DWORD error = ::GetLastError();
644 if (error != ERROR_PIPE_CONNECTED) {
645 PLOG(ERROR) << "Unable to connect '" << input_pipe_name << "'";
646 OnError();
647 return;
651 if (!::ConnectNamedPipe(delegate_read_handle.Get(), NULL)) {
652 DWORD error = ::GetLastError();
653 if (error != ERROR_PIPE_CONNECTED) {
654 PLOG(ERROR) << "Unable to connect '" << output_pipe_name << "'";
655 OnError();
656 return;
660 // Set up the native messaging channel to talk to the elevated host.
661 // Note that input for the elevate channel is output forthe elevated host.
662 elevated_channel_.reset(new NativeMessagingChannel(
663 base::File(delegate_read_handle.Take()),
664 base::File(delegate_write_handle.Take())));
666 elevated_channel_->Start(
667 base::Bind(&Me2MeNativeMessagingHost::ProcessDelegateResponse, weak_ptr_),
668 base::Bind(&Me2MeNativeMessagingHost::Stop, weak_ptr_));
670 elevated_host_timer_.Start(
671 FROM_HERE, base::TimeDelta::FromSeconds(kElevatedHostTimeoutSeconds),
672 this, &Me2MeNativeMessagingHost::DisconnectElevatedHost);
675 void Me2MeNativeMessagingHost::ProcessDelegateResponse(
676 scoped_ptr<base::DictionaryValue> message) {
677 DCHECK(thread_checker_.CalledOnValidThread());
679 // Simply pass along the response from the elevated host to the client.
680 channel_->SendMessage(message.Pass());
683 void Me2MeNativeMessagingHost::DisconnectElevatedHost() {
684 DCHECK(thread_checker_.CalledOnValidThread());
686 // This will send an EOF to the elevated host, triggering its shutdown.
687 elevated_channel_.reset();
690 #else // defined(OS_WIN)
692 bool Me2MeNativeMessagingHost::DelegateToElevatedHost(
693 scoped_ptr<base::DictionaryValue> message) {
694 NOTREACHED();
695 return false;
698 #endif // !defined(OS_WIN)
700 } // namespace remoting