| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/host/ipc_util.h" |
| |
| #include "base/files/file.h" |
| #include "base/logging.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/win/scoped_handle.h" |
| #include "base/win/win_util.h" |
| #include "ipc/ipc_channel.h" |
| #include "ipc/ipc_channel_proxy.h" |
| #include "remoting/host/win/security_descriptor.h" |
| |
| using base::win::ScopedHandle; |
| |
| namespace remoting { |
| |
| // Pipe name prefix used by Chrome IPC channels to convert a channel name into |
| // a pipe name. |
| const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome."; |
| |
| bool CreateConnectedIpcChannel( |
| scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
| IPC::Listener* listener, |
| base::File* client_out, |
| scoped_ptr<IPC::ChannelProxy>* server_out) { |
| // presubmit: allow wstring |
| std::wstring user_sid; |
| if (!base::win::GetUserSidString(&user_sid)) { |
| LOG(ERROR) << "Failed to query the current user SID."; |
| return false; |
| } |
| |
| // Create a security descriptor that will be used to protect the named pipe in |
| // between CreateNamedPipe() and CreateFile() calls before it will be passed |
| // to the network process. It gives full access to the account that |
| // the calling code is running under and denies access by anyone else. |
| std::string security_descriptor = base::StringPrintf( |
| "O:%1$sG:%1$sD:(A;;GA;;;%1$s)", base::WideToUTF8(user_sid).c_str()); |
| |
| // Generate a unique name for the channel. |
| std::string channel_name = IPC::Channel::GenerateUniqueRandomChannelID(); |
| |
| // Create the server end of the channel. |
| ScopedHandle pipe; |
| if (!CreateIpcChannel(channel_name, security_descriptor, &pipe)) { |
| return false; |
| } |
| |
| // Wrap the pipe into an IPC channel. |
| scoped_ptr<IPC::ChannelProxy> server = |
| IPC::ChannelProxy::Create(IPC::ChannelHandle(pipe), |
| IPC::Channel::MODE_SERVER, |
| listener, |
| io_task_runner); |
| |
| // Convert the channel name to the pipe name. |
| std::string pipe_name(kChromePipeNamePrefix); |
| pipe_name.append(channel_name); |
| |
| SECURITY_ATTRIBUTES security_attributes = {0}; |
| security_attributes.nLength = sizeof(security_attributes); |
| security_attributes.lpSecurityDescriptor = NULL; |
| security_attributes.bInheritHandle = TRUE; |
| |
| // Create the client end of the channel. This code should match the code in |
| // IPC::Channel. |
| base::File client(CreateFile(base::UTF8ToUTF16(pipe_name).c_str(), |
| GENERIC_READ | GENERIC_WRITE, |
| 0, |
| &security_attributes, |
| OPEN_EXISTING, |
| SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION | |
| FILE_FLAG_OVERLAPPED, |
| NULL)); |
| if (!client.IsValid()) { |
| PLOG(ERROR) << "Failed to connect to '" << pipe_name << "'"; |
| return false; |
| } |
| |
| *client_out = client.Pass(); |
| *server_out = server.Pass(); |
| return true; |
| } |
| |
| bool CreateIpcChannel( |
| const std::string& channel_name, |
| const std::string& pipe_security_descriptor, |
| base::win::ScopedHandle* pipe_out) { |
| // Create security descriptor for the channel. |
| ScopedSd sd = ConvertSddlToSd(pipe_security_descriptor); |
| if (!sd) { |
| PLOG(ERROR) << "Failed to create a security descriptor for the Chromoting " |
| "IPC channel"; |
| return false; |
| } |
| |
| SECURITY_ATTRIBUTES security_attributes = {0}; |
| security_attributes.nLength = sizeof(security_attributes); |
| security_attributes.lpSecurityDescriptor = sd.get(); |
| security_attributes.bInheritHandle = FALSE; |
| |
| // Convert the channel name to the pipe name. |
| std::string pipe_name(kChromePipeNamePrefix); |
| pipe_name.append(channel_name); |
| |
| // Create the server end of the pipe. This code should match the code in |
| // IPC::Channel with exception of passing a non-default security descriptor. |
| base::win::ScopedHandle pipe; |
| pipe.Set(CreateNamedPipe( |
| base::UTF8ToUTF16(pipe_name).c_str(), |
| PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, |
| PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, |
| 1, |
| IPC::Channel::kReadBufferSize, |
| IPC::Channel::kReadBufferSize, |
| 5000, |
| &security_attributes)); |
| if (!pipe.IsValid()) { |
| PLOG(ERROR) |
| << "Failed to create the server end of the Chromoting IPC channel"; |
| return false; |
| } |
| |
| *pipe_out = pipe.Pass(); |
| return true; |
| } |
| |
| } // namespace remoting |