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