| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/it2me/it2me_native_messaging_host_main.h" | 5 #include "remoting/host/it2me/it2me_native_messaging_host_main.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/at_exit.h" | 9 #include "base/at_exit.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 | 30 |
| 31 #include "base/linux_util.h" | 31 #include "base/linux_util.h" |
| 32 #endif // defined(OS_LINUX) | 32 #endif // defined(OS_LINUX) |
| 33 | 33 |
| 34 #if defined(OS_MACOSX) | 34 #if defined(OS_MACOSX) |
| 35 #include "base/mac/scoped_nsautorelease_pool.h" | 35 #include "base/mac/scoped_nsautorelease_pool.h" |
| 36 #endif // defined(OS_MACOSX) | 36 #endif // defined(OS_MACOSX) |
| 37 | 37 |
| 38 #if defined(OS_WIN) | 38 #if defined(OS_WIN) |
| 39 #include <commctrl.h> | 39 #include <commctrl.h> |
| 40 |
| 41 #include "remoting/host/switches.h" |
| 42 #include "remoting/host/win/elevation_helpers.h" |
| 40 #endif // defined(OS_WIN) | 43 #endif // defined(OS_WIN) |
| 41 | 44 |
| 42 namespace remoting { | 45 namespace remoting { |
| 43 | 46 |
| 44 // Creates a It2MeNativeMessagingHost instance, attaches it to stdin/stdout and | 47 // Creates a It2MeNativeMessagingHost instance, attaches it to stdin/stdout and |
| 45 // runs the message loop until It2MeNativeMessagingHost signals shutdown. | 48 // runs the message loop until It2MeNativeMessagingHost signals shutdown. |
| 46 int StartIt2MeNativeMessagingHost() { | 49 int StartIt2MeNativeMessagingHost() { |
| 47 #if defined(OS_MACOSX) | 50 #if defined(OS_MACOSX) |
| 48 // Needed so we don't leak objects when threads are created. | 51 // Needed so we don't leak objects when threads are created. |
| 49 base::mac::ScopedNSAutoreleasePool pool; | 52 base::mac::ScopedNSAutoreleasePool pool; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 | 86 |
| 84 // Need to prime the host OS version value for linux to prevent IO on the | 87 // Need to prime the host OS version value for linux to prevent IO on the |
| 85 // network thread. base::GetLinuxDistro() caches the result. | 88 // network thread. base::GetLinuxDistro() caches the result. |
| 86 base::GetLinuxDistro(); | 89 base::GetLinuxDistro(); |
| 87 #endif // OS_LINUX | 90 #endif // OS_LINUX |
| 88 | 91 |
| 89 // Enable support for SSL server sockets, which must be done while still | 92 // Enable support for SSL server sockets, which must be done while still |
| 90 // single-threaded. | 93 // single-threaded. |
| 91 net::EnableSSLServerSockets(); | 94 net::EnableSSLServerSockets(); |
| 92 | 95 |
| 96 base::File read_file; |
| 97 base::File write_file; |
| 98 bool needs_elevation = false; |
| 99 |
| 93 #if defined(OS_WIN) | 100 #if defined(OS_WIN) |
| 94 // GetStdHandle() returns pseudo-handles for stdin and stdout even if | |
| 95 // the hosting executable specifies "Windows" subsystem. However the returned | |
| 96 // handles are invalid in that case unless standard input and output are | |
| 97 // redirected to a pipe or file. | |
| 98 base::File read_file(GetStdHandle(STD_INPUT_HANDLE)); | |
| 99 base::File write_file(GetStdHandle(STD_OUTPUT_HANDLE)); | |
| 100 | 101 |
| 101 // After the native messaging channel starts the native messaging reader | 102 const base::CommandLine* command_line = |
| 102 // will keep doing blocking read operations on the input named pipe. | 103 base::CommandLine::ForCurrentProcess(); |
| 103 // If any other thread tries to perform any operation on STDIN, it will also | 104 |
| 104 // block because the input named pipe is synchronous (non-overlapped). | 105 if (command_line->HasSwitch(kElevateSwitchName)) { |
| 105 // It is pretty common for a DLL to query the device info (GetFileType) of | 106 #if defined(OFFICIAL_BUILD) |
| 106 // the STD* handles at startup. So any LoadLibrary request can potentially | 107 // Unofficial builds won't have 'UiAccess' since it requires signing. |
| 107 // be blocked. To prevent that from happening we close STDIN and STDOUT | 108 if (!CurrentProcessHasUiAccess()) { |
| 108 // handles as soon as we retrieve the corresponding file handles. | 109 LOG(ERROR) << "UiAccess permission missing from elevated It2Me process."; |
| 109 SetStdHandle(STD_INPUT_HANDLE, nullptr); | 110 } |
| 110 SetStdHandle(STD_OUTPUT_HANDLE, nullptr); | 111 #endif // defined(OFFICIAL_BUILD) |
| 112 |
| 113 // The UiAccess binary should always have the "input" and "output" switches |
| 114 // specified, they represent the name of the named pipes that should be used |
| 115 // in place of stdin and stdout. |
| 116 DCHECK(command_line->HasSwitch(kInputSwitchName)); |
| 117 DCHECK(command_line->HasSwitch(kOutputSwitchName)); |
| 118 |
| 119 // presubmit: allow wstring |
| 120 std::wstring input_pipe_name = |
| 121 command_line->GetSwitchValueNative(kInputSwitchName); |
| 122 // presubmit: allow wstring |
| 123 std::wstring output_pipe_name = |
| 124 command_line->GetSwitchValueNative(kOutputSwitchName); |
| 125 |
| 126 // A NULL SECURITY_ATTRIBUTES signifies that the handle can't be inherited. |
| 127 read_file = |
| 128 base::File(CreateFile(input_pipe_name.c_str(), GENERIC_READ, 0, nullptr, |
| 129 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); |
| 130 if (!read_file.IsValid()) { |
| 131 PLOG(ERROR) << "CreateFile failed on '" << input_pipe_name << "'"; |
| 132 return kInitializationFailed; |
| 133 } |
| 134 |
| 135 write_file = base::File(CreateFile(output_pipe_name.c_str(), GENERIC_WRITE, |
| 136 0, nullptr, OPEN_EXISTING, |
| 137 FILE_ATTRIBUTE_NORMAL, nullptr)); |
| 138 if (!write_file.IsValid()) { |
| 139 PLOG(ERROR) << "CreateFile failed on '" << output_pipe_name << "'"; |
| 140 return kInitializationFailed; |
| 141 } |
| 142 } else { |
| 143 needs_elevation = true; |
| 144 |
| 145 // GetStdHandle() returns pseudo-handles for stdin and stdout even if |
| 146 // the hosting executable specifies "Windows" subsystem. However the |
| 147 // returned handles are invalid in that case unless standard input and |
| 148 // output are redirected to a pipe or file. |
| 149 read_file = base::File(GetStdHandle(STD_INPUT_HANDLE)); |
| 150 write_file = base::File(GetStdHandle(STD_OUTPUT_HANDLE)); |
| 151 |
| 152 // After the native messaging channel starts the native messaging reader |
| 153 // will keep doing blocking read operations on the input named pipe. |
| 154 // If any other thread tries to perform any operation on STDIN, it will also |
| 155 // block because the input named pipe is synchronous (non-overlapped). |
| 156 // It is pretty common for a DLL to query the device info (GetFileType) of |
| 157 // the STD* handles at startup. So any LoadLibrary request can potentially |
| 158 // be blocked. To prevent that from happening we close STDIN and STDOUT |
| 159 // handles as soon as we retrieve the corresponding file handles. |
| 160 SetStdHandle(STD_INPUT_HANDLE, nullptr); |
| 161 SetStdHandle(STD_OUTPUT_HANDLE, nullptr); |
| 162 } |
| 111 #elif defined(OS_POSIX) | 163 #elif defined(OS_POSIX) |
| 112 // The files are automatically closed. | 164 // The files are automatically closed. |
| 113 base::File read_file(STDIN_FILENO); | 165 read_file = base::File(STDIN_FILENO); |
| 114 base::File write_file(STDOUT_FILENO); | 166 write_file = base::File(STDOUT_FILENO); |
| 115 #else | 167 #else |
| 116 #error Not implemented. | 168 #error Not implemented. |
| 117 #endif | 169 #endif |
| 118 | 170 |
| 119 base::MessageLoopForUI message_loop; | 171 base::MessageLoopForUI message_loop; |
| 120 base::RunLoop run_loop; | 172 base::RunLoop run_loop; |
| 121 | 173 |
| 122 std::unique_ptr<It2MeHostFactory> factory(new It2MeHostFactory()); | 174 std::unique_ptr<It2MeHostFactory> factory(new It2MeHostFactory()); |
| 123 | 175 |
| 124 std::unique_ptr<NativeMessagingPipe> native_messaging_pipe( | 176 std::unique_ptr<NativeMessagingPipe> native_messaging_pipe( |
| 125 new NativeMessagingPipe()); | 177 new NativeMessagingPipe()); |
| 126 | 178 |
| 127 // Set up the native messaging channel. | 179 // Set up the native messaging channel. |
| 128 std::unique_ptr<extensions::NativeMessagingChannel> channel( | 180 std::unique_ptr<extensions::NativeMessagingChannel> channel( |
| 129 new PipeMessagingChannel(std::move(read_file), std::move(write_file))); | 181 new PipeMessagingChannel(std::move(read_file), std::move(write_file))); |
| 130 | 182 |
| 131 std::unique_ptr<ChromotingHostContext> context = | 183 std::unique_ptr<ChromotingHostContext> context = |
| 132 ChromotingHostContext::Create(new remoting::AutoThreadTaskRunner( | 184 ChromotingHostContext::Create(new remoting::AutoThreadTaskRunner( |
| 133 message_loop.task_runner(), run_loop.QuitClosure())); | 185 message_loop.task_runner(), run_loop.QuitClosure())); |
| 134 std::unique_ptr<extensions::NativeMessageHost> host( | 186 std::unique_ptr<extensions::NativeMessageHost> host( |
| 135 new It2MeNativeMessagingHost(std::move(context), std::move(factory))); | 187 new It2MeNativeMessagingHost(needs_elevation, /*policy_service=*/nullptr, |
| 188 std::move(context), std::move(factory))); |
| 136 | 189 |
| 137 host->Start(native_messaging_pipe.get()); | 190 host->Start(native_messaging_pipe.get()); |
| 138 | 191 |
| 139 native_messaging_pipe->Start(std::move(host), std::move(channel)); | 192 native_messaging_pipe->Start(std::move(host), std::move(channel)); |
| 140 | 193 |
| 141 // Run the loop until channel is alive. | 194 // Run the loop until channel is alive. |
| 142 run_loop.Run(); | 195 run_loop.Run(); |
| 143 | 196 |
| 144 return kSuccessExitCode; | 197 return kSuccessExitCode; |
| 145 } | 198 } |
| 146 | 199 |
| 147 int It2MeNativeMessagingHostMain(int argc, char** argv) { | 200 int It2MeNativeMessagingHostMain(int argc, char** argv) { |
| 148 // This object instance is required by Chrome code (such as MessageLoop). | 201 // This object instance is required by Chrome code (such as MessageLoop). |
| 149 base::AtExitManager exit_manager; | 202 base::AtExitManager exit_manager; |
| 150 | 203 |
| 151 base::CommandLine::Init(argc, argv); | 204 base::CommandLine::Init(argc, argv); |
| 152 remoting::InitHostLogging(); | 205 remoting::InitHostLogging(); |
| 153 | 206 |
| 154 return StartIt2MeNativeMessagingHost(); | 207 return StartIt2MeNativeMessagingHost(); |
| 155 } | 208 } |
| 156 | 209 |
| 157 } // namespace remoting | 210 } // namespace remoting |
| OLD | NEW |