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       PLOG(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       PLOG(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       PLOG(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       PLOG(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   base::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(
    383       IPC::ChannelProxy::Create(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                                   base::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                               base::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       PLOG(ERROR) << "Failed to assign the worker to the job object";
    412       ReportFatalError();
    413       return;
    414     }
    415   }
    416 
    417   if (!ResumeThread(worker_thread)) {
    418     PLOG(ERROR) << "Failed to resume the worker thread";
    419     ReportFatalError();
    420     return;
    421   }
    422 
    423   channel_ = channel.Pass();
    424   pipe_ = pipe.Pass();
    425 
    426   // Report success if the worker process is lauched directly. Otherwise, PID of
    427   // the client connected to the pipe will be used later. See
    428   // OnChannelConnected().
    429   if (!launch_elevated_)
    430     ReportProcessLaunched(worker_process.Pass());
    431 }
    432 
    433 void WtsSessionProcessDelegate::Core::DrainJobNotifications() {
    434   DCHECK(io_task_runner_->BelongsToCurrentThread());
    435 
    436   // DrainJobNotifications() is posted after the job object is destroyed, so
    437   // by this time all notifications from the job object have been processed
    438   // already. Let the main thread know that the queue has been drained.
    439   caller_task_runner_->PostTask(FROM_HERE, base::Bind(
    440       &Core::DrainJobNotificationsCompleted, this));
    441 }
    442 
    443 void WtsSessionProcessDelegate::Core::DrainJobNotificationsCompleted() {
    444   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    445 
    446   if (job_.IsValid()) {
    447     job_.Close();
    448 
    449     // Drain the completion queue to make sure all job object notification have
    450     // been received.
    451     io_task_runner_->PostTask(FROM_HERE, base::Bind(
    452         &Core::DrainJobNotifications, this));
    453   }
    454 }
    455 
    456 void WtsSessionProcessDelegate::Core::InitializeJob(
    457     scoped_ptr<base::win::ScopedHandle> job) {
    458   DCHECK(io_task_runner_->BelongsToCurrentThread());
    459 
    460   // Register to receive job notifications via the I/O thread's completion port.
    461   if (!base::MessageLoopForIO::current()->RegisterJobObject(job->Get(), this)) {
    462     PLOG(ERROR) << "Failed to associate the job object with a completion port";
    463     return;
    464   }
    465 
    466   // Let the main thread know that initialization is complete.
    467   caller_task_runner_->PostTask(FROM_HERE, base::Bind(
    468       &Core::InitializeJobCompleted, this, base::Passed(&job)));
    469 }
    470 
    471 void WtsSessionProcessDelegate::Core::InitializeJobCompleted(
    472     scoped_ptr<ScopedHandle> job) {
    473   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    474   DCHECK(!job_.IsValid());
    475 
    476   job_ = job->Pass();
    477 
    478   if (launch_pending_)
    479     DoLaunchProcess();
    480 }
    481 
    482 void WtsSessionProcessDelegate::Core::OnActiveProcessZero() {
    483   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    484 
    485   if (launch_pending_) {
    486     LOG(ERROR) << "The worker process exited before connecting via IPC.";
    487     launch_pending_ = false;
    488     ReportFatalError();
    489   }
    490 }
    491 
    492 void WtsSessionProcessDelegate::Core::ReportFatalError() {
    493   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    494 
    495   channel_.reset();
    496   pipe_.Close();
    497 
    498   WorkerProcessLauncher* event_handler = event_handler_;
    499   event_handler_ = NULL;
    500   event_handler->OnFatalError();
    501 }
    502 
    503 void WtsSessionProcessDelegate::Core::ReportProcessLaunched(
    504     base::win::ScopedHandle worker_process) {
    505   DCHECK(caller_task_runner_->BelongsToCurrentThread());
    506   DCHECK(!worker_process_.IsValid());
    507 
    508   worker_process_ = worker_process.Pass();
    509 
    510   // Report a handle that can be used to wait for the worker process completion,
    511   // query information about the process and duplicate handles.
    512   DWORD desired_access =
    513       SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION;
    514   HANDLE temp_handle;
    515   if (!DuplicateHandle(GetCurrentProcess(),
    516                        worker_process_,
    517                        GetCurrentProcess(),
    518                        &temp_handle,
    519                        desired_access,
    520                        FALSE,
    521                        0)) {
    522     PLOG(ERROR) << "Failed to duplicate a handle";
    523     ReportFatalError();
    524     return;
    525   }
    526   ScopedHandle limited_handle(temp_handle);
    527 
    528   event_handler_->OnProcessLaunched(limited_handle.Pass());
    529 }
    530 
    531 WtsSessionProcessDelegate::WtsSessionProcessDelegate(
    532     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
    533     scoped_ptr<CommandLine> target_command,
    534     bool launch_elevated,
    535     const std::string& channel_security) {
    536   core_ = new Core(io_task_runner,
    537                    target_command.Pass(),
    538                    launch_elevated,
    539                    channel_security);
    540 }
    541 
    542 WtsSessionProcessDelegate::~WtsSessionProcessDelegate() {
    543   core_->Stop();
    544 }
    545 
    546 bool WtsSessionProcessDelegate::Initialize(uint32 session_id) {
    547   return core_->Initialize(session_id);
    548 }
    549 
    550 void WtsSessionProcessDelegate::LaunchProcess(
    551     WorkerProcessLauncher* event_handler) {
    552   core_->LaunchProcess(event_handler);
    553 }
    554 
    555 void WtsSessionProcessDelegate::Send(IPC::Message* message) {
    556   core_->Send(message);
    557 }
    558 
    559 void WtsSessionProcessDelegate::CloseChannel() {
    560   core_->CloseChannel();
    561 }
    562 
    563 void WtsSessionProcessDelegate::KillProcess() {
    564   core_->KillProcess();
    565 }
    566 
    567 }  // namespace remoting
    568