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
32using base::win::ScopedHandle;
33
34// Name of the default session desktop.
35const char kDefaultDesktopName[] = "winsta0\\default";
36
37namespace 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.
42class 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
144WtsSessionProcessDelegate::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
159bool 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.Get(),
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
218void 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
228void 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
237void 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
247void WtsSessionProcessDelegate::Core::CloseChannel() {
248  DCHECK(caller_task_runner_->BelongsToCurrentThread());
249
250  channel_.reset();
251  pipe_.Close();
252}
253
254void 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_.Get(), CONTROL_C_EXIT);
265  } else {
266    if (worker_process_.IsValid())
267      TerminateProcess(worker_process_.Get(), CONTROL_C_EXIT);
268  }
269
270  worker_process_.Close();
271}
272
273WtsSessionProcessDelegate::Core::~Core() {
274  DCHECK(!channel_);
275  DCHECK(!event_handler_);
276  DCHECK(!pipe_.IsValid());
277  DCHECK(!worker_process_.IsValid());
278}
279
280void 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
294bool WtsSessionProcessDelegate::Core::OnMessageReceived(
295    const IPC::Message& message) {
296  DCHECK(caller_task_runner_->BelongsToCurrentThread());
297
298  return event_handler_->OnMessageReceived(message);
299}
300
301void 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_.Get(), &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
339void WtsSessionProcessDelegate::Core::OnChannelError() {
340  DCHECK(caller_task_runner_->BelongsToCurrentThread());
341
342  event_handler_->OnChannelError();
343}
344
345void 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.Get()),
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_.Get(),
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_.Get(), worker_process.Get())) {
411      PLOG(ERROR) << "Failed to assign the worker to the job object";
412      ReportFatalError();
413      return;
414    }
415  }
416
417  if (!ResumeThread(worker_thread.Get())) {
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
433void 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
443void 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
456void 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
471void 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
482void 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
492void 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
503void 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_.Get(),
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
531WtsSessionProcessDelegate::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
542WtsSessionProcessDelegate::~WtsSessionProcessDelegate() {
543  core_->Stop();
544}
545
546bool WtsSessionProcessDelegate::Initialize(uint32 session_id) {
547  return core_->Initialize(session_id);
548}
549
550void WtsSessionProcessDelegate::LaunchProcess(
551    WorkerProcessLauncher* event_handler) {
552  core_->LaunchProcess(event_handler);
553}
554
555void WtsSessionProcessDelegate::Send(IPC::Message* message) {
556  core_->Send(message);
557}
558
559void WtsSessionProcessDelegate::CloseChannel() {
560  core_->CloseChannel();
561}
562
563void WtsSessionProcessDelegate::KillProcess() {
564  core_->KillProcess();
565}
566
567}  // namespace remoting
568