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.
5 // This file implements a standalone host process for Me2Me.
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/memory/scoped_ptr.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/synchronization/waitable_event.h"
23 #include "base/threading/thread.h"
24 #include "build/build_config.h"
25 #include "crypto/nss_util.h"
26 #include "ipc/ipc_channel.h"
27 #include "ipc/ipc_channel_proxy.h"
28 #include "ipc/ipc_listener.h"
29 #include "media/base/media.h"
30 #include "net/base/network_change_notifier.h"
31 #include "net/socket/client_socket_factory.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/logging.h"
38 #include "remoting/base/rsa_key_pair.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/config_watcher.h"
45 #include "remoting/host/desktop_environment.h"
46 #include "remoting/host/desktop_session_connector.h"
47 #include "remoting/host/dns_blackhole_checker.h"
48 #include "remoting/host/heartbeat_sender.h"
49 #include "remoting/host/host_change_notification_listener.h"
50 #include "remoting/host/host_config.h"
51 #include "remoting/host/host_event_logger.h"
52 #include "remoting/host/host_exit_codes.h"
53 #include "remoting/host/host_main.h"
54 #include "remoting/host/host_status_sender.h"
55 #include "remoting/host/ipc_constants.h"
56 #include "remoting/host/ipc_desktop_environment.h"
57 #include "remoting/host/ipc_host_event_logger.h"
58 #include "remoting/host/json_host_config.h"
59 #include "remoting/host/log_to_server.h"
60 #include "remoting/host/logging.h"
61 #include "remoting/host/me2me_desktop_environment.h"
62 #include "remoting/host/pairing_registry_delegate.h"
63 #include "remoting/host/policy_hack/policy_watcher.h"
64 #include "remoting/host/service_urls.h"
65 #include "remoting/host/session_manager_factory.h"
66 #include "remoting/host/signaling_connector.h"
67 #include "remoting/host/token_validator_factory_impl.h"
68 #include "remoting/host/usage_stats_consent.h"
69 #include "remoting/host/username.h"
70 #include "remoting/jingle_glue/network_settings.h"
71 #include "remoting/jingle_glue/xmpp_signal_strategy.h"
72 #include "remoting/protocol/me2me_host_authenticator_factory.h"
73 #include "remoting/protocol/pairing_registry.h"
77 #include <sys/types.h>
79 #include "base/file_descriptor_posix.h"
80 #include "remoting/host/pam_authorization_factory_posix.h"
81 #include "remoting/host/posix/signal_handler.h"
82 #endif // defined(OS_POSIX)
84 #if defined(OS_MACOSX)
85 #include "base/mac/scoped_cftyperef.h"
86 #endif // defined(OS_MACOSX)
89 #include "remoting/host/audio_capturer_linux.h"
90 #endif // defined(OS_LINUX)
94 #include "base/win/registry.h"
95 #include "base/win/scoped_handle.h"
96 #include "remoting/host/pairing_registry_delegate_win.h"
97 #include "remoting/host/win/session_desktop_environment.h"
98 #endif // defined(OS_WIN)
100 #if defined(TOOLKIT_GTK)
101 #include "ui/gfx/gtk_util.h"
102 #endif // defined(TOOLKIT_GTK)
104 using remoting::protocol::PairingRegistry;
108 // This is used for tagging system event logs.
109 const char kApplicationName[] = "chromoting";
111 #if defined(OS_LINUX)
112 // The command line switch used to pass name of the pipe to capture audio on
114 const char kAudioPipeSwitchName[] = "audio-pipe-name";
115 #endif // defined(OS_LINUX)
117 // The command line switch used by the parent to request the host to signal it
118 // when it is successfully started.
119 const char kSignalParentSwitchName[] = "signal-parent";
121 // Value used for --host-config option to indicate that the path must be read
123 const char kStdinConfigPath[] = "-";
130 : public ConfigWatcher::Delegate,
131 public HeartbeatSender::Listener,
132 public HostChangeNotificationListener::Listener,
133 public IPC::Listener,
134 public base::RefCountedThreadSafe<HostProcess> {
136 HostProcess(scoped_ptr<ChromotingHostContext> context,
139 // ConfigWatcher::Delegate interface.
140 virtual void OnConfigUpdated(const std::string& serialized_config) OVERRIDE;
141 virtual void OnConfigWatcherError() OVERRIDE;
143 // IPC::Listener implementation.
144 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
145 virtual void OnChannelError() OVERRIDE;
147 // HeartbeatSender::Listener overrides.
148 virtual void OnHeartbeatSuccessful() OVERRIDE;
149 virtual void OnUnknownHostIdError() OVERRIDE;
151 // HostChangeNotificationListener::Listener overrides.
152 virtual void OnHostDeleted() OVERRIDE;
154 // Initializes the pairing registry on Windows.
155 void OnInitializePairingRegistry(
156 IPC::PlatformFileForTransit privileged_key,
157 IPC::PlatformFileForTransit unprivileged_key);
161 // Host process has just been started. Waiting for config and policies to be
162 // read from the disk.
165 // Host is started and running.
168 // Host is being stopped and will need to be started again.
169 HOST_STOPPING_TO_RESTART,
171 // Host is being stopped.
174 // Host has been stopped.
177 // Allowed state transitions:
178 // INITIALIZING->STARTED
179 // INITIALIZING->STOPPED
180 // STARTED->STOPPING_TO_RESTART
182 // STOPPING_TO_RESTART->STARTED
183 // STOPPING_TO_RESTART->STOPPING
187 // |host_| must be NULL in INITIALIZING and STOPPED states and not-NULL in
191 friend class base::RefCountedThreadSafe<HostProcess>;
192 virtual ~HostProcess();
194 void StartOnNetworkThread();
196 #if defined(OS_POSIX)
197 // Callback passed to RegisterSignalHandler() to handle SIGTERM events.
198 void SigTermHandler(int signal_number);
201 // Called to initialize resources on the UI thread.
202 void StartOnUiThread();
204 // Initializes IPC control channel and config file path from |cmd_line|.
205 // Called on the UI thread.
206 bool InitWithCommandLine(const CommandLine* cmd_line);
208 // Called on the UI thread to start monitoring the configuration file.
209 void StartWatchingConfigChanges();
211 // Called on the network thread to set the host's Authenticator factory.
212 void CreateAuthenticatorFactory();
214 // Tear down resources that run on the UI thread.
215 void ShutdownOnUiThread();
217 // Applies the host config, returning true if successful.
218 bool ApplyConfig(scoped_ptr<JsonHostConfig> config);
220 void OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies);
221 bool OnHostDomainPolicyUpdate(const std::string& host_domain);
222 bool OnUsernamePolicyUpdate(bool curtain_required,
223 bool username_match_required);
224 bool OnNatPolicyUpdate(bool nat_traversal_enabled);
225 void OnCurtainPolicyUpdate(bool curtain_required);
226 bool OnHostTalkGadgetPrefixPolicyUpdate(const std::string& talkgadget_prefix);
227 bool OnHostTokenUrlPolicyUpdate(
228 const GURL& token_url,
229 const GURL& token_validation_url,
230 const std::string& token_validation_cert_issuer);
231 bool OnPairingPolicyUpdate(bool pairing_enabled);
239 // Stops the host and shuts down the process with the specified |exit_code|.
240 void ShutdownHost(HostExitCodes exit_code);
242 void ScheduleHostShutdown();
244 void ShutdownOnNetworkThread();
246 // Crashes the process in response to a daemon's request. The daemon passes
247 // the location of the code that detected the fatal error resulted in this
249 void OnCrash(const std::string& function_name,
250 const std::string& file_name,
251 const int& line_number);
253 scoped_ptr<ChromotingHostContext> context_;
255 // Created on the UI thread but used from the network thread.
256 scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
258 // Accessed on the UI thread.
259 scoped_ptr<IPC::ChannelProxy> daemon_channel_;
261 // XMPP server/remoting bot configuration (initialized from the command line).
262 XmppSignalStrategy::XmppServerConfig xmpp_server_config_;
263 std::string directory_bot_jid_;
265 // Created on the UI thread but used from the network thread.
266 base::FilePath host_config_path_;
267 std::string host_config_;
268 scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_;
270 // Accessed on the network thread.
273 scoped_ptr<ConfigWatcher> config_watcher_;
275 std::string host_id_;
276 protocol::SharedSecretHash host_secret_hash_;
277 scoped_refptr<RsaKeyPair> key_pair_;
278 std::string oauth_refresh_token_;
279 std::string serialized_config_;
280 std::string host_owner_;
281 bool use_service_account_;
282 scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
283 bool allow_nat_traversal_;
284 std::string talkgadget_prefix_;
287 bool curtain_required_;
288 ThirdPartyAuthConfig third_party_auth_config_;
290 scoped_ptr<OAuthTokenGetter> oauth_token_getter_;
291 scoped_ptr<XmppSignalStrategy> signal_strategy_;
292 scoped_ptr<SignalingConnector> signaling_connector_;
293 scoped_ptr<HeartbeatSender> heartbeat_sender_;
294 scoped_ptr<HostStatusSender> host_status_sender_;
295 scoped_ptr<HostChangeNotificationListener> host_change_notification_listener_;
296 scoped_ptr<LogToServer> log_to_server_;
297 scoped_ptr<HostEventLogger> host_event_logger_;
299 scoped_ptr<ChromotingHost> host_;
301 // Used to keep this HostProcess alive until it is shutdown.
302 scoped_refptr<HostProcess> self_;
304 #if defined(REMOTING_MULTI_PROCESS)
305 DesktopSessionConnector* desktop_session_connector_;
306 #endif // defined(REMOTING_MULTI_PROCESS)
311 scoped_ptr<PairingRegistry::Delegate> pairing_registry_delegate_;
314 HostProcess::HostProcess(scoped_ptr<ChromotingHostContext> context,
316 : context_(context.Pass()),
317 state_(HOST_INITIALIZING),
318 use_service_account_(false),
319 allow_nat_traversal_(true),
320 allow_pairing_(true),
321 curtain_required_(false),
322 #if defined(REMOTING_MULTI_PROCESS)
323 desktop_session_connector_(NULL),
324 #endif // defined(REMOTING_MULTI_PROCESS)
326 exit_code_out_(exit_code_out),
327 signal_parent_(false) {
331 HostProcess::~HostProcess() {
332 // Verify that UI components have been torn down.
333 DCHECK(!config_watcher_);
334 DCHECK(!daemon_channel_);
335 DCHECK(!desktop_environment_factory_);
337 // We might be getting deleted on one of the threads the |host_context| owns,
338 // so we need to post it back to the caller thread to safely join & delete the
339 // threads it contains. This will go away when we move to AutoThread.
340 // |context_release()| will null |context_| before the method is invoked, so
341 // we need to pull out the task-runner on which to call DeleteSoon first.
342 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
343 context_->ui_task_runner();
344 task_runner->DeleteSoon(FROM_HERE, context_.release());
347 bool HostProcess::InitWithCommandLine(const CommandLine* cmd_line) {
348 #if defined(REMOTING_MULTI_PROCESS)
349 // Parse the handle value and convert it to a handle/file descriptor.
350 std::string channel_name =
351 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
354 if (channel_name.empty() ||
355 !base::StringToInt(channel_name, &pipe_handle)) {
356 LOG(ERROR) << "Invalid '" << kDaemonPipeSwitchName
357 << "' value: " << channel_name;
362 base::win::ScopedHandle pipe(reinterpret_cast<HANDLE>(pipe_handle));
363 IPC::ChannelHandle channel_handle(pipe);
364 #elif defined(OS_POSIX)
365 base::FileDescriptor pipe(pipe_handle, true);
366 IPC::ChannelHandle channel_handle(channel_name, pipe);
367 #endif // defined(OS_POSIX)
369 // Connect to the daemon process.
370 daemon_channel_.reset(new IPC::ChannelProxy(
372 IPC::Channel::MODE_CLIENT,
374 context_->network_task_runner()));
375 #else // !defined(REMOTING_MULTI_PROCESS)
376 // Connect to the daemon process.
377 std::string channel_name =
378 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
379 if (!channel_name.empty()) {
380 daemon_channel_.reset(
381 new IPC::ChannelProxy(channel_name,
382 IPC::Channel::MODE_CLIENT,
384 context_->network_task_runner().get()));
387 if (cmd_line->HasSwitch(kHostConfigSwitchName)) {
388 host_config_path_ = cmd_line->GetSwitchValuePath(kHostConfigSwitchName);
390 // Read config from stdin if necessary.
391 if (host_config_path_ == base::FilePath(kStdinConfigPath)) {
394 while ((len = fread(buf, 1, sizeof(buf), stdin)) > 0) {
395 host_config_.append(buf, len);
399 base::FilePath default_config_dir = remoting::GetConfigDir();
400 host_config_path_ = default_config_dir.Append(kDefaultHostConfigFile);
403 if (host_config_path_ != base::FilePath(kStdinConfigPath) &&
404 !base::PathExists(host_config_path_)) {
405 LOG(ERROR) << "Can't find host config at " << host_config_path_.value();
408 #endif // !defined(REMOTING_MULTI_PROCESS)
410 // Ignore certificate requests - the host currently has no client certificate
411 // support, so ignoring certificate requests allows connecting to servers that
412 // request, but don't require, a certificate (optional client authentication).
413 net::URLFetcher::SetIgnoreCertificateRequests(true);
415 ServiceUrls* service_urls = ServiceUrls::GetInstance();
416 bool xmpp_server_valid = net::ParseHostAndPort(
417 service_urls->xmpp_server_address(),
418 &xmpp_server_config_.host, &xmpp_server_config_.port);
419 if (!xmpp_server_valid) {
420 LOG(ERROR) << "Invalid XMPP server: " <<
421 service_urls->xmpp_server_address();
424 xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls();
425 directory_bot_jid_ = service_urls->directory_bot_jid();
427 signal_parent_ = cmd_line->HasSwitch(kSignalParentSwitchName);
432 void HostProcess::OnConfigUpdated(
433 const std::string& serialized_config) {
434 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
435 context_->network_task_runner()->PostTask(FROM_HERE,
436 base::Bind(&HostProcess::OnConfigUpdated, this, serialized_config));
440 // Filter out duplicates.
441 if (serialized_config_ == serialized_config)
444 HOST_LOG << "Processing new host configuration.";
446 serialized_config_ = serialized_config;
447 scoped_ptr<JsonHostConfig> config(new JsonHostConfig(base::FilePath()));
448 if (!config->SetSerializedData(serialized_config)) {
449 LOG(ERROR) << "Invalid configuration.";
450 ShutdownHost(kInvalidHostConfigurationExitCode);
454 if (!ApplyConfig(config.Pass())) {
455 LOG(ERROR) << "Failed to apply the configuration.";
456 ShutdownHost(kInvalidHostConfigurationExitCode);
460 if (state_ == HOST_INITIALIZING) {
461 // TODO(sergeyu): Currently OnPolicyUpdate() assumes that host config is
462 // already loaded so PolicyWatcher has to be started here. Separate policy
463 // loading from policy verifications and move |policy_watcher_|
464 // initialization to StartOnNetworkThread().
465 policy_watcher_.reset(
466 policy_hack::PolicyWatcher::Create(context_->file_task_runner()));
467 policy_watcher_->StartWatching(
468 base::Bind(&HostProcess::OnPolicyUpdate, base::Unretained(this)));
469 } else if (state_ == HOST_STARTED) {
470 // TODO(sergeyu): Here we assume that PIN is the only part of the config
471 // that may change while the service is running. Change ApplyConfig() to
472 // detect other changes in the config and restart host if necessary here.
473 CreateAuthenticatorFactory();
477 void HostProcess::OnConfigWatcherError() {
478 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
479 ShutdownHost(kInvalidHostConfigurationExitCode);
482 void HostProcess::StartOnNetworkThread() {
483 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
485 #if !defined(REMOTING_MULTI_PROCESS)
486 if (host_config_path_ == base::FilePath(kStdinConfigPath)) {
487 // Process config we've read from stdin.
488 OnConfigUpdated(host_config_);
490 // Start watching the host configuration file.
491 config_watcher_.reset(new ConfigFileWatcher(context_->network_task_runner(),
492 context_->file_task_runner(),
494 config_watcher_->Watch(this);
496 #endif // !defined(REMOTING_MULTI_PROCESS)
498 #if defined(OS_POSIX)
499 remoting::RegisterSignalHandler(
501 base::Bind(&HostProcess::SigTermHandler, base::Unretained(this)));
502 #endif // defined(OS_POSIX)
505 #if defined(OS_POSIX)
506 void HostProcess::SigTermHandler(int signal_number) {
507 DCHECK(signal_number == SIGTERM);
508 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
509 HOST_LOG << "Caught SIGTERM: Shutting down...";
510 ShutdownHost(kSuccessExitCode);
514 void HostProcess::CreateAuthenticatorFactory() {
515 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
517 if (state_ != HOST_STARTED)
520 std::string local_certificate = key_pair_->GenerateCertificate();
521 if (local_certificate.empty()) {
522 LOG(ERROR) << "Failed to generate host certificate.";
523 ShutdownHost(kInitializationFailed);
527 scoped_refptr<PairingRegistry> pairing_registry = NULL;
528 if (allow_pairing_) {
529 if (!pairing_registry_delegate_)
530 pairing_registry_delegate_ = CreatePairingRegistryDelegate();
532 if (pairing_registry_delegate_) {
533 pairing_registry = new PairingRegistry(context_->file_task_runner(),
534 pairing_registry_delegate_.Pass());
538 scoped_ptr<protocol::AuthenticatorFactory> factory;
540 if (third_party_auth_config_.is_empty()) {
541 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
542 use_service_account_, host_owner_, local_certificate, key_pair_,
543 host_secret_hash_, pairing_registry);
545 } else if (third_party_auth_config_.is_valid()) {
546 scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidatorFactory>
547 token_validator_factory(new TokenValidatorFactoryImpl(
548 third_party_auth_config_,
549 key_pair_, context_->url_request_context_getter()));
550 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
551 use_service_account_, host_owner_, local_certificate, key_pair_,
552 token_validator_factory.Pass());
555 // TODO(rmsousa): If the policy is bad the host should not go online. It
556 // should keep running, but not connected, until the policies are fixed.
557 // Having it show up as online and then reject all clients is misleading.
558 LOG(ERROR) << "One of the third-party token URLs is empty or invalid. "
559 << "Host will reject all clients until policies are corrected. "
560 << "TokenUrl: " << third_party_auth_config_.token_url << ", "
561 << "TokenValidationUrl: "
562 << third_party_auth_config_.token_validation_url;
563 factory = protocol::Me2MeHostAuthenticatorFactory::CreateRejecting();
566 #if defined(OS_POSIX)
567 // On Linux and Mac, perform a PAM authorization step after authentication.
568 factory.reset(new PamAuthorizationFactory(factory.Pass()));
570 host_->SetAuthenticatorFactory(factory.Pass());
572 host_->set_pairing_registry(pairing_registry);
575 // IPC::Listener implementation.
576 bool HostProcess::OnMessageReceived(const IPC::Message& message) {
577 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
579 #if defined(REMOTING_MULTI_PROCESS)
581 IPC_BEGIN_MESSAGE_MAP(HostProcess, message)
582 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash)
583 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Configuration,
585 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_InitializePairingRegistry,
586 OnInitializePairingRegistry)
588 ChromotingDaemonNetworkMsg_DesktopAttached,
589 desktop_session_connector_,
590 DesktopSessionConnector::OnDesktopSessionAgentAttached)
591 IPC_MESSAGE_FORWARD(ChromotingDaemonNetworkMsg_TerminalDisconnected,
592 desktop_session_connector_,
593 DesktopSessionConnector::OnTerminalDisconnected)
594 IPC_MESSAGE_UNHANDLED(handled = false)
595 IPC_END_MESSAGE_MAP()
597 CHECK(handled) << "Received unexpected IPC type: " << message.type();
600 #else // !defined(REMOTING_MULTI_PROCESS)
602 #endif // !defined(REMOTING_MULTI_PROCESS)
605 void HostProcess::OnChannelError() {
606 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
608 // Shutdown the host if the daemon process disconnects the IPC channel.
609 context_->network_task_runner()->PostTask(
611 base::Bind(&HostProcess::ShutdownHost, this, kSuccessExitCode));
614 void HostProcess::StartOnUiThread() {
615 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
617 if (!InitWithCommandLine(CommandLine::ForCurrentProcess())) {
618 // Shutdown the host if the command line is invalid.
619 context_->network_task_runner()->PostTask(
620 FROM_HERE, base::Bind(&HostProcess::ShutdownHost, this,
625 #if defined(OS_LINUX)
626 // If an audio pipe is specific on the command-line then initialize
627 // AudioCapturerLinux to capture from it.
628 base::FilePath audio_pipe_name = CommandLine::ForCurrentProcess()->
629 GetSwitchValuePath(kAudioPipeSwitchName);
630 if (!audio_pipe_name.empty()) {
631 remoting::AudioCapturerLinux::InitializePipeReader(
632 context_->audio_task_runner(), audio_pipe_name);
634 #endif // defined(OS_LINUX)
636 // Create a desktop environment factory appropriate to the build type &
639 IpcDesktopEnvironmentFactory* desktop_environment_factory =
640 new IpcDesktopEnvironmentFactory(
641 context_->audio_task_runner(),
642 context_->network_task_runner(),
643 context_->video_capture_task_runner(),
644 context_->network_task_runner(),
645 daemon_channel_.get());
646 desktop_session_connector_ = desktop_environment_factory;
647 #else // !defined(OS_WIN)
648 DesktopEnvironmentFactory* desktop_environment_factory =
649 new Me2MeDesktopEnvironmentFactory(
650 context_->network_task_runner(),
651 context_->input_task_runner(),
652 context_->ui_task_runner());
653 #endif // !defined(OS_WIN)
655 desktop_environment_factory_.reset(desktop_environment_factory);
657 context_->network_task_runner()->PostTask(
659 base::Bind(&HostProcess::StartOnNetworkThread, this));
662 void HostProcess::ShutdownOnUiThread() {
663 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
665 // Tear down resources that need to be torn down on the UI thread.
666 network_change_notifier_.reset();
667 daemon_channel_.reset();
668 desktop_environment_factory_.reset();
670 // It is now safe for the HostProcess to be deleted.
673 #if defined(OS_LINUX)
674 // Cause the global AudioPipeReader to be freed, otherwise the audio
675 // thread will remain in-use and prevent the process from exiting.
676 // TODO(wez): DesktopEnvironmentFactory should own the pipe reader.
677 // See crbug.com/161373 and crbug.com/104544.
678 AudioCapturerLinux::InitializePipeReader(NULL, base::FilePath());
682 // Overridden from HeartbeatSender::Listener
683 void HostProcess::OnUnknownHostIdError() {
684 LOG(ERROR) << "Host ID not found.";
685 ShutdownHost(kInvalidHostIdExitCode);
688 void HostProcess::OnHeartbeatSuccessful() {
689 HOST_LOG << "Host ready to receive connections.";
690 #if defined(OS_POSIX)
691 if (signal_parent_) {
692 kill(getppid(), SIGUSR1);
693 signal_parent_ = false;
698 void HostProcess::OnHostDeleted() {
699 LOG(ERROR) << "Host was deleted from the directory.";
700 ShutdownHost(kInvalidHostIdExitCode);
703 void HostProcess::OnInitializePairingRegistry(
704 IPC::PlatformFileForTransit privileged_key,
705 IPC::PlatformFileForTransit unprivileged_key) {
706 DCHECK(!pairing_registry_delegate_);
709 // Initialize the pairing registry delegate.
710 scoped_ptr<PairingRegistryDelegateWin> delegate(
711 new PairingRegistryDelegateWin());
712 bool result = delegate->SetRootKeys(
713 reinterpret_cast<HKEY>(
714 IPC::PlatformFileForTransitToPlatformFile(privileged_key)),
715 reinterpret_cast<HKEY>(
716 IPC::PlatformFileForTransitToPlatformFile(unprivileged_key)));
720 pairing_registry_delegate_ = delegate.PassAs<PairingRegistry::Delegate>();
721 #else // !defined(OS_WIN)
723 #endif // !defined(OS_WIN)
726 // Applies the host config, returning true if successful.
727 bool HostProcess::ApplyConfig(scoped_ptr<JsonHostConfig> config) {
728 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
730 if (!config->GetString(kHostIdConfigPath, &host_id_)) {
731 LOG(ERROR) << "host_id is not defined in the config.";
735 std::string key_base64;
736 if (!config->GetString(kPrivateKeyConfigPath, &key_base64)) {
737 LOG(ERROR) << "Private key couldn't be read from the config file.";
741 key_pair_ = RsaKeyPair::FromString(key_base64);
742 if (!key_pair_.get()) {
743 LOG(ERROR) << "Invalid private key in the config file.";
747 std::string host_secret_hash_string;
748 if (!config->GetString(kHostSecretHashConfigPath,
749 &host_secret_hash_string)) {
750 host_secret_hash_string = "plain:";
753 if (!host_secret_hash_.Parse(host_secret_hash_string)) {
754 LOG(ERROR) << "Invalid host_secret_hash.";
758 // Use an XMPP connection to the Talk network for session signalling.
759 if (!config->GetString(kXmppLoginConfigPath, &xmpp_server_config_.username) ||
760 !(config->GetString(kXmppAuthTokenConfigPath,
761 &xmpp_server_config_.auth_token) ||
762 config->GetString(kOAuthRefreshTokenConfigPath,
763 &oauth_refresh_token_))) {
764 LOG(ERROR) << "XMPP credentials are not defined in the config.";
768 if (!oauth_refresh_token_.empty()) {
769 // SignalingConnector is responsible for getting OAuth token.
770 xmpp_server_config_.auth_token = "";
771 xmpp_server_config_.auth_service = "oauth2";
772 } else if (!config->GetString(kXmppAuthServiceConfigPath,
773 &xmpp_server_config_.auth_service)) {
774 // For the me2me host, we default to ClientLogin token for chromiumsync
775 // because earlier versions of the host had no HTTP stack with which to
776 // request an OAuth2 access token.
777 xmpp_server_config_.auth_service = kChromotingTokenDefaultServiceName;
780 if (config->GetString(kHostOwnerConfigPath, &host_owner_)) {
781 // Service account configs have a host_owner, different from the xmpp_login.
782 use_service_account_ = true;
784 // User credential configs only have an xmpp_login, which is also the owner.
785 host_owner_ = xmpp_server_config_.username;
786 use_service_account_ = false;
791 void HostProcess::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) {
792 // TODO(rmsousa): Consolidate all On*PolicyUpdate methods into this one.
793 // TODO(sergeyu): Currently polices are verified only when they are loaded.
794 // Separate policy loading from policy verifications - this will allow to
795 // check policies again later, e.g. when host config changes.
797 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
798 context_->network_task_runner()->PostTask(FROM_HERE, base::Bind(
799 &HostProcess::OnPolicyUpdate, this, base::Passed(&policies)));
803 bool restart_required = false;
805 std::string string_value;
806 if (policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName,
808 restart_required |= OnHostDomainPolicyUpdate(string_value);
810 bool curtain_required = false;
811 if (policies->GetBoolean(
812 policy_hack::PolicyWatcher::kHostRequireCurtainPolicyName,
813 &curtain_required)) {
814 OnCurtainPolicyUpdate(curtain_required);
816 if (policies->GetBoolean(
817 policy_hack::PolicyWatcher::kHostMatchUsernamePolicyName,
819 restart_required |= OnUsernamePolicyUpdate(curtain_required, bool_value);
821 if (policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName,
823 restart_required |= OnNatPolicyUpdate(bool_value);
825 if (policies->GetString(
826 policy_hack::PolicyWatcher::kHostTalkGadgetPrefixPolicyName,
828 restart_required |= OnHostTalkGadgetPrefixPolicyUpdate(string_value);
830 std::string token_url_string, token_validation_url_string;
831 std::string token_validation_cert_issuer;
832 if (policies->GetString(
833 policy_hack::PolicyWatcher::kHostTokenUrlPolicyName,
834 &token_url_string) &&
836 policy_hack::PolicyWatcher::kHostTokenValidationUrlPolicyName,
837 &token_validation_url_string) &&
839 policy_hack::PolicyWatcher::kHostTokenValidationCertIssuerPolicyName,
840 &token_validation_cert_issuer)) {
841 restart_required |= OnHostTokenUrlPolicyUpdate(
842 GURL(token_url_string), GURL(token_validation_url_string),
843 token_validation_cert_issuer);
845 if (policies->GetBoolean(
846 policy_hack::PolicyWatcher::kHostAllowClientPairing,
848 restart_required |= OnPairingPolicyUpdate(bool_value);
851 if (state_ == HOST_INITIALIZING) {
853 } else if (state_ == HOST_STARTED && restart_required) {
858 bool HostProcess::OnHostDomainPolicyUpdate(const std::string& host_domain) {
859 // Returns true if the host has to be restarted after this policy update.
860 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
862 HOST_LOG << "Policy sets host domain: " << host_domain;
864 if (!host_domain.empty() &&
865 !EndsWith(host_owner_, std::string("@") + host_domain, false)) {
866 ShutdownHost(kInvalidHostDomainExitCode);
871 bool HostProcess::OnUsernamePolicyUpdate(bool curtain_required,
872 bool host_username_match_required) {
873 // Returns false: never restart the host after this policy update.
874 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
876 if (host_username_match_required) {
877 HOST_LOG << "Policy requires host username match.";
878 std::string username = GetUsername();
879 bool shutdown = username.empty() ||
880 !StartsWithASCII(host_owner_, username + std::string("@"),
883 #if defined(OS_MACOSX)
884 // On Mac, we run as root at the login screen, so the username won't match.
885 // However, there's no need to enforce the policy at the login screen, as
886 // the client will have to reconnect if a login occurs.
887 if (shutdown && getuid() == 0) {
892 // Curtain-mode on Windows presents the standard OS login prompt to the user
893 // for each connection, removing the need for an explicit user-name matching
895 #if defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
896 if (curtain_required)
898 #endif // defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
900 // Shutdown the host if the username does not match.
902 LOG(ERROR) << "The host username does not match.";
903 ShutdownHost(kUsernameMismatchExitCode);
906 HOST_LOG << "Policy does not require host username match.";
912 bool HostProcess::OnNatPolicyUpdate(bool nat_traversal_enabled) {
913 // Returns true if the host has to be restarted after this policy update.
914 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
916 if (allow_nat_traversal_ != nat_traversal_enabled) {
917 if (nat_traversal_enabled)
918 HOST_LOG << "Policy enables NAT traversal.";
920 HOST_LOG << "Policy disables NAT traversal.";
921 allow_nat_traversal_ = nat_traversal_enabled;
927 void HostProcess::OnCurtainPolicyUpdate(bool curtain_required) {
928 // Returns true if the host has to be restarted after this policy update.
929 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
931 #if defined(OS_MACOSX)
932 if (curtain_required) {
933 // When curtain mode is in effect on Mac, the host process runs in the
934 // user's switched-out session, but launchd will also run an instance at
935 // the console login screen. Even if no user is currently logged-on, we
936 // can't support remote-access to the login screen because the current host
937 // process model disconnects the client during login, which would leave
938 // the logged in session un-curtained on the console until they reconnect.
940 // TODO(jamiewalch): Fix this once we have implemented the multi-process
941 // daemon architecture (crbug.com/134894)
943 LOG(ERROR) << "Running the host in the console login session is yet not "
945 ShutdownHost(kLoginScreenNotSupportedExitCode);
951 if (curtain_required_ != curtain_required) {
952 if (curtain_required)
953 HOST_LOG << "Policy requires curtain-mode.";
955 HOST_LOG << "Policy does not require curtain-mode.";
956 curtain_required_ = curtain_required;
958 host_->SetEnableCurtaining(curtain_required_);
962 bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate(
963 const std::string& talkgadget_prefix) {
964 // Returns true if the host has to be restarted after this policy update.
965 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
967 if (talkgadget_prefix != talkgadget_prefix_) {
968 HOST_LOG << "Policy sets talkgadget prefix: " << talkgadget_prefix;
969 talkgadget_prefix_ = talkgadget_prefix;
975 bool HostProcess::OnHostTokenUrlPolicyUpdate(
976 const GURL& token_url,
977 const GURL& token_validation_url,
978 const std::string& token_validation_cert_issuer) {
979 // Returns true if the host has to be restarted after this policy update.
980 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
982 if (third_party_auth_config_.token_url != token_url ||
983 third_party_auth_config_.token_validation_url != token_validation_url ||
984 third_party_auth_config_.token_validation_cert_issuer !=
985 token_validation_cert_issuer) {
986 HOST_LOG << "Policy sets third-party token URLs: "
987 << "TokenUrl: " << token_url << ", "
988 << "TokenValidationUrl: " << token_validation_url
989 << "TokenValidationCertificateIssuer: "
990 << token_validation_cert_issuer;
991 third_party_auth_config_.token_url = token_url;
992 third_party_auth_config_.token_validation_url = token_validation_url;
993 third_party_auth_config_.token_validation_cert_issuer =
994 token_validation_cert_issuer;
1001 bool HostProcess::OnPairingPolicyUpdate(bool allow_pairing) {
1002 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1004 if (allow_pairing_ == allow_pairing)
1008 HOST_LOG << "Policy enables client pairing.";
1010 HOST_LOG << "Policy disables client pairing.";
1011 allow_pairing_ = allow_pairing;
1015 void HostProcess::StartHost() {
1016 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1018 DCHECK(!signal_strategy_.get());
1019 DCHECK(state_ == HOST_INITIALIZING || state_ == HOST_STOPPING_TO_RESTART ||
1020 state_ == HOST_STOPPED) << state_;
1021 state_ = HOST_STARTED;
1023 signal_strategy_.reset(
1024 new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
1025 context_->url_request_context_getter(),
1026 xmpp_server_config_));
1028 scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker(
1029 new DnsBlackholeChecker(context_->url_request_context_getter(),
1030 talkgadget_prefix_));
1032 // Create a NetworkChangeNotifier for use by the signaling connector.
1033 network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
1035 signaling_connector_.reset(new SignalingConnector(
1036 signal_strategy_.get(),
1037 dns_blackhole_checker.Pass(),
1038 base::Bind(&HostProcess::OnAuthFailed, this)));
1040 if (!oauth_refresh_token_.empty()) {
1041 scoped_ptr<OAuthTokenGetter::OAuthCredentials> oauth_credentials;
1042 oauth_credentials.reset(
1043 new OAuthTokenGetter::OAuthCredentials(
1044 xmpp_server_config_.username, oauth_refresh_token_,
1045 use_service_account_));
1047 oauth_token_getter_.reset(new OAuthTokenGetter(
1048 oauth_credentials.Pass(), context_->url_request_context_getter()));
1050 signaling_connector_->EnableOAuth(oauth_token_getter_.get());
1053 NetworkSettings network_settings(
1054 allow_nat_traversal_ ?
1055 NetworkSettings::NAT_TRAVERSAL_ENABLED :
1056 NetworkSettings::NAT_TRAVERSAL_DISABLED);
1057 if (!allow_nat_traversal_) {
1058 network_settings.min_port = NetworkSettings::kDefaultMinPort;
1059 network_settings.max_port = NetworkSettings::kDefaultMaxPort;
1062 host_.reset(new ChromotingHost(
1063 signal_strategy_.get(),
1064 desktop_environment_factory_.get(),
1065 CreateHostSessionManager(signal_strategy_.get(), network_settings,
1066 context_->url_request_context_getter()),
1067 context_->audio_task_runner(),
1068 context_->input_task_runner(),
1069 context_->video_capture_task_runner(),
1070 context_->video_encode_task_runner(),
1071 context_->network_task_runner(),
1072 context_->ui_task_runner()));
1074 // TODO(simonmorris): Get the maximum session duration from a policy.
1075 #if defined(OS_LINUX)
1076 host_->SetMaximumSessionDuration(base::TimeDelta::FromHours(20));
1079 heartbeat_sender_.reset(new HeartbeatSender(
1080 this, host_id_, signal_strategy_.get(), key_pair_,
1081 directory_bot_jid_));
1083 host_status_sender_.reset(new HostStatusSender(
1084 host_id_, signal_strategy_.get(), key_pair_, directory_bot_jid_));
1086 host_change_notification_listener_.reset(new HostChangeNotificationListener(
1087 this, host_id_, signal_strategy_.get(), directory_bot_jid_));
1089 log_to_server_.reset(
1090 new LogToServer(host_->AsWeakPtr(), ServerLogEntry::ME2ME,
1091 signal_strategy_.get(), directory_bot_jid_));
1093 // Set up repoting the host status notifications.
1094 #if defined(REMOTING_MULTI_PROCESS)
1095 host_event_logger_.reset(
1096 new IpcHostEventLogger(host_->AsWeakPtr(), daemon_channel_.get()));
1097 #else // !defined(REMOTING_MULTI_PROCESS)
1098 host_event_logger_ =
1099 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName);
1100 #endif // !defined(REMOTING_MULTI_PROCESS)
1102 host_->SetEnableCurtaining(curtain_required_);
1103 host_->Start(host_owner_);
1105 CreateAuthenticatorFactory();
1108 void HostProcess::OnAuthFailed() {
1109 ShutdownHost(kInvalidOauthCredentialsExitCode);
1112 void HostProcess::RestartHost() {
1113 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1114 DCHECK_EQ(state_, HOST_STARTED);
1116 state_ = HOST_STOPPING_TO_RESTART;
1117 ShutdownOnNetworkThread();
1120 void HostProcess::ShutdownHost(HostExitCodes exit_code) {
1121 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1123 *exit_code_out_ = exit_code;
1126 case HOST_INITIALIZING:
1127 state_ = HOST_STOPPING;
1128 ShutdownOnNetworkThread();
1132 state_ = HOST_STOPPING;
1133 host_status_sender_->SendOfflineStatus(exit_code);
1134 ScheduleHostShutdown();
1137 case HOST_STOPPING_TO_RESTART:
1138 state_ = HOST_STOPPING;
1143 // Host is already stopped or being stopped. No action is required.
1148 // TODO(weitaosu): shut down the host once we get an ACK for the offline status
1150 void HostProcess::ScheduleHostShutdown() {
1151 // Delay the shutdown by 2 second to allow SendOfflineStatus to complete.
1152 context_->network_task_runner()->PostDelayedTask(
1154 base::Bind(&HostProcess::ShutdownOnNetworkThread, base::Unretained(this)),
1155 base::TimeDelta::FromSeconds(2));
1158 void HostProcess::ShutdownOnNetworkThread() {
1159 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1162 host_event_logger_.reset();
1163 log_to_server_.reset();
1164 heartbeat_sender_.reset();
1165 host_status_sender_.reset();
1166 host_change_notification_listener_.reset();
1167 signaling_connector_.reset();
1168 oauth_token_getter_.reset();
1169 signal_strategy_.reset();
1170 network_change_notifier_.reset();
1172 if (state_ == HOST_STOPPING_TO_RESTART) {
1174 } else if (state_ == HOST_STOPPING) {
1175 state_ = HOST_STOPPED;
1177 if (policy_watcher_.get()) {
1178 base::WaitableEvent done_event(true, false);
1179 policy_watcher_->StopWatching(&done_event);
1181 policy_watcher_.reset();
1184 config_watcher_.reset();
1186 // Complete the rest of shutdown on the main thread.
1187 context_->ui_task_runner()->PostTask(
1189 base::Bind(&HostProcess::ShutdownOnUiThread, this));
1191 // This method is only called in STOPPING_TO_RESTART and STOPPING states.
1196 void HostProcess::OnCrash(const std::string& function_name,
1197 const std::string& file_name,
1198 const int& line_number) {
1200 base::snprintf(message, sizeof(message),
1201 "Requested by %s at %s, line %d.",
1202 function_name.c_str(), file_name.c_str(), line_number);
1203 base::debug::Alias(message);
1205 // The daemon requested us to crash the process.
1206 CHECK(false) << message;
1209 int HostProcessMain() {
1210 #if defined(TOOLKIT_GTK)
1211 // Required for any calls into GTK functions, such as the Disconnect and
1212 // Continue windows, though these should not be used for the Me2Me case
1213 // (crbug.com/104377).
1214 gfx::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
1215 #endif // TOOLKIT_GTK
1217 // Enable support for SSL server sockets, which must be done while still
1219 net::EnableSSLServerSockets();
1221 // Ensures runtime specific CPU features are initialized.
1222 media::InitializeCPUSpecificMediaFeatures();
1224 // Create the main message loop and start helper threads.
1225 base::MessageLoopForUI message_loop;
1226 scoped_ptr<ChromotingHostContext> context =
1227 ChromotingHostContext::Create(new AutoThreadTaskRunner(
1228 message_loop.message_loop_proxy(), base::MessageLoop::QuitClosure()));
1230 return kInitializationFailed;
1232 // Create & start the HostProcess using these threads.
1233 // TODO(wez): The HostProcess holds a reference to itself until Shutdown().
1234 // Remove this hack as part of the multi-process refactoring.
1235 int exit_code = kSuccessExitCode;
1236 new HostProcess(context.Pass(), &exit_code);
1238 // Run the main (also UI) message loop until the host no longer needs it.
1244 } // namespace remoting
1246 #if !defined(OS_WIN)
1247 int main(int argc, char** argv) {
1248 return remoting::HostMain(argc, argv);
1250 #endif // !defined(OS_WIN)