blob: d658499af081647eff8f1df67f93458249a88128 [file] [log] [blame]
[email protected]60ccc242012-10-17 21:06:241// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/host/desktop_session_win.h"
6
robliaoeb9bfd642017-05-18 17:35:167#include <objbase.h>
[email protected]5b731f3e2013-03-15 07:28:228#include <sddl.h>
Robert Liao1a378352017-10-18 01:31:179#include <wrl/client.h>
sergeyu1417e0132015-12-23 19:01:2210
avic5960f32015-12-22 22:49:4811#include <limits>
dcheng0765c492016-04-06 22:41:5312#include <memory>
sergeyu1417e0132015-12-23 19:01:2213#include <utility>
[email protected]5b731f3e2013-03-15 07:28:2214
[email protected]9410c0a2013-02-23 06:07:2115#include "base/base_switches.h"
16#include "base/command_line.h"
[email protected]5b731f3e2013-03-15 07:28:2217#include "base/files/file_path.h"
[email protected]a4eca0a2013-06-20 22:15:0518#include "base/guid.h"
avic5960f32015-12-22 22:49:4819#include "base/macros.h"
[email protected]5b731f3e2013-03-15 07:28:2220#include "base/memory/ref_counted.h"
[email protected]5b731f3e2013-03-15 07:28:2221#include "base/memory/weak_ptr.h"
[email protected]eaf92532013-06-11 07:39:1922#include "base/strings/stringprintf.h"
[email protected]906265872013-06-07 22:40:4523#include "base/strings/utf_string_conversions.h"
[email protected]5b731f3e2013-03-15 07:28:2224#include "base/threading/thread_checker.h"
[email protected]5d7eb862013-06-28 15:21:2425#include "base/timer/timer.h"
joedow69094d5f2016-05-03 20:00:0226#include "base/win/registry.h"
[email protected]a4eca0a2013-06-20 22:15:0527#include "base/win/scoped_bstr.h"
[email protected]5b731f3e2013-03-15 07:28:2228#include "base/win/scoped_handle.h"
[email protected]85c7fda22013-05-18 01:35:4729#include "base/win/windows_version.h"
[email protected]12066cb2012-10-25 03:25:4330#include "ipc/ipc_message_macros.h"
[email protected]5b731f3e2013-03-15 07:28:2231#include "ipc/ipc_platform_file.h"
[email protected]12066cb2012-10-25 03:25:4332#include "remoting/base/auto_thread_task_runner.h"
[email protected]12066cb2012-10-25 03:25:4333#include "remoting/host/chromoting_messages.h"
[email protected]60ccc242012-10-17 21:06:2434#include "remoting/host/daemon_process.h"
[email protected]5b731f3e2013-03-15 07:28:2235#include "remoting/host/desktop_session.h"
[email protected]9410c0a2013-02-23 06:07:2136#include "remoting/host/host_main.h"
37#include "remoting/host/ipc_constants.h"
[email protected]0dffd552012-12-07 01:08:0938#include "remoting/host/sas_injector.h"
[email protected]739e2802013-03-18 01:03:4839#include "remoting/host/screen_resolution.h"
Zijie He9bb41492017-07-30 21:14:4940#include "remoting/host/switches.h"
nicholsse3320ae2016-09-16 20:12:5941// MIDL-generated declarations and definitions.
42#include "remoting/host/win/chromoting_lib.h"
[email protected]5b731f3e2013-03-15 07:28:2243#include "remoting/host/win/host_service.h"
[email protected]60ccc242012-10-17 21:06:2444#include "remoting/host/win/worker_process_launcher.h"
[email protected]60ccc242012-10-17 21:06:2445#include "remoting/host/win/wts_session_process_delegate.h"
[email protected]3fd005e22013-02-28 20:11:2946#include "remoting/host/win/wts_terminal_monitor.h"
[email protected]5b731f3e2013-03-15 07:28:2247#include "remoting/host/win/wts_terminal_observer.h"
48#include "remoting/host/worker_process_ipc_delegate.h"
[email protected]60ccc242012-10-17 21:06:2449
[email protected]12066cb2012-10-25 03:25:4350using base::win::ScopedHandle;
51
[email protected]5b731f3e2013-03-15 07:28:2252namespace remoting {
53
[email protected]60ccc242012-10-17 21:06:2454namespace {
55
[email protected]60ccc242012-10-17 21:06:2456// The security descriptor of the daemon IPC endpoint. It gives full access
[email protected]6d65223d2013-03-05 20:32:4657// to SYSTEM and denies access by anyone else.
[email protected]5b731f3e2013-03-15 07:28:2258const wchar_t kDaemonIpcSecurityDescriptor[] =
59 SDDL_OWNER L":" SDDL_LOCAL_SYSTEM
60 SDDL_GROUP L":" SDDL_LOCAL_SYSTEM
61 SDDL_DACL L":("
62 SDDL_ACCESS_ALLOWED L";;" SDDL_GENERIC_ALL L";;;" SDDL_LOCAL_SYSTEM
63 L")";
[email protected]60ccc242012-10-17 21:06:2464
[email protected]9410c0a2013-02-23 06:07:2165// The command line parameters that should be copied from the service's command
[email protected]f0ce8fbb2014-06-16 18:36:1766// line to the desktop process.
[email protected]9410c0a2013-02-23 06:07:2167const char* kCopiedSwitchNames[] = { switches::kV, switches::kVModule };
68
[email protected]3c6ae172013-03-18 08:50:5869// The default screen dimensions for an RDP session.
[email protected]792c4f42013-04-06 16:05:2170const int kDefaultRdpScreenWidth = 1280;
[email protected]3c6ae172013-03-18 08:50:5871const int kDefaultRdpScreenHeight = 768;
72
[email protected]5b731f3e2013-03-15 07:28:2273// RDC 6.1 (W2K8) supports dimensions of up to 4096x2048.
74const int kMaxRdpScreenWidth = 4096;
75const int kMaxRdpScreenHeight = 2048;
[email protected]60ccc242012-10-17 21:06:2476
[email protected]5b731f3e2013-03-15 07:28:2277// The minimum effective screen dimensions supported by Windows are 800x600.
78const int kMinRdpScreenWidth = 800;
79const int kMinRdpScreenHeight = 600;
[email protected]60ccc242012-10-17 21:06:2480
[email protected]739e2802013-03-18 01:03:4881// Default dots per inch used by RDP is 96 DPI.
82const int kDefaultRdpDpi = 96;
[email protected]5b731f3e2013-03-15 07:28:2283
84// The session attach notification should arrive within 30 seconds.
85const int kSessionAttachTimeoutSeconds = 30;
86
joedow69094d5f2016-05-03 20:00:0287// The default port number used for establishing an RDP session.
88const int kDefaultRdpPort = 3389;
89
joedow0bf730db2016-05-03 20:09:0190// Used for validating the required RDP registry values.
91const int kRdpConnectionsDisabled = 1;
92const int kNetworkLevelAuthEnabled = 1;
93const int kSecurityLayerTlsRequired = 2;
94
joedow69094d5f2016-05-03 20:00:0295// The values used to establish RDP connections are stored in the registry.
joedow0bf730db2016-05-03 20:09:0196const wchar_t kRdpSettingsKeyName[] =
97 L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server";
joedow69094d5f2016-05-03 20:00:0298const wchar_t kRdpTcpSettingsKeyName[] = L"SYSTEM\\CurrentControlSet\\"
99 L"Control\\Terminal Server\\WinStations\\RDP-Tcp";
100const wchar_t kRdpPortValueName[] = L"PortNumber";
joedow0bf730db2016-05-03 20:09:01101const wchar_t kDenyTsConnectionsValueName[] = L"fDenyTSConnections";
102const wchar_t kNetworkLevelAuthValueName[] = L"UserAuthentication";
103const wchar_t kSecurityLayerValueName[] = L"SecurityLayer";
joedow69094d5f2016-05-03 20:00:02104
joedowb7a9ca32016-12-23 00:15:25105webrtc::DesktopSize GetBoundedRdpDesktopSize(int width, int height) {
106 return webrtc::DesktopSize(
107 std::min(kMaxRdpScreenWidth, std::max(kMinRdpScreenWidth, width)),
108 std::min(kMaxRdpScreenHeight, std::max(kMinRdpScreenHeight, height)));
109}
110
[email protected]5b731f3e2013-03-15 07:28:22111// DesktopSession implementation which attaches to the host's physical console.
112// Receives IPC messages from the desktop process, running in the console
113// session, via |WorkerProcessIpcDelegate|, and monitors console session
joedow69094d5f2016-05-03 20:00:02114// attach/detach events via |WtsConsoleObserver|.
[email protected]5b731f3e2013-03-15 07:28:22115class ConsoleSession : public DesktopSessionWin {
116 public:
117 // Same as DesktopSessionWin().
118 ConsoleSession(
119 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
[email protected]12066cb2012-10-25 03:25:43120 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
[email protected]60ccc242012-10-17 21:06:24121 DaemonProcess* daemon_process,
122 int id,
[email protected]5b731f3e2013-03-15 07:28:22123 WtsTerminalMonitor* monitor);
nick697f4292015-04-23 18:22:31124 ~ConsoleSession() override;
[email protected]5b731f3e2013-03-15 07:28:22125
126 protected:
[email protected]6f526ce2013-03-18 04:38:56127 // DesktopSession overrides.
nick697f4292015-04-23 18:22:31128 void SetScreenResolution(const ScreenResolution& resolution) override;
[email protected]6f526ce2013-03-18 04:38:56129
[email protected]5b731f3e2013-03-15 07:28:22130 // DesktopSessionWin overrides.
nick697f4292015-04-23 18:22:31131 void InjectSas() override;
[email protected]5b731f3e2013-03-15 07:28:22132
133 private:
dcheng0765c492016-04-06 22:41:53134 std::unique_ptr<SasInjector> sas_injector_;
[email protected]5b731f3e2013-03-15 07:28:22135
136 DISALLOW_COPY_AND_ASSIGN(ConsoleSession);
137};
138
139// DesktopSession implementation which attaches to virtual RDP console.
140// Receives IPC messages from the desktop process, running in the console
141// session, via |WorkerProcessIpcDelegate|, and monitors console session
joedow69094d5f2016-05-03 20:00:02142// attach/detach events via |WtsConsoleObserver|.
[email protected]5b731f3e2013-03-15 07:28:22143class RdpSession : public DesktopSessionWin {
144 public:
145 // Same as DesktopSessionWin().
146 RdpSession(
147 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
148 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
149 DaemonProcess* daemon_process,
150 int id,
151 WtsTerminalMonitor* monitor);
nick697f4292015-04-23 18:22:31152 ~RdpSession() override;
[email protected]5b731f3e2013-03-15 07:28:22153
154 // Performs the part of initialization that can fail.
[email protected]739e2802013-03-18 01:03:48155 bool Initialize(const ScreenResolution& resolution);
[email protected]5b731f3e2013-03-15 07:28:22156
157 // Mirrors IRdpDesktopSessionEventHandler.
[email protected]a4eca0a2013-06-20 22:15:05158 void OnRdpConnected();
[email protected]5b731f3e2013-03-15 07:28:22159 void OnRdpClosed();
160
161 protected:
[email protected]6f526ce2013-03-18 04:38:56162 // DesktopSession overrides.
nick697f4292015-04-23 18:22:31163 void SetScreenResolution(const ScreenResolution& resolution) override;
[email protected]6f526ce2013-03-18 04:38:56164
[email protected]5b731f3e2013-03-15 07:28:22165 // DesktopSessionWin overrides.
nick697f4292015-04-23 18:22:31166 void InjectSas() override;
[email protected]5b731f3e2013-03-15 07:28:22167
168 private:
169 // An implementation of IRdpDesktopSessionEventHandler interface that forwards
170 // notifications to the owning desktop session.
171 class EventHandler : public IRdpDesktopSessionEventHandler {
172 public:
173 explicit EventHandler(base::WeakPtr<RdpSession> desktop_session);
174 virtual ~EventHandler();
175
176 // IUnknown interface.
mostynb11d989c2014-10-08 16:58:09177 STDMETHOD_(ULONG, AddRef)() override;
178 STDMETHOD_(ULONG, Release)() override;
179 STDMETHOD(QueryInterface)(REFIID riid, void** ppv) override;
[email protected]5b731f3e2013-03-15 07:28:22180
181 // IRdpDesktopSessionEventHandler interface.
mostynb11d989c2014-10-08 16:58:09182 STDMETHOD(OnRdpConnected)() override;
183 STDMETHOD(OnRdpClosed)() override;
[email protected]5b731f3e2013-03-15 07:28:22184
185 private:
186 ULONG ref_count_;
187
188 // Points to the desktop session object receiving OnRdpXxx() notifications.
189 base::WeakPtr<RdpSession> desktop_session_;
190
191 // This class must be used on a single thread.
192 base::ThreadChecker thread_checker_;
193
194 DISALLOW_COPY_AND_ASSIGN(EventHandler);
195 };
196
joedow0bf730db2016-05-03 20:09:01197 // Examines the system settings required to establish an RDP session.
198 // This method returns false if the values are retrieved and any of them would
199 // prevent us from creating an RDP connection.
200 bool VerifyRdpSettings();
201
joedow69094d5f2016-05-03 20:00:02202 // Retrieves a DWORD value from the registry. Returns true on success.
203 bool RetrieveDwordRegistryValue(const wchar_t* key_name,
204 const wchar_t* value_name,
205 DWORD* value);
206
[email protected]5b731f3e2013-03-15 07:28:22207 // Used to create an RDP desktop session.
Robert Liao1a378352017-10-18 01:31:17208 Microsoft::WRL::ComPtr<IRdpDesktopSession> rdp_desktop_session_;
[email protected]5b731f3e2013-03-15 07:28:22209
[email protected]a4eca0a2013-06-20 22:15:05210 // Used to match |rdp_desktop_session_| with the session it is attached to.
211 std::string terminal_id_;
212
[email protected]5b731f3e2013-03-15 07:28:22213 base::WeakPtrFactory<RdpSession> weak_factory_;
214
215 DISALLOW_COPY_AND_ASSIGN(RdpSession);
216};
217
218ConsoleSession::ConsoleSession(
219 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
220 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
221 DaemonProcess* daemon_process,
222 int id,
223 WtsTerminalMonitor* monitor)
224 : DesktopSessionWin(caller_task_runner, io_task_runner, daemon_process, id,
225 monitor) {
[email protected]a4eca0a2013-06-20 22:15:05226 StartMonitoring(WtsTerminalMonitor::kConsole);
[email protected]5b731f3e2013-03-15 07:28:22227}
228
229ConsoleSession::~ConsoleSession() {
230}
231
[email protected]6f526ce2013-03-18 04:38:56232void ConsoleSession::SetScreenResolution(const ScreenResolution& resolution) {
233 // Do nothing. The screen resolution of the console session is controlled by
234 // the DesktopSessionAgent instance running in that session.
235 DCHECK(caller_task_runner()->BelongsToCurrentThread());
236}
237
[email protected]5b731f3e2013-03-15 07:28:22238void ConsoleSession::InjectSas() {
[email protected]dd81166082013-03-18 20:33:33239 DCHECK(caller_task_runner()->BelongsToCurrentThread());
240
[email protected]5b731f3e2013-03-15 07:28:22241 if (!sas_injector_)
242 sas_injector_ = SasInjector::Create();
243 if (!sas_injector_->InjectSas())
244 LOG(ERROR) << "Failed to inject Secure Attention Sequence.";
245}
246
247RdpSession::RdpSession(
248 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
249 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
250 DaemonProcess* daemon_process,
251 int id,
252 WtsTerminalMonitor* monitor)
253 : DesktopSessionWin(caller_task_runner, io_task_runner, daemon_process, id,
254 monitor),
[email protected]aa46ba52013-04-27 00:00:44255 weak_factory_(this) {
[email protected]5b731f3e2013-03-15 07:28:22256}
257
258RdpSession::~RdpSession() {
259}
260
[email protected]739e2802013-03-18 01:03:48261bool RdpSession::Initialize(const ScreenResolution& resolution) {
[email protected]5b731f3e2013-03-15 07:28:22262 DCHECK(caller_task_runner()->BelongsToCurrentThread());
263
joedow0bf730db2016-05-03 20:09:01264 if (!VerifyRdpSettings()) {
265 LOG(ERROR) << "Could not create an RDP session due to invalid settings.";
266 return false;
267 }
268
[email protected]5b731f3e2013-03-15 07:28:22269 // Create the RDP wrapper object.
robliaoeb9bfd642017-05-18 17:35:16270 HRESULT result =
271 ::CoCreateInstance(__uuidof(RdpDesktopSession), nullptr, CLSCTX_ALL,
272 IID_PPV_ARGS(&rdp_desktop_session_));
[email protected]5b731f3e2013-03-15 07:28:22273 if (FAILED(result)) {
274 LOG(ERROR) << "Failed to create RdpSession object, 0x"
275 << std::hex << result << std::dec << ".";
276 return false;
277 }
278
[email protected]3c6ae172013-03-18 08:50:58279 ScreenResolution local_resolution = resolution;
280
281 // If the screen resolution is not specified, use the default screen
282 // resolution.
283 if (local_resolution.IsEmpty()) {
[email protected]b9ed58f2013-05-16 10:45:24284 local_resolution = ScreenResolution(
285 webrtc::DesktopSize(kDefaultRdpScreenWidth, kDefaultRdpScreenHeight),
286 webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
[email protected]3c6ae172013-03-18 08:50:58287 }
288
[email protected]739e2802013-03-18 01:03:48289 // Get the screen dimensions assuming the default DPI.
[email protected]b9ed58f2013-05-16 10:45:24290 webrtc::DesktopSize host_size = local_resolution.ScaleDimensionsToDpi(
291 webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
[email protected]5b731f3e2013-03-15 07:28:22292
293 // Make sure that the host resolution is within the limits supported by RDP.
joedowb7a9ca32016-12-23 00:15:25294 host_size = GetBoundedRdpDesktopSize(host_size.width(), host_size.height());
[email protected]5b731f3e2013-03-15 07:28:22295
joedow69094d5f2016-05-03 20:00:02296 // Read the port number used by RDP.
297 DWORD server_port = kDefaultRdpPort;
298 if (RetrieveDwordRegistryValue(kRdpTcpSettingsKeyName, kRdpPortValueName,
299 &server_port) &&
300 server_port > 65535) {
301 LOG(ERROR) << "Invalid RDP port specified: " << server_port;
302 return false;
303 }
304
[email protected]5b731f3e2013-03-15 07:28:22305 // Create an RDP session.
Robert Liao1a378352017-10-18 01:31:17306 Microsoft::WRL::ComPtr<IRdpDesktopSessionEventHandler> event_handler(
[email protected]5b731f3e2013-03-15 07:28:22307 new EventHandler(weak_factory_.GetWeakPtr()));
[email protected]a4eca0a2013-06-20 22:15:05308 terminal_id_ = base::GenerateGUID();
[email protected]6c3bf032013-12-25 19:37:03309 base::win::ScopedBstr terminal_id(base::UTF8ToUTF16(terminal_id_).c_str());
dcheng858fd172014-11-13 01:17:30310 result = rdp_desktop_session_->Connect(host_size.width(), host_size.height(),
joedowb7a9ca32016-12-23 00:15:25311 kDefaultRdpDpi, kDefaultRdpDpi,
joedow69094d5f2016-05-03 20:00:02312 terminal_id, server_port,
robliaob44b9072017-04-19 00:28:09313 event_handler.Get());
[email protected]5b731f3e2013-03-15 07:28:22314 if (FAILED(result)) {
315 LOG(ERROR) << "RdpSession::Create() failed, 0x"
316 << std::hex << result << std::dec << ".";
317 return false;
318 }
319
320 return true;
321}
322
[email protected]a4eca0a2013-06-20 22:15:05323void RdpSession::OnRdpConnected() {
[email protected]5b731f3e2013-03-15 07:28:22324 DCHECK(caller_task_runner()->BelongsToCurrentThread());
325
326 StopMonitoring();
[email protected]a4eca0a2013-06-20 22:15:05327 StartMonitoring(terminal_id_);
[email protected]5b731f3e2013-03-15 07:28:22328}
329
330void RdpSession::OnRdpClosed() {
331 DCHECK(caller_task_runner()->BelongsToCurrentThread());
332
[email protected]a4b39952013-06-21 03:57:08333 TerminateSession();
[email protected]5b731f3e2013-03-15 07:28:22334}
335
[email protected]6f526ce2013-03-18 04:38:56336void RdpSession::SetScreenResolution(const ScreenResolution& resolution) {
337 DCHECK(caller_task_runner()->BelongsToCurrentThread());
joedowb7a9ca32016-12-23 00:15:25338 DCHECK(!resolution.IsEmpty());
[email protected]6f526ce2013-03-18 04:38:56339
joedowb7a9ca32016-12-23 00:15:25340 webrtc::DesktopSize new_size = resolution.ScaleDimensionsToDpi(
341 webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
342 new_size = GetBoundedRdpDesktopSize(new_size.width(), new_size.height());
343
344 rdp_desktop_session_->ChangeResolution(new_size.width(), new_size.height(),
345 kDefaultRdpDpi, kDefaultRdpDpi);
[email protected]6f526ce2013-03-18 04:38:56346}
347
[email protected]5b731f3e2013-03-15 07:28:22348void RdpSession::InjectSas() {
349 DCHECK(caller_task_runner()->BelongsToCurrentThread());
350
[email protected]97328ee2013-06-04 06:46:59351 rdp_desktop_session_->InjectSas();
[email protected]5b731f3e2013-03-15 07:28:22352}
353
joedow0bf730db2016-05-03 20:09:01354bool RdpSession::VerifyRdpSettings() {
355 // Verify RDP connections are enabled.
356 DWORD deny_ts_connections_flag = 0;
357 if (RetrieveDwordRegistryValue(kRdpSettingsKeyName,
358 kDenyTsConnectionsValueName,
359 &deny_ts_connections_flag) &&
360 deny_ts_connections_flag == kRdpConnectionsDisabled) {
361 LOG(ERROR) << "RDP Connections must be enabled.";
362 return false;
363 }
364
365 // Verify Network Level Authentication is disabled.
366 DWORD network_level_auth_flag = 0;
367 if (RetrieveDwordRegistryValue(kRdpTcpSettingsKeyName,
368 kNetworkLevelAuthValueName,
369 &network_level_auth_flag) &&
370 network_level_auth_flag == kNetworkLevelAuthEnabled) {
371 LOG(ERROR) << "Network Level Authentication for RDP must be disabled.";
372 return false;
373 }
374
375 // Verify Security Layer is not set to TLS. It can be either of the other two
376 // values, but forcing TLS will prevent us from establishing a connection.
377 DWORD security_layer_flag = 0;
378 if (RetrieveDwordRegistryValue(kRdpTcpSettingsKeyName,
379 kSecurityLayerValueName,
380 &security_layer_flag) &&
381 security_layer_flag == kSecurityLayerTlsRequired) {
382 LOG(ERROR) << "RDP SecurityLayer must not be set to TLS.";
383 return false;
384 }
385
386 return true;
387}
388
joedow69094d5f2016-05-03 20:00:02389bool RdpSession::RetrieveDwordRegistryValue(const wchar_t* key_name,
390 const wchar_t* value_name,
391 DWORD* value) {
392 DCHECK(key_name);
393 DCHECK(value_name);
394 DCHECK(value);
395
396 base::win::RegKey key(HKEY_LOCAL_MACHINE, key_name, KEY_READ);
397 if (!key.Valid()) {
398 LOG(WARNING) << "Failed to open key: " << key_name;
399 return false;
400 }
401
402 if (key.ReadValueDW(value_name, value) != ERROR_SUCCESS) {
403 LOG(WARNING) << "Failed to read registry value: " << value_name;
404 return false;
405 }
406
407 return true;
408}
409
[email protected]5b731f3e2013-03-15 07:28:22410RdpSession::EventHandler::EventHandler(
411 base::WeakPtr<RdpSession> desktop_session)
412 : ref_count_(0),
413 desktop_session_(desktop_session) {
414}
415
416RdpSession::EventHandler::~EventHandler() {
417 DCHECK(thread_checker_.CalledOnValidThread());
418
[email protected]1bf06232013-06-07 13:50:24419 if (desktop_session_)
[email protected]5b731f3e2013-03-15 07:28:22420 desktop_session_->OnRdpClosed();
421}
422
423ULONG STDMETHODCALLTYPE RdpSession::EventHandler::AddRef() {
424 DCHECK(thread_checker_.CalledOnValidThread());
425
426 return ++ref_count_;
427}
428
429ULONG STDMETHODCALLTYPE RdpSession::EventHandler::Release() {
430 DCHECK(thread_checker_.CalledOnValidThread());
431
432 if (--ref_count_ == 0) {
433 delete this;
434 return 0;
435 }
436
437 return ref_count_;
438}
439
440STDMETHODIMP RdpSession::EventHandler::QueryInterface(REFIID riid, void** ppv) {
441 DCHECK(thread_checker_.CalledOnValidThread());
442
443 if (riid == IID_IUnknown ||
444 riid == IID_IRdpDesktopSessionEventHandler) {
445 *ppv = static_cast<IRdpDesktopSessionEventHandler*>(this);
446 AddRef();
447 return S_OK;
448 }
449
sergeyuc5f104b2015-01-09 19:33:24450 *ppv = nullptr;
[email protected]5b731f3e2013-03-15 07:28:22451 return E_NOINTERFACE;
452}
453
[email protected]a4eca0a2013-06-20 22:15:05454STDMETHODIMP RdpSession::EventHandler::OnRdpConnected() {
[email protected]5b731f3e2013-03-15 07:28:22455 DCHECK(thread_checker_.CalledOnValidThread());
456
[email protected]a4eca0a2013-06-20 22:15:05457 if (desktop_session_)
458 desktop_session_->OnRdpConnected();
[email protected]5b731f3e2013-03-15 07:28:22459
[email protected]5b731f3e2013-03-15 07:28:22460 return S_OK;
461}
462
463STDMETHODIMP RdpSession::EventHandler::OnRdpClosed() {
464 DCHECK(thread_checker_.CalledOnValidThread());
465
[email protected]1bf06232013-06-07 13:50:24466 if (!desktop_session_)
[email protected]5b731f3e2013-03-15 07:28:22467 return S_OK;
468
469 base::WeakPtr<RdpSession> desktop_session = desktop_session_;
470 desktop_session_.reset();
471 desktop_session->OnRdpClosed();
472 return S_OK;
473}
474
475} // namespace
476
477// static
dcheng0765c492016-04-06 22:41:53478std::unique_ptr<DesktopSession> DesktopSessionWin::CreateForConsole(
[email protected]5b731f3e2013-03-15 07:28:22479 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
480 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
481 DaemonProcess* daemon_process,
482 int id,
[email protected]739e2802013-03-18 01:03:48483 const ScreenResolution& resolution) {
Jinho Bang138fde32018-01-18 23:13:42484 return std::make_unique<ConsoleSession>(caller_task_runner, io_task_runner,
ricea68860bd2016-08-22 02:48:56485 daemon_process, id,
486 HostService::GetInstance());
[email protected]5b731f3e2013-03-15 07:28:22487}
488
489// static
dcheng0765c492016-04-06 22:41:53490std::unique_ptr<DesktopSession> DesktopSessionWin::CreateForVirtualTerminal(
[email protected]5b731f3e2013-03-15 07:28:22491 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
492 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
493 DaemonProcess* daemon_process,
494 int id,
[email protected]739e2802013-03-18 01:03:48495 const ScreenResolution& resolution) {
dcheng0765c492016-04-06 22:41:53496 std::unique_ptr<RdpSession> session(
497 new RdpSession(caller_task_runner, io_task_runner, daemon_process, id,
498 HostService::GetInstance()));
[email protected]739e2802013-03-18 01:03:48499 if (!session->Initialize(resolution))
sergeyuafce9782014-09-29 19:38:30500 return nullptr;
[email protected]5b731f3e2013-03-15 07:28:22501
sergeyu1417e0132015-12-23 19:01:22502 return std::move(session);
[email protected]5b731f3e2013-03-15 07:28:22503}
504
505DesktopSessionWin::DesktopSessionWin(
506 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
507 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
508 DaemonProcess* daemon_process,
509 int id,
[email protected]3fd005e22013-02-28 20:11:29510 WtsTerminalMonitor* monitor)
[email protected]60ccc242012-10-17 21:06:24511 : DesktopSession(daemon_process, id),
[email protected]5b731f3e2013-03-15 07:28:22512 caller_task_runner_(caller_task_runner),
[email protected]60ccc242012-10-17 21:06:24513 io_task_runner_(io_task_runner),
[email protected]5b731f3e2013-03-15 07:28:22514 monitor_(monitor),
515 monitoring_notifications_(false) {
516 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]94618e72013-05-14 00:13:08517
518 ReportElapsedTime("created");
[email protected]60ccc242012-10-17 21:06:24519}
520
521DesktopSessionWin::~DesktopSessionWin() {
[email protected]5b731f3e2013-03-15 07:28:22522 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24523
[email protected]5b731f3e2013-03-15 07:28:22524 StopMonitoring();
525}
526
527void DesktopSessionWin::OnSessionAttachTimeout() {
528 DCHECK(caller_task_runner_->BelongsToCurrentThread());
529
530 LOG(ERROR) << "Session attach notification didn't arrived within "
531 << kSessionAttachTimeoutSeconds << " seconds.";
[email protected]a4b39952013-06-21 03:57:08532 TerminateSession();
[email protected]5b731f3e2013-03-15 07:28:22533}
534
[email protected]a4eca0a2013-06-20 22:15:05535void DesktopSessionWin::StartMonitoring(const std::string& terminal_id) {
[email protected]5b731f3e2013-03-15 07:28:22536 DCHECK(caller_task_runner_->BelongsToCurrentThread());
537 DCHECK(!monitoring_notifications_);
538 DCHECK(!session_attach_timer_.IsRunning());
539
[email protected]94618e72013-05-14 00:13:08540 ReportElapsedTime("started monitoring");
541
[email protected]5b731f3e2013-03-15 07:28:22542 session_attach_timer_.Start(
543 FROM_HERE, base::TimeDelta::FromSeconds(kSessionAttachTimeoutSeconds),
544 this, &DesktopSessionWin::OnSessionAttachTimeout);
545
546 monitoring_notifications_ = true;
[email protected]a4eca0a2013-06-20 22:15:05547 monitor_->AddWtsTerminalObserver(terminal_id, this);
[email protected]5b731f3e2013-03-15 07:28:22548}
549
550void DesktopSessionWin::StopMonitoring() {
551 DCHECK(caller_task_runner_->BelongsToCurrentThread());
552
553 if (monitoring_notifications_) {
[email protected]94618e72013-05-14 00:13:08554 ReportElapsedTime("stopped monitoring");
555
[email protected]5b731f3e2013-03-15 07:28:22556 monitoring_notifications_ = false;
557 monitor_->RemoveWtsTerminalObserver(this);
558 }
559
560 session_attach_timer_.Stop();
561 OnSessionDetached();
[email protected]60ccc242012-10-17 21:06:24562}
563
[email protected]a4b39952013-06-21 03:57:08564void DesktopSessionWin::TerminateSession() {
565 DCHECK(caller_task_runner_->BelongsToCurrentThread());
566
567 StopMonitoring();
568
569 // This call will delete |this| so it should be at the very end of the method.
570 daemon_process()->CloseDesktopSession(id());
571}
572
avic5960f32015-12-22 22:49:48573void DesktopSessionWin::OnChannelConnected(int32_t peer_pid) {
[email protected]5b731f3e2013-03-15 07:28:22574 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]12066cb2012-10-25 03:25:43575
[email protected]94618e72013-05-14 00:13:08576 ReportElapsedTime("channel connected");
577
[email protected]12066cb2012-10-25 03:25:43578 VLOG(1) << "IPC: daemon <- desktop (" << peer_pid << ")";
[email protected]60ccc242012-10-17 21:06:24579}
580
581bool DesktopSessionWin::OnMessageReceived(const IPC::Message& message) {
[email protected]5b731f3e2013-03-15 07:28:22582 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24583
[email protected]12066cb2012-10-25 03:25:43584 bool handled = true;
585 IPC_BEGIN_MESSAGE_MAP(DesktopSessionWin, message)
586 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached,
587 OnDesktopSessionAgentAttached)
[email protected]0dffd552012-12-07 01:08:09588 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_InjectSas,
[email protected]5b731f3e2013-03-15 07:28:22589 InjectSas)
[email protected]12066cb2012-10-25 03:25:43590 IPC_MESSAGE_UNHANDLED(handled = false)
591 IPC_END_MESSAGE_MAP()
[email protected]f5f0f402013-03-05 22:46:38592
593 if (!handled) {
594 LOG(ERROR) << "Received unexpected IPC type: " << message.type();
[email protected]e9057a6f2013-03-08 22:37:55595 CrashDesktopProcess(FROM_HERE);
[email protected]f5f0f402013-03-05 22:46:38596 }
597
[email protected]12066cb2012-10-25 03:25:43598 return handled;
[email protected]60ccc242012-10-17 21:06:24599}
600
[email protected]a4b39952013-06-21 03:57:08601void DesktopSessionWin::OnPermanentError(int exit_code) {
[email protected]5b731f3e2013-03-15 07:28:22602 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24603
[email protected]a4b39952013-06-21 03:57:08604 TerminateSession();
[email protected]60ccc242012-10-17 21:06:24605}
606
zijiehedda3acb2017-06-29 23:19:16607void DesktopSessionWin::OnWorkerProcessStopped() {}
608
avic5960f32015-12-22 22:49:48609void DesktopSessionWin::OnSessionAttached(uint32_t session_id) {
[email protected]5b731f3e2013-03-15 07:28:22610 DCHECK(caller_task_runner_->BelongsToCurrentThread());
611 DCHECK(!launcher_);
612 DCHECK(monitoring_notifications_);
[email protected]60ccc242012-10-17 21:06:24613
[email protected]94618e72013-05-14 00:13:08614 ReportElapsedTime("attached");
615
joedow1cdb04812016-12-13 06:11:15616 // Launch elevated on Win8+ to enable injection of Alt+Tab and Ctrl+Alt+Del.
[email protected]85c7fda22013-05-18 01:35:47617 bool launch_elevated = base::win::GetVersion() >= base::win::VERSION_WIN8;
618
619 // Get the name of the executable to run. |kDesktopBinaryName| specifies
joedow1cdb04812016-12-13 06:11:15620 // uiAccess="true" in its manifest.
[email protected]9410c0a2013-02-23 06:07:21621 base::FilePath desktop_binary;
[email protected]85c7fda22013-05-18 01:35:47622 bool result;
623 if (launch_elevated) {
624 result = GetInstalledBinaryPath(kDesktopBinaryName, &desktop_binary);
625 } else {
626 result = GetInstalledBinaryPath(kHostBinaryName, &desktop_binary);
627 }
628
629 if (!result) {
[email protected]a4b39952013-06-21 03:57:08630 TerminateSession();
[email protected]9410c0a2013-02-23 06:07:21631 return;
[email protected]60ccc242012-10-17 21:06:24632 }
633
[email protected]5b731f3e2013-03-15 07:28:22634 session_attach_timer_.Stop();
635
dcheng0765c492016-04-06 22:41:53636 std::unique_ptr<base::CommandLine> target(
637 new base::CommandLine(desktop_binary));
[email protected]9410c0a2013-02-23 06:07:21638 target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeDesktop);
[email protected]5b731f3e2013-03-15 07:28:22639 // Copy the command line switches enabling verbose logging.
avi429bbdd2014-12-23 00:27:27640 target->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
641 kCopiedSwitchNames, arraysize(kCopiedSwitchNames));
[email protected]9410c0a2013-02-23 06:07:21642
[email protected]5b731f3e2013-03-15 07:28:22643 // Create a delegate capable of launching a process in a different session.
dcheng0765c492016-04-06 22:41:53644 std::unique_ptr<WtsSessionProcessDelegate> delegate(
645 new WtsSessionProcessDelegate(
646 io_task_runner_, std::move(target), launch_elevated,
joedowf84fffae2016-12-20 03:35:51647 base::WideToUTF8(kDaemonIpcSecurityDescriptor)));
[email protected]85c7fda22013-05-18 01:35:47648 if (!delegate->Initialize(session_id)) {
[email protected]a4b39952013-06-21 03:57:08649 TerminateSession();
[email protected]85c7fda22013-05-18 01:35:47650 return;
651 }
[email protected]60ccc242012-10-17 21:06:24652
653 // Create a launcher for the desktop process, using the per-session delegate.
sergeyu1417e0132015-12-23 19:01:22654 launcher_.reset(new WorkerProcessLauncher(std::move(delegate), this));
sammcf9cd299a2016-11-02 22:13:26655 session_id_ = session_id;
[email protected]60ccc242012-10-17 21:06:24656}
657
658void DesktopSessionWin::OnSessionDetached() {
[email protected]5b731f3e2013-03-15 07:28:22659 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24660
661 launcher_.reset();
sammcf9cd299a2016-11-02 22:13:26662 session_id_ = UINT32_MAX;
[email protected]5b731f3e2013-03-15 07:28:22663
664 if (monitoring_notifications_) {
[email protected]94618e72013-05-14 00:13:08665 ReportElapsedTime("detached");
666
[email protected]5b731f3e2013-03-15 07:28:22667 session_attach_timer_.Start(
668 FROM_HERE, base::TimeDelta::FromSeconds(kSessionAttachTimeoutSeconds),
669 this, &DesktopSessionWin::OnSessionAttachTimeout);
670 }
[email protected]60ccc242012-10-17 21:06:24671}
672
[email protected]12066cb2012-10-25 03:25:43673void DesktopSessionWin::OnDesktopSessionAgentAttached(
sammce66272fae2016-11-01 03:49:04674 const IPC::ChannelHandle& desktop_pipe) {
sammcf9cd299a2016-11-02 22:13:26675 if (!daemon_process()->OnDesktopSessionAgentAttached(id(), session_id_,
676 desktop_pipe)) {
[email protected]e9057a6f2013-03-08 22:37:55677 CrashDesktopProcess(FROM_HERE);
[email protected]12066cb2012-10-25 03:25:43678 }
679}
680
Brett Wilson9c361992017-09-12 06:05:21681void DesktopSessionWin::CrashDesktopProcess(const base::Location& location) {
[email protected]5b731f3e2013-03-15 07:28:22682 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]12066cb2012-10-25 03:25:43683
[email protected]e9057a6f2013-03-08 22:37:55684 launcher_->Crash(location);
[email protected]12066cb2012-10-25 03:25:43685}
686
[email protected]94618e72013-05-14 00:13:08687void DesktopSessionWin::ReportElapsedTime(const std::string& event) {
688 base::Time now = base::Time::Now();
689
690 std::string passed;
691 if (!last_timestamp_.is_null()) {
692 passed = base::StringPrintf(", %.2fs passed",
693 (now - last_timestamp_).InSecondsF());
694 }
695
696 base::Time::Exploded exploded;
697 now.LocalExplode(&exploded);
698 VLOG(1) << base::StringPrintf("session(%d): %s at %02d:%02d:%02d.%03d%s",
699 id(),
700 event.c_str(),
701 exploded.hour,
702 exploded.minute,
703 exploded.second,
704 exploded.millisecond,
705 passed.c_str());
706
707 last_timestamp_ = now;
708}
709
[email protected]60ccc242012-10-17 21:06:24710} // namespace remoting