Home | History | Annotate | Download | only in win
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 // This file implements the Windows service controlling Me2Me host processes
      6 // running within user sessions.
      7 
      8 #include "remoting/host/win/wts_session_process_delegate.h"
      9 
     10 #include "base/bind.h"
     11 #include "base/command_line.h"
     12 #include "base/files/file_path.h"
     13 #include "base/logging.h"
     14 #include "base/message_loop/message_loop.h"
     15 #include "base/single_thread_task_runner.h"
     16 #include "base/strings/utf_string_conversions.h"
     17 #include "base/thread_task_runner_handle.h"
     18 #include "base/win/scoped_handle.h"
     19 #include "base/win/windows_version.h"
     20 #include "ipc/ipc_channel.h"
     21 #include "ipc/ipc_channel_proxy.h"
     22 #include "ipc/ipc_listener.h"
     23 #include "ipc/ipc_message.h"
     24 #include "remoting/host/host_main.h"
     25 #include "remoting/host/ipc_constants.h"
     26 #include "remoting/host/ipc_util.h"
     27 #include "remoting/host/win/launch_process_with_token.h"
     28 #include "remoting/host/win/worker_process_launcher.h"
     29 #include "remoting/host/win/wts_terminal_monitor.h"
     30 #include "remoting/host/worker_process_ipc_delegate.h"
     31 
     32 using base::win::ScopedHandle;
     33 
     34 // Name of the default session desktop.
     35 const char kDefaultDesktopName[] = "winsta0\\default";
     36 
     37 namespace remoting {
     38 
     39 // A private class actually implementing the functionality provided by
     40 // |WtsSessionProcessDelegate|. This class is ref-counted and implements
     41 // asynchronous fire-and-forget shutdown.
     42 class WtsSessionProcessDelegate::Core
     43     : public base::RefCountedThreadSafe<Core>,
     44       public base::MessagePumpForIO::IOHandler,
     45       public IPC::Listener {
     46  public:
     47   Core(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
     48        scoped_ptr<CommandLine> target,
     49        bool launch_elevated,
     50        const std::string& channel_security);
     51 
     52   // Initializes the object returning true on success.
     53   bool Initialize(uint32 session_id);
     54 
     55   // Stops the object asynchronously.
     56   void Stop();
     57 
     58   // Mirrors WorkerProcessLauncher::Delegate.
     59   void LaunchProcess(WorkerProcessLauncher* event_handler);
     60   void Send(IPC::Message* message);
     61   void CloseChannel();
     62   void KillProcess();
     63 
     64  private:
     65   friend class base::RefCountedThreadSafe<Core>;
     66   virtual ~Core();
     67 
     68   // base::MessagePumpForIO::IOHandler implementation.
     69   virtual void OnIOCompleted(base::MessagePumpForIO::IOContext* context,
     70                              DWORD bytes_transferred,
     71                              DWORD error) OVERRIDE;
     72 
     73   // IPC::Listener implementation.
     74   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
     75   virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
     76   virtual void OnChannelError() OVERRIDE;
     77 
     78   // The actual implementation of LaunchProcess()
     79   void DoLaunchProcess();
     80 
     81   // Drains the completion port queue to make sure that all job object
     82   // notifications have been received.
     83   void DrainJobNotifications();
     84 
     85   // Notified that the completion port queue has been drained.
     86   void DrainJobNotificationsCompleted();
     87 
     88   // Creates and initializes the job object that will sandbox the launched child
     89   // processes.
     90   void InitializeJob(scoped_ptr<base::win::ScopedHandle> job);
     91 
     92   // Notified that the job object initialization is complete.
     93   void InitializeJobCompleted(scoped_ptr<base::win::ScopedHandle> job);
     94 
     95   // Called when the number of processes running in the job reaches zero.
     96   void OnActiveProcessZero();
     97 
     98   void ReportFatalError();
     99   void ReportProcessLaunched(base::win::ScopedHandle worker_process);
    100 
    101   // The task runner all public methods of this class should be called on.
    102   scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
    103 
    104   // The task runner serving job object notifications.
    105   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
    106 
    107   // The server end of the IPC channel used to communicate to the worker
    108   // process.
    109   scoped_ptr<IPC::ChannelProxy> channel_;
    110 
    111   // Security descriptor (as SDDL) to be applied to |channel_|.
    112   std::string channel_security_;
    113 
    114   WorkerProcessLauncher* event_handler_;
    115 
    116   // Pointer to GetNamedPipeClientProcessId() API if it is available.
    117   typedef BOOL (WINAPI * GetNamedPipeClientProcessIdFn)(HANDLE, DWORD*);
    118   GetNamedPipeClientProcessIdFn get_named_pipe_client_pid_;
    119 
    120   // The job object used to control the lifetime of child processes.
    121   base::win::ScopedHandle job_;
    122 
    123   // True if the worker process should be launched elevated.
    124   bool launch_elevated_;
    125 
    126   // True if a laucnh attemp is pending.
    127   bool launch_pending_;
    128 
    129   // The named pipe used as the transport by |channel_|.
    130   base::win::ScopedHandle pipe_;
    131 
    132   // The token to be used to launch a process in a different session.
    133   base::win::ScopedHandle session_token_;
    134 
    135   // Command line of the launched process.
    136   scoped_ptr<CommandLine> target_command_;
    137 
    138   // The handle of the worker process, if launched.
    139   base::win::ScopedHandle worker_process_;
    140 
    141   DISALLOW_COPY_AND_ASSIGN(Core);
    142 };
    143 
    144 WtsSessionProcessDelegate::Core::Core(
    145     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
    146     scoped_ptr<CommandLine> target_command,
    147     bool launch_elevated,
    148     const std::string& channel_security)
    149     : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()),
    150       io_task_runner_(io_task_runner),
    151       channel_security_(channel_security),
    152       event_handler_(NULL),
    153       get_named_pipe_client_pid_(NULL),
    154       launch_elevated_(launch_elevated),
    155       launch_pending_(false),
    156       target_command_(target_command.Pass()) {
    157 }
    158 
    159 bool WtsSessionProcessDelegate::Core::Initialize(uint32 session_id) {
    160   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    161 
    162   // Windows XP does not support elevation.
    163   if (base::win::GetVersion() < base::win::VERSION_VISTA)
    164     launch_elevated_ = false;
    165 
    166   if (launch_elevated_) {
    167     // GetNamedPipeClientProcessId() is available starting from Vista.
    168     HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll");
    169     CHECK(kernel32 != NULL);
    170 
    171     get_named_pipe_client_pid_ =
    172         reinterpret_cast<GetNamedPipeClientProcessIdFn>(
    173             GetProcAddress(kernel32, "GetNamedPipeClientProcessId"));
    174     CHECK(get_named_pipe_client_pid_ != NULL);
    175 
    176     ScopedHandle job;
    177     job.Set(CreateJobObject(NULL, NULL));
    178     if (!job.IsValid()) {
    179       LOG_GETLASTERROR(ERROR) << "Failed to create a job object";
    180       return false;
    181     }
    182 
    183     // Limit the number of active processes in the job to two (the helper
    184     // process performing elevation and the worker process itself) and make sure
    185     // that all processes will be killed once the job object is destroyed.
    186     JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
    187     memset(&info, 0, sizeof(info));
    188     info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_ACTIVE_PROCESS |
    189         JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
    190     info.BasicLimitInformation.ActiveProcessLimit = 2;
    191     if (!SetInformationJobObject(job,
    192                                  JobObjectExtendedLimitInformation,
    193                                  &info,
    194                                  sizeof(info))) {
    195       LOG_GETLASTERROR(ERROR) << "Failed to set limits on the job object";
    196       return false;
    197     }
    198 
    199     // ScopedHandle is not compatible with base::Passed, so we wrap it to
    200     // a scoped pointer.
    201     scoped_ptr<ScopedHandle> job_wrapper(new ScopedHandle());
    202     *job_wrapper = job.Pass();
    203 
    204     // To receive job object notifications the job object is registered with
    205     // the completion port represented by |io_task_runner|. The registration has
    206     // to be done on the I/O thread because
    207     // MessageLoopForIO::RegisterJobObject() can only be called via
    208     // MessageLoopForIO::current().
    209     io_task_runner_->PostTask(
    210         FROM_HERE,
    211         base::Bind(&Core::InitializeJob, this, base::Passed(&job_wrapper)));
    212   }
    213 
    214   // Create a session token for the launched process.
    215   return CreateSessionToken(session_id, &session_token_);
    216 }
    217 
    218 void WtsSessionProcessDelegate::Core::Stop() {
    219   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    220 
    221   KillProcess();
    222 
    223   // Drain the completion queue to make sure all job object notifications have
    224   // been received.
    225   DrainJobNotificationsCompleted();
    226 }
    227 
    228 void WtsSessionProcessDelegate::Core::LaunchProcess(
    229     WorkerProcessLauncher* event_handler) {
    230   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    231   DCHECK(!event_handler_);
    232 
    233   event_handler_ = event_handler;
    234   DoLaunchProcess();
    235 }
    236 
    237 void WtsSessionProcessDelegate::Core::Send(IPC::Message* message) {
    238   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    239 
    240   if (channel_) {
    241     channel_->Send(message);
    242   } else {
    243     delete message;
    244   }
    245 }
    246 
    247 void WtsSessionProcessDelegate::Core::CloseChannel() {
    248   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    249 
    250   channel_.reset();
    251   pipe_.Close();
    252 }
    253 
    254 void WtsSessionProcessDelegate::Core::KillProcess() {
    255   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    256 
    257   channel_.reset();
    258   event_handler_ = NULL;
    259   launch_pending_ = false;
    260   pipe_.Close();
    261 
    262   if (launch_elevated_) {
    263     if (job_.IsValid())
    264       TerminateJobObject(job_, CONTROL_C_EXIT);
    265   } else {
    266     if (worker_process_.IsValid())
    267       TerminateProcess(worker_process_, CONTROL_C_EXIT);
    268   }
    269 
    270   worker_process_.Close();
    271 }
    272 
    273 WtsSessionProcessDelegate::Core::~Core() {
    274   DCHECK(!channel_);
    275   DCHECK(!event_handler_);
    276   DCHECK(!pipe_.IsValid());
    277   DCHECK(!worker_process_.IsValid());
    278 }
    279 
    280 void WtsSessionProcessDelegate::Core::OnIOCompleted(
    281     base::MessagePumpForIO::IOContext* context,
    282     DWORD bytes_transferred,
    283     DWORD error) {
    284   DCHECK(io_task_runner_->BelongsToCurrentThread());
    285 
    286   // |bytes_transferred| is used in job object notifications to supply
    287   // the message ID; |context| carries process ID.
    288   if (bytes_transferred == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) {
    289     caller_task_runner_->PostTask(FROM_HERE,
    290                                   base::Bind(&Core::OnActiveProcessZero, this));
    291   }
    292 }
    293 
    294 bool WtsSessionProcessDelegate::Core::OnMessageReceived(
    295     const IPC::Message& message) {
    296   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    297 
    298   return event_handler_->OnMessageReceived(message);
    299 }
    300 
    301 void WtsSessionProcessDelegate::Core::OnChannelConnected(int32 peer_pid) {
    302   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    303 
    304   // Report the worker PID now if the worker process is launched indirectly.
    305   // Note that in this case the pipe's security descriptor is the only
    306   // protection against a malicious processed connecting to the pipe.
    307   if (launch_elevated_) {
    308     DWORD pid;
    309     if (!get_named_pipe_client_pid_(pipe_, &pid)) {
    310       LOG_GETLASTERROR(ERROR) << "Failed to retrive PID of the client";
    311       ReportFatalError();
    312       return;
    313     }
    314 
    315     if (pid != static_cast<DWORD>(peer_pid)) {
    316       LOG(ERROR) << "The actual client PID " << pid
    317                  << " does not match the one reported by the client: "
    318                  << peer_pid;
    319       ReportFatalError();
    320       return;
    321     }
    322 
    323     DWORD desired_access =
    324         SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION;
    325     ScopedHandle worker_process(OpenProcess(desired_access, false, pid));
    326     if (!worker_process.IsValid()) {
    327       LOG_GETLASTERROR(ERROR) << "Failed to open process " << pid;
    328       ReportFatalError();
    329       return;
    330     }
    331 
    332     ReportProcessLaunched(worker_process.Pass());
    333   }
    334 
    335   if (event_handler_)
    336     event_handler_->OnChannelConnected(peer_pid);
    337 }
    338 
    339 void WtsSessionProcessDelegate::Core::OnChannelError() {
    340   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    341 
    342   event_handler_->OnChannelError();
    343 }
    344 
    345 void WtsSessionProcessDelegate::Core::DoLaunchProcess() {
    346   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    347   DCHECK(!channel_);
    348   DCHECK(!pipe_.IsValid());
    349   DCHECK(!worker_process_.IsValid());
    350 
    351   CommandLine command_line(target_command_->argv());
    352   if (launch_elevated_) {
    353     // The job object is not ready. Retry starting the host process later.
    354     if (!job_.IsValid()) {
    355       launch_pending_ = true;
    356       return;
    357     }
    358 
    359     // Construct the helper binary name.
    360     base::FilePath helper_binary;
    361     if (!GetInstalledBinaryPath(kHostBinaryName, &helper_binary)) {
    362       ReportFatalError();
    363       return;
    364     }
    365 
    366     // Create the command line passing the name of the IPC channel to use and
    367     // copying known switches from the caller's command line.
    368     command_line.SetProgram(helper_binary);
    369     command_line.AppendSwitchPath(kElevateSwitchName,
    370                                   target_command_->GetProgram());
    371   }
    372 
    373   // Create the server end of the IPC channel.
    374   std::string channel_name = IPC::Channel::GenerateUniqueRandomChannelID();
    375   ScopedHandle pipe;
    376   if (!CreateIpcChannel(channel_name, channel_security_, &pipe)) {
    377     ReportFatalError();
    378     return;
    379   }
    380 
    381   // Wrap the pipe into an IPC channel.
    382   scoped_ptr<IPC::ChannelProxy> channel(new IPC::ChannelProxy(
    383       IPC::ChannelHandle(pipe),
    384       IPC::Channel::MODE_SERVER,
    385       this,
    386       io_task_runner_));
    387 
    388   // Pass the name of the IPC channel to use.
    389   command_line.AppendSwitchNative(kDaemonPipeSwitchName,
    390                                   UTF8ToWide(channel_name));
    391 
    392   // Try to launch the process.
    393   ScopedHandle worker_process;
    394   ScopedHandle worker_thread;
    395   if (!LaunchProcessWithToken(command_line.GetProgram(),
    396                               command_line.GetCommandLineString(),
    397                               session_token_,
    398                               NULL,
    399                               NULL,
    400                               false,
    401                               CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB,
    402                               UTF8ToUTF16(kDefaultDesktopName).c_str(),
    403                               &worker_process,
    404                               &worker_thread)) {
    405     ReportFatalError();
    406     return;
    407   }
    408 
    409   if (launch_elevated_) {
    410     if (!AssignProcessToJobObject(job_, worker_process)) {
    411       LOG_GETLASTERROR(ERROR)
    412           << "Failed to assign the worker to the job object";
    413       ReportFatalError();
    414       return;
    415     }
    416   }
    417 
    418   if (!ResumeThread(worker_thread)) {
    419     LOG_GETLASTERROR(ERROR) << "Failed to resume the worker thread";
    420     ReportFatalError();
    421     return;
    422   }
    423 
    424   channel_ = channel.Pass();
    425   pipe_ = pipe.Pass();
    426 
    427   // Report success if the worker process is lauched directly. Otherwise, PID of
    428   // the client connected to the pipe will be used later. See
    429   // OnChannelConnected().
    430   if (!launch_elevated_)
    431     ReportProcessLaunched(worker_process.Pass());
    432 }
    433 
    434 void WtsSessionProcessDelegate::Core::DrainJobNotifications() {
    435   DCHECK(io_task_runner_->BelongsToCurrentThread());
    436 
    437   // DrainJobNotifications() is posted after the job object is destroyed, so
    438   // by this time all notifications from the job object have been processed
    439   // already. Let the main thread know that the queue has been drained.
    440   caller_task_runner_->PostTask(FROM_HERE, base::Bind(
    441       &Core::DrainJobNotificationsCompleted, this));
    442 }
    443 
    444 void WtsSessionProcessDelegate::Core::DrainJobNotificationsCompleted() {
    445   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    446 
    447   if (job_.IsValid()) {
    448     job_.Close();
    449 
    450     // Drain the completion queue to make sure all job object notification have
    451     // been received.
    452     io_task_runner_->PostTask(FROM_HERE, base::Bind(
    453         &Core::DrainJobNotifications, this));
    454   }
    455 }
    456 
    457 void WtsSessionProcessDelegate::Core::InitializeJob(
    458     scoped_ptr<base::win::ScopedHandle> job) {
    459   DCHECK(io_task_runner_->BelongsToCurrentThread());
    460 
    461   // Register to receive job notifications via the I/O thread's completion port.
    462   if (!base::MessageLoopForIO::current()->RegisterJobObject(job->Get(), this)) {
    463     LOG_GETLASTERROR(ERROR)
    464         << "Failed to associate the job object with a completion port";
    465     return;
    466   }
    467 
    468   // Let the main thread know that initialization is complete.
    469   caller_task_runner_->PostTask(FROM_HERE, base::Bind(
    470       &Core::InitializeJobCompleted, this, base::Passed(&job)));
    471 }
    472 
    473 void WtsSessionProcessDelegate::Core::InitializeJobCompleted(
    474     scoped_ptr<ScopedHandle> job) {
    475   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    476   DCHECK(!job_.IsValid());
    477 
    478   job_ = job->Pass();
    479 
    480   if (launch_pending_)
    481     DoLaunchProcess();
    482 }
    483 
    484 void WtsSessionProcessDelegate::Core::OnActiveProcessZero() {
    485   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    486 
    487   if (launch_pending_) {
    488     LOG(ERROR) << "The worker process exited before connecting via IPC.";
    489     launch_pending_ = false;
    490     ReportFatalError();
    491   }
    492 }
    493 
    494 void WtsSessionProcessDelegate::Core::ReportFatalError() {
    495   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    496 
    497   channel_.reset();
    498   pipe_.Close();
    499 
    500   WorkerProcessLauncher* event_handler = event_handler_;
    501   event_handler_ = NULL;
    502   event_handler->OnFatalError();
    503 }
    504 
    505 void WtsSessionProcessDelegate::Core::ReportProcessLaunched(
    506     base::win::ScopedHandle worker_process) {
    507   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    508   DCHECK(!worker_process_.IsValid());
    509 
    510   worker_process_ = worker_process.Pass();
    511 
    512   // Report a handle that can be used to wait for the worker process completion,
    513   // query information about the process and duplicate handles.
    514   DWORD desired_access =
    515       SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION;
    516   ScopedHandle limited_handle;
    517   if (!DuplicateHandle(GetCurrentProcess(),
    518                        worker_process_,
    519                        GetCurrentProcess(),
    520                        limited_handle.Receive(),
    521                        desired_access,
    522                        FALSE,
    523                        0)) {
    524     LOG_GETLASTERROR(ERROR) << "Failed to duplicate a handle";
    525     ReportFatalError();
    526     return;
    527   }
    528 
    529   event_handler_->OnProcessLaunched(limited_handle.Pass());
    530 }
    531 
    532 WtsSessionProcessDelegate::WtsSessionProcessDelegate(
    533     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
    534     scoped_ptr<CommandLine> target_command,
    535     bool launch_elevated,
    536     const std::string& channel_security) {
    537   core_ = new Core(io_task_runner,
    538                    target_command.Pass(),
    539                    launch_elevated,
    540                    channel_security);
    541 }
    542 
    543 WtsSessionProcessDelegate::~WtsSessionProcessDelegate() {
    544   core_->Stop();
    545 }
    546 
    547 bool WtsSessionProcessDelegate::Initialize(uint32 session_id) {
    548   return core_->Initialize(session_id);
    549 }
    550 
    551 void WtsSessionProcessDelegate::LaunchProcess(
    552     WorkerProcessLauncher* event_handler) {
    553   core_->LaunchProcess(event_handler);
    554 }
    555 
    556 void WtsSessionProcessDelegate::Send(IPC::Message* message) {
    557   core_->Send(message);
    558 }
    559 
    560 void WtsSessionProcessDelegate::CloseChannel() {
    561   core_->CloseChannel();
    562 }
    563 
    564 void WtsSessionProcessDelegate::KillProcess() {
    565   core_->KillProcess();
    566 }
    567 
    568 } // namespace remoting
    569