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..8b2ec459bd77d3302e9ebc55726dbdc625258ca1 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,77 @@ 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. |
+ if (!CurrentProcessHasUiAccess()) { |
+ LOG(ERROR) << "UiAccess permission missing from elevated It2Me process."; |
+ } |
+#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 +184,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()); |