Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / remoting / host / setup / me2me_native_messaging_host.cc
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.
4
5 #include "remoting/host/setup/me2me_native_messaging_host.h"
6 #include <string>
7
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/native_messaging/pipe_messaging_channel.h"
25 #include "remoting/host/pin_hash.h"
26 #include "remoting/host/setup/oauth_client.h"
27 #include "remoting/protocol/pairing_registry.h"
28
29 #if defined(OS_WIN)
30 #include <shellapi.h>
31 #include "base/win/win_util.h"
32 #include "remoting/host/win/security_descriptor.h"
33 #endif  // defined(OS_WIN)
34
35 namespace {
36
37 #if defined(OS_WIN)
38 // Windows will use default buffer size when 0 is passed to CreateNamedPipeW().
39 const DWORD kBufferSize = 0;
40 const int kTimeOutMilliseconds = 2000;
41 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome_remote_desktop.";
42 const int kElevatedHostTimeoutSeconds = 300;
43 #endif  // defined(OS_WIN)
44
45 // redirect_uri to use when authenticating service accounts (service account
46 // codes are obtained "out-of-band", i.e., not through an OAuth redirect).
47 const char* kServiceAccountRedirectUri = "oob";
48
49 // Features supported in addition to the base protocol.
50 const char* kSupportedFeatures[] = {
51   "pairingRegistry",
52   "oauthClient"
53 };
54
55 // Helper to extract the "config" part of a message as a DictionaryValue.
56 // Returns NULL on failure, and logs an error message.
57 scoped_ptr<base::DictionaryValue> ConfigDictionaryFromMessage(
58     scoped_ptr<base::DictionaryValue> message) {
59   scoped_ptr<base::DictionaryValue> result;
60   const base::DictionaryValue* config_dict;
61   if (message->GetDictionary("config", &config_dict)) {
62     result.reset(config_dict->DeepCopy());
63   } else {
64     LOG(ERROR) << "'config' dictionary not found";
65   }
66   return result.Pass();
67 }
68
69 }  // namespace
70
71 namespace remoting {
72
73 Me2MeNativeMessagingHost::Me2MeNativeMessagingHost(
74     bool needs_elevation,
75     intptr_t parent_window_handle,
76     scoped_ptr<extensions::NativeMessagingChannel> channel,
77     scoped_refptr<DaemonController> daemon_controller,
78     scoped_refptr<protocol::PairingRegistry> pairing_registry,
79     scoped_ptr<OAuthClient> oauth_client)
80     : needs_elevation_(needs_elevation),
81       parent_window_handle_(parent_window_handle),
82       channel_(channel.Pass()),
83       daemon_controller_(daemon_controller),
84       pairing_registry_(pairing_registry),
85       oauth_client_(oauth_client.Pass()),
86       weak_factory_(this) {
87   weak_ptr_ = weak_factory_.GetWeakPtr();
88 }
89
90 Me2MeNativeMessagingHost::~Me2MeNativeMessagingHost() {
91   DCHECK(thread_checker_.CalledOnValidThread());
92 }
93
94 void Me2MeNativeMessagingHost::Start(
95       const base::Closure& quit_closure) {
96   DCHECK(thread_checker_.CalledOnValidThread());
97   DCHECK(!quit_closure.is_null());
98
99   quit_closure_ = quit_closure;
100
101   channel_->Start(this);
102 }
103
104 void Me2MeNativeMessagingHost::OnMessage(scoped_ptr<base::Value> message) {
105   DCHECK(thread_checker_.CalledOnValidThread());
106
107   scoped_ptr<base::DictionaryValue> message_dict(
108       static_cast<base::DictionaryValue*>(message.release()));
109   scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue());
110
111   // If the client supplies an ID, it will expect it in the response. This
112   // might be a string or a number, so cope with both.
113   const base::Value* id;
114   if (message_dict->Get("id", &id))
115     response->Set("id", id->DeepCopy());
116
117   std::string type;
118   if (!message_dict->GetString("type", &type)) {
119     LOG(ERROR) << "'type' not found";
120     channel_->SendMessage(scoped_ptr<base::Value>());
121     return;
122   }
123
124   response->SetString("type", type + "Response");
125
126   if (type == "hello") {
127     ProcessHello(message_dict.Pass(), response.Pass());
128   } else if (type == "clearPairedClients") {
129     ProcessClearPairedClients(message_dict.Pass(), response.Pass());
130   } else if (type == "deletePairedClient") {
131     ProcessDeletePairedClient(message_dict.Pass(), response.Pass());
132   } else if (type == "getHostName") {
133     ProcessGetHostName(message_dict.Pass(), response.Pass());
134   } else if (type == "getPinHash") {
135     ProcessGetPinHash(message_dict.Pass(), response.Pass());
136   } else if (type == "generateKeyPair") {
137     ProcessGenerateKeyPair(message_dict.Pass(), response.Pass());
138   } else if (type == "updateDaemonConfig") {
139     ProcessUpdateDaemonConfig(message_dict.Pass(), response.Pass());
140   } else if (type == "getDaemonConfig") {
141     ProcessGetDaemonConfig(message_dict.Pass(), response.Pass());
142   } else if (type == "getPairedClients") {
143     ProcessGetPairedClients(message_dict.Pass(), response.Pass());
144   } else if (type == "getUsageStatsConsent") {
145     ProcessGetUsageStatsConsent(message_dict.Pass(), response.Pass());
146   } else if (type == "startDaemon") {
147     ProcessStartDaemon(message_dict.Pass(), response.Pass());
148   } else if (type == "stopDaemon") {
149     ProcessStopDaemon(message_dict.Pass(), response.Pass());
150   } else if (type == "getDaemonState") {
151     ProcessGetDaemonState(message_dict.Pass(), response.Pass());
152   } else if (type == "getHostClientId") {
153     ProcessGetHostClientId(message_dict.Pass(), response.Pass());
154   } else if (type == "getCredentialsFromAuthCode") {
155     ProcessGetCredentialsFromAuthCode(message_dict.Pass(), response.Pass());
156   } else {
157     LOG(ERROR) << "Unsupported request type: " << type;
158     OnError();
159   }
160 }
161
162 void Me2MeNativeMessagingHost::OnDisconnect() {
163   if (!quit_closure_.is_null())
164     base::ResetAndReturn(&quit_closure_).Run();
165 }
166
167 void Me2MeNativeMessagingHost::ProcessHello(
168     scoped_ptr<base::DictionaryValue> message,
169     scoped_ptr<base::DictionaryValue> response) {
170   DCHECK(thread_checker_.CalledOnValidThread());
171
172   response->SetString("version", STRINGIZE(VERSION));
173   scoped_ptr<base::ListValue> supported_features_list(new base::ListValue());
174   supported_features_list->AppendStrings(std::vector<std::string>(
175       kSupportedFeatures, kSupportedFeatures + arraysize(kSupportedFeatures)));
176   response->Set("supportedFeatures", supported_features_list.release());
177   channel_->SendMessage(response.PassAs<base::Value>());
178 }
179
180 void Me2MeNativeMessagingHost::ProcessClearPairedClients(
181     scoped_ptr<base::DictionaryValue> message,
182     scoped_ptr<base::DictionaryValue> response) {
183   DCHECK(thread_checker_.CalledOnValidThread());
184
185   if (needs_elevation_) {
186     if (!DelegateToElevatedHost(message.Pass()))
187       SendBooleanResult(response.Pass(), false);
188     return;
189   }
190
191   if (pairing_registry_.get()) {
192     pairing_registry_->ClearAllPairings(
193         base::Bind(&Me2MeNativeMessagingHost::SendBooleanResult, weak_ptr_,
194                    base::Passed(&response)));
195   } else {
196     SendBooleanResult(response.Pass(), false);
197   }
198 }
199
200 void Me2MeNativeMessagingHost::ProcessDeletePairedClient(
201     scoped_ptr<base::DictionaryValue> message,
202     scoped_ptr<base::DictionaryValue> response) {
203   DCHECK(thread_checker_.CalledOnValidThread());
204
205   if (needs_elevation_) {
206     if (!DelegateToElevatedHost(message.Pass()))
207       SendBooleanResult(response.Pass(), false);
208     return;
209   }
210
211   std::string client_id;
212   if (!message->GetString(protocol::PairingRegistry::kClientIdKey,
213                           &client_id)) {
214     LOG(ERROR) << "'" << protocol::PairingRegistry::kClientIdKey
215                << "' string not found.";
216     OnError();
217     return;
218   }
219
220   if (pairing_registry_.get()) {
221     pairing_registry_->DeletePairing(
222         client_id, base::Bind(&Me2MeNativeMessagingHost::SendBooleanResult,
223                               weak_ptr_, base::Passed(&response)));
224   } else {
225     SendBooleanResult(response.Pass(), false);
226   }
227 }
228
229 void Me2MeNativeMessagingHost::ProcessGetHostName(
230     scoped_ptr<base::DictionaryValue> message,
231     scoped_ptr<base::DictionaryValue> response) {
232   DCHECK(thread_checker_.CalledOnValidThread());
233
234   response->SetString("hostname", net::GetHostName());
235   channel_->SendMessage(response.PassAs<base::Value>());
236 }
237
238 void Me2MeNativeMessagingHost::ProcessGetPinHash(
239     scoped_ptr<base::DictionaryValue> message,
240     scoped_ptr<base::DictionaryValue> response) {
241   DCHECK(thread_checker_.CalledOnValidThread());
242
243   std::string host_id;
244   if (!message->GetString("hostId", &host_id)) {
245     LOG(ERROR) << "'hostId' not found: " << message;
246     OnError();
247     return;
248   }
249   std::string pin;
250   if (!message->GetString("pin", &pin)) {
251     LOG(ERROR) << "'pin' not found: " << message;
252     OnError();
253     return;
254   }
255   response->SetString("hash", MakeHostPinHash(host_id, pin));
256   channel_->SendMessage(response.PassAs<base::Value>());
257 }
258
259 void Me2MeNativeMessagingHost::ProcessGenerateKeyPair(
260     scoped_ptr<base::DictionaryValue> message,
261     scoped_ptr<base::DictionaryValue> response) {
262   DCHECK(thread_checker_.CalledOnValidThread());
263
264   scoped_refptr<RsaKeyPair> key_pair = RsaKeyPair::Generate();
265   response->SetString("privateKey", key_pair->ToString());
266   response->SetString("publicKey", key_pair->GetPublicKey());
267   channel_->SendMessage(response.PassAs<base::Value>());
268 }
269
270 void Me2MeNativeMessagingHost::ProcessUpdateDaemonConfig(
271     scoped_ptr<base::DictionaryValue> message,
272     scoped_ptr<base::DictionaryValue> response) {
273   DCHECK(thread_checker_.CalledOnValidThread());
274
275   scoped_ptr<base::DictionaryValue> config_dict =
276       ConfigDictionaryFromMessage(message.Pass());
277   if (!config_dict) {
278     OnError();
279     return;
280   }
281
282   daemon_controller_->UpdateConfig(
283       config_dict.Pass(),
284       base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
285                  base::Passed(&response)));
286 }
287
288 void Me2MeNativeMessagingHost::ProcessGetDaemonConfig(
289     scoped_ptr<base::DictionaryValue> message,
290     scoped_ptr<base::DictionaryValue> response) {
291   DCHECK(thread_checker_.CalledOnValidThread());
292
293   daemon_controller_->GetConfig(
294       base::Bind(&Me2MeNativeMessagingHost::SendConfigResponse, weak_ptr_,
295                  base::Passed(&response)));
296 }
297
298 void Me2MeNativeMessagingHost::ProcessGetPairedClients(
299     scoped_ptr<base::DictionaryValue> message,
300     scoped_ptr<base::DictionaryValue> response) {
301   DCHECK(thread_checker_.CalledOnValidThread());
302
303   if (pairing_registry_.get()) {
304     pairing_registry_->GetAllPairings(
305         base::Bind(&Me2MeNativeMessagingHost::SendPairedClientsResponse,
306                    weak_ptr_, base::Passed(&response)));
307   } else {
308     scoped_ptr<base::ListValue> no_paired_clients(new base::ListValue);
309     SendPairedClientsResponse(response.Pass(), no_paired_clients.Pass());
310   }
311 }
312
313 void Me2MeNativeMessagingHost::ProcessGetUsageStatsConsent(
314     scoped_ptr<base::DictionaryValue> message,
315     scoped_ptr<base::DictionaryValue> response) {
316   DCHECK(thread_checker_.CalledOnValidThread());
317
318   daemon_controller_->GetUsageStatsConsent(
319       base::Bind(&Me2MeNativeMessagingHost::SendUsageStatsConsentResponse,
320                  weak_ptr_, base::Passed(&response)));
321 }
322
323 void Me2MeNativeMessagingHost::ProcessStartDaemon(
324     scoped_ptr<base::DictionaryValue> message,
325     scoped_ptr<base::DictionaryValue> response) {
326   DCHECK(thread_checker_.CalledOnValidThread());
327
328   bool consent;
329   if (!message->GetBoolean("consent", &consent)) {
330     LOG(ERROR) << "'consent' not found.";
331     OnError();
332     return;
333   }
334
335   scoped_ptr<base::DictionaryValue> config_dict =
336       ConfigDictionaryFromMessage(message.Pass());
337   if (!config_dict) {
338     OnError();
339     return;
340   }
341
342   daemon_controller_->SetConfigAndStart(
343       config_dict.Pass(), consent,
344       base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
345                  base::Passed(&response)));
346 }
347
348 void Me2MeNativeMessagingHost::ProcessStopDaemon(
349     scoped_ptr<base::DictionaryValue> message,
350     scoped_ptr<base::DictionaryValue> response) {
351   DCHECK(thread_checker_.CalledOnValidThread());
352
353   daemon_controller_->Stop(
354       base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
355                  base::Passed(&response)));
356 }
357
358 void Me2MeNativeMessagingHost::ProcessGetDaemonState(
359     scoped_ptr<base::DictionaryValue> message,
360     scoped_ptr<base::DictionaryValue> response) {
361   DCHECK(thread_checker_.CalledOnValidThread());
362
363   DaemonController::State state = daemon_controller_->GetState();
364   switch (state) {
365     case DaemonController::STATE_NOT_IMPLEMENTED:
366       response->SetString("state", "NOT_IMPLEMENTED");
367       break;
368     case DaemonController::STATE_NOT_INSTALLED:
369       response->SetString("state", "NOT_INSTALLED");
370       break;
371     case DaemonController::STATE_INSTALLING:
372       response->SetString("state", "INSTALLING");
373       break;
374     case DaemonController::STATE_STOPPED:
375       response->SetString("state", "STOPPED");
376       break;
377     case DaemonController::STATE_STARTING:
378       response->SetString("state", "STARTING");
379       break;
380     case DaemonController::STATE_STARTED:
381       response->SetString("state", "STARTED");
382       break;
383     case DaemonController::STATE_STOPPING:
384       response->SetString("state", "STOPPING");
385       break;
386     case DaemonController::STATE_UNKNOWN:
387       response->SetString("state", "UNKNOWN");
388       break;
389   }
390   channel_->SendMessage(response.PassAs<base::Value>());
391 }
392
393 void Me2MeNativeMessagingHost::ProcessGetHostClientId(
394     scoped_ptr<base::DictionaryValue> message,
395     scoped_ptr<base::DictionaryValue> response) {
396   DCHECK(thread_checker_.CalledOnValidThread());
397
398   response->SetString("clientId", google_apis::GetOAuth2ClientID(
399       google_apis::CLIENT_REMOTING_HOST));
400   channel_->SendMessage(response.PassAs<base::Value>());
401 }
402
403 void Me2MeNativeMessagingHost::ProcessGetCredentialsFromAuthCode(
404     scoped_ptr<base::DictionaryValue> message,
405     scoped_ptr<base::DictionaryValue> response) {
406   DCHECK(thread_checker_.CalledOnValidThread());
407
408   std::string auth_code;
409   if (!message->GetString("authorizationCode", &auth_code)) {
410     LOG(ERROR) << "'authorizationCode' string not found.";
411     OnError();
412     return;
413   }
414
415   gaia::OAuthClientInfo oauth_client_info = {
416     google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING_HOST),
417     google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING_HOST),
418     kServiceAccountRedirectUri
419   };
420
421   oauth_client_->GetCredentialsFromAuthCode(
422       oauth_client_info, auth_code, base::Bind(
423           &Me2MeNativeMessagingHost::SendCredentialsResponse, weak_ptr_,
424           base::Passed(&response)));
425 }
426
427 void Me2MeNativeMessagingHost::SendConfigResponse(
428     scoped_ptr<base::DictionaryValue> response,
429     scoped_ptr<base::DictionaryValue> config) {
430   DCHECK(thread_checker_.CalledOnValidThread());
431
432   if (config) {
433     response->Set("config", config.release());
434   } else {
435     response->Set("config", base::Value::CreateNullValue());
436   }
437   channel_->SendMessage(response.PassAs<base::Value>());
438 }
439
440 void Me2MeNativeMessagingHost::SendPairedClientsResponse(
441     scoped_ptr<base::DictionaryValue> response,
442     scoped_ptr<base::ListValue> pairings) {
443   DCHECK(thread_checker_.CalledOnValidThread());
444
445   response->Set("pairedClients", pairings.release());
446   channel_->SendMessage(response.PassAs<base::Value>());
447 }
448
449 void Me2MeNativeMessagingHost::SendUsageStatsConsentResponse(
450     scoped_ptr<base::DictionaryValue> response,
451     const DaemonController::UsageStatsConsent& consent) {
452   DCHECK(thread_checker_.CalledOnValidThread());
453
454   response->SetBoolean("supported", consent.supported);
455   response->SetBoolean("allowed", consent.allowed);
456   response->SetBoolean("setByPolicy", consent.set_by_policy);
457   channel_->SendMessage(response.PassAs<base::Value>());
458 }
459
460 void Me2MeNativeMessagingHost::SendAsyncResult(
461     scoped_ptr<base::DictionaryValue> response,
462     DaemonController::AsyncResult result) {
463   DCHECK(thread_checker_.CalledOnValidThread());
464
465   switch (result) {
466     case DaemonController::RESULT_OK:
467       response->SetString("result", "OK");
468       break;
469     case DaemonController::RESULT_FAILED:
470       response->SetString("result", "FAILED");
471       break;
472     case DaemonController::RESULT_CANCELLED:
473       response->SetString("result", "CANCELLED");
474       break;
475     case DaemonController::RESULT_FAILED_DIRECTORY:
476       response->SetString("result", "FAILED_DIRECTORY");
477       break;
478   }
479   channel_->SendMessage(response.PassAs<base::Value>());
480 }
481
482 void Me2MeNativeMessagingHost::SendBooleanResult(
483     scoped_ptr<base::DictionaryValue> response, bool result) {
484   DCHECK(thread_checker_.CalledOnValidThread());
485
486   response->SetBoolean("result", result);
487   channel_->SendMessage(response.PassAs<base::Value>());
488 }
489
490 void Me2MeNativeMessagingHost::SendCredentialsResponse(
491     scoped_ptr<base::DictionaryValue> response,
492     const std::string& user_email,
493     const std::string& refresh_token) {
494   DCHECK(thread_checker_.CalledOnValidThread());
495
496   response->SetString("userEmail", user_email);
497   response->SetString("refreshToken", refresh_token);
498   channel_->SendMessage(response.PassAs<base::Value>());
499 }
500
501 void Me2MeNativeMessagingHost::OnError() {
502   // Trigger a host shutdown by sending a NULL message.
503   channel_->SendMessage(scoped_ptr<base::Value>());
504 }
505
506 void Me2MeNativeMessagingHost::Stop() {
507   DCHECK(thread_checker_.CalledOnValidThread());
508
509   if (!quit_closure_.is_null())
510     base::ResetAndReturn(&quit_closure_).Run();
511 }
512
513 #if defined(OS_WIN)
514 Me2MeNativeMessagingHost::ElevatedChannelEventHandler::
515     ElevatedChannelEventHandler(Me2MeNativeMessagingHost* host)
516     : parent_(host) {
517 }
518
519 void Me2MeNativeMessagingHost::ElevatedChannelEventHandler::OnMessage(
520     scoped_ptr<base::Value> message) {
521   DCHECK(parent_->thread_checker_.CalledOnValidThread());
522
523   // Simply pass along the response from the elevated host to the client.
524   parent_->channel_->SendMessage(message.Pass());
525 }
526
527 void Me2MeNativeMessagingHost::ElevatedChannelEventHandler::OnDisconnect() {
528   parent_->OnDisconnect();
529 }
530
531 bool Me2MeNativeMessagingHost::DelegateToElevatedHost(
532     scoped_ptr<base::DictionaryValue> message) {
533   DCHECK(thread_checker_.CalledOnValidThread());
534
535   EnsureElevatedHostCreated();
536
537   // elevated_channel_ will be null if user rejects the UAC request.
538   if (elevated_channel_)
539     elevated_channel_->SendMessage(message.PassAs<base::Value>());
540
541   return elevated_channel_ != NULL;
542 }
543
544 void Me2MeNativeMessagingHost::EnsureElevatedHostCreated() {
545   DCHECK(thread_checker_.CalledOnValidThread());
546   DCHECK(needs_elevation_);
547
548   if (elevated_channel_)
549     return;
550
551   // presubmit: allow wstring
552   std::wstring user_sid;
553   if (!base::win::GetUserSidString(&user_sid)) {
554     LOG(ERROR) << "Failed to query the current user SID.";
555     OnError();
556     return;
557   }
558
559   // Create a security descriptor that gives full access to the caller and
560   // denies access by anyone else.
561   std::string security_descriptor = base::StringPrintf(
562       "O:%1$sG:%1$sD:(A;;GA;;;%1$s)", base::UTF16ToASCII(user_sid).c_str());
563
564   ScopedSd sd = ConvertSddlToSd(security_descriptor);
565   if (!sd) {
566     PLOG(ERROR) << "Failed to create a security descriptor for the"
567                 << "Chromoting Me2Me native messaging host.";
568     OnError();
569     return;
570   }
571
572   SECURITY_ATTRIBUTES security_attributes = {0};
573   security_attributes.nLength = sizeof(security_attributes);
574   security_attributes.lpSecurityDescriptor = sd.get();
575   security_attributes.bInheritHandle = FALSE;
576
577   // Generate a unique name for the input channel.
578   std::string input_pipe_name(kChromePipeNamePrefix);
579   input_pipe_name.append(IPC::Channel::GenerateUniqueRandomChannelID());
580
581   base::win::ScopedHandle delegate_write_handle(::CreateNamedPipe(
582       base::ASCIIToUTF16(input_pipe_name).c_str(),
583       PIPE_ACCESS_OUTBOUND,
584       PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
585       1,
586       kBufferSize,
587       kBufferSize,
588       kTimeOutMilliseconds,
589       &security_attributes));
590
591   if (!delegate_write_handle.IsValid()) {
592     PLOG(ERROR) << "Failed to create named pipe '" << input_pipe_name << "'";
593     OnError();
594     return;
595   }
596
597   // Generate a unique name for the input channel.
598   std::string output_pipe_name(kChromePipeNamePrefix);
599   output_pipe_name.append(IPC::Channel::GenerateUniqueRandomChannelID());
600
601   base::win::ScopedHandle delegate_read_handle(::CreateNamedPipe(
602       base::ASCIIToUTF16(output_pipe_name).c_str(),
603       PIPE_ACCESS_INBOUND,
604       PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
605       1,
606       kBufferSize,
607       kBufferSize,
608       kTimeOutMilliseconds,
609       &security_attributes));
610
611   if (!delegate_read_handle.IsValid()) {
612     PLOG(ERROR) << "Failed to create named pipe '" << output_pipe_name << "'";
613     OnError();
614     return;
615   }
616
617   const base::CommandLine* current_command_line =
618       base::CommandLine::ForCurrentProcess();
619   const base::CommandLine::SwitchMap& switches =
620       current_command_line->GetSwitches();
621   base::CommandLine::StringVector args = current_command_line->GetArgs();
622
623   // Create the child process command line by copying switches from the current
624   // command line.
625   base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
626   command_line.AppendSwitch(kElevatingSwitchName);
627   command_line.AppendSwitchASCII(kInputSwitchName, input_pipe_name);
628   command_line.AppendSwitchASCII(kOutputSwitchName, output_pipe_name);
629
630   DCHECK(!current_command_line->HasSwitch(kElevatingSwitchName));
631   for (base::CommandLine::SwitchMap::const_iterator i = switches.begin();
632        i != switches.end(); ++i) {
633       command_line.AppendSwitchNative(i->first, i->second);
634   }
635   for (base::CommandLine::StringVector::const_iterator i = args.begin();
636        i != args.end(); ++i) {
637     command_line.AppendArgNative(*i);
638   }
639
640   // Get the name of the binary to launch.
641   base::FilePath binary = current_command_line->GetProgram();
642   base::CommandLine::StringType parameters =
643       command_line.GetCommandLineString();
644
645   // Launch the child process requesting elevation.
646   SHELLEXECUTEINFO info;
647   memset(&info, 0, sizeof(info));
648   info.cbSize = sizeof(info);
649   info.hwnd = reinterpret_cast<HWND>(parent_window_handle_);
650   info.lpVerb = L"runas";
651   info.lpFile = binary.value().c_str();
652   info.lpParameters = parameters.c_str();
653   info.nShow = SW_HIDE;
654
655   if (!ShellExecuteEx(&info)) {
656     DWORD error = ::GetLastError();
657     PLOG(ERROR) << "Unable to launch '" << binary.value() << "'";
658     if (error != ERROR_CANCELLED) {
659       OnError();
660     }
661     return;
662   }
663
664   if (!::ConnectNamedPipe(delegate_write_handle.Get(), NULL)) {
665     DWORD error = ::GetLastError();
666     if (error != ERROR_PIPE_CONNECTED) {
667       PLOG(ERROR) << "Unable to connect '" << input_pipe_name << "'";
668       OnError();
669       return;
670     }
671   }
672
673   if (!::ConnectNamedPipe(delegate_read_handle.Get(), NULL)) {
674     DWORD error = ::GetLastError();
675     if (error != ERROR_PIPE_CONNECTED) {
676       PLOG(ERROR) << "Unable to connect '" << output_pipe_name << "'";
677       OnError();
678       return;
679     }
680   }
681
682   // Set up the native messaging channel to talk to the elevated host.
683   // Note that input for the elevated channel is output for the elevated host.
684   elevated_channel_.reset(
685       new PipeMessagingChannel(base::File(delegate_read_handle.Take()),
686                                base::File(delegate_write_handle.Take())));
687
688   elevated_channel_event_handler_.reset(
689       new Me2MeNativeMessagingHost::ElevatedChannelEventHandler(this));
690   elevated_channel_->Start(elevated_channel_event_handler_.get());
691
692   elevated_host_timer_.Start(
693       FROM_HERE, base::TimeDelta::FromSeconds(kElevatedHostTimeoutSeconds),
694       this, &Me2MeNativeMessagingHost::DisconnectElevatedHost);
695 }
696
697 void Me2MeNativeMessagingHost::DisconnectElevatedHost() {
698   DCHECK(thread_checker_.CalledOnValidThread());
699
700   // This will send an EOF to the elevated host, triggering its shutdown.
701   elevated_channel_.reset();
702 }
703
704 #else  // defined(OS_WIN)
705
706 bool Me2MeNativeMessagingHost::DelegateToElevatedHost(
707     scoped_ptr<base::DictionaryValue> message) {
708   NOTREACHED();
709   return false;
710 }
711
712 #endif  // !defined(OS_WIN)
713
714 }  // namespace remoting