| 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/wts_session_process_launcher_win.h" | 8 #include "remoting/host/wts_session_process_launcher_win.h" |
| 9 | 9 |
| 10 #include <windows.h> | 10 #include <windows.h> |
| 11 #include <sddl.h> | 11 #include <sddl.h> |
| 12 #include <limits> | 12 #include <limits> |
| 13 | 13 |
| 14 #include "base/bind.h" |
| 15 #include "base/bind_helpers.h" |
| 14 #include "base/command_line.h" | 16 #include "base/command_line.h" |
| 15 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/message_loop_proxy.h" |
| 16 #include "base/process_util.h" | 19 #include "base/process_util.h" |
| 17 #include "base/rand_util.h" | 20 #include "base/rand_util.h" |
| 18 #include "base/string16.h" | 21 #include "base/string16.h" |
| 19 #include "base/stringprintf.h" | 22 #include "base/stringprintf.h" |
| 20 #include "base/threading/thread.h" | |
| 21 #include "base/utf_string_conversions.h" | 23 #include "base/utf_string_conversions.h" |
| 22 #include "base/win/scoped_handle.h" | 24 #include "base/win/scoped_handle.h" |
| 23 #include "base/win/scoped_process_information.h" | 25 #include "base/win/scoped_process_information.h" |
| 24 #include "ipc/ipc_channel_proxy.h" | 26 #include "ipc/ipc_channel_proxy.h" |
| 25 #include "ipc/ipc_message.h" | 27 #include "ipc/ipc_message.h" |
| 26 #include "ipc/ipc_message_macros.h" | 28 #include "ipc/ipc_message_macros.h" |
| 27 | 29 |
| 28 #include "remoting/host/chromoting_messages.h" | 30 #include "remoting/host/chromoting_messages.h" |
| 29 #include "remoting/host/sas_injector.h" | 31 #include "remoting/host/sas_injector.h" |
| 30 #include "remoting/host/wts_console_monitor_win.h" | 32 #include "remoting/host/wts_console_monitor_win.h" |
| 31 | 33 |
| 32 using base::win::ScopedHandle; | 34 using base::win::ScopedHandle; |
| 33 using base::TimeDelta; | 35 using base::TimeDelta; |
| 34 | 36 |
| 35 namespace { | 37 namespace { |
| 36 | 38 |
| 39 // The exit code returned by the host process when its configuration is not |
| 40 // valid. |
| 41 const int kInvalidHostConfigurationExitCode = 1; |
| 42 |
| 37 // The minimum and maximum delays between attempts to inject host process into | 43 // The minimum and maximum delays between attempts to inject host process into |
| 38 // a session. | 44 // a session. |
| 39 const int kMaxLaunchDelaySeconds = 60; | 45 const int kMaxLaunchDelaySeconds = 60; |
| 40 const int kMinLaunchDelaySeconds = 1; | 46 const int kMinLaunchDelaySeconds = 1; |
| 41 | 47 |
| 42 // Name of the default session desktop. | 48 // Name of the default session desktop. |
| 43 const char kDefaultDesktopName[] = "winsta0\\default"; | 49 const char kDefaultDesktopName[] = "winsta0\\default"; |
| 44 | 50 |
| 45 // Match the pipe name prefix used by Chrome IPC channels. | 51 // Match the pipe name prefix used by Chrome IPC channels. |
| 46 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome."; | 52 const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome."; |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 return true; | 246 return true; |
| 241 } | 247 } |
| 242 | 248 |
| 243 } // namespace | 249 } // namespace |
| 244 | 250 |
| 245 namespace remoting { | 251 namespace remoting { |
| 246 | 252 |
| 247 WtsSessionProcessLauncher::WtsSessionProcessLauncher( | 253 WtsSessionProcessLauncher::WtsSessionProcessLauncher( |
| 248 WtsConsoleMonitor* monitor, | 254 WtsConsoleMonitor* monitor, |
| 249 const FilePath& host_binary, | 255 const FilePath& host_binary, |
| 250 base::Thread* io_thread) | 256 scoped_refptr<base::MessageLoopProxy> main_message_loop, |
| 257 scoped_refptr<base::MessageLoopProxy> ipc_message_loop) |
| 251 : host_binary_(host_binary), | 258 : host_binary_(host_binary), |
| 252 io_thread_(io_thread), | 259 main_message_loop_(main_message_loop), |
| 260 ipc_message_loop_(ipc_message_loop), |
| 253 monitor_(monitor), | 261 monitor_(monitor), |
| 254 state_(StateDetached) { | 262 state_(StateDetached) { |
| 255 monitor_->AddWtsConsoleObserver(this); | 263 monitor_->AddWtsConsoleObserver(this); |
| 256 } | 264 } |
| 257 | 265 |
| 258 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() { | 266 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() { |
| 259 DCHECK(state_ == StateDetached); | 267 DCHECK(state_ == StateDetached); |
| 260 DCHECK(!timer_.IsRunning()); | 268 DCHECK(!timer_.IsRunning()); |
| 261 DCHECK(process_.handle() == NULL); | 269 DCHECK(process_.handle() == NULL); |
| 262 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 270 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 263 DCHECK(chromoting_channel_.get() == NULL); | 271 DCHECK(chromoting_channel_.get() == NULL); |
| 264 | 272 if (monitor_ != NULL) { |
| 265 monitor_->RemoveWtsConsoleObserver(this); | 273 monitor_->RemoveWtsConsoleObserver(this); |
| 274 } |
| 266 } | 275 } |
| 267 | 276 |
| 268 void WtsSessionProcessLauncher::LaunchProcess() { | 277 void WtsSessionProcessLauncher::LaunchProcess() { |
| 278 DCHECK(main_message_loop_->BelongsToCurrentThread()); |
| 269 DCHECK(state_ == StateStarting); | 279 DCHECK(state_ == StateStarting); |
| 270 DCHECK(!timer_.IsRunning()); | 280 DCHECK(!timer_.IsRunning()); |
| 271 DCHECK(process_.handle() == NULL); | 281 DCHECK(process_.handle() == NULL); |
| 272 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 282 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 273 DCHECK(chromoting_channel_.get() == NULL); | 283 DCHECK(chromoting_channel_.get() == NULL); |
| 274 | 284 |
| 275 launch_time_ = base::Time::Now(); | 285 launch_time_ = base::Time::Now(); |
| 276 | 286 |
| 277 string16 channel_name; | 287 string16 channel_name; |
| 278 ScopedHandle pipe; | 288 ScopedHandle pipe; |
| 279 if (CreatePipeForIpcChannel(this, &channel_name, &pipe)) { | 289 if (CreatePipeForIpcChannel(this, &channel_name, &pipe)) { |
| 280 // Wrap the pipe into an IPC channel. | 290 // Wrap the pipe into an IPC channel. |
| 281 chromoting_channel_.reset(new IPC::ChannelProxy( | 291 chromoting_channel_.reset(new IPC::ChannelProxy( |
| 282 IPC::ChannelHandle(pipe.Get()), | 292 IPC::ChannelHandle(pipe.Get()), |
| 283 IPC::Channel::MODE_SERVER, | 293 IPC::Channel::MODE_SERVER, |
| 284 this, | 294 this, |
| 285 io_thread_->message_loop_proxy().get())); | 295 ipc_message_loop_)); |
| 286 | 296 |
| 287 // Create the host process command line passing the name of the IPC channel | 297 // Create the host process command line passing the name of the IPC channel |
| 288 // to use and copying known switches from the service's command line. | 298 // to use and copying known switches from the service's command line. |
| 289 CommandLine command_line(host_binary_); | 299 CommandLine command_line(host_binary_); |
| 290 command_line.AppendSwitchNative(kChromotingIpcSwitchName, channel_name); | 300 command_line.AppendSwitchNative(kChromotingIpcSwitchName, channel_name); |
| 291 command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(), | 301 command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(), |
| 292 kCopiedSwitchNames, | 302 kCopiedSwitchNames, |
| 293 _countof(kCopiedSwitchNames)); | 303 _countof(kCopiedSwitchNames)); |
| 294 | 304 |
| 295 // Try to launch the process and attach an object watcher to the returned | 305 // Try to launch the process and attach an object watcher to the returned |
| (...skipping 17 matching lines...) Expand all Loading... |
| 313 // is limited by exponential backoff. | 323 // is limited by exponential backoff. |
| 314 launch_backoff_ = std::max(launch_backoff_ * 2, | 324 launch_backoff_ = std::max(launch_backoff_ * 2, |
| 315 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); | 325 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); |
| 316 launch_backoff_ = std::min(launch_backoff_, | 326 launch_backoff_ = std::min(launch_backoff_, |
| 317 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); | 327 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); |
| 318 timer_.Start(FROM_HERE, launch_backoff_, | 328 timer_.Start(FROM_HERE, launch_backoff_, |
| 319 this, &WtsSessionProcessLauncher::LaunchProcess); | 329 this, &WtsSessionProcessLauncher::LaunchProcess); |
| 320 } | 330 } |
| 321 | 331 |
| 322 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { | 332 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { |
| 323 DCHECK(state_ == StateAttached); | 333 if (!main_message_loop_->BelongsToCurrentThread()) { |
| 334 main_message_loop_->PostTask( |
| 335 FROM_HERE, base::Bind(&WtsSessionProcessLauncher::OnObjectSignaled, |
| 336 base::Unretained(this), object)); |
| 337 return; |
| 338 } |
| 339 |
| 340 // It is possible that OnObjectSignaled() task will be queued by another |
| 341 // thread right before |process_watcher_| was stopped. It such a case it is |
| 342 // safe to ignore this notification. |
| 343 if (state_ != StateAttached) { |
| 344 return; |
| 345 } |
| 346 |
| 324 DCHECK(!timer_.IsRunning()); | 347 DCHECK(!timer_.IsRunning()); |
| 325 DCHECK(process_.handle() != NULL); | 348 DCHECK(process_.handle() != NULL); |
| 326 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 349 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 327 DCHECK(chromoting_channel_.get() != NULL); | 350 DCHECK(chromoting_channel_.get() != NULL); |
| 328 | 351 |
| 352 // Stop trying to restart the host if its process exited due to |
| 353 // misconfiguration. |
| 354 DWORD exit_code; |
| 355 bool stop_trying = GetExitCodeProcess(process_.handle(), &exit_code) && |
| 356 exit_code == kInvalidHostConfigurationExitCode; |
| 357 |
| 329 // The host process has been terminated for some reason. The handle can now be | 358 // The host process has been terminated for some reason. The handle can now be |
| 330 // closed. | 359 // closed. |
| 331 process_.Close(); | 360 process_.Close(); |
| 332 chromoting_channel_.reset(); | 361 chromoting_channel_.reset(); |
| 362 state_ = StateStarting; |
| 363 |
| 364 if (stop_trying) { |
| 365 OnSessionDetached(); |
| 366 |
| 367 // N.B. The service will stop once the last observer is removed from |
| 368 // the list. |
| 369 monitor_->RemoveWtsConsoleObserver(this); |
| 370 monitor_ = NULL; |
| 371 return; |
| 372 } |
| 333 | 373 |
| 334 // Expand the backoff interval if the process has died quickly or reset it if | 374 // Expand the backoff interval if the process has died quickly or reset it if |
| 335 // it was up longer than the maximum backoff delay. | 375 // it was up longer than the maximum backoff delay. |
| 336 base::TimeDelta delta = base::Time::Now() - launch_time_; | 376 base::TimeDelta delta = base::Time::Now() - launch_time_; |
| 337 if (delta < base::TimeDelta() || | 377 if (delta < base::TimeDelta() || |
| 338 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { | 378 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) { |
| 339 launch_backoff_ = base::TimeDelta(); | 379 launch_backoff_ = base::TimeDelta(); |
| 340 } else { | 380 } else { |
| 341 launch_backoff_ = std::max(launch_backoff_ * 2, | 381 launch_backoff_ = std::max(launch_backoff_ * 2, |
| 342 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); | 382 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); |
| 343 launch_backoff_ = std::min(launch_backoff_, | 383 launch_backoff_ = std::min(launch_backoff_, |
| 344 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); | 384 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); |
| 345 } | 385 } |
| 346 | 386 |
| 347 // Try to restart the host. | 387 // Try to restart the host. |
| 348 state_ = StateStarting; | |
| 349 timer_.Start(FROM_HERE, launch_backoff_, | 388 timer_.Start(FROM_HERE, launch_backoff_, |
| 350 this, &WtsSessionProcessLauncher::LaunchProcess); | 389 this, &WtsSessionProcessLauncher::LaunchProcess); |
| 351 } | 390 } |
| 352 | 391 |
| 353 bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) { | 392 bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) { |
| 354 bool handled = true; | 393 bool handled = true; |
| 355 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message) | 394 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message) |
| 356 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole, | 395 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole, |
| 357 OnSendSasToConsole) | 396 OnSendSasToConsole) |
| 358 IPC_MESSAGE_UNHANDLED(handled = false) | 397 IPC_MESSAGE_UNHANDLED(handled = false) |
| 359 IPC_END_MESSAGE_MAP() | 398 IPC_END_MESSAGE_MAP() |
| 360 return handled; | 399 return handled; |
| 361 } | 400 } |
| 362 | 401 |
| 363 void WtsSessionProcessLauncher::OnSendSasToConsole() { | 402 void WtsSessionProcessLauncher::OnSendSasToConsole() { |
| 403 if (!main_message_loop_->BelongsToCurrentThread()) { |
| 404 main_message_loop_->PostTask( |
| 405 FROM_HERE, base::Bind(&WtsSessionProcessLauncher::OnSendSasToConsole, |
| 406 base::Unretained(this))); |
| 407 return; |
| 408 } |
| 409 |
| 364 if (state_ == StateAttached) { | 410 if (state_ == StateAttached) { |
| 365 if (sas_injector_.get() == NULL) { | 411 if (sas_injector_.get() == NULL) { |
| 366 sas_injector_ = SasInjector::Create(); | 412 sas_injector_ = SasInjector::Create(); |
| 367 } | 413 } |
| 368 | 414 |
| 369 if (sas_injector_.get() != NULL) { | 415 if (sas_injector_.get() != NULL) { |
| 370 sas_injector_->InjectSas(); | 416 sas_injector_->InjectSas(); |
| 371 } | 417 } |
| 372 } | 418 } |
| 373 } | 419 } |
| 374 | 420 |
| 375 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { | 421 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { |
| 422 DCHECK(main_message_loop_->BelongsToCurrentThread()); |
| 376 DCHECK(state_ == StateDetached); | 423 DCHECK(state_ == StateDetached); |
| 377 DCHECK(!timer_.IsRunning()); | 424 DCHECK(!timer_.IsRunning()); |
| 378 DCHECK(process_.handle() == NULL); | 425 DCHECK(process_.handle() == NULL); |
| 379 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 426 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 380 DCHECK(chromoting_channel_.get() == NULL); | 427 DCHECK(chromoting_channel_.get() == NULL); |
| 381 | 428 |
| 382 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is | 429 // Temporarily enable the SE_TCB_NAME privilege. The privileged token is |
| 383 // created as needed and kept for later reuse. | 430 // created as needed and kept for later reuse. |
| 384 if (privileged_token_.Get() == NULL) { | 431 if (privileged_token_.Get() == NULL) { |
| 385 if (!CreatePrivilegedToken(&privileged_token_)) { | 432 if (!CreatePrivilegedToken(&privileged_token_)) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 403 | 450 |
| 404 if (!result) | 451 if (!result) |
| 405 return; | 452 return; |
| 406 | 453 |
| 407 // Now try to launch the host. | 454 // Now try to launch the host. |
| 408 state_ = StateStarting; | 455 state_ = StateStarting; |
| 409 LaunchProcess(); | 456 LaunchProcess(); |
| 410 } | 457 } |
| 411 | 458 |
| 412 void WtsSessionProcessLauncher::OnSessionDetached() { | 459 void WtsSessionProcessLauncher::OnSessionDetached() { |
| 460 DCHECK(main_message_loop_->BelongsToCurrentThread()); |
| 413 DCHECK(state_ == StateDetached || | 461 DCHECK(state_ == StateDetached || |
| 414 state_ == StateStarting || | 462 state_ == StateStarting || |
| 415 state_ == StateAttached); | 463 state_ == StateAttached); |
| 416 | 464 |
| 417 switch (state_) { | 465 switch (state_) { |
| 418 case StateDetached: | 466 case StateDetached: |
| 419 DCHECK(!timer_.IsRunning()); | 467 DCHECK(!timer_.IsRunning()); |
| 420 DCHECK(process_.handle() == NULL); | 468 DCHECK(process_.handle() == NULL); |
| 421 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 469 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 422 DCHECK(chromoting_channel_.get() == NULL); | 470 DCHECK(chromoting_channel_.get() == NULL); |
| 423 break; | 471 break; |
| 424 | 472 |
| 425 case StateStarting: | 473 case StateStarting: |
| 426 DCHECK(timer_.IsRunning()); | |
| 427 DCHECK(process_.handle() == NULL); | 474 DCHECK(process_.handle() == NULL); |
| 428 DCHECK(process_watcher_.GetWatchedObject() == NULL); | 475 DCHECK(process_watcher_.GetWatchedObject() == NULL); |
| 429 DCHECK(chromoting_channel_.get() == NULL); | 476 DCHECK(chromoting_channel_.get() == NULL); |
| 430 | 477 |
| 431 timer_.Stop(); | 478 timer_.Stop(); |
| 432 launch_backoff_ = base::TimeDelta(); | 479 launch_backoff_ = base::TimeDelta(); |
| 433 state_ = StateDetached; | 480 state_ = StateDetached; |
| 434 break; | 481 break; |
| 435 | 482 |
| 436 case StateAttached: | 483 case StateAttached: |
| 437 DCHECK(!timer_.IsRunning()); | 484 DCHECK(!timer_.IsRunning()); |
| 438 DCHECK(process_.handle() != NULL); | 485 DCHECK(process_.handle() != NULL); |
| 439 DCHECK(process_watcher_.GetWatchedObject() != NULL); | 486 DCHECK(process_watcher_.GetWatchedObject() != NULL); |
| 440 DCHECK(chromoting_channel_.get() != NULL); | 487 DCHECK(chromoting_channel_.get() != NULL); |
| 441 | 488 |
| 442 process_watcher_.StopWatching(); | 489 process_watcher_.StopWatching(); |
| 443 process_.Terminate(0); | 490 process_.Terminate(0); |
| 444 process_.Close(); | 491 process_.Close(); |
| 445 chromoting_channel_.reset(); | 492 chromoting_channel_.reset(); |
| 446 state_ = StateDetached; | 493 state_ = StateDetached; |
| 447 break; | 494 break; |
| 448 } | 495 } |
| 449 } | 496 } |
| 450 | 497 |
| 451 } // namespace remoting | 498 } // namespace remoting |
| OLD | NEW |