| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // This file implements the Windows service controlling Me2Me host processes | 5 // This file implements the Windows service controlling Me2Me host processes |
| 6 // running within user sessions. | 6 // running within user sessions. |
| 7 | 7 |
| 8 #include "remoting/host/win/wts_session_process_delegate.h" | 8 #include "remoting/host/win/wts_session_process_delegate.h" |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 CHECK(kernel32 != NULL); | 169 CHECK(kernel32 != NULL); |
| 170 | 170 |
| 171 get_named_pipe_client_pid_ = | 171 get_named_pipe_client_pid_ = |
| 172 reinterpret_cast<GetNamedPipeClientProcessIdFn>( | 172 reinterpret_cast<GetNamedPipeClientProcessIdFn>( |
| 173 GetProcAddress(kernel32, "GetNamedPipeClientProcessId")); | 173 GetProcAddress(kernel32, "GetNamedPipeClientProcessId")); |
| 174 CHECK(get_named_pipe_client_pid_ != NULL); | 174 CHECK(get_named_pipe_client_pid_ != NULL); |
| 175 | 175 |
| 176 ScopedHandle job; | 176 ScopedHandle job; |
| 177 job.Set(CreateJobObject(NULL, NULL)); | 177 job.Set(CreateJobObject(NULL, NULL)); |
| 178 if (!job.IsValid()) { | 178 if (!job.IsValid()) { |
| 179 LOG_GETLASTERROR(ERROR) << "Failed to create a job object"; | 179 PLOG(ERROR) << "Failed to create a job object"; |
| 180 return false; | 180 return false; |
| 181 } | 181 } |
| 182 | 182 |
| 183 // Limit the number of active processes in the job to two (the helper | 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 | 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. | 185 // that all processes will be killed once the job object is destroyed. |
| 186 JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; | 186 JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; |
| 187 memset(&info, 0, sizeof(info)); | 187 memset(&info, 0, sizeof(info)); |
| 188 info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_ACTIVE_PROCESS | | 188 info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_ACTIVE_PROCESS | |
| 189 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; | 189 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; |
| 190 info.BasicLimitInformation.ActiveProcessLimit = 2; | 190 info.BasicLimitInformation.ActiveProcessLimit = 2; |
| 191 if (!SetInformationJobObject(job, | 191 if (!SetInformationJobObject(job, |
| 192 JobObjectExtendedLimitInformation, | 192 JobObjectExtendedLimitInformation, |
| 193 &info, | 193 &info, |
| 194 sizeof(info))) { | 194 sizeof(info))) { |
| 195 LOG_GETLASTERROR(ERROR) << "Failed to set limits on the job object"; | 195 PLOG(ERROR) << "Failed to set limits on the job object"; |
| 196 return false; | 196 return false; |
| 197 } | 197 } |
| 198 | 198 |
| 199 // ScopedHandle is not compatible with base::Passed, so we wrap it to | 199 // ScopedHandle is not compatible with base::Passed, so we wrap it to |
| 200 // a scoped pointer. | 200 // a scoped pointer. |
| 201 scoped_ptr<ScopedHandle> job_wrapper(new ScopedHandle()); | 201 scoped_ptr<ScopedHandle> job_wrapper(new ScopedHandle()); |
| 202 *job_wrapper = job.Pass(); | 202 *job_wrapper = job.Pass(); |
| 203 | 203 |
| 204 // To receive job object notifications the job object is registered with | 204 // To receive job object notifications the job object is registered with |
| 205 // the completion port represented by |io_task_runner|. The registration has | 205 // the completion port represented by |io_task_runner|. The registration has |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 | 300 |
| 301 void WtsSessionProcessDelegate::Core::OnChannelConnected(int32 peer_pid) { | 301 void WtsSessionProcessDelegate::Core::OnChannelConnected(int32 peer_pid) { |
| 302 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 302 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 303 | 303 |
| 304 // Report the worker PID now if the worker process is launched indirectly. | 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 | 305 // Note that in this case the pipe's security descriptor is the only |
| 306 // protection against a malicious processed connecting to the pipe. | 306 // protection against a malicious processed connecting to the pipe. |
| 307 if (launch_elevated_) { | 307 if (launch_elevated_) { |
| 308 DWORD pid; | 308 DWORD pid; |
| 309 if (!get_named_pipe_client_pid_(pipe_, &pid)) { | 309 if (!get_named_pipe_client_pid_(pipe_, &pid)) { |
| 310 LOG_GETLASTERROR(ERROR) << "Failed to retrive PID of the client"; | 310 PLOG(ERROR) << "Failed to retrive PID of the client"; |
| 311 ReportFatalError(); | 311 ReportFatalError(); |
| 312 return; | 312 return; |
| 313 } | 313 } |
| 314 | 314 |
| 315 if (pid != static_cast<DWORD>(peer_pid)) { | 315 if (pid != static_cast<DWORD>(peer_pid)) { |
| 316 LOG(ERROR) << "The actual client PID " << pid | 316 LOG(ERROR) << "The actual client PID " << pid |
| 317 << " does not match the one reported by the client: " | 317 << " does not match the one reported by the client: " |
| 318 << peer_pid; | 318 << peer_pid; |
| 319 ReportFatalError(); | 319 ReportFatalError(); |
| 320 return; | 320 return; |
| 321 } | 321 } |
| 322 | 322 |
| 323 DWORD desired_access = | 323 DWORD desired_access = |
| 324 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; | 324 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; |
| 325 ScopedHandle worker_process(OpenProcess(desired_access, false, pid)); | 325 ScopedHandle worker_process(OpenProcess(desired_access, false, pid)); |
| 326 if (!worker_process.IsValid()) { | 326 if (!worker_process.IsValid()) { |
| 327 LOG_GETLASTERROR(ERROR) << "Failed to open process " << pid; | 327 PLOG(ERROR) << "Failed to open process " << pid; |
| 328 ReportFatalError(); | 328 ReportFatalError(); |
| 329 return; | 329 return; |
| 330 } | 330 } |
| 331 | 331 |
| 332 ReportProcessLaunched(worker_process.Pass()); | 332 ReportProcessLaunched(worker_process.Pass()); |
| 333 } | 333 } |
| 334 | 334 |
| 335 if (event_handler_) | 335 if (event_handler_) |
| 336 event_handler_->OnChannelConnected(peer_pid); | 336 event_handler_->OnChannelConnected(peer_pid); |
| 337 } | 337 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, | 401 CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, |
| 402 base::UTF8ToUTF16(kDefaultDesktopName).c_str(), | 402 base::UTF8ToUTF16(kDefaultDesktopName).c_str(), |
| 403 &worker_process, | 403 &worker_process, |
| 404 &worker_thread)) { | 404 &worker_thread)) { |
| 405 ReportFatalError(); | 405 ReportFatalError(); |
| 406 return; | 406 return; |
| 407 } | 407 } |
| 408 | 408 |
| 409 if (launch_elevated_) { | 409 if (launch_elevated_) { |
| 410 if (!AssignProcessToJobObject(job_, worker_process)) { | 410 if (!AssignProcessToJobObject(job_, worker_process)) { |
| 411 LOG_GETLASTERROR(ERROR) | 411 PLOG(ERROR) << "Failed to assign the worker to the job object"; |
| 412 << "Failed to assign the worker to the job object"; | |
| 413 ReportFatalError(); | 412 ReportFatalError(); |
| 414 return; | 413 return; |
| 415 } | 414 } |
| 416 } | 415 } |
| 417 | 416 |
| 418 if (!ResumeThread(worker_thread)) { | 417 if (!ResumeThread(worker_thread)) { |
| 419 LOG_GETLASTERROR(ERROR) << "Failed to resume the worker thread"; | 418 PLOG(ERROR) << "Failed to resume the worker thread"; |
| 420 ReportFatalError(); | 419 ReportFatalError(); |
| 421 return; | 420 return; |
| 422 } | 421 } |
| 423 | 422 |
| 424 channel_ = channel.Pass(); | 423 channel_ = channel.Pass(); |
| 425 pipe_ = pipe.Pass(); | 424 pipe_ = pipe.Pass(); |
| 426 | 425 |
| 427 // Report success if the worker process is lauched directly. Otherwise, PID of | 426 // Report success if the worker process is lauched directly. Otherwise, PID of |
| 428 // the client connected to the pipe will be used later. See | 427 // the client connected to the pipe will be used later. See |
| 429 // OnChannelConnected(). | 428 // OnChannelConnected(). |
| (...skipping 23 matching lines...) Expand all Loading... |
| 453 &Core::DrainJobNotifications, this)); | 452 &Core::DrainJobNotifications, this)); |
| 454 } | 453 } |
| 455 } | 454 } |
| 456 | 455 |
| 457 void WtsSessionProcessDelegate::Core::InitializeJob( | 456 void WtsSessionProcessDelegate::Core::InitializeJob( |
| 458 scoped_ptr<base::win::ScopedHandle> job) { | 457 scoped_ptr<base::win::ScopedHandle> job) { |
| 459 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 458 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 460 | 459 |
| 461 // Register to receive job notifications via the I/O thread's completion port. | 460 // Register to receive job notifications via the I/O thread's completion port. |
| 462 if (!base::MessageLoopForIO::current()->RegisterJobObject(job->Get(), this)) { | 461 if (!base::MessageLoopForIO::current()->RegisterJobObject(job->Get(), this)) { |
| 463 LOG_GETLASTERROR(ERROR) | 462 PLOG(ERROR) << "Failed to associate the job object with a completion port"; |
| 464 << "Failed to associate the job object with a completion port"; | |
| 465 return; | 463 return; |
| 466 } | 464 } |
| 467 | 465 |
| 468 // Let the main thread know that initialization is complete. | 466 // Let the main thread know that initialization is complete. |
| 469 caller_task_runner_->PostTask(FROM_HERE, base::Bind( | 467 caller_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 470 &Core::InitializeJobCompleted, this, base::Passed(&job))); | 468 &Core::InitializeJobCompleted, this, base::Passed(&job))); |
| 471 } | 469 } |
| 472 | 470 |
| 473 void WtsSessionProcessDelegate::Core::InitializeJobCompleted( | 471 void WtsSessionProcessDelegate::Core::InitializeJobCompleted( |
| 474 scoped_ptr<ScopedHandle> job) { | 472 scoped_ptr<ScopedHandle> job) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 514 DWORD desired_access = | 512 DWORD desired_access = |
| 515 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; | 513 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; |
| 516 HANDLE temp_handle; | 514 HANDLE temp_handle; |
| 517 if (!DuplicateHandle(GetCurrentProcess(), | 515 if (!DuplicateHandle(GetCurrentProcess(), |
| 518 worker_process_, | 516 worker_process_, |
| 519 GetCurrentProcess(), | 517 GetCurrentProcess(), |
| 520 &temp_handle, | 518 &temp_handle, |
| 521 desired_access, | 519 desired_access, |
| 522 FALSE, | 520 FALSE, |
| 523 0)) { | 521 0)) { |
| 524 LOG_GETLASTERROR(ERROR) << "Failed to duplicate a handle"; | 522 PLOG(ERROR) << "Failed to duplicate a handle"; |
| 525 ReportFatalError(); | 523 ReportFatalError(); |
| 526 return; | 524 return; |
| 527 } | 525 } |
| 528 ScopedHandle limited_handle(temp_handle); | 526 ScopedHandle limited_handle(temp_handle); |
| 529 | 527 |
| 530 event_handler_->OnProcessLaunched(limited_handle.Pass()); | 528 event_handler_->OnProcessLaunched(limited_handle.Pass()); |
| 531 } | 529 } |
| 532 | 530 |
| 533 WtsSessionProcessDelegate::WtsSessionProcessDelegate( | 531 WtsSessionProcessDelegate::WtsSessionProcessDelegate( |
| 534 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, | 532 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 560 | 558 |
| 561 void WtsSessionProcessDelegate::CloseChannel() { | 559 void WtsSessionProcessDelegate::CloseChannel() { |
| 562 core_->CloseChannel(); | 560 core_->CloseChannel(); |
| 563 } | 561 } |
| 564 | 562 |
| 565 void WtsSessionProcessDelegate::KillProcess() { | 563 void WtsSessionProcessDelegate::KillProcess() { |
| 566 core_->KillProcess(); | 564 core_->KillProcess(); |
| 567 } | 565 } |
| 568 | 566 |
| 569 } // namespace remoting | 567 } // namespace remoting |
| OLD | NEW |