Chromium Code Reviews| Index: remoting/host/it2me/it2me_native_messaging_host_main.cc |
| diff --git a/remoting/host/it2me/it2me_native_messaging_host_main.cc b/remoting/host/it2me/it2me_native_messaging_host_main.cc |
| index 3c9671941c0a4e4219c8403aba8ba47bb69a6808..6729ad66a4eabf30d89681aebdc7da1cf19b3dee 100644 |
| --- a/remoting/host/it2me/it2me_native_messaging_host_main.cc |
| +++ b/remoting/host/it2me/it2me_native_messaging_host_main.cc |
| @@ -37,6 +37,9 @@ |
| #if defined(OS_WIN) |
| #include <commctrl.h> |
| + |
| +#include "remoting/host/switches.h" |
| +#include "remoting/host/win/elevation_helpers.h" |
| #endif // defined(OS_WIN) |
| namespace remoting { |
| @@ -90,28 +93,75 @@ int StartIt2MeNativeMessagingHost() { |
| // single-threaded. |
| net::EnableSSLServerSockets(); |
| + base::File read_file; |
| + base::File write_file; |
| + bool needs_elevation = false; |
| + |
| #if defined(OS_WIN) |
| - // GetStdHandle() returns pseudo-handles for stdin and stdout even if |
| - // the hosting executable specifies "Windows" subsystem. However the returned |
| - // handles are invalid in that case unless standard input and output are |
| - // redirected to a pipe or file. |
| - base::File read_file(GetStdHandle(STD_INPUT_HANDLE)); |
| - base::File write_file(GetStdHandle(STD_OUTPUT_HANDLE)); |
| - |
| - // After the native messaging channel starts the native messaging reader |
| - // will keep doing blocking read operations on the input named pipe. |
| - // If any other thread tries to perform any operation on STDIN, it will also |
| - // block because the input named pipe is synchronous (non-overlapped). |
| - // It is pretty common for a DLL to query the device info (GetFileType) of |
| - // the STD* handles at startup. So any LoadLibrary request can potentially |
| - // be blocked. To prevent that from happening we close STDIN and STDOUT |
| - // handles as soon as we retrieve the corresponding file handles. |
| - SetStdHandle(STD_INPUT_HANDLE, nullptr); |
| - SetStdHandle(STD_OUTPUT_HANDLE, nullptr); |
| + |
| + const base::CommandLine* command_line = |
| + base::CommandLine::ForCurrentProcess(); |
| + |
| + if (command_line->HasSwitch(kElevateSwitchName)) { |
| +#if defined(OFFICIAL_BUILD) |
| + // Unofficial builds won't have 'UiAccess' since it requires signing. |
| + CHECK(CurrentProcessHasUiAccess()); |
|
Sergey Ulanov
2016/09/02 23:21:14
Do we actually need to crash the process in this c
joedow
2016/09/06 22:51:59
I chose to use a CHECK here as this functionality
|
| +#endif // defined(OFFICIAL_BUILD) |
| + |
| + // The UiAccess binary should always have the "input" and "output" switches |
| + // specified, they represent the name of the named pipes that should be used |
| + // in place of stdin and stdout. |
| + DCHECK(command_line->HasSwitch(kInputSwitchName)); |
| + DCHECK(command_line->HasSwitch(kOutputSwitchName)); |
| + |
| + // presubmit: allow wstring |
| + std::wstring input_pipe_name = |
| + command_line->GetSwitchValueNative(kInputSwitchName); |
| + // presubmit: allow wstring |
| + std::wstring output_pipe_name = |
| + command_line->GetSwitchValueNative(kOutputSwitchName); |
| + |
| + // A NULL SECURITY_ATTRIBUTES signifies that the handle can't be inherited. |
| + read_file = |
| + base::File(CreateFile(input_pipe_name.c_str(), GENERIC_READ, 0, nullptr, |
| + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); |
| + if (!read_file.IsValid()) { |
| + PLOG(ERROR) << "CreateFile failed on '" << input_pipe_name << "'"; |
| + return kInitializationFailed; |
| + } |
| + |
| + write_file = base::File(CreateFile(output_pipe_name.c_str(), GENERIC_WRITE, |
| + 0, nullptr, OPEN_EXISTING, |
| + FILE_ATTRIBUTE_NORMAL, nullptr)); |
| + if (!write_file.IsValid()) { |
| + PLOG(ERROR) << "CreateFile failed on '" << output_pipe_name << "'"; |
| + return kInitializationFailed; |
| + } |
| + } else { |
| + needs_elevation = true; |
| + |
| + // GetStdHandle() returns pseudo-handles for stdin and stdout even if |
| + // the hosting executable specifies "Windows" subsystem. However the |
| + // returned handles are invalid in that case unless standard input and |
| + // output are redirected to a pipe or file. |
| + read_file = base::File(GetStdHandle(STD_INPUT_HANDLE)); |
| + write_file = base::File(GetStdHandle(STD_OUTPUT_HANDLE)); |
| + |
| + // After the native messaging channel starts the native messaging reader |
| + // will keep doing blocking read operations on the input named pipe. |
| + // If any other thread tries to perform any operation on STDIN, it will also |
| + // block because the input named pipe is synchronous (non-overlapped). |
| + // It is pretty common for a DLL to query the device info (GetFileType) of |
| + // the STD* handles at startup. So any LoadLibrary request can potentially |
| + // be blocked. To prevent that from happening we close STDIN and STDOUT |
| + // handles as soon as we retrieve the corresponding file handles. |
| + SetStdHandle(STD_INPUT_HANDLE, nullptr); |
| + SetStdHandle(STD_OUTPUT_HANDLE, nullptr); |
| + } |
| #elif defined(OS_POSIX) |
| // The files are automatically closed. |
| - base::File read_file(STDIN_FILENO); |
| - base::File write_file(STDOUT_FILENO); |
| + read_file = base::File(STDIN_FILENO); |
| + write_file = base::File(STDOUT_FILENO); |
| #else |
| #error Not implemented. |
| #endif |
| @@ -132,7 +182,8 @@ int StartIt2MeNativeMessagingHost() { |
| ChromotingHostContext::Create(new remoting::AutoThreadTaskRunner( |
| message_loop.task_runner(), run_loop.QuitClosure())); |
| std::unique_ptr<extensions::NativeMessageHost> host( |
| - new It2MeNativeMessagingHost(std::move(context), std::move(factory))); |
| + new It2MeNativeMessagingHost(needs_elevation, /*policy_service=*/nullptr, |
| + std::move(context), std::move(factory))); |
| host->Start(native_messaging_pipe.get()); |