Home | History | Annotate | Download | only in host
      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/ipc_util.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/single_thread_task_runner.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "base/win/scoped_handle.h"
     12 #include "base/win/win_util.h"
     13 #include "ipc/ipc_channel.h"
     14 #include "ipc/ipc_channel_proxy.h"
     15 #include "remoting/host/win/security_descriptor.h"
     16 
     17 using base::win::ScopedHandle;
     18 
     19 namespace remoting {
     20 
     21 // Pipe name prefix used by Chrome IPC channels to convert a channel name into
     22 // a pipe name.
     23 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome.";
     24 
     25 bool CreateConnectedIpcChannel(
     26     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
     27     IPC::Listener* listener,
     28     IPC::PlatformFileForTransit* client_out,
     29     scoped_ptr<IPC::ChannelProxy>* server_out) {
     30   // presubmit: allow wstring
     31   std::wstring user_sid;
     32   if (!base::win::GetUserSidString(&user_sid)) {
     33     LOG(ERROR) << "Failed to query the current user SID.";
     34     return false;
     35   }
     36 
     37   // Create a security descriptor that will be used to protect the named pipe in
     38   // between CreateNamedPipe() and CreateFile() calls before it will be passed
     39   // to the network process. It gives full access to the account that
     40   // the calling code is running under and  denies access by anyone else.
     41   std::string security_descriptor = base::StringPrintf(
     42       "O:%1$sG:%1$sD:(A;;GA;;;%1$s)", WideToUTF8(user_sid).c_str());
     43 
     44   // Generate a unique name for the channel.
     45   std::string channel_name = IPC::Channel::GenerateUniqueRandomChannelID();
     46 
     47   // Create the server end of the channel.
     48   ScopedHandle pipe;
     49   if (!CreateIpcChannel(channel_name, security_descriptor, &pipe)) {
     50     return false;
     51   }
     52 
     53   // Wrap the pipe into an IPC channel.
     54   scoped_ptr<IPC::ChannelProxy> server(new IPC::ChannelProxy(
     55       IPC::ChannelHandle(pipe),
     56       IPC::Channel::MODE_SERVER,
     57       listener,
     58       io_task_runner));
     59 
     60   // Convert the channel name to the pipe name.
     61   std::string pipe_name(kChromePipeNamePrefix);
     62   pipe_name.append(channel_name);
     63 
     64   SECURITY_ATTRIBUTES security_attributes = {0};
     65   security_attributes.nLength = sizeof(security_attributes);
     66   security_attributes.lpSecurityDescriptor = NULL;
     67   security_attributes.bInheritHandle = TRUE;
     68 
     69   // Create the client end of the channel. This code should match the code in
     70   // IPC::Channel.
     71   ScopedHandle client;
     72   client.Set(CreateFile(UTF8ToUTF16(pipe_name).c_str(),
     73                         GENERIC_READ | GENERIC_WRITE,
     74                         0,
     75                         &security_attributes,
     76                         OPEN_EXISTING,
     77                         SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
     78                             FILE_FLAG_OVERLAPPED,
     79                         NULL));
     80   if (!client.IsValid()) {
     81     LOG_GETLASTERROR(ERROR) << "Failed to connect to '" << pipe_name << "'";
     82     return false;
     83   }
     84 
     85   *client_out = client.Take();
     86   *server_out = server.Pass();
     87   return true;
     88 }
     89 
     90 bool CreateIpcChannel(
     91     const std::string& channel_name,
     92     const std::string& pipe_security_descriptor,
     93     base::win::ScopedHandle* pipe_out) {
     94   // Create security descriptor for the channel.
     95   ScopedSd sd = ConvertSddlToSd(pipe_security_descriptor);
     96   if (!sd) {
     97     LOG_GETLASTERROR(ERROR) <<
     98         "Failed to create a security descriptor for the Chromoting IPC channel";
     99     return false;
    100   }
    101 
    102   SECURITY_ATTRIBUTES security_attributes = {0};
    103   security_attributes.nLength = sizeof(security_attributes);
    104   security_attributes.lpSecurityDescriptor = sd.get();
    105   security_attributes.bInheritHandle = FALSE;
    106 
    107   // Convert the channel name to the pipe name.
    108   std::string pipe_name(kChromePipeNamePrefix);
    109   pipe_name.append(channel_name);
    110 
    111   // Create the server end of the pipe. This code should match the code in
    112   // IPC::Channel with exception of passing a non-default security descriptor.
    113   base::win::ScopedHandle pipe;
    114   pipe.Set(CreateNamedPipe(
    115       UTF8ToUTF16(pipe_name).c_str(),
    116       PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
    117       PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
    118       1,
    119       IPC::Channel::kReadBufferSize,
    120       IPC::Channel::kReadBufferSize,
    121       5000,
    122       &security_attributes));
    123   if (!pipe.IsValid()) {
    124     LOG_GETLASTERROR(ERROR) <<
    125         "Failed to create the server end of the Chromoting IPC channel";
    126     return false;
    127   }
    128 
    129   *pipe_out = pipe.Pass();
    130   return true;
    131 }
    132 
    133 } // namespace remoting
    134