| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/host/curtain_mode.h" |
| |
| #include "base/callback.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/single_thread_task_runner.h" |
| #include "remoting/base/logging.h" |
| #include "remoting/host/client_session_control.h" |
| #include "ui/gfx/x/connection.h" |
| #include "ui/gfx/x/future.h" |
| #include "ui/gfx/x/xinput.h" |
| #include "ui/gfx/x/xproto_types.h" |
| |
| namespace remoting { |
| |
| class CurtainModeLinux : public CurtainMode { |
| public: |
| CurtainModeLinux(); |
| |
| // Overriden from CurtainMode. |
| bool Activate() override; |
| |
| private: |
| // Returns true if the host is running under a virtual session. |
| bool IsVirtualSession(); |
| |
| DISALLOW_COPY_AND_ASSIGN(CurtainModeLinux); |
| }; |
| |
| CurtainModeLinux::CurtainModeLinux() = default; |
| |
| bool CurtainModeLinux::Activate() { |
| // We can't curtain the session in run-time in Linux. |
| // Either the session is running in a virtual session (i.e. always curtained), |
| // or it is attached to the physical console (i.e. impossible to curtain). |
| if (!IsVirtualSession()) { |
| LOG(ERROR) << "Curtain-mode is not supported when running on non-virtual " |
| "X server"; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool CurtainModeLinux::IsVirtualSession() { |
| // Try to identify a virtual session. Since there's no way to tell from the |
| // vendor string, we check for known virtual input devices. |
| // TODO(rmsousa): Find a similar way to determine that the *output* is secure. |
| x11::Connection* connection = x11::Connection::Get(); |
| if (!connection->xinput().present()) { |
| // If XInput is not available, assume it is not a virtual session. |
| LOG(ERROR) << "X Input extension not available"; |
| return false; |
| } |
| |
| auto devices = connection->xinput().ListInputDevices().Sync(); |
| if (!devices) { |
| LOG(ERROR) << "ListInputDevices failed"; |
| return false; |
| } |
| |
| bool found_xvfb_mouse = false; |
| bool found_xvfb_keyboard = false; |
| bool found_crd_void_input = false; |
| bool found_other_devices = false; |
| for (size_t i = 0; i < devices->devices.size(); i++) { |
| const auto& device_info = devices->devices[i]; |
| const std::string& name = devices->names[i].name; |
| if (device_info.device_use == x11::Input::DeviceUse::IsXExtensionPointer) { |
| if (name == "Xvfb mouse") { |
| found_xvfb_mouse = true; |
| } else if (name == "Chrome Remote Desktop Input") { |
| found_crd_void_input = true; |
| } else if (name != "Virtual core XTEST pointer") { |
| found_other_devices = true; |
| HOST_LOG << "Non-virtual mouse found: " << name; |
| } |
| } else if (device_info.device_use == |
| x11::Input::DeviceUse::IsXExtensionKeyboard) { |
| if (name == "Xvfb keyboard") { |
| found_xvfb_keyboard = true; |
| } else if (name != "Virtual core XTEST keyboard") { |
| found_other_devices = true; |
| HOST_LOG << "Non-virtual keyboard found: " << name; |
| } |
| } else if (device_info.device_use == x11::Input::DeviceUse::IsXPointer) { |
| if (name != "Virtual core pointer") { |
| found_other_devices = true; |
| HOST_LOG << "Non-virtual mouse found: " << name; |
| } |
| } else if (device_info.device_use == x11::Input::DeviceUse::IsXKeyboard) { |
| if (name != "Virtual core keyboard") { |
| found_other_devices = true; |
| HOST_LOG << "Non-virtual keyboard found: " << name; |
| } |
| } else { |
| found_other_devices = true; |
| HOST_LOG << "Non-virtual device found: " << name; |
| } |
| } |
| return ((found_xvfb_mouse && found_xvfb_keyboard) || found_crd_void_input) && |
| !found_other_devices; |
| } |
| |
| // static |
| std::unique_ptr<CurtainMode> CurtainMode::Create( |
| scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
| scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| base::WeakPtr<ClientSessionControl> client_session_control) { |
| return base::WrapUnique(new CurtainModeLinux()); |
| } |
| |
| } // namespace remoting |