Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / remoting / host / setup / me2me_native_messaging_host_main.cc
index 7b48a74..ac929b8 100644 (file)
 #include "remoting/host/pairing_registry_delegate.h"
 #include "remoting/host/setup/me2me_native_messaging_host.h"
 
+#if defined(OS_WIN)
+#include "base/win/registry.h"
+#include "base/win/windows_version.h"
+#include "remoting/host/pairing_registry_delegate_win.h"
+#endif  // defined(OS_WIN)
+
+using remoting::protocol::PairingRegistry;
+
 namespace {
 
 const char kParentWindowSwitchName[] = "parent-window";
@@ -21,21 +29,29 @@ const char kParentWindowSwitchName[] = "parent-window";
 
 namespace remoting {
 
-int Me2MeNativeMessagingHostMain() {
 #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::PlatformFile read_file = GetStdHandle(STD_INPUT_HANDLE);
-  base::PlatformFile write_file = GetStdHandle(STD_OUTPUT_HANDLE);
-#elif defined(OS_POSIX)
-  base::PlatformFile read_file = STDIN_FILENO;
-  base::PlatformFile write_file = STDOUT_FILENO;
-#else
-#error Not implemented.
-#endif
+bool IsProcessElevated() {
+  // Conceptually, all processes running on a pre-VISTA version of Windows can
+  // be considered "elevated".
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return true;
+
+  HANDLE process_token;
+  OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token);
+
+  base::win::ScopedHandle scoped_process_token(process_token);
+
+  // Unlike TOKEN_ELEVATION_TYPE which returns TokenElevationTypeDefault when
+  // UAC is turned off, TOKEN_ELEVATION will tell you the process is elevated.
+  DWORD size;
+  TOKEN_ELEVATION elevation;
+  GetTokenInformation(process_token, TokenElevation,
+                      &elevation, sizeof(elevation), &size);
+  return elevation.TokenIsElevated != 0;
+}
+#endif  // defined(OS_WIN)
 
+int Me2MeNativeMessagingHostMain() {
   // Mac OS X requires that the main thread be a UI message loop in order to
   // receive distributed notifications from the System Preferences pane. An
   // IO thread is needed for the pairing registry and URL context getter.
@@ -64,6 +80,62 @@ int Me2MeNativeMessagingHostMain() {
     }
   }
 
+  base::PlatformFile read_file;
+  base::PlatformFile write_file;
+  bool needs_elevation = false;
+
+#if defined(OS_WIN)
+  needs_elevation = !IsProcessElevated();
+
+  if (command_line->HasSwitch(kElevatingSwitchName)) {
+    DCHECK(!needs_elevation);
+
+    // The "elevate" switch is always accompanied by the "input" and "output"
+    // switches whose values name 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 = CreateFile(
+        input_pipe_name.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING,
+        FILE_ATTRIBUTE_NORMAL, NULL);
+    if (read_file == INVALID_HANDLE_VALUE) {
+      LOG_GETLASTERROR(ERROR) <<
+          "CreateFile failed on '" << input_pipe_name << "'";
+      return kInitializationFailed;
+    }
+
+    write_file = CreateFile(
+        output_pipe_name.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+        FILE_ATTRIBUTE_NORMAL, NULL);
+    if (write_file == INVALID_HANDLE_VALUE) {
+      LOG_GETLASTERROR(ERROR) <<
+          "CreateFile failed on '" << output_pipe_name << "'";
+      return kInitializationFailed;
+    }
+  } else {
+    // 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 = GetStdHandle(STD_INPUT_HANDLE);
+    write_file = GetStdHandle(STD_OUTPUT_HANDLE);
+  }
+#elif defined(OS_POSIX)
+  read_file = STDIN_FILENO;
+  write_file = STDOUT_FILENO;
+#else
+#error Not implemented.
+#endif
+
   // OAuth client (for credential requests).
   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter(
       new URLRequestContextGetter(io_thread.message_loop_proxy()));
@@ -72,19 +144,68 @@ int Me2MeNativeMessagingHostMain() {
 
   net::URLFetcher::SetIgnoreCertificateRequests(true);
 
-  // Create the pairing registry and native messaging host.
-  scoped_refptr<protocol::PairingRegistry> pairing_registry =
+  // Create the pairing registry.
+  scoped_refptr<PairingRegistry> pairing_registry;
+
+#if defined(OS_WIN)
+  base::win::RegKey root;
+  LONG result = root.Open(HKEY_LOCAL_MACHINE, kPairingRegistryKeyName,
+                          KEY_READ);
+  if (result != ERROR_SUCCESS) {
+    SetLastError(result);
+    PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistryKeyName;
+    return kInitializationFailed;
+  }
+
+  base::win::RegKey unprivileged;
+  result = unprivileged.Open(root.Handle(), kPairingRegistrySecretsKeyName,
+                             needs_elevation ? KEY_READ : KEY_READ | KEY_WRITE);
+  if (result != ERROR_SUCCESS) {
+    SetLastError(result);
+    PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistrySecretsKeyName
+                << "\\" << kPairingRegistrySecretsKeyName;
+    return kInitializationFailed;
+  }
+
+  // Only try to open the privileged key if the current process is elevated.
+  base::win::RegKey privileged;
+  if (!needs_elevation) {
+    result = privileged.Open(root.Handle(), kPairingRegistryClientsKeyName,
+                             KEY_READ | KEY_WRITE);
+    if (result != ERROR_SUCCESS) {
+      SetLastError(result);
+      PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistryKeyName << "\\"
+                  << kPairingRegistryClientsKeyName;
+      return kInitializationFailed;
+    }
+  }
+
+  // Initialize the pairing registry delegate and set the root keys.
+  scoped_ptr<PairingRegistryDelegateWin> delegate(
+      new PairingRegistryDelegateWin());
+  if (!delegate->SetRootKeys(privileged.Take(), unprivileged.Take()))
+    return kInitializationFailed;
+
+  pairing_registry = new PairingRegistry(
+      io_thread.message_loop_proxy(),
+      delegate.PassAs<PairingRegistry::Delegate>());
+#else  // defined(OS_WIN)
+  pairing_registry =
       CreatePairingRegistry(io_thread.message_loop_proxy());
+#endif  // !defined(OS_WIN)
 
   // Set up the native messaging channel.
   scoped_ptr<NativeMessagingChannel> channel(
       new NativeMessagingChannel(read_file, write_file));
 
+  // Create the native messaging host.
   scoped_ptr<Me2MeNativeMessagingHost> host(
-      new Me2MeNativeMessagingHost(channel.Pass(),
-                              daemon_controller,
-                              pairing_registry,
-                              oauth_client.Pass()));
+      new Me2MeNativeMessagingHost(
+          needs_elevation,
+          channel.Pass(),
+          daemon_controller,
+          pairing_registry,
+          oauth_client.Pass()));
   host->Start(run_loop.QuitClosure());
 
   // Run the loop until channel is alive.