blob: 00fc956d20e77778f480e9afade7e0e2d2fa3da8 [file] [log] [blame]
Avi Drissmand6cdf9b2022-09-15 19:52:531// Copyright 2012 The Chromium Authors
[email protected]60ccc242012-10-17 21:06:242// 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>
David Bienvenubb3fd1a2023-01-10 16:42:1713#include <string>
sergeyu1417e0132015-12-23 19:01:2214#include <utility>
[email protected]5b731f3e2013-03-15 07:28:2215
[email protected]9410c0a2013-02-23 06:07:2116#include "base/base_switches.h"
17#include "base/command_line.h"
Lei Zhang71d3a022021-05-27 17:08:4218#include "base/cxx17_backports.h"
[email protected]5b731f3e2013-03-15 07:28:2219#include "base/files/file_path.h"
[email protected]a4eca0a2013-06-20 22:15:0520#include "base/guid.h"
Ken Rockot33f8dfb2020-08-31 20:17:4021#include "base/logging.h"
[email protected]5b731f3e2013-03-15 07:28:2222#include "base/memory/ref_counted.h"
[email protected]5b731f3e2013-03-15 07:28:2223#include "base/memory/weak_ptr.h"
[email protected]eaf92532013-06-11 07:39:1924#include "base/strings/stringprintf.h"
[email protected]906265872013-06-07 22:40:4525#include "base/strings/utf_string_conversions.h"
[email protected]5b731f3e2013-03-15 07:28:2226#include "base/threading/thread_checker.h"
[email protected]5d7eb862013-06-28 15:21:2427#include "base/timer/timer.h"
joedow69094d5f2016-05-03 20:00:0228#include "base/win/registry.h"
[email protected]a4eca0a2013-06-20 22:15:0529#include "base/win/scoped_bstr.h"
[email protected]5b731f3e2013-03-15 07:28:2230#include "base/win/scoped_handle.h"
[email protected]12066cb2012-10-25 03:25:4331#include "remoting/base/auto_thread_task_runner.h"
Joe Downingb0fb5422021-12-07 21:26:2032#include "remoting/host/base/screen_resolution.h"
33#include "remoting/host/base/switches.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"
nicholsse3320ae2016-09-16 20:12:5939// MIDL-generated declarations and definitions.
40#include "remoting/host/win/chromoting_lib.h"
[email protected]5b731f3e2013-03-15 07:28:2241#include "remoting/host/win/host_service.h"
Yuwei Huangaa06bab42022-02-25 21:24:4042#include "remoting/host/win/trust_util.h"
[email protected]60ccc242012-10-17 21:06:2443#include "remoting/host/win/worker_process_launcher.h"
[email protected]60ccc242012-10-17 21:06:2444#include "remoting/host/win/wts_session_process_delegate.h"
[email protected]3fd005e22013-02-28 20:11:2945#include "remoting/host/win/wts_terminal_monitor.h"
[email protected]5b731f3e2013-03-15 07:28:2246#include "remoting/host/win/wts_terminal_observer.h"
47#include "remoting/host/worker_process_ipc_delegate.h"
[email protected]60ccc242012-10-17 21:06:2448
[email protected]12066cb2012-10-25 03:25:4349using base::win::ScopedHandle;
50
[email protected]5b731f3e2013-03-15 07:28:2251namespace remoting {
52
[email protected]60ccc242012-10-17 21:06:2453namespace {
54
[email protected]60ccc242012-10-17 21:06:2455// The security descriptor of the daemon IPC endpoint. It gives full access
[email protected]6d65223d2013-03-05 20:32:4656// to SYSTEM and denies access by anyone else.
[email protected]5b731f3e2013-03-15 07:28:2257const wchar_t kDaemonIpcSecurityDescriptor[] =
58 SDDL_OWNER L":" SDDL_LOCAL_SYSTEM
59 SDDL_GROUP L":" SDDL_LOCAL_SYSTEM
60 SDDL_DACL L":("
61 SDDL_ACCESS_ALLOWED L";;" SDDL_GENERIC_ALL L";;;" SDDL_LOCAL_SYSTEM
62 L")";
[email protected]60ccc242012-10-17 21:06:2463
[email protected]9410c0a2013-02-23 06:07:2164// The command line parameters that should be copied from the service's command
[email protected]f0ce8fbb2014-06-16 18:36:1765// line to the desktop process.
Joe Downingfd8a4222023-01-11 23:39:4066const char* kCopiedSwitchNames[] = {switches::kV, switches::kVModule};
[email protected]9410c0a2013-02-23 06:07:2167
[email protected]3c6ae172013-03-18 08:50:5868// The default screen dimensions for an RDP session.
[email protected]792c4f42013-04-06 16:05:2169const int kDefaultRdpScreenWidth = 1280;
[email protected]3c6ae172013-03-18 08:50:5870const int kDefaultRdpScreenHeight = 768;
71
[email protected]5b731f3e2013-03-15 07:28:2272// The minimum effective screen dimensions supported by Windows are 800x600.
73const int kMinRdpScreenWidth = 800;
74const int kMinRdpScreenHeight = 600;
[email protected]60ccc242012-10-17 21:06:2475
David Bienvenubb3fd1a2023-01-10 16:42:1776// Windows supports dimensions up to 8192x8192.
77const int kMaxRdpScreenWidth = 8192;
78const int kMaxRdpScreenHeight = 8192;
Joe Downing4cc20bee2021-07-02 18:14:5779
[email protected]739e2802013-03-18 01:03:4880// Default dots per inch used by RDP is 96 DPI.
81const int kDefaultRdpDpi = 96;
[email protected]5b731f3e2013-03-15 07:28:2282
83// The session attach notification should arrive within 30 seconds.
84const int kSessionAttachTimeoutSeconds = 30;
85
joedow69094d5f2016-05-03 20:00:0286// The default port number used for establishing an RDP session.
87const int kDefaultRdpPort = 3389;
88
joedow0bf730db2016-05-03 20:09:0189// Used for validating the required RDP registry values.
90const int kRdpConnectionsDisabled = 1;
91const int kNetworkLevelAuthEnabled = 1;
92const int kSecurityLayerTlsRequired = 2;
93
joedow69094d5f2016-05-03 20:00:0294// The values used to establish RDP connections are stored in the registry.
joedow0bf730db2016-05-03 20:09:0195const wchar_t kRdpSettingsKeyName[] =
96 L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server";
Joe Downingfd8a4222023-01-11 23:39:4097const wchar_t kRdpTcpSettingsKeyName[] =
98 L"SYSTEM\\CurrentControlSet\\"
joedow69094d5f2016-05-03 20:00:0299 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(
David Bienvenubb3fd1a2023-01-10 16:42:17107 base::clamp(width, kMinRdpScreenWidth, kMaxRdpScreenWidth),
108 base::clamp(height, kMinRdpScreenHeight, kMaxRdpScreenHeight));
joedowb7a9ca32016-12-23 00:15:25109}
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().
Joe Downingfd8a4222023-01-11 23:39:40118 ConsoleSession(scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
119 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
120 DaemonProcess* daemon_process,
121 int id,
122 WtsTerminalMonitor* monitor);
Peter Boströme9178e42021-09-22 18:11:49123
124 ConsoleSession(const ConsoleSession&) = delete;
125 ConsoleSession& operator=(const ConsoleSession&) = delete;
126
nick697f4292015-04-23 18:22:31127 ~ConsoleSession() override;
[email protected]5b731f3e2013-03-15 07:28:22128
129 protected:
[email protected]6f526ce2013-03-18 04:38:56130 // DesktopSession overrides.
nick697f4292015-04-23 18:22:31131 void SetScreenResolution(const ScreenResolution& resolution) override;
[email protected]6f526ce2013-03-18 04:38:56132
[email protected]5b731f3e2013-03-15 07:28:22133 // DesktopSessionWin overrides.
nick697f4292015-04-23 18:22:31134 void InjectSas() override;
[email protected]5b731f3e2013-03-15 07:28:22135
136 private:
dcheng0765c492016-04-06 22:41:53137 std::unique_ptr<SasInjector> sas_injector_;
[email protected]5b731f3e2013-03-15 07:28:22138};
139
140// DesktopSession implementation which attaches to virtual RDP console.
141// Receives IPC messages from the desktop process, running in the console
142// session, via |WorkerProcessIpcDelegate|, and monitors console session
joedow69094d5f2016-05-03 20:00:02143// attach/detach events via |WtsConsoleObserver|.
[email protected]5b731f3e2013-03-15 07:28:22144class RdpSession : public DesktopSessionWin {
145 public:
146 // Same as DesktopSessionWin().
Joe Downingfd8a4222023-01-11 23:39:40147 RdpSession(scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
148 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
149 DaemonProcess* daemon_process,
150 int id,
151 WtsTerminalMonitor* monitor);
Peter Boströme9178e42021-09-22 18:11:49152
153 RdpSession(const RdpSession&) = delete;
154 RdpSession& operator=(const RdpSession&) = delete;
155
nick697f4292015-04-23 18:22:31156 ~RdpSession() override;
[email protected]5b731f3e2013-03-15 07:28:22157
158 // Performs the part of initialization that can fail.
[email protected]739e2802013-03-18 01:03:48159 bool Initialize(const ScreenResolution& resolution);
[email protected]5b731f3e2013-03-15 07:28:22160
161 // Mirrors IRdpDesktopSessionEventHandler.
[email protected]a4eca0a2013-06-20 22:15:05162 void OnRdpConnected();
[email protected]5b731f3e2013-03-15 07:28:22163 void OnRdpClosed();
164
165 protected:
[email protected]6f526ce2013-03-18 04:38:56166 // DesktopSession overrides.
nick697f4292015-04-23 18:22:31167 void SetScreenResolution(const ScreenResolution& resolution) override;
[email protected]6f526ce2013-03-18 04:38:56168
[email protected]5b731f3e2013-03-15 07:28:22169 // DesktopSessionWin overrides.
nick697f4292015-04-23 18:22:31170 void InjectSas() override;
[email protected]5b731f3e2013-03-15 07:28:22171
172 private:
173 // An implementation of IRdpDesktopSessionEventHandler interface that forwards
174 // notifications to the owning desktop session.
175 class EventHandler : public IRdpDesktopSessionEventHandler {
176 public:
177 explicit EventHandler(base::WeakPtr<RdpSession> desktop_session);
Peter Boströme9178e42021-09-22 18:11:49178
179 EventHandler(const EventHandler&) = delete;
180 EventHandler& operator=(const EventHandler&) = delete;
181
[email protected]5b731f3e2013-03-15 07:28:22182 virtual ~EventHandler();
183
184 // IUnknown interface.
mostynb11d989c2014-10-08 16:58:09185 STDMETHOD_(ULONG, AddRef)() override;
186 STDMETHOD_(ULONG, Release)() override;
187 STDMETHOD(QueryInterface)(REFIID riid, void** ppv) override;
[email protected]5b731f3e2013-03-15 07:28:22188
189 // IRdpDesktopSessionEventHandler interface.
mostynb11d989c2014-10-08 16:58:09190 STDMETHOD(OnRdpConnected)() override;
191 STDMETHOD(OnRdpClosed)() override;
[email protected]5b731f3e2013-03-15 07:28:22192
193 private:
194 ULONG ref_count_;
195
196 // Points to the desktop session object receiving OnRdpXxx() notifications.
197 base::WeakPtr<RdpSession> desktop_session_;
198
199 // This class must be used on a single thread.
200 base::ThreadChecker thread_checker_;
[email protected]5b731f3e2013-03-15 07:28:22201 };
202
joedow0bf730db2016-05-03 20:09:01203 // Examines the system settings required to establish an RDP session.
204 // This method returns false if the values are retrieved and any of them would
205 // prevent us from creating an RDP connection.
206 bool VerifyRdpSettings();
207
joedow69094d5f2016-05-03 20:00:02208 // Retrieves a DWORD value from the registry. Returns true on success.
209 bool RetrieveDwordRegistryValue(const wchar_t* key_name,
210 const wchar_t* value_name,
211 DWORD* value);
212
[email protected]5b731f3e2013-03-15 07:28:22213 // Used to create an RDP desktop session.
Robert Liao1a378352017-10-18 01:31:17214 Microsoft::WRL::ComPtr<IRdpDesktopSession> rdp_desktop_session_;
[email protected]5b731f3e2013-03-15 07:28:22215
[email protected]a4eca0a2013-06-20 22:15:05216 // Used to match |rdp_desktop_session_| with the session it is attached to.
217 std::string terminal_id_;
218
Jeremy Roman2b7c9502019-08-21 22:34:08219 base::WeakPtrFactory<RdpSession> weak_factory_{this};
[email protected]5b731f3e2013-03-15 07:28:22220};
221
222ConsoleSession::ConsoleSession(
223 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
224 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
225 DaemonProcess* daemon_process,
226 int id,
227 WtsTerminalMonitor* monitor)
Joe Downingfd8a4222023-01-11 23:39:40228 : DesktopSessionWin(caller_task_runner,
229 io_task_runner,
230 daemon_process,
231 id,
[email protected]5b731f3e2013-03-15 07:28:22232 monitor) {
[email protected]a4eca0a2013-06-20 22:15:05233 StartMonitoring(WtsTerminalMonitor::kConsole);
[email protected]5b731f3e2013-03-15 07:28:22234}
235
Joe Downingfd8a4222023-01-11 23:39:40236ConsoleSession::~ConsoleSession() {}
[email protected]5b731f3e2013-03-15 07:28:22237
[email protected]6f526ce2013-03-18 04:38:56238void ConsoleSession::SetScreenResolution(const ScreenResolution& resolution) {
239 // Do nothing. The screen resolution of the console session is controlled by
240 // the DesktopSessionAgent instance running in that session.
241 DCHECK(caller_task_runner()->BelongsToCurrentThread());
242}
243
[email protected]5b731f3e2013-03-15 07:28:22244void ConsoleSession::InjectSas() {
[email protected]dd81166082013-03-18 20:33:33245 DCHECK(caller_task_runner()->BelongsToCurrentThread());
246
Joe Downingfd8a4222023-01-11 23:39:40247 if (!sas_injector_) {
[email protected]5b731f3e2013-03-15 07:28:22248 sas_injector_ = SasInjector::Create();
Joe Downingfd8a4222023-01-11 23:39:40249 }
250 if (!sas_injector_->InjectSas()) {
[email protected]5b731f3e2013-03-15 07:28:22251 LOG(ERROR) << "Failed to inject Secure Attention Sequence.";
Joe Downingfd8a4222023-01-11 23:39:40252 }
[email protected]5b731f3e2013-03-15 07:28:22253}
254
Jeremy Roman2b7c9502019-08-21 22:34:08255RdpSession::RdpSession(scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
256 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
257 DaemonProcess* daemon_process,
258 int id,
259 WtsTerminalMonitor* monitor)
260 : DesktopSessionWin(caller_task_runner,
261 io_task_runner,
262 daemon_process,
263 id,
264 monitor) {}
[email protected]5b731f3e2013-03-15 07:28:22265
Joe Downingfd8a4222023-01-11 23:39:40266RdpSession::~RdpSession() {}
[email protected]5b731f3e2013-03-15 07:28:22267
[email protected]739e2802013-03-18 01:03:48268bool RdpSession::Initialize(const ScreenResolution& resolution) {
[email protected]5b731f3e2013-03-15 07:28:22269 DCHECK(caller_task_runner()->BelongsToCurrentThread());
270
joedow0bf730db2016-05-03 20:09:01271 if (!VerifyRdpSettings()) {
272 LOG(ERROR) << "Could not create an RDP session due to invalid settings.";
273 return false;
274 }
275
[email protected]5b731f3e2013-03-15 07:28:22276 // Create the RDP wrapper object.
robliaoeb9bfd642017-05-18 17:35:16277 HRESULT result =
278 ::CoCreateInstance(__uuidof(RdpDesktopSession), nullptr, CLSCTX_ALL,
279 IID_PPV_ARGS(&rdp_desktop_session_));
[email protected]5b731f3e2013-03-15 07:28:22280 if (FAILED(result)) {
Joe Downingfd8a4222023-01-11 23:39:40281 LOG(ERROR) << "Failed to create RdpSession object, 0x" << std::hex << result
282 << std::dec << ".";
[email protected]5b731f3e2013-03-15 07:28:22283 return false;
284 }
285
[email protected]3c6ae172013-03-18 08:50:58286 ScreenResolution local_resolution = resolution;
287
288 // If the screen resolution is not specified, use the default screen
289 // resolution.
290 if (local_resolution.IsEmpty()) {
[email protected]b9ed58f2013-05-16 10:45:24291 local_resolution = ScreenResolution(
292 webrtc::DesktopSize(kDefaultRdpScreenWidth, kDefaultRdpScreenHeight),
293 webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
[email protected]3c6ae172013-03-18 08:50:58294 }
295
Joe Downing90e213f2023-02-13 19:13:01296 // Get the screen dimensions using the default DPI for the RDP client window.
[email protected]b9ed58f2013-05-16 10:45:24297 webrtc::DesktopSize host_size = local_resolution.ScaleDimensionsToDpi(
298 webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
[email protected]5b731f3e2013-03-15 07:28:22299
300 // Make sure that the host resolution is within the limits supported by RDP.
joedowb7a9ca32016-12-23 00:15:25301 host_size = GetBoundedRdpDesktopSize(host_size.width(), host_size.height());
[email protected]5b731f3e2013-03-15 07:28:22302
joedow69094d5f2016-05-03 20:00:02303 // Read the port number used by RDP.
304 DWORD server_port = kDefaultRdpPort;
305 if (RetrieveDwordRegistryValue(kRdpTcpSettingsKeyName, kRdpPortValueName,
306 &server_port) &&
307 server_port > 65535) {
308 LOG(ERROR) << "Invalid RDP port specified: " << server_port;
309 return false;
310 }
311
[email protected]5b731f3e2013-03-15 07:28:22312 // Create an RDP session.
Robert Liao1a378352017-10-18 01:31:17313 Microsoft::WRL::ComPtr<IRdpDesktopSessionEventHandler> event_handler(
[email protected]5b731f3e2013-03-15 07:28:22314 new EventHandler(weak_factory_.GetWeakPtr()));
[email protected]a4eca0a2013-06-20 22:15:05315 terminal_id_ = base::GenerateGUID();
Jan Wilken Dörrie06451e62021-02-22 18:07:29316 base::win::ScopedBstr terminal_id(base::UTF8ToWide(terminal_id_));
Robert Liao7dfd293b2020-02-06 21:11:48317 result = rdp_desktop_session_->Connect(
318 host_size.width(), host_size.height(), kDefaultRdpDpi, kDefaultRdpDpi,
319 terminal_id.Get(), server_port, event_handler.Get());
[email protected]5b731f3e2013-03-15 07:28:22320 if (FAILED(result)) {
Joe Downingfd8a4222023-01-11 23:39:40321 LOG(ERROR) << "RdpSession::Create() failed, 0x" << std::hex << result
322 << std::dec << ".";
[email protected]5b731f3e2013-03-15 07:28:22323 return false;
324 }
325
326 return true;
327}
328
[email protected]a4eca0a2013-06-20 22:15:05329void RdpSession::OnRdpConnected() {
[email protected]5b731f3e2013-03-15 07:28:22330 DCHECK(caller_task_runner()->BelongsToCurrentThread());
331
332 StopMonitoring();
[email protected]a4eca0a2013-06-20 22:15:05333 StartMonitoring(terminal_id_);
[email protected]5b731f3e2013-03-15 07:28:22334}
335
336void RdpSession::OnRdpClosed() {
337 DCHECK(caller_task_runner()->BelongsToCurrentThread());
338
[email protected]a4b39952013-06-21 03:57:08339 TerminateSession();
[email protected]5b731f3e2013-03-15 07:28:22340}
341
[email protected]6f526ce2013-03-18 04:38:56342void RdpSession::SetScreenResolution(const ScreenResolution& resolution) {
343 DCHECK(caller_task_runner()->BelongsToCurrentThread());
joedowb7a9ca32016-12-23 00:15:25344 DCHECK(!resolution.IsEmpty());
[email protected]6f526ce2013-03-18 04:38:56345
Joe Downing90e213f2023-02-13 19:13:01346 webrtc::DesktopSize bounded_size = GetBoundedRdpDesktopSize(
347 resolution.dimensions().width(), resolution.dimensions().height());
joedowb7a9ca32016-12-23 00:15:25348
Joe Downing90e213f2023-02-13 19:13:01349 rdp_desktop_session_->ChangeResolution(
350 bounded_size.width(), bounded_size.height(), resolution.dpi().x(),
351 resolution.dpi().y());
[email protected]6f526ce2013-03-18 04:38:56352}
353
[email protected]5b731f3e2013-03-15 07:28:22354void RdpSession::InjectSas() {
355 DCHECK(caller_task_runner()->BelongsToCurrentThread());
356
[email protected]97328ee2013-06-04 06:46:59357 rdp_desktop_session_->InjectSas();
[email protected]5b731f3e2013-03-15 07:28:22358}
359
joedow0bf730db2016-05-03 20:09:01360bool RdpSession::VerifyRdpSettings() {
361 // Verify RDP connections are enabled.
362 DWORD deny_ts_connections_flag = 0;
363 if (RetrieveDwordRegistryValue(kRdpSettingsKeyName,
364 kDenyTsConnectionsValueName,
365 &deny_ts_connections_flag) &&
366 deny_ts_connections_flag == kRdpConnectionsDisabled) {
367 LOG(ERROR) << "RDP Connections must be enabled.";
368 return false;
369 }
370
371 // Verify Network Level Authentication is disabled.
372 DWORD network_level_auth_flag = 0;
373 if (RetrieveDwordRegistryValue(kRdpTcpSettingsKeyName,
374 kNetworkLevelAuthValueName,
375 &network_level_auth_flag) &&
376 network_level_auth_flag == kNetworkLevelAuthEnabled) {
377 LOG(ERROR) << "Network Level Authentication for RDP must be disabled.";
378 return false;
379 }
380
381 // Verify Security Layer is not set to TLS. It can be either of the other two
382 // values, but forcing TLS will prevent us from establishing a connection.
383 DWORD security_layer_flag = 0;
384 if (RetrieveDwordRegistryValue(kRdpTcpSettingsKeyName,
385 kSecurityLayerValueName,
386 &security_layer_flag) &&
387 security_layer_flag == kSecurityLayerTlsRequired) {
388 LOG(ERROR) << "RDP SecurityLayer must not be set to TLS.";
389 return false;
390 }
391
392 return true;
393}
394
joedow69094d5f2016-05-03 20:00:02395bool RdpSession::RetrieveDwordRegistryValue(const wchar_t* key_name,
396 const wchar_t* value_name,
397 DWORD* value) {
398 DCHECK(key_name);
399 DCHECK(value_name);
400 DCHECK(value);
401
402 base::win::RegKey key(HKEY_LOCAL_MACHINE, key_name, KEY_READ);
403 if (!key.Valid()) {
404 LOG(WARNING) << "Failed to open key: " << key_name;
405 return false;
406 }
407
408 if (key.ReadValueDW(value_name, value) != ERROR_SUCCESS) {
409 LOG(WARNING) << "Failed to read registry value: " << value_name;
410 return false;
411 }
412
413 return true;
414}
415
[email protected]5b731f3e2013-03-15 07:28:22416RdpSession::EventHandler::EventHandler(
417 base::WeakPtr<RdpSession> desktop_session)
Joe Downingfd8a4222023-01-11 23:39:40418 : ref_count_(0), desktop_session_(desktop_session) {}
[email protected]5b731f3e2013-03-15 07:28:22419
420RdpSession::EventHandler::~EventHandler() {
421 DCHECK(thread_checker_.CalledOnValidThread());
422
Joe Downingfd8a4222023-01-11 23:39:40423 if (desktop_session_) {
[email protected]5b731f3e2013-03-15 07:28:22424 desktop_session_->OnRdpClosed();
Joe Downingfd8a4222023-01-11 23:39:40425 }
[email protected]5b731f3e2013-03-15 07:28:22426}
427
Nico Weber793099e2022-02-03 21:16:34428ULONG STDMETHODCALLTYPE RdpSession::EventHandler::AddRef() {
[email protected]5b731f3e2013-03-15 07:28:22429 DCHECK(thread_checker_.CalledOnValidThread());
430
431 return ++ref_count_;
432}
433
Nico Weber793099e2022-02-03 21:16:34434ULONG STDMETHODCALLTYPE RdpSession::EventHandler::Release() {
[email protected]5b731f3e2013-03-15 07:28:22435 DCHECK(thread_checker_.CalledOnValidThread());
436
437 if (--ref_count_ == 0) {
438 delete this;
439 return 0;
440 }
441
442 return ref_count_;
443}
444
Nico Weber793099e2022-02-03 21:16:34445STDMETHODIMP
Nico Weber829c6df2021-11-26 19:13:39446RdpSession::EventHandler::QueryInterface(REFIID riid, void** ppv) {
[email protected]5b731f3e2013-03-15 07:28:22447 DCHECK(thread_checker_.CalledOnValidThread());
448
Joe Downingfd8a4222023-01-11 23:39:40449 if (riid == IID_IUnknown || riid == IID_IRdpDesktopSessionEventHandler) {
[email protected]5b731f3e2013-03-15 07:28:22450 *ppv = static_cast<IRdpDesktopSessionEventHandler*>(this);
451 AddRef();
452 return S_OK;
453 }
454
sergeyuc5f104b2015-01-09 19:33:24455 *ppv = nullptr;
[email protected]5b731f3e2013-03-15 07:28:22456 return E_NOINTERFACE;
457}
458
Nico Weber793099e2022-02-03 21:16:34459STDMETHODIMP RdpSession::EventHandler::OnRdpConnected() {
[email protected]5b731f3e2013-03-15 07:28:22460 DCHECK(thread_checker_.CalledOnValidThread());
461
Joe Downingfd8a4222023-01-11 23:39:40462 if (desktop_session_) {
[email protected]a4eca0a2013-06-20 22:15:05463 desktop_session_->OnRdpConnected();
Joe Downingfd8a4222023-01-11 23:39:40464 }
[email protected]5b731f3e2013-03-15 07:28:22465
[email protected]5b731f3e2013-03-15 07:28:22466 return S_OK;
467}
468
Nico Weber793099e2022-02-03 21:16:34469STDMETHODIMP RdpSession::EventHandler::OnRdpClosed() {
[email protected]5b731f3e2013-03-15 07:28:22470 DCHECK(thread_checker_.CalledOnValidThread());
471
Joe Downingfd8a4222023-01-11 23:39:40472 if (!desktop_session_) {
[email protected]5b731f3e2013-03-15 07:28:22473 return S_OK;
Joe Downingfd8a4222023-01-11 23:39:40474 }
[email protected]5b731f3e2013-03-15 07:28:22475
476 base::WeakPtr<RdpSession> desktop_session = desktop_session_;
477 desktop_session_.reset();
478 desktop_session->OnRdpClosed();
479 return S_OK;
480}
481
David Bienvenubb3fd1a2023-01-10 16:42:17482} // namespace
[email protected]5b731f3e2013-03-15 07:28:22483
484// static
dcheng0765c492016-04-06 22:41:53485std::unique_ptr<DesktopSession> DesktopSessionWin::CreateForConsole(
[email protected]5b731f3e2013-03-15 07:28:22486 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
487 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
488 DaemonProcess* daemon_process,
489 int id,
[email protected]739e2802013-03-18 01:03:48490 const ScreenResolution& resolution) {
Jinho Bang138fde32018-01-18 23:13:42491 return std::make_unique<ConsoleSession>(caller_task_runner, io_task_runner,
ricea68860bd2016-08-22 02:48:56492 daemon_process, id,
493 HostService::GetInstance());
[email protected]5b731f3e2013-03-15 07:28:22494}
495
496// static
dcheng0765c492016-04-06 22:41:53497std::unique_ptr<DesktopSession> DesktopSessionWin::CreateForVirtualTerminal(
[email protected]5b731f3e2013-03-15 07:28:22498 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
499 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
500 DaemonProcess* daemon_process,
501 int id,
[email protected]739e2802013-03-18 01:03:48502 const ScreenResolution& resolution) {
dcheng0765c492016-04-06 22:41:53503 std::unique_ptr<RdpSession> session(
504 new RdpSession(caller_task_runner, io_task_runner, daemon_process, id,
505 HostService::GetInstance()));
Joe Downingfd8a4222023-01-11 23:39:40506 if (!session->Initialize(resolution)) {
sergeyuafce9782014-09-29 19:38:30507 return nullptr;
Joe Downingfd8a4222023-01-11 23:39:40508 }
[email protected]5b731f3e2013-03-15 07:28:22509
sergeyu1417e0132015-12-23 19:01:22510 return std::move(session);
[email protected]5b731f3e2013-03-15 07:28:22511}
512
513DesktopSessionWin::DesktopSessionWin(
514 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
515 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
516 DaemonProcess* daemon_process,
517 int id,
[email protected]3fd005e22013-02-28 20:11:29518 WtsTerminalMonitor* monitor)
[email protected]60ccc242012-10-17 21:06:24519 : DesktopSession(daemon_process, id),
[email protected]5b731f3e2013-03-15 07:28:22520 caller_task_runner_(caller_task_runner),
[email protected]60ccc242012-10-17 21:06:24521 io_task_runner_(io_task_runner),
[email protected]5b731f3e2013-03-15 07:28:22522 monitor_(monitor),
523 monitoring_notifications_(false) {
524 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]94618e72013-05-14 00:13:08525
526 ReportElapsedTime("created");
[email protected]60ccc242012-10-17 21:06:24527}
528
529DesktopSessionWin::~DesktopSessionWin() {
[email protected]5b731f3e2013-03-15 07:28:22530 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24531
[email protected]5b731f3e2013-03-15 07:28:22532 StopMonitoring();
533}
534
535void DesktopSessionWin::OnSessionAttachTimeout() {
536 DCHECK(caller_task_runner_->BelongsToCurrentThread());
537
538 LOG(ERROR) << "Session attach notification didn't arrived within "
539 << kSessionAttachTimeoutSeconds << " seconds.";
[email protected]a4b39952013-06-21 03:57:08540 TerminateSession();
[email protected]5b731f3e2013-03-15 07:28:22541}
542
[email protected]a4eca0a2013-06-20 22:15:05543void DesktopSessionWin::StartMonitoring(const std::string& terminal_id) {
[email protected]5b731f3e2013-03-15 07:28:22544 DCHECK(caller_task_runner_->BelongsToCurrentThread());
545 DCHECK(!monitoring_notifications_);
546 DCHECK(!session_attach_timer_.IsRunning());
547
[email protected]94618e72013-05-14 00:13:08548 ReportElapsedTime("started monitoring");
549
Peter Kastinge5a38ed2021-10-02 03:06:35550 session_attach_timer_.Start(FROM_HERE,
551 base::Seconds(kSessionAttachTimeoutSeconds), this,
552 &DesktopSessionWin::OnSessionAttachTimeout);
[email protected]5b731f3e2013-03-15 07:28:22553
554 monitoring_notifications_ = true;
[email protected]a4eca0a2013-06-20 22:15:05555 monitor_->AddWtsTerminalObserver(terminal_id, this);
[email protected]5b731f3e2013-03-15 07:28:22556}
557
558void DesktopSessionWin::StopMonitoring() {
559 DCHECK(caller_task_runner_->BelongsToCurrentThread());
560
561 if (monitoring_notifications_) {
[email protected]94618e72013-05-14 00:13:08562 ReportElapsedTime("stopped monitoring");
563
[email protected]5b731f3e2013-03-15 07:28:22564 monitoring_notifications_ = false;
565 monitor_->RemoveWtsTerminalObserver(this);
566 }
567
568 session_attach_timer_.Stop();
569 OnSessionDetached();
[email protected]60ccc242012-10-17 21:06:24570}
571
[email protected]a4b39952013-06-21 03:57:08572void DesktopSessionWin::TerminateSession() {
573 DCHECK(caller_task_runner_->BelongsToCurrentThread());
574
575 StopMonitoring();
576
577 // This call will delete |this| so it should be at the very end of the method.
578 daemon_process()->CloseDesktopSession(id());
579}
580
avic5960f32015-12-22 22:49:48581void DesktopSessionWin::OnChannelConnected(int32_t peer_pid) {
[email protected]5b731f3e2013-03-15 07:28:22582 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]12066cb2012-10-25 03:25:43583
[email protected]94618e72013-05-14 00:13:08584 ReportElapsedTime("channel connected");
585
[email protected]12066cb2012-10-25 03:25:43586 VLOG(1) << "IPC: daemon <- desktop (" << peer_pid << ")";
[email protected]60ccc242012-10-17 21:06:24587}
588
[email protected]a4b39952013-06-21 03:57:08589void DesktopSessionWin::OnPermanentError(int exit_code) {
[email protected]5b731f3e2013-03-15 07:28:22590 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24591
[email protected]a4b39952013-06-21 03:57:08592 TerminateSession();
[email protected]60ccc242012-10-17 21:06:24593}
594
zijiehedda3acb2017-06-29 23:19:16595void DesktopSessionWin::OnWorkerProcessStopped() {}
596
Joe Downingd4d6f342021-09-23 22:12:09597void DesktopSessionWin::OnAssociatedInterfaceRequest(
598 const std::string& interface_name,
599 mojo::ScopedInterfaceEndpointHandle handle) {
600 if (interface_name == mojom::DesktopSessionRequestHandler::Name_) {
601 if (desktop_session_request_handler_.is_bound()) {
602 LOG(ERROR) << "Receiver already bound for associated interface: "
603 << mojom::DesktopSessionRequestHandler::Name_;
604 CrashDesktopProcess(FROM_HERE);
605 }
606
607 mojo::PendingAssociatedReceiver<mojom::DesktopSessionRequestHandler>
608 pending_receiver(std::move(handle));
609 desktop_session_request_handler_.Bind(std::move(pending_receiver));
Joe Downing82480202021-11-02 22:41:12610
Joe Downingcae37b52021-11-09 18:54:42611 // Reset the receiver on disconnect so |desktop_session_request_handler_|
612 // can be re-bound if |launcher_| spawns a new desktop process.
613 desktop_session_request_handler_.reset_on_disconnect();
Joe Downingd4d6f342021-09-23 22:12:09614 } else {
615 LOG(ERROR) << "Unknown associated interface requested: " << interface_name
616 << ", crashing the desktop process";
617 CrashDesktopProcess(FROM_HERE);
618 }
619}
620
avic5960f32015-12-22 22:49:48621void DesktopSessionWin::OnSessionAttached(uint32_t session_id) {
[email protected]5b731f3e2013-03-15 07:28:22622 DCHECK(caller_task_runner_->BelongsToCurrentThread());
623 DCHECK(!launcher_);
624 DCHECK(monitoring_notifications_);
[email protected]60ccc242012-10-17 21:06:24625
[email protected]94618e72013-05-14 00:13:08626 ReportElapsedTime("attached");
627
David Bienvenubb3fd1a2023-01-10 16:42:17628 // Get the name of the executable to run. `kDesktopBinaryName` specifies
629 // uiAccess="true" in its manifest. Prefer kDesktopBinaryName but fall back
630 // to kHostBinaryName if there is a problem loading it.
[email protected]9410c0a2013-02-23 06:07:21631 base::FilePath desktop_binary;
David Bienvenubb3fd1a2023-01-10 16:42:17632 bool result = GetInstalledBinaryPath(kDesktopBinaryName, &desktop_binary);
633
Joe Downing9aa63b5e72021-08-24 21:19:25634 if (!result || !IsBinaryTrusted(desktop_binary)) {
[email protected]85c7fda22013-05-18 01:35:47635 result = GetInstalledBinaryPath(kHostBinaryName, &desktop_binary);
636 }
637
638 if (!result) {
[email protected]a4b39952013-06-21 03:57:08639 TerminateSession();
[email protected]9410c0a2013-02-23 06:07:21640 return;
[email protected]60ccc242012-10-17 21:06:24641 }
642
[email protected]5b731f3e2013-03-15 07:28:22643 session_attach_timer_.Stop();
644
dcheng0765c492016-04-06 22:41:53645 std::unique_ptr<base::CommandLine> target(
646 new base::CommandLine(desktop_binary));
[email protected]9410c0a2013-02-23 06:07:21647 target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeDesktop);
[email protected]5b731f3e2013-03-15 07:28:22648 // Copy the command line switches enabling verbose logging.
avi429bbdd2014-12-23 00:27:27649 target->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
Daniel Cheng9327fd312022-02-26 09:26:52650 kCopiedSwitchNames, std::size(kCopiedSwitchNames));
[email protected]9410c0a2013-02-23 06:07:21651
[email protected]5b731f3e2013-03-15 07:28:22652 // Create a delegate capable of launching a process in a different session.
David Bienvenubb3fd1a2023-01-10 16:42:17653 // Launch elevated to enable injection of Alt+Tab and Ctrl+Alt+Del.
dcheng0765c492016-04-06 22:41:53654 std::unique_ptr<WtsSessionProcessDelegate> delegate(
655 new WtsSessionProcessDelegate(
David Bienvenubb3fd1a2023-01-10 16:42:17656 io_task_runner_, std::move(target), /*launch_elevated=*/true,
joedowf84fffae2016-12-20 03:35:51657 base::WideToUTF8(kDaemonIpcSecurityDescriptor)));
[email protected]85c7fda22013-05-18 01:35:47658 if (!delegate->Initialize(session_id)) {
[email protected]a4b39952013-06-21 03:57:08659 TerminateSession();
[email protected]85c7fda22013-05-18 01:35:47660 return;
661 }
[email protected]60ccc242012-10-17 21:06:24662
663 // Create a launcher for the desktop process, using the per-session delegate.
Peter Boström560859d2021-05-01 01:31:25664 launcher_ =
665 std::make_unique<WorkerProcessLauncher>(std::move(delegate), this);
sammcf9cd299a2016-11-02 22:13:26666 session_id_ = session_id;
[email protected]60ccc242012-10-17 21:06:24667}
668
669void DesktopSessionWin::OnSessionDetached() {
[email protected]5b731f3e2013-03-15 07:28:22670 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]60ccc242012-10-17 21:06:24671
672 launcher_.reset();
Joe Downingd4d6f342021-09-23 22:12:09673 desktop_session_request_handler_.reset();
sammcf9cd299a2016-11-02 22:13:26674 session_id_ = UINT32_MAX;
[email protected]5b731f3e2013-03-15 07:28:22675
676 if (monitoring_notifications_) {
[email protected]94618e72013-05-14 00:13:08677 ReportElapsedTime("detached");
678
[email protected]5b731f3e2013-03-15 07:28:22679 session_attach_timer_.Start(
Peter Kastinge5a38ed2021-10-02 03:06:35680 FROM_HERE, base::Seconds(kSessionAttachTimeoutSeconds), this,
681 &DesktopSessionWin::OnSessionAttachTimeout);
[email protected]5b731f3e2013-03-15 07:28:22682 }
[email protected]60ccc242012-10-17 21:06:24683}
684
Joe Downingd4d6f342021-09-23 22:12:09685void DesktopSessionWin::ConnectDesktopChannel(
686 mojo::ScopedMessagePipeHandle desktop_pipe) {
687 DCHECK(caller_task_runner_->BelongsToCurrentThread());
688
689 if (!daemon_process()->OnDesktopSessionAgentAttached(
Joe Downing185945a2022-02-15 18:57:19690 id(), session_id_, std::move(desktop_pipe))) {
[email protected]e9057a6f2013-03-08 22:37:55691 CrashDesktopProcess(FROM_HERE);
[email protected]12066cb2012-10-25 03:25:43692 }
693}
694
Joe Downingd4d6f342021-09-23 22:12:09695void DesktopSessionWin::InjectSecureAttentionSequence() {
696 InjectSas();
697}
698
699void DesktopSessionWin::CrashNetworkProcess() {
700 daemon_process()->CrashNetworkProcess(FROM_HERE);
701}
702
Brett Wilson9c361992017-09-12 06:05:21703void DesktopSessionWin::CrashDesktopProcess(const base::Location& location) {
[email protected]5b731f3e2013-03-15 07:28:22704 DCHECK(caller_task_runner_->BelongsToCurrentThread());
[email protected]12066cb2012-10-25 03:25:43705
[email protected]e9057a6f2013-03-08 22:37:55706 launcher_->Crash(location);
[email protected]12066cb2012-10-25 03:25:43707}
708
[email protected]94618e72013-05-14 00:13:08709void DesktopSessionWin::ReportElapsedTime(const std::string& event) {
710 base::Time now = base::Time::Now();
711
712 std::string passed;
713 if (!last_timestamp_.is_null()) {
714 passed = base::StringPrintf(", %.2fs passed",
715 (now - last_timestamp_).InSecondsF());
716 }
717
718 base::Time::Exploded exploded;
719 now.LocalExplode(&exploded);
720 VLOG(1) << base::StringPrintf("session(%d): %s at %02d:%02d:%02d.%03d%s",
Joe Downingfd8a4222023-01-11 23:39:40721 id(), event.c_str(), exploded.hour,
722 exploded.minute, exploded.second,
723 exploded.millisecond, passed.c_str());
[email protected]94618e72013-05-14 00:13:08724
725 last_timestamp_ = now;
726}
727
[email protected]60ccc242012-10-17 21:06:24728} // namespace remoting