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