// 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.Get()),
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