remoting_me2me_host.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
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 a standalone host process for Me2Me. 6 7#include <string> 8 9#include "base/at_exit.h" 10#include "base/bind.h" 11#include "base/callback.h" 12#include "base/command_line.h" 13#include "base/debug/alias.h" 14#include "base/file_util.h" 15#include "base/files/file_path.h" 16#include "base/logging.h" 17#include "base/memory/scoped_ptr.h" 18#include "base/message_loop/message_loop.h" 19#include "base/single_thread_task_runner.h" 20#include "base/strings/string_number_conversions.h" 21#include "base/strings/string_util.h" 22#include "base/strings/utf_string_conversions.h" 23#include "base/synchronization/waitable_event.h" 24#include "base/threading/thread.h" 25#include "build/build_config.h" 26#include "crypto/nss_util.h" 27#include "ipc/ipc_channel.h" 28#include "ipc/ipc_channel_proxy.h" 29#include "ipc/ipc_listener.h" 30#include "media/base/media.h" 31#include "net/base/network_change_notifier.h" 32#include "net/socket/ssl_server_socket.h" 33#include "net/url_request/url_fetcher.h" 34#include "remoting/base/auto_thread_task_runner.h" 35#include "remoting/base/breakpad.h" 36#include "remoting/base/constants.h" 37#include "remoting/base/rsa_key_pair.h" 38#include "remoting/base/util.h" 39#include "remoting/host/branding.h" 40#include "remoting/host/chromoting_host.h" 41#include "remoting/host/chromoting_host_context.h" 42#include "remoting/host/chromoting_messages.h" 43#include "remoting/host/config_file_watcher.h" 44#include "remoting/host/desktop_environment.h" 45#include "remoting/host/desktop_session_connector.h" 46#include "remoting/host/dns_blackhole_checker.h" 47#include "remoting/host/heartbeat_sender.h" 48#include "remoting/host/host_change_notification_listener.h" 49#include "remoting/host/host_config.h" 50#include "remoting/host/host_event_logger.h" 51#include "remoting/host/host_exit_codes.h" 52#include "remoting/host/host_main.h" 53#include "remoting/host/host_status_sender.h" 54#include "remoting/host/ipc_constants.h" 55#include "remoting/host/ipc_desktop_environment.h" 56#include "remoting/host/ipc_host_event_logger.h" 57#include "remoting/host/json_host_config.h" 58#include "remoting/host/log_to_server.h" 59#include "remoting/host/logging.h" 60#include "remoting/host/me2me_desktop_environment.h" 61#include "remoting/host/pairing_registry_delegate.h" 62#include "remoting/host/policy_hack/policy_watcher.h" 63#include "remoting/host/service_urls.h" 64#include "remoting/host/session_manager_factory.h" 65#include "remoting/host/signaling_connector.h" 66#include "remoting/host/token_validator_factory_impl.h" 67#include "remoting/host/ui_strings.h" 68#include "remoting/host/usage_stats_consent.h" 69#include "remoting/jingle_glue/network_settings.h" 70#include "remoting/jingle_glue/xmpp_signal_strategy.h" 71#include "remoting/protocol/me2me_host_authenticator_factory.h" 72#include "remoting/protocol/pairing_registry.h" 73 74#if defined(OS_POSIX) 75#include <signal.h> 76#include <sys/types.h> 77#include <unistd.h> 78#include "base/file_descriptor_posix.h" 79#include "remoting/host/pam_authorization_factory_posix.h" 80#include "remoting/host/posix/signal_handler.h" 81#endif // defined(OS_POSIX) 82 83#if defined(OS_MACOSX) 84#include "base/mac/scoped_cftyperef.h" 85#endif // defined(OS_MACOSX) 86 87#if defined(OS_LINUX) 88#include "remoting/host/audio_capturer_linux.h" 89#endif // defined(OS_LINUX) 90 91#if defined(OS_WIN) 92#include <commctrl.h> 93#include "base/win/scoped_handle.h" 94#include "remoting/host/win/session_desktop_environment.h" 95#endif // defined(OS_WIN) 96 97#if defined(TOOLKIT_GTK) 98#include "ui/gfx/gtk_util.h" 99#endif // defined(TOOLKIT_GTK) 100 101namespace { 102 103// This is used for tagging system event logs. 104const char kApplicationName[] = "chromoting"; 105 106// The command line switch used to pass name of the pipe to capture audio on 107// linux. 108const char kAudioPipeSwitchName[] = "audio-pipe-name"; 109 110// The command line switch used by the parent to request the host to signal it 111// when it is successfully started. 112const char kSignalParentSwitchName[] = "signal-parent"; 113 114void QuitMessageLoop(base::MessageLoop* message_loop) { 115 message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); 116} 117 118} // namespace 119 120namespace remoting { 121 122class HostProcess 123 : public ConfigFileWatcher::Delegate, 124 public HeartbeatSender::Listener, 125 public HostChangeNotificationListener::Listener, 126 public IPC::Listener, 127 public base::RefCountedThreadSafe<HostProcess> { 128 public: 129 HostProcess(scoped_ptr<ChromotingHostContext> context, 130 int* exit_code_out); 131 132 // ConfigFileWatcher::Delegate interface. 133 virtual void OnConfigUpdated(const std::string& serialized_config) OVERRIDE; 134 virtual void OnConfigWatcherError() OVERRIDE; 135 136 // IPC::Listener implementation. 137 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 138 virtual void OnChannelError() OVERRIDE; 139 140 // HeartbeatSender::Listener overrides. 141 virtual void OnHeartbeatSuccessful() OVERRIDE; 142 virtual void OnUnknownHostIdError() OVERRIDE; 143 144 // HostChangeNotificationListener::Listener overrides. 145 virtual void OnHostDeleted() OVERRIDE; 146 147 private: 148 enum HostState { 149 // Host process has just been started. Waiting for config and policies to be 150 // read from the disk. 151 HOST_INITIALIZING, 152 153 // Host is started and running. 154 HOST_STARTED, 155 156 // Host is being stopped and will need to be started again. 157 HOST_STOPPING_TO_RESTART, 158 159 // Host is being stopped. 160 HOST_STOPPING, 161 162 // Host has been stopped. 163 HOST_STOPPED, 164 165 // Allowed state transitions: 166 // INITIALIZING->STARTED 167 // INITIALIZING->STOPPED 168 // STARTED->STOPPING_TO_RESTART 169 // STARTED->STOPPING 170 // STOPPING_TO_RESTART->STARTED 171 // STOPPING_TO_RESTART->STOPPING 172 // STOPPING->STOPPED 173 // STOPPED->STARTED 174 // 175 // |host_| must be NULL in INITIALIZING and STOPPED states and not-NULL in 176 // all other states. 177 }; 178 179 friend class base::RefCountedThreadSafe<HostProcess>; 180 virtual ~HostProcess(); 181 182 void StartOnNetworkThread(); 183 184#if defined(OS_POSIX) 185 // Callback passed to RegisterSignalHandler() to handle SIGTERM events. 186 void SigTermHandler(int signal_number); 187#endif 188 189 // Called to initialize resources on the UI thread. 190 void StartOnUiThread(); 191 192 // Initializes IPC control channel and config file path from |cmd_line|. 193 // Called on the UI thread. 194 bool InitWithCommandLine(const CommandLine* cmd_line); 195 196 // Called on the UI thread to start monitoring the configuration file. 197 void StartWatchingConfigChanges(); 198 199 // Called on the network thread to set the host's Authenticator factory. 200 void CreateAuthenticatorFactory(); 201 202 // Tear down resources that run on the UI thread. 203 void ShutdownOnUiThread(); 204 205 // Applies the host config, returning true if successful. 206 bool ApplyConfig(scoped_ptr<JsonHostConfig> config); 207 208 void OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies); 209 bool OnHostDomainPolicyUpdate(const std::string& host_domain); 210 bool OnUsernamePolicyUpdate(bool curtain_required, 211 bool username_match_required); 212 bool OnNatPolicyUpdate(bool nat_traversal_enabled); 213 void OnCurtainPolicyUpdate(bool curtain_required); 214 bool OnHostTalkGadgetPrefixPolicyUpdate(const std::string& talkgadget_prefix); 215 bool OnHostTokenUrlPolicyUpdate(const GURL& token_url, 216 const GURL& token_validation_url); 217 218 void StartHost(); 219 220 void OnAuthFailed(); 221 222 void RestartHost(); 223 224 // Stops the host and shuts down the process with the specified |exit_code|. 225 void ShutdownHost(HostExitCodes exit_code); 226 227 void ScheduleHostShutdown(); 228 229 void ShutdownOnNetworkThread(); 230 231 // Crashes the process in response to a daemon's request. The daemon passes 232 // the location of the code that detected the fatal error resulted in this 233 // request. 234 void OnCrash(const std::string& function_name, 235 const std::string& file_name, 236 const int& line_number); 237 238 scoped_ptr<ChromotingHostContext> context_; 239 240 // Created on the UI thread but used from the network thread. 241 scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_; 242 243 // Accessed on the UI thread. 244 scoped_ptr<IPC::ChannelProxy> daemon_channel_; 245 246 // XMPP server/remoting bot configuration (initialized from the command line). 247 XmppSignalStrategy::XmppServerConfig xmpp_server_config_; 248 std::string directory_bot_jid_; 249 250 // Created on the UI thread but used from the network thread. 251 base::FilePath host_config_path_; 252 scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_; 253 254 // Accessed on the network thread. 255 HostState state_; 256 257 scoped_ptr<ConfigFileWatcher> config_watcher_; 258 259 std::string host_id_; 260 protocol::SharedSecretHash host_secret_hash_; 261 scoped_refptr<RsaKeyPair> key_pair_; 262 std::string oauth_refresh_token_; 263 std::string serialized_config_; 264 std::string xmpp_login_; 265 std::string xmpp_auth_token_; 266 std::string xmpp_auth_service_; 267 scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_; 268 bool allow_nat_traversal_; 269 std::string talkgadget_prefix_; 270 271 bool curtain_required_; 272 GURL token_url_; 273 GURL token_validation_url_; 274 275 scoped_ptr<XmppSignalStrategy> signal_strategy_; 276 scoped_ptr<SignalingConnector> signaling_connector_; 277 scoped_ptr<HeartbeatSender> heartbeat_sender_; 278 scoped_ptr<HostStatusSender> host_status_sender_; 279 scoped_ptr<HostChangeNotificationListener> host_change_notification_listener_; 280 scoped_ptr<LogToServer> log_to_server_; 281 scoped_ptr<HostEventLogger> host_event_logger_; 282 283 scoped_ptr<ChromotingHost> host_; 284 285 // Used to keep this HostProcess alive until it is shutdown. 286 scoped_refptr<HostProcess> self_; 287 288#if defined(REMOTING_MULTI_PROCESS) 289 DesktopSessionConnector* desktop_session_connector_; 290#endif // defined(REMOTING_MULTI_PROCESS) 291 292 int* exit_code_out_; 293 bool signal_parent_; 294}; 295 296HostProcess::HostProcess(scoped_ptr<ChromotingHostContext> context, 297 int* exit_code_out) 298 : context_(context.Pass()), 299 state_(HOST_INITIALIZING), 300 allow_nat_traversal_(true), 301 curtain_required_(false), 302#if defined(REMOTING_MULTI_PROCESS) 303 desktop_session_connector_(NULL), 304#endif // defined(REMOTING_MULTI_PROCESS) 305 self_(this), 306 exit_code_out_(exit_code_out), 307 signal_parent_(false) { 308 StartOnUiThread(); 309} 310 311HostProcess::~HostProcess() { 312 // Verify that UI components have been torn down. 313 DCHECK(!config_watcher_); 314 DCHECK(!daemon_channel_); 315 DCHECK(!desktop_environment_factory_); 316 317 // We might be getting deleted on one of the threads the |host_context| owns, 318 // so we need to post it back to the caller thread to safely join & delete the 319 // threads it contains. This will go away when we move to AutoThread. 320 // |context_release()| will null |context_| before the method is invoked, so 321 // we need to pull out the task-runner on which to call DeleteSoon first. 322 scoped_refptr<base::SingleThreadTaskRunner> task_runner = 323 context_->ui_task_runner(); 324 task_runner->DeleteSoon(FROM_HERE, context_.release()); 325} 326 327bool HostProcess::InitWithCommandLine(const CommandLine* cmd_line) { 328#if defined(REMOTING_MULTI_PROCESS) 329 // Parse the handle value and convert it to a handle/file descriptor. 330 std::string channel_name = 331 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName); 332 333 int pipe_handle = 0; 334 if (channel_name.empty() || 335 !base::StringToInt(channel_name, &pipe_handle)) { 336 LOG(ERROR) << "Invalid '" << kDaemonPipeSwitchName 337 << "' value: " << channel_name; 338 return false; 339 } 340 341#if defined(OS_WIN) 342 base::win::ScopedHandle pipe(reinterpret_cast<HANDLE>(pipe_handle)); 343 IPC::ChannelHandle channel_handle(pipe); 344#elif defined(OS_POSIX) 345 base::FileDescriptor pipe(pipe_handle, true); 346 IPC::ChannelHandle channel_handle(channel_name, pipe); 347#endif // defined(OS_POSIX) 348 349 // Connect to the daemon process. 350 daemon_channel_.reset(new IPC::ChannelProxy( 351 channel_handle, 352 IPC::Channel::MODE_CLIENT, 353 this, 354 context_->network_task_runner())); 355#else // !defined(REMOTING_MULTI_PROCESS) 356 // Connect to the daemon process. 357 std::string channel_name = 358 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName); 359 if (!channel_name.empty()) { 360 daemon_channel_.reset( 361 new IPC::ChannelProxy(channel_name, 362 IPC::Channel::MODE_CLIENT, 363 this, 364 context_->network_task_runner().get())); 365 } 366 367 base::FilePath default_config_dir = remoting::GetConfigDir(); 368 host_config_path_ = default_config_dir.Append(kDefaultHostConfigFile); 369 if (cmd_line->HasSwitch(kHostConfigSwitchName)) { 370 host_config_path_ = cmd_line->GetSwitchValuePath(kHostConfigSwitchName); 371 } 372#endif // !defined(REMOTING_MULTI_PROCESS) 373 374 ServiceUrls* service_urls = ServiceUrls::GetInstance(); 375 if (service_urls->ignore_urlfetcher_cert_requests()) { 376 net::URLFetcher::SetIgnoreCertificateRequests(true); 377 } 378 bool xmpp_server_valid = net::ParseHostAndPort( 379 service_urls->xmpp_server_address(), 380 &xmpp_server_config_.host, &xmpp_server_config_.port); 381 if (!xmpp_server_valid) { 382 LOG(ERROR) << "Invalid XMPP server: " << 383 service_urls->xmpp_server_address(); 384 return false; 385 } 386 xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls(); 387 directory_bot_jid_ = service_urls->directory_bot_jid(); 388 389 signal_parent_ = cmd_line->HasSwitch(kSignalParentSwitchName); 390 391 return true; 392} 393 394void HostProcess::OnConfigUpdated( 395 const std::string& serialized_config) { 396 if (!context_->network_task_runner()->BelongsToCurrentThread()) { 397 context_->network_task_runner()->PostTask(FROM_HERE, 398 base::Bind(&HostProcess::OnConfigUpdated, this, serialized_config)); 399 return; 400 } 401 402 // Filter out duplicates. 403 if (serialized_config_ == serialized_config) 404 return; 405 406 LOG(INFO) << "Processing new host configuration."; 407 408 serialized_config_ = serialized_config; 409 scoped_ptr<JsonHostConfig> config(new JsonHostConfig(base::FilePath())); 410 if (!config->SetSerializedData(serialized_config)) { 411 LOG(ERROR) << "Invalid configuration."; 412 ShutdownHost(kInvalidHostConfigurationExitCode); 413 return; 414 } 415 416 if (!ApplyConfig(config.Pass())) { 417 LOG(ERROR) << "Failed to apply the configuration."; 418 ShutdownHost(kInvalidHostConfigurationExitCode); 419 return; 420 } 421 422 if (state_ == HOST_INITIALIZING) { 423 // TODO(sergeyu): Currently OnPolicyUpdate() assumes that host config is 424 // already loaded so PolicyWatcher has to be started here. Separate policy 425 // loading from policy verifications and move |policy_watcher_| 426 // initialization to StartOnNetworkThread(). 427 policy_watcher_.reset( 428 policy_hack::PolicyWatcher::Create(context_->file_task_runner())); 429 policy_watcher_->StartWatching( 430 base::Bind(&HostProcess::OnPolicyUpdate, base::Unretained(this))); 431 } else if (state_ == HOST_STARTED) { 432 // TODO(sergeyu): Here we assume that PIN is the only part of the config 433 // that may change while the service is running. Change ApplyConfig() to 434 // detect other changes in the config and restart host if necessary here. 435 CreateAuthenticatorFactory(); 436 } 437} 438 439void HostProcess::OnConfigWatcherError() { 440 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 441 ShutdownHost(kInvalidHostConfigurationExitCode); 442} 443 444void HostProcess::StartOnNetworkThread() { 445 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 446 447#if !defined(REMOTING_MULTI_PROCESS) 448 // Start watching the host configuration file. 449 config_watcher_.reset(new ConfigFileWatcher(context_->network_task_runner(), 450 context_->file_task_runner(), 451 this)); 452 config_watcher_->Watch(host_config_path_); 453#endif // !defined(REMOTING_MULTI_PROCESS) 454 455#if defined(OS_POSIX) 456 remoting::RegisterSignalHandler( 457 SIGTERM, 458 base::Bind(&HostProcess::SigTermHandler, base::Unretained(this))); 459#endif // defined(OS_POSIX) 460} 461 462#if defined(OS_POSIX) 463void HostProcess::SigTermHandler(int signal_number) { 464 DCHECK(signal_number == SIGTERM); 465 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 466 LOG(INFO) << "Caught SIGTERM: Shutting down..."; 467 ShutdownHost(kSuccessExitCode); 468} 469#endif // OS_POSIX 470 471void HostProcess::CreateAuthenticatorFactory() { 472 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 473 474 if (state_ != HOST_STARTED) 475 return; 476 477 std::string local_certificate = key_pair_->GenerateCertificate(); 478 if (local_certificate.empty()) { 479 LOG(ERROR) << "Failed to generate host certificate."; 480 ShutdownHost(kInitializationFailed); 481 return; 482 } 483 484 // TODO(jamiewalch): Create a pairing registry here once all the code 485 // is committed. 486 scoped_refptr<remoting::protocol::PairingRegistry> pairing_registry = NULL; 487 488 scoped_ptr<protocol::AuthenticatorFactory> factory; 489 490 if (token_url_.is_empty() && token_validation_url_.is_empty()) { 491 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret( 492 local_certificate, key_pair_, host_secret_hash_, pairing_registry); 493 494 } else if (token_url_.is_valid() && token_validation_url_.is_valid()) { 495 scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidatorFactory> 496 token_validator_factory(new TokenValidatorFactoryImpl( 497 token_url_, token_validation_url_, key_pair_, 498 context_->url_request_context_getter())); 499 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth( 500 local_certificate, key_pair_, token_validator_factory.Pass()); 501 502 } else { 503 // TODO(rmsousa): If the policy is bad the host should not go online. It 504 // should keep running, but not connected, until the policies are fixed. 505 // Having it show up as online and then reject all clients is misleading. 506 LOG(ERROR) << "One of the third-party token URLs is empty or invalid. " 507 << "Host will reject all clients until policies are corrected. " 508 << "TokenUrl: " << token_url_ << ", " 509 << "TokenValidationUrl: " << token_validation_url_; 510 factory = protocol::Me2MeHostAuthenticatorFactory::CreateRejecting(); 511 } 512 513#if defined(OS_POSIX) 514 // On Linux and Mac, perform a PAM authorization step after authentication. 515 factory.reset(new PamAuthorizationFactory(factory.Pass())); 516#endif 517 host_->SetAuthenticatorFactory(factory.Pass()); 518 519 host_->set_pairing_registry(pairing_registry); 520} 521 522// IPC::Listener implementation. 523bool HostProcess::OnMessageReceived(const IPC::Message& message) { 524 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); 525 526#if defined(REMOTING_MULTI_PROCESS) 527 bool handled = true; 528 IPC_BEGIN_MESSAGE_MAP(HostProcess, message) 529 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash) 530 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Configuration, 531 OnConfigUpdated) 532 IPC_MESSAGE_FORWARD( 533 ChromotingDaemonNetworkMsg_DesktopAttached, 534 desktop_session_connector_, 535 DesktopSessionConnector::OnDesktopSessionAgentAttached) 536 IPC_MESSAGE_FORWARD(ChromotingDaemonNetworkMsg_TerminalDisconnected, 537 desktop_session_connector_, 538 DesktopSessionConnector::OnTerminalDisconnected) 539 IPC_MESSAGE_UNHANDLED(handled = false) 540 IPC_END_MESSAGE_MAP() 541 542 CHECK(handled) << "Received unexpected IPC type: " << message.type(); 543 return handled; 544 545#else // !defined(REMOTING_MULTI_PROCESS) 546 return false; 547#endif // !defined(REMOTING_MULTI_PROCESS) 548} 549 550void HostProcess::OnChannelError() { 551 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); 552 553 // Shutdown the host if the daemon process disconnects the IPC channel. 554 context_->network_task_runner()->PostTask( 555 FROM_HERE, 556 base::Bind(&HostProcess::ShutdownHost, this, kSuccessExitCode)); 557} 558 559void HostProcess::StartOnUiThread() { 560 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); 561 562 if (!InitWithCommandLine(CommandLine::ForCurrentProcess())) { 563 // Shutdown the host if the command line is invalid. 564 context_->network_task_runner()->PostTask( 565 FROM_HERE, base::Bind(&HostProcess::ShutdownHost, this, 566 kInvalidHostConfigurationExitCode)); 567 return; 568 } 569 570#if defined(OS_LINUX) 571 // If an audio pipe is specific on the command-line then initialize 572 // AudioCapturerLinux to capture from it. 573 base::FilePath audio_pipe_name = CommandLine::ForCurrentProcess()-> 574 GetSwitchValuePath(kAudioPipeSwitchName); 575 if (!audio_pipe_name.empty()) { 576 remoting::AudioCapturerLinux::InitializePipeReader( 577 context_->audio_task_runner(), audio_pipe_name); 578 } 579#endif // defined(OS_LINUX) 580 581 // TODO(alexeypa): Localize the UI strings. See http://crbug.com/155204. 582 UiStrings ui_strings; 583 584 // Create a desktop environment factory appropriate to the build type & 585 // platform. 586#if defined(OS_WIN) 587 IpcDesktopEnvironmentFactory* desktop_environment_factory = 588 new IpcDesktopEnvironmentFactory( 589 context_->audio_task_runner(), 590 context_->network_task_runner(), 591 context_->video_capture_task_runner(), 592 context_->network_task_runner(), 593 daemon_channel_.get()); 594 desktop_session_connector_ = desktop_environment_factory; 595#else // !defined(OS_WIN) 596 DesktopEnvironmentFactory* desktop_environment_factory = 597 new Me2MeDesktopEnvironmentFactory( 598 context_->network_task_runner(), 599 context_->input_task_runner(), 600 context_->ui_task_runner(), 601 ui_strings); 602#endif // !defined(OS_WIN) 603 604 desktop_environment_factory_.reset(desktop_environment_factory); 605 606 context_->network_task_runner()->PostTask( 607 FROM_HERE, 608 base::Bind(&HostProcess::StartOnNetworkThread, this)); 609} 610 611void HostProcess::ShutdownOnUiThread() { 612 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); 613 614 // Tear down resources that need to be torn down on the UI thread. 615 network_change_notifier_.reset(); 616 daemon_channel_.reset(); 617 desktop_environment_factory_.reset(); 618 619 // It is now safe for the HostProcess to be deleted. 620 self_ = NULL; 621 622#if defined(OS_LINUX) 623 // Cause the global AudioPipeReader to be freed, otherwise the audio 624 // thread will remain in-use and prevent the process from exiting. 625 // TODO(wez): DesktopEnvironmentFactory should own the pipe reader. 626 // See crbug.com/161373 and crbug.com/104544. 627 AudioCapturerLinux::InitializePipeReader(NULL, base::FilePath()); 628#endif 629} 630 631// Overridden from HeartbeatSender::Listener 632void HostProcess::OnUnknownHostIdError() { 633 LOG(ERROR) << "Host ID not found."; 634 ShutdownHost(kInvalidHostIdExitCode); 635} 636 637void HostProcess::OnHeartbeatSuccessful() { 638 LOG(INFO) << "Host ready to receive connections."; 639#if defined(OS_POSIX) 640 if (signal_parent_) { 641 kill(getppid(), SIGUSR1); 642 signal_parent_ = false; 643 } 644#endif 645} 646 647void HostProcess::OnHostDeleted() { 648 LOG(ERROR) << "Host was deleted from the directory."; 649 ShutdownHost(kInvalidHostIdExitCode); 650} 651 652// Applies the host config, returning true if successful. 653bool HostProcess::ApplyConfig(scoped_ptr<JsonHostConfig> config) { 654 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 655 656 if (!config->GetString(kHostIdConfigPath, &host_id_)) { 657 LOG(ERROR) << "host_id is not defined in the config."; 658 return false; 659 } 660 661 std::string key_base64; 662 if (!config->GetString(kPrivateKeyConfigPath, &key_base64)) { 663 LOG(ERROR) << "Private key couldn't be read from the config file."; 664 return false; 665 } 666 667 key_pair_ = RsaKeyPair::FromString(key_base64); 668 if (!key_pair_.get()) { 669 LOG(ERROR) << "Invalid private key in the config file."; 670 return false; 671 } 672 673 std::string host_secret_hash_string; 674 if (!config->GetString(kHostSecretHashConfigPath, 675 &host_secret_hash_string)) { 676 host_secret_hash_string = "plain:"; 677 } 678 679 if (!host_secret_hash_.Parse(host_secret_hash_string)) { 680 LOG(ERROR) << "Invalid host_secret_hash."; 681 return false; 682 } 683 684 // Use an XMPP connection to the Talk network for session signalling. 685 if (!config->GetString(kXmppLoginConfigPath, &xmpp_login_) || 686 !(config->GetString(kXmppAuthTokenConfigPath, &xmpp_auth_token_) || 687 config->GetString(kOAuthRefreshTokenConfigPath, 688 &oauth_refresh_token_))) { 689 LOG(ERROR) << "XMPP credentials are not defined in the config."; 690 return false; 691 } 692 693 if (!oauth_refresh_token_.empty()) { 694 xmpp_auth_token_ = ""; // This will be set to the access token later. 695 xmpp_auth_service_ = "oauth2"; 696 } else if (!config->GetString(kXmppAuthServiceConfigPath, 697 &xmpp_auth_service_)) { 698 // For the me2me host, we default to ClientLogin token for chromiumsync 699 // because earlier versions of the host had no HTTP stack with which to 700 // request an OAuth2 access token. 701 xmpp_auth_service_ = kChromotingTokenDefaultServiceName; 702 } 703 return true; 704} 705 706void HostProcess::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) { 707 // TODO(rmsousa): Consolidate all On*PolicyUpdate methods into this one. 708 // TODO(sergeyu): Currently polices are verified only when they are loaded. 709 // Separate policy loading from policy verifications - this will allow to 710 // check policies again later, e.g. when host config changes. 711 712 if (!context_->network_task_runner()->BelongsToCurrentThread()) { 713 context_->network_task_runner()->PostTask(FROM_HERE, base::Bind( 714 &HostProcess::OnPolicyUpdate, this, base::Passed(&policies))); 715 return; 716 } 717 718 bool restart_required = false; 719 bool bool_value; 720 std::string string_value; 721 if (policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName, 722 &string_value)) { 723 restart_required |= OnHostDomainPolicyUpdate(string_value); 724 } 725 bool curtain_required = false; 726 if (policies->GetBoolean( 727 policy_hack::PolicyWatcher::kHostRequireCurtainPolicyName, 728 &curtain_required)) { 729 OnCurtainPolicyUpdate(curtain_required); 730 } 731 if (policies->GetBoolean( 732 policy_hack::PolicyWatcher::kHostMatchUsernamePolicyName, 733 &bool_value)) { 734 restart_required |= OnUsernamePolicyUpdate(curtain_required, bool_value); 735 } 736 if (policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName, 737 &bool_value)) { 738 restart_required |= OnNatPolicyUpdate(bool_value); 739 } 740 if (policies->GetString( 741 policy_hack::PolicyWatcher::kHostTalkGadgetPrefixPolicyName, 742 &string_value)) { 743 restart_required |= OnHostTalkGadgetPrefixPolicyUpdate(string_value); 744 } 745 std::string token_url_string, token_validation_url_string; 746 if (policies->GetString( 747 policy_hack::PolicyWatcher::kHostTokenUrlPolicyName, 748 &token_url_string) && 749 policies->GetString( 750 policy_hack::PolicyWatcher::kHostTokenValidationUrlPolicyName, 751 &token_validation_url_string)) { 752 restart_required |= OnHostTokenUrlPolicyUpdate( 753 GURL(token_url_string), GURL(token_validation_url_string)); 754 } 755 756 if (state_ == HOST_INITIALIZING) { 757 StartHost(); 758 } else if (state_ == HOST_STARTED && restart_required) { 759 RestartHost(); 760 } 761} 762 763bool HostProcess::OnHostDomainPolicyUpdate(const std::string& host_domain) { 764 // Returns true if the host has to be restarted after this policy update. 765 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 766 767 LOG(INFO) << "Policy sets host domain: " << host_domain; 768 769 if (!host_domain.empty() && 770 !EndsWith(xmpp_login_, std::string("@") + host_domain, false)) { 771 ShutdownHost(kInvalidHostDomainExitCode); 772 } 773 return false; 774} 775 776bool HostProcess::OnUsernamePolicyUpdate(bool curtain_required, 777 bool host_username_match_required) { 778 // Returns false: never restart the host after this policy update. 779 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 780 781 if (host_username_match_required) { 782 LOG(INFO) << "Policy requires host username match."; 783 std::string username = GetUsername(); 784 bool shutdown = username.empty() || 785 !StartsWithASCII(xmpp_login_, username + std::string("@"), 786 false); 787 788#if defined(OS_MACOSX) 789 // On Mac, we run as root at the login screen, so the username won't match. 790 // However, there's no need to enforce the policy at the login screen, as 791 // the client will have to reconnect if a login occurs. 792 if (shutdown && getuid() == 0) { 793 shutdown = false; 794 } 795#endif 796 797 // Curtain-mode on Windows presents the standard OS login prompt to the user 798 // for each connection, removing the need for an explicit user-name matching 799 // check. 800#if defined(OS_WIN) && defined(REMOTING_RDP_SESSION) 801 if (curtain_required) 802 return false; 803#endif // defined(OS_WIN) && defined(REMOTING_RDP_SESSION) 804 805 // Shutdown the host if the username does not match. 806 if (shutdown) { 807 LOG(ERROR) << "The host username does not match."; 808 ShutdownHost(kUsernameMismatchExitCode); 809 } 810 } else { 811 LOG(INFO) << "Policy does not require host username match."; 812 } 813 814 return false; 815} 816 817bool HostProcess::OnNatPolicyUpdate(bool nat_traversal_enabled) { 818 // Returns true if the host has to be restarted after this policy update. 819 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 820 821 if (allow_nat_traversal_ != nat_traversal_enabled) { 822 if (nat_traversal_enabled) 823 LOG(INFO) << "Policy enables NAT traversal."; 824 else 825 LOG(INFO) << "Policy disables NAT traversal."; 826 allow_nat_traversal_ = nat_traversal_enabled; 827 return true; 828 } 829 return false; 830} 831 832void HostProcess::OnCurtainPolicyUpdate(bool curtain_required) { 833 // Returns true if the host has to be restarted after this policy update. 834 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 835 836#if defined(OS_MACOSX) 837 if (curtain_required) { 838 // When curtain mode is in effect on Mac, the host process runs in the 839 // user's switched-out session, but launchd will also run an instance at 840 // the console login screen. Even if no user is currently logged-on, we 841 // can't support remote-access to the login screen because the current host 842 // process model disconnects the client during login, which would leave 843 // the logged in session un-curtained on the console until they reconnect. 844 // 845 // TODO(jamiewalch): Fix this once we have implemented the multi-process 846 // daemon architecture (crbug.com/134894) 847 if (getuid() == 0) { 848 LOG(ERROR) << "Running the host in the console login session is yet not " 849 "supported."; 850 ShutdownHost(kLoginScreenNotSupportedExitCode); 851 return; 852 } 853 } 854#endif 855 856 if (curtain_required_ != curtain_required) { 857 if (curtain_required) 858 LOG(INFO) << "Policy requires curtain-mode."; 859 else 860 LOG(INFO) << "Policy does not require curtain-mode."; 861 curtain_required_ = curtain_required; 862 if (host_) 863 host_->SetEnableCurtaining(curtain_required_); 864 } 865} 866 867bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate( 868 const std::string& talkgadget_prefix) { 869 // Returns true if the host has to be restarted after this policy update. 870 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 871 872 if (talkgadget_prefix != talkgadget_prefix_) { 873 LOG(INFO) << "Policy sets talkgadget prefix: " << talkgadget_prefix; 874 talkgadget_prefix_ = talkgadget_prefix; 875 return true; 876 } 877 return false; 878} 879 880bool HostProcess::OnHostTokenUrlPolicyUpdate( 881 const GURL& token_url, 882 const GURL& token_validation_url) { 883 // Returns true if the host has to be restarted after this policy update. 884 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 885 886 if (token_url_ != token_url || 887 token_validation_url_ != token_validation_url) { 888 LOG(INFO) << "Policy sets third-party token URLs: " 889 << "TokenUrl: " << token_url << ", " 890 << "TokenValidationUrl: " << token_validation_url; 891 892 token_url_ = token_url; 893 token_validation_url_ = token_validation_url; 894 return true; 895 } 896 897 return false; 898} 899 900void HostProcess::StartHost() { 901 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 902 DCHECK(!host_); 903 DCHECK(!signal_strategy_.get()); 904 DCHECK(state_ == HOST_INITIALIZING || state_ == HOST_STOPPING_TO_RESTART || 905 state_ == HOST_STOPPED) << state_; 906 state_ = HOST_STARTED; 907 908 signal_strategy_.reset( 909 new XmppSignalStrategy(context_->url_request_context_getter(), 910 xmpp_login_, xmpp_auth_token_, 911 xmpp_auth_service_, xmpp_server_config_)); 912 913 scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker( 914 new DnsBlackholeChecker(context_->url_request_context_getter(), 915 talkgadget_prefix_)); 916 917 // Create a NetworkChangeNotifier for use by the signaling connector. 918 network_change_notifier_.reset(net::NetworkChangeNotifier::Create()); 919 920 signaling_connector_.reset(new SignalingConnector( 921 signal_strategy_.get(), 922 context_->url_request_context_getter(), 923 dns_blackhole_checker.Pass(), 924 base::Bind(&HostProcess::OnAuthFailed, this))); 925 926 if (!oauth_refresh_token_.empty()) { 927 scoped_ptr<SignalingConnector::OAuthCredentials> oauth_credentials( 928 new SignalingConnector::OAuthCredentials( 929 xmpp_login_, oauth_refresh_token_)); 930 signaling_connector_->EnableOAuth(oauth_credentials.Pass()); 931 } 932 933 NetworkSettings network_settings( 934 allow_nat_traversal_ ? 935 NetworkSettings::NAT_TRAVERSAL_ENABLED : 936 NetworkSettings::NAT_TRAVERSAL_DISABLED); 937 if (!allow_nat_traversal_) { 938 network_settings.min_port = NetworkSettings::kDefaultMinPort; 939 network_settings.max_port = NetworkSettings::kDefaultMaxPort; 940 } 941 942 host_.reset(new ChromotingHost( 943 signal_strategy_.get(), 944 desktop_environment_factory_.get(), 945 CreateHostSessionManager(network_settings, 946 context_->url_request_context_getter()), 947 context_->audio_task_runner(), 948 context_->input_task_runner(), 949 context_->video_capture_task_runner(), 950 context_->video_encode_task_runner(), 951 context_->network_task_runner(), 952 context_->ui_task_runner())); 953 954 // TODO(simonmorris): Get the maximum session duration from a policy. 955#if defined(OS_LINUX) 956 host_->SetMaximumSessionDuration(base::TimeDelta::FromHours(20)); 957#endif 958 959 heartbeat_sender_.reset(new HeartbeatSender( 960 this, host_id_, signal_strategy_.get(), key_pair_, 961 directory_bot_jid_)); 962 963 host_status_sender_.reset(new HostStatusSender( 964 host_id_, signal_strategy_.get(), key_pair_, directory_bot_jid_)); 965 966 host_change_notification_listener_.reset(new HostChangeNotificationListener( 967 this, host_id_, signal_strategy_.get(), directory_bot_jid_)); 968 969 log_to_server_.reset( 970 new LogToServer(host_->AsWeakPtr(), ServerLogEntry::ME2ME, 971 signal_strategy_.get(), directory_bot_jid_)); 972 973 // Set up repoting the host status notifications. 974#if defined(REMOTING_MULTI_PROCESS) 975 host_event_logger_.reset( 976 new IpcHostEventLogger(host_->AsWeakPtr(), daemon_channel_.get())); 977#else // !defined(REMOTING_MULTI_PROCESS) 978 host_event_logger_ = 979 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName); 980#endif // !defined(REMOTING_MULTI_PROCESS) 981 982 host_->SetEnableCurtaining(curtain_required_); 983 host_->Start(xmpp_login_); 984 985 CreateAuthenticatorFactory(); 986} 987 988void HostProcess::OnAuthFailed() { 989 ShutdownHost(kInvalidOauthCredentialsExitCode); 990} 991 992void HostProcess::RestartHost() { 993 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 994 DCHECK_EQ(state_, HOST_STARTED); 995 996 state_ = HOST_STOPPING_TO_RESTART; 997 ShutdownOnNetworkThread(); 998} 999 1000void HostProcess::ShutdownHost(HostExitCodes exit_code) { 1001 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1002 1003 *exit_code_out_ = exit_code; 1004 1005 switch (state_) { 1006 case HOST_INITIALIZING: 1007 case HOST_STARTED: 1008 state_ = HOST_STOPPING; 1009 host_status_sender_->SendOfflineStatus(exit_code); 1010 ScheduleHostShutdown(); 1011 break; 1012 1013 case HOST_STOPPING_TO_RESTART: 1014 state_ = HOST_STOPPING; 1015 break; 1016 1017 case HOST_STOPPING: 1018 case HOST_STOPPED: 1019 // Host is already stopped or being stopped. No action is required. 1020 break; 1021 } 1022} 1023 1024// TODO(weitaosu): shut down the host once we get an ACK for the offline status 1025// XMPP message. 1026void HostProcess::ScheduleHostShutdown() { 1027 // Delay the shutdown by 2 second to allow SendOfflineStatus to complete. 1028 context_->network_task_runner()->PostDelayedTask( 1029 FROM_HERE, 1030 base::Bind(&HostProcess::ShutdownOnNetworkThread, base::Unretained(this)), 1031 base::TimeDelta::FromSeconds(2)); 1032} 1033 1034void HostProcess::ShutdownOnNetworkThread() { 1035 DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); 1036 1037 host_.reset(); 1038 host_event_logger_.reset(); 1039 log_to_server_.reset(); 1040 heartbeat_sender_.reset(); 1041 host_status_sender_.reset(); 1042 host_change_notification_listener_.reset(); 1043 signaling_connector_.reset(); 1044 signal_strategy_.reset(); 1045 network_change_notifier_.reset(); 1046 1047 if (state_ == HOST_STOPPING_TO_RESTART) { 1048 StartHost(); 1049 } else if (state_ == HOST_STOPPING) { 1050 state_ = HOST_STOPPED; 1051 1052 if (policy_watcher_.get()) { 1053 base::WaitableEvent done_event(true, false); 1054 policy_watcher_->StopWatching(&done_event); 1055 done_event.Wait(); 1056 policy_watcher_.reset(); 1057 } 1058 1059 config_watcher_.reset(); 1060 1061 // Complete the rest of shutdown on the main thread. 1062 context_->ui_task_runner()->PostTask( 1063 FROM_HERE, 1064 base::Bind(&HostProcess::ShutdownOnUiThread, this)); 1065 } else { 1066 // This method is only called in STOPPING_TO_RESTART and STOPPING states. 1067 NOTREACHED(); 1068 } 1069} 1070 1071void HostProcess::OnCrash(const std::string& function_name, 1072 const std::string& file_name, 1073 const int& line_number) { 1074 char message[1024]; 1075 base::snprintf(message, sizeof(message), 1076 "Requested by %s at %s, line %d.", 1077 function_name.c_str(), file_name.c_str(), line_number); 1078 base::debug::Alias(message); 1079 1080 // The daemon requested us to crash the process. 1081 CHECK(false) << message; 1082} 1083 1084int HostProcessMain() { 1085#if defined(TOOLKIT_GTK) 1086 // Required for any calls into GTK functions, such as the Disconnect and 1087 // Continue windows, though these should not be used for the Me2Me case 1088 // (crbug.com/104377). 1089 gfx::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess()); 1090#endif // TOOLKIT_GTK 1091 1092 // Enable support for SSL server sockets, which must be done while still 1093 // single-threaded. 1094 net::EnableSSLServerSockets(); 1095 1096 // Ensures runtime specific CPU features are initialized. 1097 media::InitializeCPUSpecificMediaFeatures(); 1098 1099 // Create the main message loop and start helper threads. 1100 base::MessageLoop message_loop(base::MessageLoop::TYPE_UI); 1101 scoped_ptr<ChromotingHostContext> context = 1102 ChromotingHostContext::Create(new AutoThreadTaskRunner( 1103 message_loop.message_loop_proxy(), base::MessageLoop::QuitClosure())); 1104 if (!context) 1105 return kInitializationFailed; 1106 1107 // Create & start the HostProcess using these threads. 1108 // TODO(wez): The HostProcess holds a reference to itself until Shutdown(). 1109 // Remove this hack as part of the multi-process refactoring. 1110 int exit_code = kSuccessExitCode; 1111 new HostProcess(context.Pass(), &exit_code); 1112 1113 // Run the main (also UI) message loop until the host no longer needs it. 1114 message_loop.Run(); 1115 1116 return exit_code; 1117} 1118 1119} // namespace remoting 1120 1121#if !defined(OS_WIN) 1122int main(int argc, char** argv) { 1123 return remoting::HostMain(argc, argv); 1124} 1125#endif // !defined(OS_WIN) 1126