1 // 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
7 #include <objbase.h>
8 #include <sddl.h>
9 #include <wrl/client.h>
10
11 #include <limits>
12 #include <memory>
13 #include <utility>
14
15 #include "base/base_switches.h"
16 #include "base/command_line.h"
17 #include "base/files/file_path.h"
18 #include "base/guid.h"
19 #include "base/logging.h"
20 #include "base/memory/ref_counted.h"
21 #include "base/memory/weak_ptr.h"
22 #include "base/numerics/ranges.h"
23 #include "base/stl_util.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "base/threading/thread_checker.h"
27 #include "base/timer/timer.h"
28 #include "base/win/registry.h"
29 #include "base/win/scoped_bstr.h"
30 #include "base/win/scoped_handle.h"
31 #include "base/win/windows_version.h"
32 #include "ipc/ipc_message_macros.h"
33 #include "ipc/ipc_platform_file.h"
34 #include "remoting/base/auto_thread_task_runner.h"
35 #include "remoting/host/chromoting_messages.h"
36 #include "remoting/host/daemon_process.h"
37 #include "remoting/host/desktop_session.h"
38 #include "remoting/host/host_main.h"
39 #include "remoting/host/ipc_constants.h"
40 #include "remoting/host/sas_injector.h"
41 #include "remoting/host/screen_resolution.h"
42 #include "remoting/host/switches.h"
43 // MIDL-generated declarations and definitions.
44 #include "remoting/host/win/chromoting_lib.h"
45 #include "remoting/host/win/host_service.h"
46 #include "remoting/host/win/worker_process_launcher.h"
47 #include "remoting/host/win/wts_session_process_delegate.h"
48 #include "remoting/host/win/wts_terminal_monitor.h"
49 #include "remoting/host/win/wts_terminal_observer.h"
50 #include "remoting/host/worker_process_ipc_delegate.h"
51
52 using base::win::ScopedHandle;
53
54 namespace remoting {
55
56 namespace {
57
58 // The security descriptor of the daemon IPC endpoint. It gives full access
59 // to SYSTEM and denies access by anyone else.
60 const wchar_t kDaemonIpcSecurityDescriptor[] =
61 SDDL_OWNER L":" SDDL_LOCAL_SYSTEM
62 SDDL_GROUP L":" SDDL_LOCAL_SYSTEM
63 SDDL_DACL L":("
64 SDDL_ACCESS_ALLOWED L";;" SDDL_GENERIC_ALL L";;;" SDDL_LOCAL_SYSTEM
65 L")";
66
67 // The command line parameters that should be copied from the service's command
68 // line to the desktop process.
69 const char* kCopiedSwitchNames[] = { switches::kV, switches::kVModule };
70
71 // The default screen dimensions for an RDP session.
72 const int kDefaultRdpScreenWidth = 1280;
73 const int kDefaultRdpScreenHeight = 768;
74
75 // RDC 6.1 (W2K8) supports dimensions of up to 4096x2048.
76 const int kMaxRdpScreenWidth = 4096;
77 const int kMaxRdpScreenHeight = 2048;
78
79 // The minimum effective screen dimensions supported by Windows are 800x600.
80 const int kMinRdpScreenWidth = 800;
81 const int kMinRdpScreenHeight = 600;
82
83 // Default dots per inch used by RDP is 96 DPI.
84 const int kDefaultRdpDpi = 96;
85
86 // The session attach notification should arrive within 30 seconds.
87 const int kSessionAttachTimeoutSeconds = 30;
88
89 // The default port number used for establishing an RDP session.
90 const int kDefaultRdpPort = 3389;
91
92 // Used for validating the required RDP registry values.
93 const int kRdpConnectionsDisabled = 1;
94 const int kNetworkLevelAuthEnabled = 1;
95 const int kSecurityLayerTlsRequired = 2;
96
97 // The values used to establish RDP connections are stored in the registry.
98 const wchar_t kRdpSettingsKeyName[] =
99 L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server";
100 const wchar_t kRdpTcpSettingsKeyName[] = L"SYSTEM\\CurrentControlSet\\"
101 L"Control\\Terminal Server\\WinStations\\RDP-Tcp";
102 const wchar_t kRdpPortValueName[] = L"PortNumber";
103 const wchar_t kDenyTsConnectionsValueName[] = L"fDenyTSConnections";
104 const wchar_t kNetworkLevelAuthValueName[] = L"UserAuthentication";
105 const wchar_t kSecurityLayerValueName[] = L"SecurityLayer";
106
GetBoundedRdpDesktopSize(int width,int height)107 webrtc::DesktopSize GetBoundedRdpDesktopSize(int width, int height) {
108 return webrtc::DesktopSize(
109 base::ClampToRange(width, kMinRdpScreenWidth, kMaxRdpScreenWidth),
110 base::ClampToRange(height, kMinRdpScreenHeight, kMaxRdpScreenHeight));
111 }
112
113 // DesktopSession implementation which attaches to the host's physical console.
114 // Receives IPC messages from the desktop process, running in the console
115 // session, via |WorkerProcessIpcDelegate|, and monitors console session
116 // attach/detach events via |WtsConsoleObserver|.
117 class ConsoleSession : public DesktopSessionWin {
118 public:
119 // Same as DesktopSessionWin().
120 ConsoleSession(
121 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
122 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
123 DaemonProcess* daemon_process,
124 int id,
125 WtsTerminalMonitor* monitor);
126 ~ConsoleSession() override;
127
128 protected:
129 // DesktopSession overrides.
130 void SetScreenResolution(const ScreenResolution& resolution) override;
131
132 // DesktopSessionWin overrides.
133 void InjectSas() override;
134
135 private:
136 std::unique_ptr<SasInjector> sas_injector_;
137
138 DISALLOW_COPY_AND_ASSIGN(ConsoleSession);
139 };
140
141 // DesktopSession implementation which attaches to virtual RDP console.
142 // Receives IPC messages from the desktop process, running in the console
143 // session, via |WorkerProcessIpcDelegate|, and monitors console session
144 // attach/detach events via |WtsConsoleObserver|.
145 class RdpSession : public DesktopSessionWin {
146 public:
147 // Same as DesktopSessionWin().
148 RdpSession(
149 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
150 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
151 DaemonProcess* daemon_process,
152 int id,
153 WtsTerminalMonitor* monitor);
154 ~RdpSession() override;
155
156 // Performs the part of initialization that can fail.
157 bool Initialize(const ScreenResolution& resolution);
158
159 // Mirrors IRdpDesktopSessionEventHandler.
160 void OnRdpConnected();
161 void OnRdpClosed();
162
163 protected:
164 // DesktopSession overrides.
165 void SetScreenResolution(const ScreenResolution& resolution) override;
166
167 // DesktopSessionWin overrides.
168 void InjectSas() override;
169
170 private:
171 // An implementation of IRdpDesktopSessionEventHandler interface that forwards
172 // notifications to the owning desktop session.
173 class EventHandler : public IRdpDesktopSessionEventHandler {
174 public:
175 explicit EventHandler(base::WeakPtr<RdpSession> desktop_session);
176 virtual ~EventHandler();
177
178 // IUnknown interface.
179 STDMETHOD_(ULONG, AddRef)() override;
180 STDMETHOD_(ULONG, Release)() override;
181 STDMETHOD(QueryInterface)(REFIID riid, void** ppv) override;
182
183 // IRdpDesktopSessionEventHandler interface.
184 STDMETHOD(OnRdpConnected)() override;
185 STDMETHOD(OnRdpClosed)() override;
186
187 private:
188 ULONG ref_count_;
189
190 // Points to the desktop session object receiving OnRdpXxx() notifications.
191 base::WeakPtr<RdpSession> desktop_session_;
192
193 // This class must be used on a single thread.
194 base::ThreadChecker thread_checker_;
195
196 DISALLOW_COPY_AND_ASSIGN(EventHandler);
197 };
198
199 // Examines the system settings required to establish an RDP session.
200 // This method returns false if the values are retrieved and any of them would
201 // prevent us from creating an RDP connection.
202 bool VerifyRdpSettings();
203
204 // Retrieves a DWORD value from the registry. Returns true on success.
205 bool RetrieveDwordRegistryValue(const wchar_t* key_name,
206 const wchar_t* value_name,
207 DWORD* value);
208
209 // Used to create an RDP desktop session.
210 Microsoft::WRL::ComPtr<IRdpDesktopSession> rdp_desktop_session_;
211
212 // Used to match |rdp_desktop_session_| with the session it is attached to.
213 std::string terminal_id_;
214
215 base::WeakPtrFactory<RdpSession> weak_factory_{this};
216
217 DISALLOW_COPY_AND_ASSIGN(RdpSession);
218 };
219
ConsoleSession(scoped_refptr<AutoThreadTaskRunner> caller_task_runner,scoped_refptr<AutoThreadTaskRunner> io_task_runner,DaemonProcess * daemon_process,int id,WtsTerminalMonitor * monitor)220 ConsoleSession::ConsoleSession(
221 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
222 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
223 DaemonProcess* daemon_process,
224 int id,
225 WtsTerminalMonitor* monitor)
226 : DesktopSessionWin(caller_task_runner, io_task_runner, daemon_process, id,
227 monitor) {
228 StartMonitoring(WtsTerminalMonitor::kConsole);
229 }
230
~ConsoleSession()231 ConsoleSession::~ConsoleSession() {
232 }
233
SetScreenResolution(const ScreenResolution & resolution)234 void ConsoleSession::SetScreenResolution(const ScreenResolution& resolution) {
235 // Do nothing. The screen resolution of the console session is controlled by
236 // the DesktopSessionAgent instance running in that session.
237 DCHECK(caller_task_runner()->BelongsToCurrentThread());
238 }
239
InjectSas()240 void ConsoleSession::InjectSas() {
241 DCHECK(caller_task_runner()->BelongsToCurrentThread());
242
243 if (!sas_injector_)
244 sas_injector_ = SasInjector::Create();
245 if (!sas_injector_->InjectSas())
246 LOG(ERROR) << "Failed to inject Secure Attention Sequence.";
247 }
248
RdpSession(scoped_refptr<AutoThreadTaskRunner> caller_task_runner,scoped_refptr<AutoThreadTaskRunner> io_task_runner,DaemonProcess * daemon_process,int id,WtsTerminalMonitor * monitor)249 RdpSession::RdpSession(scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
250 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
251 DaemonProcess* daemon_process,
252 int id,
253 WtsTerminalMonitor* monitor)
254 : DesktopSessionWin(caller_task_runner,
255 io_task_runner,
256 daemon_process,
257 id,
258 monitor) {}
259
~RdpSession()260 RdpSession::~RdpSession() {
261 }
262
Initialize(const ScreenResolution & resolution)263 bool RdpSession::Initialize(const ScreenResolution& resolution) {
264 DCHECK(caller_task_runner()->BelongsToCurrentThread());
265
266 if (!VerifyRdpSettings()) {
267 LOG(ERROR) << "Could not create an RDP session due to invalid settings.";
268 return false;
269 }
270
271 // Create the RDP wrapper object.
272 HRESULT result =
273 ::CoCreateInstance(__uuidof(RdpDesktopSession), nullptr, CLSCTX_ALL,
274 IID_PPV_ARGS(&rdp_desktop_session_));
275 if (FAILED(result)) {
276 LOG(ERROR) << "Failed to create RdpSession object, 0x"
277 << std::hex << result << std::dec << ".";
278 return false;
279 }
280
281 ScreenResolution local_resolution = resolution;
282
283 // If the screen resolution is not specified, use the default screen
284 // resolution.
285 if (local_resolution.IsEmpty()) {
286 local_resolution = ScreenResolution(
287 webrtc::DesktopSize(kDefaultRdpScreenWidth, kDefaultRdpScreenHeight),
288 webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
289 }
290
291 // Get the screen dimensions assuming the default DPI.
292 webrtc::DesktopSize host_size = local_resolution.ScaleDimensionsToDpi(
293 webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
294
295 // Make sure that the host resolution is within the limits supported by RDP.
296 host_size = GetBoundedRdpDesktopSize(host_size.width(), host_size.height());
297
298 // Read the port number used by RDP.
299 DWORD server_port = kDefaultRdpPort;
300 if (RetrieveDwordRegistryValue(kRdpTcpSettingsKeyName, kRdpPortValueName,
301 &server_port) &&
302 server_port > 65535) {
303 LOG(ERROR) << "Invalid RDP port specified: " << server_port;
304 return false;
305 }
306
307 // Create an RDP session.
308 Microsoft::WRL::ComPtr<IRdpDesktopSessionEventHandler> event_handler(
309 new EventHandler(weak_factory_.GetWeakPtr()));
310 terminal_id_ = base::GenerateGUID();
311 base::win::ScopedBstr terminal_id(base::UTF8ToUTF16(terminal_id_));
312 result = rdp_desktop_session_->Connect(
313 host_size.width(), host_size.height(), kDefaultRdpDpi, kDefaultRdpDpi,
314 terminal_id.Get(), server_port, event_handler.Get());
315 if (FAILED(result)) {
316 LOG(ERROR) << "RdpSession::Create() failed, 0x"
317 << std::hex << result << std::dec << ".";
318 return false;
319 }
320
321 return true;
322 }
323
OnRdpConnected()324 void RdpSession::OnRdpConnected() {
325 DCHECK(caller_task_runner()->BelongsToCurrentThread());
326
327 StopMonitoring();
328 StartMonitoring(terminal_id_);
329 }
330
OnRdpClosed()331 void RdpSession::OnRdpClosed() {
332 DCHECK(caller_task_runner()->BelongsToCurrentThread());
333
334 TerminateSession();
335 }
336
SetScreenResolution(const ScreenResolution & resolution)337 void RdpSession::SetScreenResolution(const ScreenResolution& resolution) {
338 DCHECK(caller_task_runner()->BelongsToCurrentThread());
339 DCHECK(!resolution.IsEmpty());
340
341 webrtc::DesktopSize new_size = resolution.ScaleDimensionsToDpi(
342 webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
343 new_size = GetBoundedRdpDesktopSize(new_size.width(), new_size.height());
344
345 rdp_desktop_session_->ChangeResolution(new_size.width(), new_size.height(),
346 kDefaultRdpDpi, kDefaultRdpDpi);
347 }
348
InjectSas()349 void RdpSession::InjectSas() {
350 DCHECK(caller_task_runner()->BelongsToCurrentThread());
351
352 rdp_desktop_session_->InjectSas();
353 }
354
VerifyRdpSettings()355 bool RdpSession::VerifyRdpSettings() {
356 // Verify RDP connections are enabled.
357 DWORD deny_ts_connections_flag = 0;
358 if (RetrieveDwordRegistryValue(kRdpSettingsKeyName,
359 kDenyTsConnectionsValueName,
360 &deny_ts_connections_flag) &&
361 deny_ts_connections_flag == kRdpConnectionsDisabled) {
362 LOG(ERROR) << "RDP Connections must be enabled.";
363 return false;
364 }
365
366 // Verify Network Level Authentication is disabled.
367 DWORD network_level_auth_flag = 0;
368 if (RetrieveDwordRegistryValue(kRdpTcpSettingsKeyName,
369 kNetworkLevelAuthValueName,
370 &network_level_auth_flag) &&
371 network_level_auth_flag == kNetworkLevelAuthEnabled) {
372 LOG(ERROR) << "Network Level Authentication for RDP must be disabled.";
373 return false;
374 }
375
376 // Verify Security Layer is not set to TLS. It can be either of the other two
377 // values, but forcing TLS will prevent us from establishing a connection.
378 DWORD security_layer_flag = 0;
379 if (RetrieveDwordRegistryValue(kRdpTcpSettingsKeyName,
380 kSecurityLayerValueName,
381 &security_layer_flag) &&
382 security_layer_flag == kSecurityLayerTlsRequired) {
383 LOG(ERROR) << "RDP SecurityLayer must not be set to TLS.";
384 return false;
385 }
386
387 return true;
388 }
389
RetrieveDwordRegistryValue(const wchar_t * key_name,const wchar_t * value_name,DWORD * value)390 bool RdpSession::RetrieveDwordRegistryValue(const wchar_t* key_name,
391 const wchar_t* value_name,
392 DWORD* value) {
393 DCHECK(key_name);
394 DCHECK(value_name);
395 DCHECK(value);
396
397 base::win::RegKey key(HKEY_LOCAL_MACHINE, key_name, KEY_READ);
398 if (!key.Valid()) {
399 LOG(WARNING) << "Failed to open key: " << key_name;
400 return false;
401 }
402
403 if (key.ReadValueDW(value_name, value) != ERROR_SUCCESS) {
404 LOG(WARNING) << "Failed to read registry value: " << value_name;
405 return false;
406 }
407
408 return true;
409 }
410
EventHandler(base::WeakPtr<RdpSession> desktop_session)411 RdpSession::EventHandler::EventHandler(
412 base::WeakPtr<RdpSession> desktop_session)
413 : ref_count_(0),
414 desktop_session_(desktop_session) {
415 }
416
~EventHandler()417 RdpSession::EventHandler::~EventHandler() {
418 DCHECK(thread_checker_.CalledOnValidThread());
419
420 if (desktop_session_)
421 desktop_session_->OnRdpClosed();
422 }
423
AddRef()424 ULONG STDMETHODCALLTYPE RdpSession::EventHandler::AddRef() {
425 DCHECK(thread_checker_.CalledOnValidThread());
426
427 return ++ref_count_;
428 }
429
Release()430 ULONG STDMETHODCALLTYPE RdpSession::EventHandler::Release() {
431 DCHECK(thread_checker_.CalledOnValidThread());
432
433 if (--ref_count_ == 0) {
434 delete this;
435 return 0;
436 }
437
438 return ref_count_;
439 }
440
QueryInterface(REFIID riid,void ** ppv)441 STDMETHODIMP RdpSession::EventHandler::QueryInterface(REFIID riid, void** ppv) {
442 DCHECK(thread_checker_.CalledOnValidThread());
443
444 if (riid == IID_IUnknown ||
445 riid == IID_IRdpDesktopSessionEventHandler) {
446 *ppv = static_cast<IRdpDesktopSessionEventHandler*>(this);
447 AddRef();
448 return S_OK;
449 }
450
451 *ppv = nullptr;
452 return E_NOINTERFACE;
453 }
454
OnRdpConnected()455 STDMETHODIMP RdpSession::EventHandler::OnRdpConnected() {
456 DCHECK(thread_checker_.CalledOnValidThread());
457
458 if (desktop_session_)
459 desktop_session_->OnRdpConnected();
460
461 return S_OK;
462 }
463
OnRdpClosed()464 STDMETHODIMP RdpSession::EventHandler::OnRdpClosed() {
465 DCHECK(thread_checker_.CalledOnValidThread());
466
467 if (!desktop_session_)
468 return S_OK;
469
470 base::WeakPtr<RdpSession> desktop_session = desktop_session_;
471 desktop_session_.reset();
472 desktop_session->OnRdpClosed();
473 return S_OK;
474 }
475
476 } // namespace
477
478 // static
CreateForConsole(scoped_refptr<AutoThreadTaskRunner> caller_task_runner,scoped_refptr<AutoThreadTaskRunner> io_task_runner,DaemonProcess * daemon_process,int id,const ScreenResolution & resolution)479 std::unique_ptr<DesktopSession> DesktopSessionWin::CreateForConsole(
480 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
481 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
482 DaemonProcess* daemon_process,
483 int id,
484 const ScreenResolution& resolution) {
485 return std::make_unique<ConsoleSession>(caller_task_runner, io_task_runner,
486 daemon_process, id,
487 HostService::GetInstance());
488 }
489
490 // static
CreateForVirtualTerminal(scoped_refptr<AutoThreadTaskRunner> caller_task_runner,scoped_refptr<AutoThreadTaskRunner> io_task_runner,DaemonProcess * daemon_process,int id,const ScreenResolution & resolution)491 std::unique_ptr<DesktopSession> DesktopSessionWin::CreateForVirtualTerminal(
492 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
493 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
494 DaemonProcess* daemon_process,
495 int id,
496 const ScreenResolution& resolution) {
497 std::unique_ptr<RdpSession> session(
498 new RdpSession(caller_task_runner, io_task_runner, daemon_process, id,
499 HostService::GetInstance()));
500 if (!session->Initialize(resolution))
501 return nullptr;
502
503 return std::move(session);
504 }
505
DesktopSessionWin(scoped_refptr<AutoThreadTaskRunner> caller_task_runner,scoped_refptr<AutoThreadTaskRunner> io_task_runner,DaemonProcess * daemon_process,int id,WtsTerminalMonitor * monitor)506 DesktopSessionWin::DesktopSessionWin(
507 scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
508 scoped_refptr<AutoThreadTaskRunner> io_task_runner,
509 DaemonProcess* daemon_process,
510 int id,
511 WtsTerminalMonitor* monitor)
512 : DesktopSession(daemon_process, id),
513 caller_task_runner_(caller_task_runner),
514 io_task_runner_(io_task_runner),
515 monitor_(monitor),
516 monitoring_notifications_(false) {
517 DCHECK(caller_task_runner_->BelongsToCurrentThread());
518
519 ReportElapsedTime("created");
520 }
521
~DesktopSessionWin()522 DesktopSessionWin::~DesktopSessionWin() {
523 DCHECK(caller_task_runner_->BelongsToCurrentThread());
524
525 StopMonitoring();
526 }
527
OnSessionAttachTimeout()528 void DesktopSessionWin::OnSessionAttachTimeout() {
529 DCHECK(caller_task_runner_->BelongsToCurrentThread());
530
531 LOG(ERROR) << "Session attach notification didn't arrived within "
532 << kSessionAttachTimeoutSeconds << " seconds.";
533 TerminateSession();
534 }
535
StartMonitoring(const std::string & terminal_id)536 void DesktopSessionWin::StartMonitoring(const std::string& terminal_id) {
537 DCHECK(caller_task_runner_->BelongsToCurrentThread());
538 DCHECK(!monitoring_notifications_);
539 DCHECK(!session_attach_timer_.IsRunning());
540
541 ReportElapsedTime("started monitoring");
542
543 session_attach_timer_.Start(
544 FROM_HERE, base::TimeDelta::FromSeconds(kSessionAttachTimeoutSeconds),
545 this, &DesktopSessionWin::OnSessionAttachTimeout);
546
547 monitoring_notifications_ = true;
548 monitor_->AddWtsTerminalObserver(terminal_id, this);
549 }
550
StopMonitoring()551 void DesktopSessionWin::StopMonitoring() {
552 DCHECK(caller_task_runner_->BelongsToCurrentThread());
553
554 if (monitoring_notifications_) {
555 ReportElapsedTime("stopped monitoring");
556
557 monitoring_notifications_ = false;
558 monitor_->RemoveWtsTerminalObserver(this);
559 }
560
561 session_attach_timer_.Stop();
562 OnSessionDetached();
563 }
564
TerminateSession()565 void DesktopSessionWin::TerminateSession() {
566 DCHECK(caller_task_runner_->BelongsToCurrentThread());
567
568 StopMonitoring();
569
570 // This call will delete |this| so it should be at the very end of the method.
571 daemon_process()->CloseDesktopSession(id());
572 }
573
OnChannelConnected(int32_t peer_pid)574 void DesktopSessionWin::OnChannelConnected(int32_t peer_pid) {
575 DCHECK(caller_task_runner_->BelongsToCurrentThread());
576
577 ReportElapsedTime("channel connected");
578
579 VLOG(1) << "IPC: daemon <- desktop (" << peer_pid << ")";
580 }
581
OnMessageReceived(const IPC::Message & message)582 bool DesktopSessionWin::OnMessageReceived(const IPC::Message& message) {
583 DCHECK(caller_task_runner_->BelongsToCurrentThread());
584
585 bool handled = true;
586 IPC_BEGIN_MESSAGE_MAP(DesktopSessionWin, message)
587 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached,
588 OnDesktopSessionAgentAttached)
589 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_InjectSas,
590 InjectSas)
591 IPC_MESSAGE_UNHANDLED(handled = false)
592 IPC_END_MESSAGE_MAP()
593
594 if (!handled) {
595 LOG(ERROR) << "Received unexpected IPC type: " << message.type();
596 CrashDesktopProcess(FROM_HERE);
597 }
598
599 return handled;
600 }
601
OnPermanentError(int exit_code)602 void DesktopSessionWin::OnPermanentError(int exit_code) {
603 DCHECK(caller_task_runner_->BelongsToCurrentThread());
604
605 TerminateSession();
606 }
607
OnWorkerProcessStopped()608 void DesktopSessionWin::OnWorkerProcessStopped() {}
609
OnSessionAttached(uint32_t session_id)610 void DesktopSessionWin::OnSessionAttached(uint32_t session_id) {
611 DCHECK(caller_task_runner_->BelongsToCurrentThread());
612 DCHECK(!launcher_);
613 DCHECK(monitoring_notifications_);
614
615 ReportElapsedTime("attached");
616
617 // Launch elevated on Win8+ to enable injection of Alt+Tab and Ctrl+Alt+Del.
618 bool launch_elevated = base::win::GetVersion() >= base::win::Version::WIN8;
619
620 // Get the name of the executable to run. |kDesktopBinaryName| specifies
621 // uiAccess="true" in its manifest.
622 base::FilePath desktop_binary;
623 bool result;
624 if (launch_elevated) {
625 result = GetInstalledBinaryPath(kDesktopBinaryName, &desktop_binary);
626 } else {
627 result = GetInstalledBinaryPath(kHostBinaryName, &desktop_binary);
628 }
629
630 if (!result) {
631 TerminateSession();
632 return;
633 }
634
635 session_attach_timer_.Stop();
636
637 std::unique_ptr<base::CommandLine> target(
638 new base::CommandLine(desktop_binary));
639 target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeDesktop);
640 // Copy the command line switches enabling verbose logging.
641 target->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
642 kCopiedSwitchNames, base::size(kCopiedSwitchNames));
643
644 // Create a delegate capable of launching a process in a different session.
645 std::unique_ptr<WtsSessionProcessDelegate> delegate(
646 new WtsSessionProcessDelegate(
647 io_task_runner_, std::move(target), launch_elevated,
648 base::WideToUTF8(kDaemonIpcSecurityDescriptor)));
649 if (!delegate->Initialize(session_id)) {
650 TerminateSession();
651 return;
652 }
653
654 // Create a launcher for the desktop process, using the per-session delegate.
655 launcher_.reset(new WorkerProcessLauncher(std::move(delegate), this));
656 session_id_ = session_id;
657 }
658
OnSessionDetached()659 void DesktopSessionWin::OnSessionDetached() {
660 DCHECK(caller_task_runner_->BelongsToCurrentThread());
661
662 launcher_.reset();
663 session_id_ = UINT32_MAX;
664
665 if (monitoring_notifications_) {
666 ReportElapsedTime("detached");
667
668 session_attach_timer_.Start(
669 FROM_HERE, base::TimeDelta::FromSeconds(kSessionAttachTimeoutSeconds),
670 this, &DesktopSessionWin::OnSessionAttachTimeout);
671 }
672 }
673
OnDesktopSessionAgentAttached(const IPC::ChannelHandle & desktop_pipe)674 void DesktopSessionWin::OnDesktopSessionAgentAttached(
675 const IPC::ChannelHandle& desktop_pipe) {
676 if (!daemon_process()->OnDesktopSessionAgentAttached(id(), session_id_,
677 desktop_pipe)) {
678 CrashDesktopProcess(FROM_HERE);
679 }
680 }
681
CrashDesktopProcess(const base::Location & location)682 void DesktopSessionWin::CrashDesktopProcess(const base::Location& location) {
683 DCHECK(caller_task_runner_->BelongsToCurrentThread());
684
685 launcher_->Crash(location);
686 }
687
ReportElapsedTime(const std::string & event)688 void DesktopSessionWin::ReportElapsedTime(const std::string& event) {
689 base::Time now = base::Time::Now();
690
691 std::string passed;
692 if (!last_timestamp_.is_null()) {
693 passed = base::StringPrintf(", %.2fs passed",
694 (now - last_timestamp_).InSecondsF());
695 }
696
697 base::Time::Exploded exploded;
698 now.LocalExplode(&exploded);
699 VLOG(1) << base::StringPrintf("session(%d): %s at %02d:%02d:%02d.%03d%s",
700 id(),
701 event.c_str(),
702 exploded.hour,
703 exploded.minute,
704 exploded.second,
705 exploded.millisecond,
706 passed.c_str());
707
708 last_timestamp_ = now;
709 }
710
711 } // namespace remoting
712