Home | History | Annotate | Download | only in setup
      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
    715