#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";
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.
}
}
+ 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()));
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.