15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file implements the Windows service controlling Me2Me host processes
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// running within user sessions.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/win/wts_session_process_delegate.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/single_thread_task_runner.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/thread_task_runner_handle.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_channel.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_channel_proxy.h"
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ipc/ipc_listener.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_message.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/host_main.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/ipc_constants.h"
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "remoting/host/ipc_util.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/win/launch_process_with_token.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/win/worker_process_launcher.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/win/wts_terminal_monitor.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/worker_process_ipc_delegate.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::ScopedHandle;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Name of the default session desktop.
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kDefaultDesktopName[] = "winsta0\\default";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A private class actually implementing the functionality provided by
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |WtsSessionProcessDelegate|. This class is ref-counted and implements
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// asynchronous fire-and-forget shutdown.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WtsSessionProcessDelegate::Core
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : public base::RefCountedThreadSafe<Core>,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public base::MessagePumpForIO::IOHandler,
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      public IPC::Listener {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Core(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       scoped_ptr<CommandLine> target,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       bool launch_elevated,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       const std::string& channel_security);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initializes the object returning true on success.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Initialize(uint32 session_id);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stops the object asynchronously.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Stop();
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Mirrors WorkerProcessLauncher::Delegate.
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void LaunchProcess(WorkerProcessLauncher* event_handler);
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void Send(IPC::Message* message);
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void CloseChannel();
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void KillProcess();
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Core>;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~Core();
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // base::MessagePumpForIO::IOHandler implementation.
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void OnIOCompleted(base::MessagePumpForIO::IOContext* context,
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                             DWORD bytes_transferred,
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                             DWORD error) OVERRIDE;
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // IPC::Listener implementation.
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void OnChannelError() OVERRIDE;
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The actual implementation of LaunchProcess()
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void DoLaunchProcess();
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Drains the completion port queue to make sure that all job object
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notifications have been received.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DrainJobNotifications();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notified that the completion port queue has been drained.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DrainJobNotificationsCompleted();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates and initializes the job object that will sandbox the launched child
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // processes.
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void InitializeJob(scoped_ptr<base::win::ScopedHandle> job);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notified that the job object initialization is complete.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void InitializeJobCompleted(scoped_ptr<base::win::ScopedHandle> job);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Called when the number of processes running in the job reaches zero.
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void OnActiveProcessZero();
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void ReportFatalError();
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void ReportProcessLaunched(base::win::ScopedHandle worker_process);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The task runner all public methods of this class should be called on.
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The task runner serving job object notifications.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The server end of the IPC channel used to communicate to the worker
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // process.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<IPC::ChannelProxy> channel_;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Security descriptor (as SDDL) to be applied to |channel_|.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string channel_security_;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  WorkerProcessLauncher* event_handler_;
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pointer to GetNamedPipeClientProcessId() API if it is available.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef BOOL (WINAPI * GetNamedPipeClientProcessIdFn)(HANDLE, DWORD*);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetNamedPipeClientProcessIdFn get_named_pipe_client_pid_;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The job object used to control the lifetime of child processes.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle job_;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // True if the worker process should be launched elevated.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool launch_elevated_;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // True if a laucnh attemp is pending.
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool launch_pending_;
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The named pipe used as the transport by |channel_|.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle pipe_;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The token to be used to launch a process in a different session.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle session_token_;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Command line of the launched process.
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<CommandLine> target_command_;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The handle of the worker process, if launched.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle worker_process_;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Core);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WtsSessionProcessDelegate::Core::Core(
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<CommandLine> target_command,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool launch_elevated,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& channel_security)
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()),
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      io_task_runner_(io_task_runner),
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      channel_security_(channel_security),
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      event_handler_(NULL),
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get_named_pipe_client_pid_(NULL),
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      launch_elevated_(launch_elevated),
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      launch_pending_(false),
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      target_command_(target_command.Pass()) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool WtsSessionProcessDelegate::Core::Initialize(uint32 session_id) {
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Windows XP does not support elevation.
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (base::win::GetVersion() < base::win::VERSION_VISTA)
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    launch_elevated_ = false;
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (launch_elevated_) {
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // GetNamedPipeClientProcessId() is available starting from Vista.
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll");
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CHECK(kernel32 != NULL);
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    get_named_pipe_client_pid_ =
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        reinterpret_cast<GetNamedPipeClientProcessIdFn>(
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            GetProcAddress(kernel32, "GetNamedPipeClientProcessId"));
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CHECK(get_named_pipe_client_pid_ != NULL);
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ScopedHandle job;
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    job.Set(CreateJobObject(NULL, NULL));
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!job.IsValid()) {
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      PLOG(ERROR) << "Failed to create a job object";
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return false;
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Limit the number of active processes in the job to two (the helper
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // process performing elevation and the worker process itself) and make sure
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // that all processes will be killed once the job object is destroyed.
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    memset(&info, 0, sizeof(info));
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_ACTIVE_PROCESS |
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    info.BasicLimitInformation.ActiveProcessLimit = 2;
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!SetInformationJobObject(job.Get(),
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                 JobObjectExtendedLimitInformation,
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                 &info,
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                 sizeof(info))) {
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      PLOG(ERROR) << "Failed to set limits on the job object";
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return false;
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // ScopedHandle is not compatible with base::Passed, so we wrap it to
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // a scoped pointer.
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scoped_ptr<ScopedHandle> job_wrapper(new ScopedHandle());
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *job_wrapper = job.Pass();
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // To receive job object notifications the job object is registered with
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // the completion port represented by |io_task_runner|. The registration has
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // to be done on the I/O thread because
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // MessageLoopForIO::RegisterJobObject() can only be called via
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // MessageLoopForIO::current().
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    io_task_runner_->PostTask(
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        FROM_HERE,
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(&Core::InitializeJob, this, base::Passed(&job_wrapper)));
21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Create a session token for the launched process.
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return CreateSessionToken(session_id, &session_token_);
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::Stop() {
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  KillProcess();
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Drain the completion queue to make sure all job object notifications have
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // been received.
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DrainJobNotificationsCompleted();
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::LaunchProcess(
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WorkerProcessLauncher* event_handler) {
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!event_handler_);
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  event_handler_ = event_handler;
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DoLaunchProcess();
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::Send(IPC::Message* message) {
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (channel_) {
24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    channel_->Send(message);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete message;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WtsSessionProcessDelegate::Core::CloseChannel() {
24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  channel_.reset();
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pipe_.Close();
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::KillProcess() {
25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  channel_.reset();
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  event_handler_ = NULL;
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  launch_pending_ = false;
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pipe_.Close();
26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (launch_elevated_) {
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (job_.IsValid())
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      TerminateJobObject(job_.Get(), CONTROL_C_EXIT);
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (worker_process_.IsValid())
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      TerminateProcess(worker_process_.Get(), CONTROL_C_EXIT);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  worker_process_.Close();
27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)WtsSessionProcessDelegate::Core::~Core() {
27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!channel_);
27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!event_handler_);
27690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!pipe_.IsValid());
27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!worker_process_.IsValid());
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::OnIOCompleted(
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessagePumpForIO::IOContext* context,
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DWORD bytes_transferred,
28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DWORD error) {
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(io_task_runner_->BelongsToCurrentThread());
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // |bytes_transferred| is used in job object notifications to supply
28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // the message ID; |context| carries process ID.
28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (bytes_transferred == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) {
28990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    caller_task_runner_->PostTask(FROM_HERE,
29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  base::Bind(&Core::OnActiveProcessZero, this));
29190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool WtsSessionProcessDelegate::Core::OnMessageReceived(
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const IPC::Message& message) {
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return event_handler_->OnMessageReceived(message);
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::OnChannelConnected(int32 peer_pid) {
30290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Report the worker PID now if the worker process is launched indirectly.
30590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Note that in this case the pipe's security descriptor is the only
30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // protection against a malicious processed connecting to the pipe.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (launch_elevated_) {
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DWORD pid;
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!get_named_pipe_client_pid_(pipe_.Get(), &pid)) {
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      PLOG(ERROR) << "Failed to retrive PID of the client";
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ReportFatalError();
31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (pid != static_cast<DWORD>(peer_pid)) {
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      LOG(ERROR) << "The actual client PID " << pid
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 << " does not match the one reported by the client: "
31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 << peer_pid;
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ReportFatalError();
32090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DWORD desired_access =
32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION;
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ScopedHandle worker_process(OpenProcess(desired_access, false, pid));
32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!worker_process.IsValid()) {
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      PLOG(ERROR) << "Failed to open process " << pid;
32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ReportFatalError();
32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ReportProcessLaunched(worker_process.Pass());
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (event_handler_)
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    event_handler_->OnChannelConnected(peer_pid);
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::OnChannelError() {
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  event_handler_->OnChannelError();
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::DoLaunchProcess() {
34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!channel_);
34890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!pipe_.IsValid());
34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!worker_process_.IsValid());
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::CommandLine command_line(target_command_->argv());
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (launch_elevated_) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The job object is not ready. Retry starting the host process later.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!job_.IsValid()) {
35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      launch_pending_ = true;
35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Construct the helper binary name.
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath helper_binary;
36190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!GetInstalledBinaryPath(kHostBinaryName, &helper_binary)) {
36290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ReportFatalError();
36390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
36490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Create the command line passing the name of the IPC channel to use and
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // copying known switches from the caller's command line.
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    command_line.SetProgram(helper_binary);
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    command_line.AppendSwitchPath(kElevateSwitchName,
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  target_command_->GetProgram());
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the server end of the IPC channel.
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string channel_name = IPC::Channel::GenerateUniqueRandomChannelID();
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHandle pipe;
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!CreateIpcChannel(channel_name, channel_security_, &pipe)) {
37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ReportFatalError();
37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
37990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wrap the pipe into an IPC channel.
38246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<IPC::ChannelProxy> channel(
3831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      IPC::ChannelProxy::Create(IPC::ChannelHandle(pipe.Get()),
38446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                IPC::Channel::MODE_SERVER,
38546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                this,
38646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                io_task_runner_));
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Pass the name of the IPC channel to use.
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendSwitchNative(kDaemonPipeSwitchName,
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  base::UTF8ToWide(channel_name));
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to launch the process.
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHandle worker_process;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHandle worker_thread;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!LaunchProcessWithToken(command_line.GetProgram(),
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              command_line.GetCommandLineString(),
3971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              session_token_.Get(),
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              NULL,
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              NULL,
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              false,
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB,
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              base::UTF8ToUTF16(kDefaultDesktopName).c_str(),
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &worker_process,
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &worker_thread)) {
40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ReportFatalError();
40690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (launch_elevated_) {
4101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!AssignProcessToJobObject(job_.Get(), worker_process.Get())) {
411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      PLOG(ERROR) << "Failed to assign the worker to the job object";
41290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      ReportFatalError();
41390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!ResumeThread(worker_thread.Get())) {
418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "Failed to resume the worker thread";
41990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ReportFatalError();
42090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  channel_ = channel.Pass();
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pipe_ = pipe.Pass();
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Report success if the worker process is lauched directly. Otherwise, PID of
42790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // the client connected to the pipe will be used later. See
42890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // OnChannelConnected().
42990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!launch_elevated_)
43090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ReportProcessLaunched(worker_process.Pass());
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WtsSessionProcessDelegate::Core::DrainJobNotifications() {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->BelongsToCurrentThread());
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DrainJobNotifications() is posted after the job object is destroyed, so
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by this time all notifications from the job object have been processed
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // already. Let the main thread know that the queue has been drained.
43990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  caller_task_runner_->PostTask(FROM_HERE, base::Bind(
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &Core::DrainJobNotificationsCompleted, this));
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WtsSessionProcessDelegate::Core::DrainJobNotificationsCompleted() {
44490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (job_.IsValid()) {
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    job_.Close();
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Drain the completion queue to make sure all job object notification have
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // been received.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    io_task_runner_->PostTask(FROM_HERE, base::Bind(
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &Core::DrainJobNotifications, this));
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::InitializeJob(
45790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scoped_ptr<base::win::ScopedHandle> job) {
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(io_task_runner_->BelongsToCurrentThread());
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register to receive job notifications via the I/O thread's completion port.
46190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!base::MessageLoopForIO::current()->RegisterJobObject(job->Get(), this)) {
462cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "Failed to associate the job object with a completion port";
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let the main thread know that initialization is complete.
46790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  caller_task_runner_->PostTask(FROM_HERE, base::Bind(
46890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      &Core::InitializeJobCompleted, this, base::Passed(&job)));
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WtsSessionProcessDelegate::Core::InitializeJobCompleted(
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<ScopedHandle> job) {
47390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!job_.IsValid());
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  job_ = job->Pass();
47790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
47890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (launch_pending_)
47990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DoLaunchProcess();
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::OnActiveProcessZero() {
48390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
48490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
48590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (launch_pending_) {
48690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << "The worker process exited before connecting via IPC.";
48790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    launch_pending_ = false;
48890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ReportFatalError();
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::ReportFatalError() {
49390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
49490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
49590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  channel_.reset();
49690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pipe_.Close();
49790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
49890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  WorkerProcessLauncher* event_handler = event_handler_;
49990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  event_handler_ = NULL;
50090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  event_handler->OnFatalError();
50190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
50290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
50390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Core::ReportProcessLaunched(
50490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::win::ScopedHandle worker_process) {
50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(caller_task_runner_->BelongsToCurrentThread());
50690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!worker_process_.IsValid());
50790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
50890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  worker_process_ = worker_process.Pass();
50990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
51090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Report a handle that can be used to wait for the worker process completion,
51190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // query information about the process and duplicate handles.
51290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DWORD desired_access =
51390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION;
514f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  HANDLE temp_handle;
51590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!DuplicateHandle(GetCurrentProcess(),
5161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       worker_process_.Get(),
51790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       GetCurrentProcess(),
518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                       &temp_handle,
51990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       desired_access,
52090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       FALSE,
52190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       0)) {
522cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "Failed to duplicate a handle";
52390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ReportFatalError();
52490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
526f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ScopedHandle limited_handle(temp_handle);
52790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
52890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  event_handler_->OnProcessLaunched(limited_handle.Pass());
52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
53090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WtsSessionProcessDelegate::WtsSessionProcessDelegate(
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<CommandLine> target_command,
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool launch_elevated,
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& channel_security) {
53690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  core_ = new Core(io_task_runner,
53790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   target_command.Pass(),
53890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   launch_elevated,
53990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   channel_security);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WtsSessionProcessDelegate::~WtsSessionProcessDelegate() {
54390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  core_->Stop();
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool WtsSessionProcessDelegate::Initialize(uint32 session_id) {
54790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return core_->Initialize(session_id);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::LaunchProcess(
55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WorkerProcessLauncher* event_handler) {
55290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  core_->LaunchProcess(event_handler);
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
55590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::Send(IPC::Message* message) {
55690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  core_->Send(message);
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::CloseChannel() {
56090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  core_->CloseChannel();
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WtsSessionProcessDelegate::KillProcess() {
56490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  core_->KillProcess();
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
567cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace remoting
568