Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / remoting / host / win / wts_session_process_delegate.cc
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.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
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_.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
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_.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
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.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
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_.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
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