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