blob: 8501177a56f9e0d29a827b6a222667edb4b73e75 [file] [log] [blame]
// 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/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;
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