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