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
Core(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,scoped_ptr<CommandLine> target_command,bool launch_elevated,const std::string & channel_security)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
Initialize(uint32 session_id)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
Stop()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
LaunchProcess(WorkerProcessLauncher * event_handler)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
Send(IPC::Message * message)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
CloseChannel()247 void WtsSessionProcessDelegate::Core::CloseChannel() {
248 DCHECK(caller_task_runner_->BelongsToCurrentThread());
249
250 channel_.reset();
251 pipe_.Close();
252 }
253
KillProcess()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
~Core()273 WtsSessionProcessDelegate::Core::~Core() {
274 DCHECK(!channel_);
275 DCHECK(!event_handler_);
276 DCHECK(!pipe_.IsValid());
277 DCHECK(!worker_process_.IsValid());
278 }
279
OnIOCompleted(base::MessagePumpForIO::IOContext * context,DWORD bytes_transferred,DWORD error)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
OnMessageReceived(const IPC::Message & message)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
OnChannelConnected(int32 peer_pid)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
OnChannelError()339 void WtsSessionProcessDelegate::Core::OnChannelError() {
340 DCHECK(caller_task_runner_->BelongsToCurrentThread());
341
342 event_handler_->OnChannelError();
343 }
344
DoLaunchProcess()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
DrainJobNotifications()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
DrainJobNotificationsCompleted()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
InitializeJob(scoped_ptr<base::win::ScopedHandle> job)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
InitializeJobCompleted(scoped_ptr<ScopedHandle> job)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
OnActiveProcessZero()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
ReportFatalError()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
ReportProcessLaunched(base::win::ScopedHandle worker_process)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 HANDLE temp_handle;
517 if (!DuplicateHandle(GetCurrentProcess(),
518 worker_process_,
519 GetCurrentProcess(),
520 &temp_handle,
521 desired_access,
522 FALSE,
523 0)) {
524 LOG_GETLASTERROR(ERROR) << "Failed to duplicate a handle";
525 ReportFatalError();
526 return;
527 }
528 ScopedHandle limited_handle(temp_handle);
529
530 event_handler_->OnProcessLaunched(limited_handle.Pass());
531 }
532
WtsSessionProcessDelegate(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,scoped_ptr<CommandLine> target_command,bool launch_elevated,const std::string & channel_security)533 WtsSessionProcessDelegate::WtsSessionProcessDelegate(
534 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
535 scoped_ptr<CommandLine> target_command,
536 bool launch_elevated,
537 const std::string& channel_security) {
538 core_ = new Core(io_task_runner,
539 target_command.Pass(),
540 launch_elevated,
541 channel_security);
542 }
543
~WtsSessionProcessDelegate()544 WtsSessionProcessDelegate::~WtsSessionProcessDelegate() {
545 core_->Stop();
546 }
547
Initialize(uint32 session_id)548 bool WtsSessionProcessDelegate::Initialize(uint32 session_id) {
549 return core_->Initialize(session_id);
550 }
551
LaunchProcess(WorkerProcessLauncher * event_handler)552 void WtsSessionProcessDelegate::LaunchProcess(
553 WorkerProcessLauncher* event_handler) {
554 core_->LaunchProcess(event_handler);
555 }
556
Send(IPC::Message * message)557 void WtsSessionProcessDelegate::Send(IPC::Message* message) {
558 core_->Send(message);
559 }
560
CloseChannel()561 void WtsSessionProcessDelegate::CloseChannel() {
562 core_->CloseChannel();
563 }
564
KillProcess()565 void WtsSessionProcessDelegate::KillProcess() {
566 core_->KillProcess();
567 }
568
569 } // namespace remoting
570