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
CreateConnectedIpcChannel(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,IPC::Listener * listener,IPC::PlatformFileForTransit * client_out,scoped_ptr<IPC::ChannelProxy> * server_out)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
CreateIpcChannel(const std::string & channel_name,const std::string & pipe_security_descriptor,base::win::ScopedHandle * pipe_out)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