diff options
author | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-04 06:46:59 +0000 |
---|---|---|
committer | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-04 06:46:59 +0000 |
commit | 97328ee0c9ae5551dffe424110936a65b0503da3 (patch) | |
tree | 7ada37ecd0db828a78fa998b16dfd9a48d06badd /remoting | |
parent | 87986edaa09ffc9c1c78947f540fcdb75eb08f9f (diff) | |
download | chromium_src-97328ee0c9ae5551dffe424110936a65b0503da3.zip chromium_src-97328ee0c9ae5551dffe424110936a65b0503da3.tar.gz chromium_src-97328ee0c9ae5551dffe424110936a65b0503da3.tar.bz2 |
Emulate pressing Ctrl+Alt+End making the RDP ActiveX control to send Secure Attention Sequence to the session.
BUG=246409
Review URL: https://chromiumcodereview.appspot.com/15894034
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203874 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/host/desktop_session_win.cc | 4 | ||||
-rw-r--r-- | remoting/host/installer/win/chromoting.wxs | 2 | ||||
-rw-r--r-- | remoting/host/win/chromoting_lib_idl.templ | 5 | ||||
-rw-r--r-- | remoting/host/win/rdp_client.cc | 19 | ||||
-rw-r--r-- | remoting/host/win/rdp_client.h | 3 | ||||
-rw-r--r-- | remoting/host/win/rdp_client_window.cc | 113 | ||||
-rw-r--r-- | remoting/host/win/rdp_client_window.h | 4 | ||||
-rw-r--r-- | remoting/host/win/rdp_desktop_session.cc | 6 | ||||
-rw-r--r-- | remoting/host/win/rdp_desktop_session.h | 1 | ||||
-rw-r--r-- | remoting/host/win/session_input_injector.cc | 2 |
10 files changed, 153 insertions, 6 deletions
diff --git a/remoting/host/desktop_session_win.cc b/remoting/host/desktop_session_win.cc index 5d126d2..1ae4fa5 100644 --- a/remoting/host/desktop_session_win.cc +++ b/remoting/host/desktop_session_win.cc @@ -287,9 +287,7 @@ void RdpSession::SetScreenResolution(const ScreenResolution& resolution) { void RdpSession::InjectSas() { DCHECK(caller_task_runner()->BelongsToCurrentThread()); - // TODO(alexeypa): implement SAS injection for RDP sessions here. - // See http://crbug.com/137696. - NOTIMPLEMENTED(); + rdp_desktop_session_->InjectSas(); } RdpSession::EventHandler::EventHandler( diff --git a/remoting/host/installer/win/chromoting.wxs b/remoting/host/installer/win/chromoting.wxs index bc1aaa9..077e373 100644 --- a/remoting/host/installer/win/chromoting.wxs +++ b/remoting/host/installer/win/chromoting.wxs @@ -36,7 +36,7 @@ <?define ControllerProgid = "ChromotingElevatedController.ElevatedController" ?> - <?define IRdpDesktopSessionId = "{126c22bc-34ef-4cfb-83ef-9b8ada3391e8}" ?> + <?define IRdpDesktopSessionId = "{1d68cef0-dbc0-4745-9755-055b28d9e5cc}" ?> <?define IRdpDesktopSessionEventHandlerId = "{987bca97-9d40-42fc-a00d-e6a701261af5}" ?> diff --git a/remoting/host/win/chromoting_lib_idl.templ b/remoting/host/win/chromoting_lib_idl.templ index 4ba0ab3b..fd6b5f4 100644 --- a/remoting/host/win/chromoting_lib_idl.templ +++ b/remoting/host/win/chromoting_lib_idl.templ @@ -88,7 +88,7 @@ interface IRdpDesktopSessionEventHandler : IUnknown { [ object, - uuid(126c22bc-34ef-4cfb-83ef-9b8ada3391e8), + uuid(1d68cef0-dbc0-4745-9755-055b28d9e5cc), nonextensible, helpstring("IRdpDesktopSession Interface"), pointer_default(unique) @@ -105,6 +105,9 @@ interface IRdpDesktopSession : IUnknown { [ id(3), helpstring("Changes the screen resolution.") ] HRESULT ChangeResolution([in] long width, [in] long height); + + [ id(4), helpstring("Sends Secure Attention Sequence to the session.") ] + HRESULT InjectSas(); }; [ diff --git a/remoting/host/win/rdp_client.cc b/remoting/host/win/rdp_client.cc index 8838398..edf7ddf 100644 --- a/remoting/host/win/rdp_client.cc +++ b/remoting/host/win/rdp_client.cc @@ -56,6 +56,9 @@ class RdpClient::Core // Initiates a graceful shutdown of the RDP connection. void Disconnect(); + // Sends Secure Attention Sequence to the session. + void InjectSas(); + // RdpClientWindow::EventHandler interface. virtual void OnConnected() OVERRIDE; virtual void OnDisconnected() OVERRIDE; @@ -129,6 +132,12 @@ RdpClient::~RdpClient() { core_->Disconnect(); } +void RdpClient::InjectSas() { + DCHECK(CalledOnValidThread()); + + core_->InjectSas(); +} + RdpClient::Core::Core( scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, @@ -207,6 +216,16 @@ void RdpClient::Core::Disconnect() { } } +void RdpClient::Core::InjectSas() { + if (!ui_task_runner_->BelongsToCurrentThread()) { + ui_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::InjectSas, this)); + return; + } + + if (rdp_client_window_) + rdp_client_window_->InjectSas(); +} + void RdpClient::Core::OnConnected() { DCHECK(ui_task_runner_->BelongsToCurrentThread()); DCHECK(rdp_client_window_); diff --git a/remoting/host/win/rdp_client.h b/remoting/host/win/rdp_client.h index 07a0238..a0537a9 100644 --- a/remoting/host/win/rdp_client.h +++ b/remoting/host/win/rdp_client.h @@ -43,6 +43,9 @@ class RdpClient : public base::NonThreadSafe { EventHandler* event_handler); virtual ~RdpClient(); + // Sends Secure Attention Sequence to the session. + void InjectSas(); + private: // The actual implementation resides in Core class. class Core; diff --git a/remoting/host/win/rdp_client_window.cc b/remoting/host/win/rdp_client_window.cc index 1f81538..e9bcdac 100644 --- a/remoting/host/win/rdp_client_window.cc +++ b/remoting/host/win/rdp_client_window.cc @@ -6,8 +6,11 @@ #include <wtsdefs.h> +#include <list> + #include "base/lazy_instance.h" #include "base/logging.h" +#include "base/string16.h" #include "base/threading/thread_local.h" #include "base/utf_string_conversions.h" #include "base/win/scoped_bstr.h" @@ -23,10 +26,53 @@ const long kDisconnectReasonLocalNotError = 1; const long kDisconnectReasonRemoteByUser = 2; const long kDisconnectReasonByServer = 3; +// Maximum length of a window class name including the terminating NULL. +const int kMaxWindowClassLength = 256; + +// Each member of the array returned by GetKeyboardState() contains status data +// for a virtual key. If the high-order bit is 1, the key is down; otherwise, it +// is up. +const BYTE kKeyPressedFlag = 0x80; + +const int kKeyboardStateLength = 256; + +// The RDP control creates 'IHWindowClass' window to handle keyboard input. +const wchar_t kRdpInputWindowClass[] = L"IHWindowClass"; + // Points to a per-thread instance of the window activation hook handle. base::LazyInstance<base::ThreadLocalPointer<RdpClientWindow::WindowHook> > g_window_hook = LAZY_INSTANCE_INITIALIZER; +// Finds a child window with the class name matching |class_name|. Unlike +// FindWindowEx() this function walks the tree of windows recursively. The walk +// is done in breadth-first order. The function returns NULL if the child window +// could not be found. +HWND FindWindowRecursively(HWND parent, const string16& class_name) { + std::list<HWND> windows; + windows.push_back(parent); + + while (!windows.empty()) { + HWND child = FindWindowEx(windows.front(), NULL, NULL, NULL); + while (child != NULL) { + // See if the window class name matches |class_name|. + WCHAR name[kMaxWindowClassLength]; + int length = GetClassName(child, name, arraysize(name)); + if (string16(name, length) == class_name) + return child; + + // Remember the window to look through its children. + windows.push_back(child); + + // Go to the next child. + child = FindWindowEx(windows.front(), child, NULL, NULL); + } + + windows.pop_front(); + } + + return NULL; +} + } // namespace // Used to close any windows activated on a particular thread. It installs @@ -87,6 +133,68 @@ void RdpClientWindow::Disconnect() { SendMessage(WM_CLOSE); } +void RdpClientWindow::InjectSas() { + if (!m_hWnd) + return; + + // Fins the window handling the keyboard input. + HWND input_window = FindWindowRecursively(m_hWnd, kRdpInputWindowClass); + if (!input_window) { + LOG(ERROR) << "Failed to find the window handling the keyboard input."; + return; + } + + VLOG(3) << "Injecting Ctrl+Alt+End to emulate SAS."; + + BYTE keyboard_state[kKeyboardStateLength]; + if (!GetKeyboardState(keyboard_state)) { + LOG_GETLASTERROR(ERROR) << "Failed to get the keyboard state."; + return; + } + + // This code is running in Session 0, so we expect no keys to be pressed. + DCHECK(!(keyboard_state[VK_CONTROL] & kKeyPressedFlag)); + DCHECK(!(keyboard_state[VK_MENU] & kKeyPressedFlag)); + DCHECK(!(keyboard_state[VK_END] & kKeyPressedFlag)); + + // Map virtual key codes to scan codes. + UINT control = MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC); + UINT alt = MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC); + UINT end = MapVirtualKey(VK_END, MAPVK_VK_TO_VSC) | KF_EXTENDED; + UINT up = KF_UP | KF_REPEAT; + + // Press 'Ctrl'. + keyboard_state[VK_CONTROL] |= kKeyPressedFlag; + keyboard_state[VK_LCONTROL] |= kKeyPressedFlag; + CHECK(SetKeyboardState(keyboard_state)); + SendMessage(input_window, WM_KEYDOWN, VK_CONTROL, MAKELPARAM(1, control)); + + // Press 'Alt'. + keyboard_state[VK_MENU] |= kKeyPressedFlag; + keyboard_state[VK_LMENU] |= kKeyPressedFlag; + CHECK(SetKeyboardState(keyboard_state)); + SendMessage(input_window, WM_KEYDOWN, VK_MENU, + MAKELPARAM(1, alt | KF_ALTDOWN)); + + // Press and release 'End'. + SendMessage(input_window, WM_KEYDOWN, VK_END, + MAKELPARAM(1, end | KF_ALTDOWN)); + SendMessage(input_window, WM_KEYUP, VK_END, + MAKELPARAM(1, end | up | KF_ALTDOWN)); + + // Release 'Alt'. + keyboard_state[VK_MENU] &= ~kKeyPressedFlag; + keyboard_state[VK_LMENU] &= ~kKeyPressedFlag; + CHECK(SetKeyboardState(keyboard_state)); + SendMessage(input_window, WM_KEYUP, VK_MENU, MAKELPARAM(1, alt | up)); + + // Release 'Ctrl'. + keyboard_state[VK_CONTROL] &= ~kKeyPressedFlag; + keyboard_state[VK_LCONTROL] &= ~kKeyPressedFlag; + CHECK(SetKeyboardState(keyboard_state)); + SendMessage(input_window, WM_KEYUP, VK_CONTROL, MAKELPARAM(1, control | up)); +} + void RdpClientWindow::OnClose() { if (!client_) { NotifyDisconnected(); @@ -182,6 +290,11 @@ LRESULT RdpClientWindow::OnCreate(CREATESTRUCT* create_struct) { if (FAILED(result)) goto done; + // Enable the Ctrl+Alt+Del screen. + result = client_settings_->put_DisableCtrlAltDel(0); + if (FAILED(result)) + goto done; + // Disable printer and clipboard redirection. result = client_settings_->put_DisableRdpdr(FALSE); if (FAILED(result)) diff --git a/remoting/host/win/rdp_client_window.h b/remoting/host/win/rdp_client_window.h index c4b71d2..f7517db 100644 --- a/remoting/host/win/rdp_client_window.h +++ b/remoting/host/win/rdp_client_window.h @@ -77,6 +77,10 @@ class RdpClientWindow // until it receives OnDisconnected() notification. void Disconnect(); + // Emulates pressing Ctrl+Alt+End combination that is translated to Secure + // Attention Sequence by the ActiveX control. + void InjectSas(); + private: typedef IDispEventImpl<1, RdpClientWindow, &__uuidof(mstsc::IMsTscAxEvents), diff --git a/remoting/host/win/rdp_desktop_session.cc b/remoting/host/win/rdp_desktop_session.cc index 977ac33..1b12266 100644 --- a/remoting/host/win/rdp_desktop_session.cc +++ b/remoting/host/win/rdp_desktop_session.cc @@ -41,6 +41,12 @@ STDMETHODIMP RdpDesktopSession::ChangeResolution(long width, long height) { return E_NOTIMPL; } +STDMETHODIMP RdpDesktopSession::InjectSas() { + if (client_) + client_->InjectSas(); + return S_OK; +} + void RdpDesktopSession::OnRdpConnected(const net::IPEndPoint& client_endpoint) { net::SockaddrStorage sockaddr; CHECK(client_endpoint.ToSockAddr(sockaddr.addr, &sockaddr.addr_len)); diff --git a/remoting/host/win/rdp_desktop_session.h b/remoting/host/win/rdp_desktop_session.h index f48512b..ff08107 100644 --- a/remoting/host/win/rdp_desktop_session.h +++ b/remoting/host/win/rdp_desktop_session.h @@ -47,6 +47,7 @@ class __declspec(uuid(RDP_DESKTOP_SESSION_CLSID)) RdpDesktopSession IRdpDesktopSessionEventHandler* event_handler); STDMETHOD(Disconnect)(); STDMETHOD(ChangeResolution)(long width, long height); + STDMETHOD(InjectSas)(); DECLARE_NO_REGISTRY() diff --git a/remoting/host/win/session_input_injector.cc b/remoting/host/win/session_input_injector.cc index 73b9cf3..4c763ee 100644 --- a/remoting/host/win/session_input_injector.cc +++ b/remoting/host/win/session_input_injector.cc @@ -143,7 +143,7 @@ void SessionInputInjectorWin::Core::InjectKeyEvent(const KeyEvent& event) { // Simulate secure attention sequence if Ctrl-Alt-Del was just pressed. if (event.usb_keycode() == kUsbDelete && CheckCtrlAndAltArePressed(pressed_keys_)) { - VLOG(3) << "Sending Secure Attention Sequence to console"; + VLOG(3) << "Sending Secure Attention Sequence to the session"; if (base::win::GetVersion() < base::win::VERSION_VISTA) { if (!sas_injector_) |