summaryrefslogtreecommitdiffstats
path: root/remoting/host/curtain_mode_linux.cc
blob: ceec4dc7ed1546ef5865e391702c84b53fef74c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// 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 <X11/extensions/XInput.h>

#include "base/callback.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "remoting/base/logging.h"
#include "remoting/host/client_session_control.h"

namespace remoting {

class CurtainModeLinux : public CurtainMode {
 public:
  CurtainModeLinux();

  // Overriden from CurtainMode.
  bool Activate() override;

 private:
  // Returns true if the host is running under an Xvfb session.
  bool IsXvfbSession();

  DISALLOW_COPY_AND_ASSIGN(CurtainModeLinux);
};

CurtainModeLinux::CurtainModeLinux() {
}

bool CurtainModeLinux::Activate() {
  // We can't curtain the session in run-time in Linux.
  // Either the session is running on Xvfb (i.e. always curtained), or it is
  // attached to the physical console (i.e. impossible to curtain).
  bool activated = IsXvfbSession();
  if (!activated) {
    LOG(ERROR) << "Curtain-mode is not supported when running on non-Xvfb "
                  "X server";
  }

  return activated;
}

bool CurtainModeLinux::IsXvfbSession() {
  // Try to identify an Xvfb session. There's no way to query what X server we
  // are running under, so we check for the Xvfb input devices.
  // TODO(rmsousa): Find a similar way to determine that the *output* is secure.
  Display* display = XOpenDisplay(nullptr);
  int opcode, event, error;
  if (!XQueryExtension(display, "XInputExtension", &opcode, &event, &error)) {
    // If XInput is not available, assume it is not an Xvfb session.
    LOG(ERROR) << "X Input extension not available: " << error;
    XCloseDisplay(display);
    return false;
  }
  int num_devices;
  XDeviceInfo* devices;
  bool found_xvfb_mouse = false;
  bool found_xvfb_keyboard = false;
  bool found_other_devices = false;
  devices = XListInputDevices(display, &num_devices);
  for (int i = 0; i < num_devices; i++) {
    XDeviceInfo* device_info = &devices[i];
    if (device_info->use == IsXExtensionPointer) {
      if (strcmp(device_info->name, "Xvfb mouse") == 0) {
        found_xvfb_mouse = true;
      } else if (strcmp(device_info->name, "Virtual core XTEST pointer") != 0) {
        found_other_devices = true;
        HOST_LOG << "Non Xvfb mouse found: " << device_info->name;
      }
    } else if (device_info->use == IsXExtensionKeyboard) {
      if (strcmp(device_info->name, "Xvfb keyboard") == 0) {
        found_xvfb_keyboard = true;
      } else if (strcmp(device_info->name,
                        "Virtual core XTEST keyboard") != 0) {
        found_other_devices = true;
        HOST_LOG << "Non Xvfb keyboard found: " << device_info->name;
      }
    } else if (device_info->use == IsXPointer) {
      if (strcmp(device_info->name, "Virtual core pointer") != 0) {
        found_other_devices = true;
        HOST_LOG << "Non Xvfb mouse found: " << device_info->name;
      }
    } else if (device_info->use == IsXKeyboard) {
      if (strcmp(device_info->name, "Virtual core keyboard") != 0) {
        found_other_devices = true;
        HOST_LOG << "Non Xvfb keyboard found: " << device_info->name;
      }
    } else {
      found_other_devices = true;
      HOST_LOG << "Non Xvfb device found: " << device_info->name;
    }
  }
  XFreeDeviceList(devices);
  XCloseDisplay(display);
  return found_xvfb_mouse && found_xvfb_keyboard && !found_other_devices;
}

// static
scoped_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 make_scoped_ptr(new CurtainModeLinux());
}

}  // namespace remoting