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/files/file.h"
8#include "base/logging.h"
9#include "base/single_thread_task_runner.h"
10#include "base/strings/stringprintf.h"
11#include "base/strings/utf_string_conversions.h"
12#include "base/win/scoped_handle.h"
13#include "base/win/win_util.h"
14#include "ipc/ipc_channel.h"
15#include "ipc/ipc_channel_proxy.h"
16#include "remoting/host/win/security_descriptor.h"
17
18using base::win::ScopedHandle;
19
20namespace remoting {
21
22// Pipe name prefix used by Chrome IPC channels to convert a channel name into
23// a pipe name.
24const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome.";
25
26bool CreateConnectedIpcChannel(
27    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
28    IPC::Listener* listener,
29    base::File* client_out,
30    scoped_ptr<IPC::ChannelProxy>* server_out) {
31  // presubmit: allow wstring
32  std::wstring user_sid;
33  if (!base::win::GetUserSidString(&user_sid)) {
34    LOG(ERROR) << "Failed to query the current user SID.";
35    return false;
36  }
37
38  // Create a security descriptor that will be used to protect the named pipe in
39  // between CreateNamedPipe() and CreateFile() calls before it will be passed
40  // to the network process. It gives full access to the account that
41  // the calling code is running under and  denies access by anyone else.
42  std::string security_descriptor = base::StringPrintf(
43      "O:%1$sG:%1$sD:(A;;GA;;;%1$s)", base::WideToUTF8(user_sid).c_str());
44
45  // Generate a unique name for the channel.
46  std::string channel_name = IPC::Channel::GenerateUniqueRandomChannelID();
47
48  // Create the server end of the channel.
49  ScopedHandle pipe;
50  if (!CreateIpcChannel(channel_name, security_descriptor, &pipe)) {
51    return false;
52  }
53
54  // Wrap the pipe into an IPC channel.
55  scoped_ptr<IPC::ChannelProxy> server =
56      IPC::ChannelProxy::Create(IPC::ChannelHandle(pipe.Get()),
57                                IPC::Channel::MODE_SERVER,
58                                listener,
59                                io_task_runner);
60
61  // Convert the channel name to the pipe name.
62  std::string pipe_name(kChromePipeNamePrefix);
63  pipe_name.append(channel_name);
64
65  SECURITY_ATTRIBUTES security_attributes = {0};
66  security_attributes.nLength = sizeof(security_attributes);
67  security_attributes.lpSecurityDescriptor = NULL;
68  security_attributes.bInheritHandle = TRUE;
69
70  // Create the client end of the channel. This code should match the code in
71  // IPC::Channel.
72  base::File client(CreateFile(base::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    PLOG(ERROR) << "Failed to connect to '" << pipe_name << "'";
82    return false;
83  }
84
85  *client_out = client.Pass();
86  *server_out = server.Pass();
87  return true;
88}
89
90bool 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    PLOG(ERROR) << "Failed to create a security descriptor for the Chromoting "
98                   "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      base::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    PLOG(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