Introduced IDR_SIGNIN_INTERNALS_INDEX_* strings to grit_whitelist.txt
[chromium-blink-merge.git] / remoting / host / remoting_me2me_host.cc
bloba2c1d94266403915dd1412951b92ce431351d8f7
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.
7 #include <string>
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/client_socket_factory.h"
33 #include "net/socket/ssl_server_socket.h"
34 #include "net/url_request/url_fetcher.h"
35 #include "remoting/base/auto_thread_task_runner.h"
36 #include "remoting/base/breakpad.h"
37 #include "remoting/base/constants.h"
38 #include "remoting/base/rsa_key_pair.h"
39 #include "remoting/base/util.h"
40 #include "remoting/host/branding.h"
41 #include "remoting/host/chromoting_host.h"
42 #include "remoting/host/chromoting_host_context.h"
43 #include "remoting/host/chromoting_messages.h"
44 #include "remoting/host/config_file_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/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"
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)
83 #if defined(OS_MACOSX)
84 #include "base/mac/scoped_cftyperef.h"
85 #endif // defined(OS_MACOSX)
87 #if defined(OS_LINUX)
88 #include "remoting/host/audio_capturer_linux.h"
89 #endif // defined(OS_LINUX)
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)
97 #if defined(TOOLKIT_GTK)
98 #include "ui/gfx/gtk_util.h"
99 #endif // defined(TOOLKIT_GTK)
101 // This is used for tagging system event logs.
102 const char kApplicationName[] = "chromoting";
104 #if defined(OS_LINUX)
105 // The command line switch used to pass name of the pipe to capture audio on
106 // linux.
107 const char kAudioPipeSwitchName[] = "audio-pipe-name";
108 #endif // defined(OS_LINUX)
110 // The command line switch used by the parent to request the host to signal it
111 // when it is successfully started.
112 const char kSignalParentSwitchName[] = "signal-parent";
114 // Value used for --host-config option to indicate that the path must be read
115 // from stdin.
116 const char kStdinConfigPath[] = "-";
118 namespace remoting {
120 class HostProcess
121 : public ConfigFileWatcher::Delegate,
122 public HeartbeatSender::Listener,
123 public HostChangeNotificationListener::Listener,
124 public IPC::Listener,
125 public base::RefCountedThreadSafe<HostProcess> {
126 public:
127 HostProcess(scoped_ptr<ChromotingHostContext> context,
128 int* exit_code_out);
130 // ConfigFileWatcher::Delegate interface.
131 virtual void OnConfigUpdated(const std::string& serialized_config) OVERRIDE;
132 virtual void OnConfigWatcherError() OVERRIDE;
134 // IPC::Listener implementation.
135 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
136 virtual void OnChannelError() OVERRIDE;
138 // HeartbeatSender::Listener overrides.
139 virtual void OnHeartbeatSuccessful() OVERRIDE;
140 virtual void OnUnknownHostIdError() OVERRIDE;
142 // HostChangeNotificationListener::Listener overrides.
143 virtual void OnHostDeleted() OVERRIDE;
145 private:
146 enum HostState {
147 // Host process has just been started. Waiting for config and policies to be
148 // read from the disk.
149 HOST_INITIALIZING,
151 // Host is started and running.
152 HOST_STARTED,
154 // Host is being stopped and will need to be started again.
155 HOST_STOPPING_TO_RESTART,
157 // Host is being stopped.
158 HOST_STOPPING,
160 // Host has been stopped.
161 HOST_STOPPED,
163 // Allowed state transitions:
164 // INITIALIZING->STARTED
165 // INITIALIZING->STOPPED
166 // STARTED->STOPPING_TO_RESTART
167 // STARTED->STOPPING
168 // STOPPING_TO_RESTART->STARTED
169 // STOPPING_TO_RESTART->STOPPING
170 // STOPPING->STOPPED
171 // STOPPED->STARTED
173 // |host_| must be NULL in INITIALIZING and STOPPED states and not-NULL in
174 // all other states.
177 friend class base::RefCountedThreadSafe<HostProcess>;
178 virtual ~HostProcess();
180 void StartOnNetworkThread();
182 #if defined(OS_POSIX)
183 // Callback passed to RegisterSignalHandler() to handle SIGTERM events.
184 void SigTermHandler(int signal_number);
185 #endif
187 // Called to initialize resources on the UI thread.
188 void StartOnUiThread();
190 // Initializes IPC control channel and config file path from |cmd_line|.
191 // Called on the UI thread.
192 bool InitWithCommandLine(const CommandLine* cmd_line);
194 // Called on the UI thread to start monitoring the configuration file.
195 void StartWatchingConfigChanges();
197 // Called on the network thread to set the host's Authenticator factory.
198 void CreateAuthenticatorFactory();
200 // Tear down resources that run on the UI thread.
201 void ShutdownOnUiThread();
203 // Applies the host config, returning true if successful.
204 bool ApplyConfig(scoped_ptr<JsonHostConfig> config);
206 void OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies);
207 bool OnHostDomainPolicyUpdate(const std::string& host_domain);
208 bool OnUsernamePolicyUpdate(bool curtain_required,
209 bool username_match_required);
210 bool OnNatPolicyUpdate(bool nat_traversal_enabled);
211 void OnCurtainPolicyUpdate(bool curtain_required);
212 bool OnHostTalkGadgetPrefixPolicyUpdate(const std::string& talkgadget_prefix);
213 bool OnHostTokenUrlPolicyUpdate(const GURL& token_url,
214 const GURL& token_validation_url);
215 bool OnPairingPolicyUpdate(bool pairing_enabled);
217 void StartHost();
219 void OnAuthFailed();
221 void RestartHost();
223 // Stops the host and shuts down the process with the specified |exit_code|.
224 void ShutdownHost(HostExitCodes exit_code);
226 void ScheduleHostShutdown();
228 void ShutdownOnNetworkThread();
230 // Crashes the process in response to a daemon's request. The daemon passes
231 // the location of the code that detected the fatal error resulted in this
232 // request.
233 void OnCrash(const std::string& function_name,
234 const std::string& file_name,
235 const int& line_number);
237 scoped_ptr<ChromotingHostContext> context_;
239 // Created on the UI thread but used from the network thread.
240 scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
242 // Accessed on the UI thread.
243 scoped_ptr<IPC::ChannelProxy> daemon_channel_;
245 // XMPP server/remoting bot configuration (initialized from the command line).
246 XmppSignalStrategy::XmppServerConfig xmpp_server_config_;
247 std::string directory_bot_jid_;
249 // Created on the UI thread but used from the network thread.
250 base::FilePath host_config_path_;
251 std::string host_config_;
252 scoped_ptr<DesktopEnvironmentFactory> desktop_environment_factory_;
254 // Accessed on the network thread.
255 HostState state_;
257 scoped_ptr<ConfigFileWatcher> config_watcher_;
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 host_owner_;
265 bool use_service_account_;
266 scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
267 bool allow_nat_traversal_;
268 std::string talkgadget_prefix_;
269 bool allow_pairing_;
271 bool curtain_required_;
272 GURL token_url_;
273 GURL token_validation_url_;
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_;
283 scoped_ptr<ChromotingHost> host_;
285 // Used to keep this HostProcess alive until it is shutdown.
286 scoped_refptr<HostProcess> self_;
288 #if defined(REMOTING_MULTI_PROCESS)
289 DesktopSessionConnector* desktop_session_connector_;
290 #endif // defined(REMOTING_MULTI_PROCESS)
292 int* exit_code_out_;
293 bool signal_parent_;
296 HostProcess::HostProcess(scoped_ptr<ChromotingHostContext> context,
297 int* exit_code_out)
298 : context_(context.Pass()),
299 state_(HOST_INITIALIZING),
300 use_service_account_(false),
301 allow_nat_traversal_(true),
302 allow_pairing_(true),
303 curtain_required_(false),
304 #if defined(REMOTING_MULTI_PROCESS)
305 desktop_session_connector_(NULL),
306 #endif // defined(REMOTING_MULTI_PROCESS)
307 self_(this),
308 exit_code_out_(exit_code_out),
309 signal_parent_(false) {
310 StartOnUiThread();
313 HostProcess::~HostProcess() {
314 // Verify that UI components have been torn down.
315 DCHECK(!config_watcher_);
316 DCHECK(!daemon_channel_);
317 DCHECK(!desktop_environment_factory_);
319 // We might be getting deleted on one of the threads the |host_context| owns,
320 // so we need to post it back to the caller thread to safely join & delete the
321 // threads it contains. This will go away when we move to AutoThread.
322 // |context_release()| will null |context_| before the method is invoked, so
323 // we need to pull out the task-runner on which to call DeleteSoon first.
324 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
325 context_->ui_task_runner();
326 task_runner->DeleteSoon(FROM_HERE, context_.release());
329 bool HostProcess::InitWithCommandLine(const CommandLine* cmd_line) {
330 #if defined(REMOTING_MULTI_PROCESS)
331 // Parse the handle value and convert it to a handle/file descriptor.
332 std::string channel_name =
333 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
335 int pipe_handle = 0;
336 if (channel_name.empty() ||
337 !base::StringToInt(channel_name, &pipe_handle)) {
338 LOG(ERROR) << "Invalid '" << kDaemonPipeSwitchName
339 << "' value: " << channel_name;
340 return false;
343 #if defined(OS_WIN)
344 base::win::ScopedHandle pipe(reinterpret_cast<HANDLE>(pipe_handle));
345 IPC::ChannelHandle channel_handle(pipe);
346 #elif defined(OS_POSIX)
347 base::FileDescriptor pipe(pipe_handle, true);
348 IPC::ChannelHandle channel_handle(channel_name, pipe);
349 #endif // defined(OS_POSIX)
351 // Connect to the daemon process.
352 daemon_channel_.reset(new IPC::ChannelProxy(
353 channel_handle,
354 IPC::Channel::MODE_CLIENT,
355 this,
356 context_->network_task_runner()));
357 #else // !defined(REMOTING_MULTI_PROCESS)
358 // Connect to the daemon process.
359 std::string channel_name =
360 cmd_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
361 if (!channel_name.empty()) {
362 daemon_channel_.reset(
363 new IPC::ChannelProxy(channel_name,
364 IPC::Channel::MODE_CLIENT,
365 this,
366 context_->network_task_runner().get()));
369 if (cmd_line->HasSwitch(kHostConfigSwitchName)) {
370 host_config_path_ = cmd_line->GetSwitchValuePath(kHostConfigSwitchName);
372 // Read config from stdin if necessary.
373 if (host_config_path_ == base::FilePath(kStdinConfigPath)) {
374 char buf[4096];
375 size_t len;
376 while ((len = fread(buf, 1, sizeof(buf), stdin)) > 0) {
377 host_config_.append(buf, len);
380 } else {
381 base::FilePath default_config_dir = remoting::GetConfigDir();
382 host_config_path_ = default_config_dir.Append(kDefaultHostConfigFile);
385 if (host_config_path_ != base::FilePath(kStdinConfigPath) &&
386 !base::PathExists(host_config_path_)) {
387 LOG(ERROR) << "Can't find host config at " << host_config_path_.value();
388 return false;
390 #endif // !defined(REMOTING_MULTI_PROCESS)
392 // Ignore certificate requests - the host currently has no client certificate
393 // support, so ignoring certificate requests allows connecting to servers that
394 // request, but don't require, a certificate (optional client authentication).
395 net::URLFetcher::SetIgnoreCertificateRequests(true);
397 ServiceUrls* service_urls = ServiceUrls::GetInstance();
398 bool xmpp_server_valid = net::ParseHostAndPort(
399 service_urls->xmpp_server_address(),
400 &xmpp_server_config_.host, &xmpp_server_config_.port);
401 if (!xmpp_server_valid) {
402 LOG(ERROR) << "Invalid XMPP server: " <<
403 service_urls->xmpp_server_address();
404 return false;
406 xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls();
407 directory_bot_jid_ = service_urls->directory_bot_jid();
409 signal_parent_ = cmd_line->HasSwitch(kSignalParentSwitchName);
411 return true;
414 void HostProcess::OnConfigUpdated(
415 const std::string& serialized_config) {
416 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
417 context_->network_task_runner()->PostTask(FROM_HERE,
418 base::Bind(&HostProcess::OnConfigUpdated, this, serialized_config));
419 return;
422 // Filter out duplicates.
423 if (serialized_config_ == serialized_config)
424 return;
426 LOG(INFO) << "Processing new host configuration.";
428 serialized_config_ = serialized_config;
429 scoped_ptr<JsonHostConfig> config(new JsonHostConfig(base::FilePath()));
430 if (!config->SetSerializedData(serialized_config)) {
431 LOG(ERROR) << "Invalid configuration.";
432 ShutdownHost(kInvalidHostConfigurationExitCode);
433 return;
436 if (!ApplyConfig(config.Pass())) {
437 LOG(ERROR) << "Failed to apply the configuration.";
438 ShutdownHost(kInvalidHostConfigurationExitCode);
439 return;
442 if (state_ == HOST_INITIALIZING) {
443 // TODO(sergeyu): Currently OnPolicyUpdate() assumes that host config is
444 // already loaded so PolicyWatcher has to be started here. Separate policy
445 // loading from policy verifications and move |policy_watcher_|
446 // initialization to StartOnNetworkThread().
447 policy_watcher_.reset(
448 policy_hack::PolicyWatcher::Create(context_->file_task_runner()));
449 policy_watcher_->StartWatching(
450 base::Bind(&HostProcess::OnPolicyUpdate, base::Unretained(this)));
451 } else if (state_ == HOST_STARTED) {
452 // TODO(sergeyu): Here we assume that PIN is the only part of the config
453 // that may change while the service is running. Change ApplyConfig() to
454 // detect other changes in the config and restart host if necessary here.
455 CreateAuthenticatorFactory();
459 void HostProcess::OnConfigWatcherError() {
460 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
461 ShutdownHost(kInvalidHostConfigurationExitCode);
464 void HostProcess::StartOnNetworkThread() {
465 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
467 #if !defined(REMOTING_MULTI_PROCESS)
468 if (host_config_path_ == base::FilePath(kStdinConfigPath)) {
469 // Process config we've read from stdin.
470 OnConfigUpdated(host_config_);
471 } else {
472 // Start watching the host configuration file.
473 config_watcher_.reset(new ConfigFileWatcher(context_->network_task_runner(),
474 context_->file_task_runner(),
475 this));
476 config_watcher_->Watch(host_config_path_);
478 #endif // !defined(REMOTING_MULTI_PROCESS)
480 #if defined(OS_POSIX)
481 remoting::RegisterSignalHandler(
482 SIGTERM,
483 base::Bind(&HostProcess::SigTermHandler, base::Unretained(this)));
484 #endif // defined(OS_POSIX)
487 #if defined(OS_POSIX)
488 void HostProcess::SigTermHandler(int signal_number) {
489 DCHECK(signal_number == SIGTERM);
490 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
491 LOG(INFO) << "Caught SIGTERM: Shutting down...";
492 ShutdownHost(kSuccessExitCode);
494 #endif // OS_POSIX
496 void HostProcess::CreateAuthenticatorFactory() {
497 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
499 if (state_ != HOST_STARTED)
500 return;
502 std::string local_certificate = key_pair_->GenerateCertificate();
503 if (local_certificate.empty()) {
504 LOG(ERROR) << "Failed to generate host certificate.";
505 ShutdownHost(kInitializationFailed);
506 return;
509 scoped_refptr<protocol::PairingRegistry> pairing_registry = NULL;
510 if (allow_pairing_) {
511 pairing_registry = CreatePairingRegistry(context_->file_task_runner());
514 scoped_ptr<protocol::AuthenticatorFactory> factory;
516 if (token_url_.is_empty() && token_validation_url_.is_empty()) {
517 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
518 host_owner_, local_certificate, key_pair_, host_secret_hash_,
519 pairing_registry);
521 } else if (token_url_.is_valid() && token_validation_url_.is_valid()) {
522 scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidatorFactory>
523 token_validator_factory(new TokenValidatorFactoryImpl(
524 token_url_, token_validation_url_, key_pair_,
525 context_->url_request_context_getter()));
526 factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
527 host_owner_, local_certificate, key_pair_,
528 token_validator_factory.Pass());
530 } else {
531 // TODO(rmsousa): If the policy is bad the host should not go online. It
532 // should keep running, but not connected, until the policies are fixed.
533 // Having it show up as online and then reject all clients is misleading.
534 LOG(ERROR) << "One of the third-party token URLs is empty or invalid. "
535 << "Host will reject all clients until policies are corrected. "
536 << "TokenUrl: " << token_url_ << ", "
537 << "TokenValidationUrl: " << token_validation_url_;
538 factory = protocol::Me2MeHostAuthenticatorFactory::CreateRejecting();
541 #if defined(OS_POSIX)
542 // On Linux and Mac, perform a PAM authorization step after authentication.
543 factory.reset(new PamAuthorizationFactory(factory.Pass()));
544 #endif
545 host_->SetAuthenticatorFactory(factory.Pass());
547 host_->set_pairing_registry(pairing_registry);
550 // IPC::Listener implementation.
551 bool HostProcess::OnMessageReceived(const IPC::Message& message) {
552 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
554 #if defined(REMOTING_MULTI_PROCESS)
555 bool handled = true;
556 IPC_BEGIN_MESSAGE_MAP(HostProcess, message)
557 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash, OnCrash)
558 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Configuration,
559 OnConfigUpdated)
560 IPC_MESSAGE_FORWARD(
561 ChromotingDaemonNetworkMsg_DesktopAttached,
562 desktop_session_connector_,
563 DesktopSessionConnector::OnDesktopSessionAgentAttached)
564 IPC_MESSAGE_FORWARD(ChromotingDaemonNetworkMsg_TerminalDisconnected,
565 desktop_session_connector_,
566 DesktopSessionConnector::OnTerminalDisconnected)
567 IPC_MESSAGE_UNHANDLED(handled = false)
568 IPC_END_MESSAGE_MAP()
570 CHECK(handled) << "Received unexpected IPC type: " << message.type();
571 return handled;
573 #else // !defined(REMOTING_MULTI_PROCESS)
574 return false;
575 #endif // !defined(REMOTING_MULTI_PROCESS)
578 void HostProcess::OnChannelError() {
579 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
581 // Shutdown the host if the daemon process disconnects the IPC channel.
582 context_->network_task_runner()->PostTask(
583 FROM_HERE,
584 base::Bind(&HostProcess::ShutdownHost, this, kSuccessExitCode));
587 void HostProcess::StartOnUiThread() {
588 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
590 if (!InitWithCommandLine(CommandLine::ForCurrentProcess())) {
591 // Shutdown the host if the command line is invalid.
592 context_->network_task_runner()->PostTask(
593 FROM_HERE, base::Bind(&HostProcess::ShutdownHost, this,
594 kUsageExitCode));
595 return;
598 #if defined(OS_LINUX)
599 // If an audio pipe is specific on the command-line then initialize
600 // AudioCapturerLinux to capture from it.
601 base::FilePath audio_pipe_name = CommandLine::ForCurrentProcess()->
602 GetSwitchValuePath(kAudioPipeSwitchName);
603 if (!audio_pipe_name.empty()) {
604 remoting::AudioCapturerLinux::InitializePipeReader(
605 context_->audio_task_runner(), audio_pipe_name);
607 #endif // defined(OS_LINUX)
609 // Create a desktop environment factory appropriate to the build type &
610 // platform.
611 #if defined(OS_WIN)
612 IpcDesktopEnvironmentFactory* desktop_environment_factory =
613 new IpcDesktopEnvironmentFactory(
614 context_->audio_task_runner(),
615 context_->network_task_runner(),
616 context_->video_capture_task_runner(),
617 context_->network_task_runner(),
618 daemon_channel_.get());
619 desktop_session_connector_ = desktop_environment_factory;
620 #else // !defined(OS_WIN)
621 DesktopEnvironmentFactory* desktop_environment_factory =
622 new Me2MeDesktopEnvironmentFactory(
623 context_->network_task_runner(),
624 context_->input_task_runner(),
625 context_->ui_task_runner());
626 #endif // !defined(OS_WIN)
628 desktop_environment_factory_.reset(desktop_environment_factory);
630 context_->network_task_runner()->PostTask(
631 FROM_HERE,
632 base::Bind(&HostProcess::StartOnNetworkThread, this));
635 void HostProcess::ShutdownOnUiThread() {
636 DCHECK(context_->ui_task_runner()->BelongsToCurrentThread());
638 // Tear down resources that need to be torn down on the UI thread.
639 network_change_notifier_.reset();
640 daemon_channel_.reset();
641 desktop_environment_factory_.reset();
643 // It is now safe for the HostProcess to be deleted.
644 self_ = NULL;
646 #if defined(OS_LINUX)
647 // Cause the global AudioPipeReader to be freed, otherwise the audio
648 // thread will remain in-use and prevent the process from exiting.
649 // TODO(wez): DesktopEnvironmentFactory should own the pipe reader.
650 // See crbug.com/161373 and crbug.com/104544.
651 AudioCapturerLinux::InitializePipeReader(NULL, base::FilePath());
652 #endif
655 // Overridden from HeartbeatSender::Listener
656 void HostProcess::OnUnknownHostIdError() {
657 LOG(ERROR) << "Host ID not found.";
658 ShutdownHost(kInvalidHostIdExitCode);
661 void HostProcess::OnHeartbeatSuccessful() {
662 LOG(INFO) << "Host ready to receive connections.";
663 #if defined(OS_POSIX)
664 if (signal_parent_) {
665 kill(getppid(), SIGUSR1);
666 signal_parent_ = false;
668 #endif
671 void HostProcess::OnHostDeleted() {
672 LOG(ERROR) << "Host was deleted from the directory.";
673 ShutdownHost(kInvalidHostIdExitCode);
676 // Applies the host config, returning true if successful.
677 bool HostProcess::ApplyConfig(scoped_ptr<JsonHostConfig> config) {
678 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
680 if (!config->GetString(kHostIdConfigPath, &host_id_)) {
681 LOG(ERROR) << "host_id is not defined in the config.";
682 return false;
685 std::string key_base64;
686 if (!config->GetString(kPrivateKeyConfigPath, &key_base64)) {
687 LOG(ERROR) << "Private key couldn't be read from the config file.";
688 return false;
691 key_pair_ = RsaKeyPair::FromString(key_base64);
692 if (!key_pair_.get()) {
693 LOG(ERROR) << "Invalid private key in the config file.";
694 return false;
697 std::string host_secret_hash_string;
698 if (!config->GetString(kHostSecretHashConfigPath,
699 &host_secret_hash_string)) {
700 host_secret_hash_string = "plain:";
703 if (!host_secret_hash_.Parse(host_secret_hash_string)) {
704 LOG(ERROR) << "Invalid host_secret_hash.";
705 return false;
708 // Use an XMPP connection to the Talk network for session signalling.
709 if (!config->GetString(kXmppLoginConfigPath, &xmpp_server_config_.username) ||
710 !(config->GetString(kXmppAuthTokenConfigPath,
711 &xmpp_server_config_.auth_token) ||
712 config->GetString(kOAuthRefreshTokenConfigPath,
713 &oauth_refresh_token_))) {
714 LOG(ERROR) << "XMPP credentials are not defined in the config.";
715 return false;
718 if (!oauth_refresh_token_.empty()) {
719 // SignalingConnector is responsible for getting OAuth token.
720 xmpp_server_config_.auth_token = "";
721 xmpp_server_config_.auth_service = "oauth2";
722 } else if (!config->GetString(kXmppAuthServiceConfigPath,
723 &xmpp_server_config_.auth_service)) {
724 // For the me2me host, we default to ClientLogin token for chromiumsync
725 // because earlier versions of the host had no HTTP stack with which to
726 // request an OAuth2 access token.
727 xmpp_server_config_.auth_service = kChromotingTokenDefaultServiceName;
730 if (config->GetString(kHostOwnerConfigPath, &host_owner_)) {
731 // Service account configs have a host_owner, different from the xmpp_login.
732 use_service_account_ = true;
733 } else {
734 // User credential configs only have an xmpp_login, which is also the owner.
735 host_owner_ = xmpp_server_config_.username;
736 use_service_account_ = false;
738 return true;
741 void HostProcess::OnPolicyUpdate(scoped_ptr<base::DictionaryValue> policies) {
742 // TODO(rmsousa): Consolidate all On*PolicyUpdate methods into this one.
743 // TODO(sergeyu): Currently polices are verified only when they are loaded.
744 // Separate policy loading from policy verifications - this will allow to
745 // check policies again later, e.g. when host config changes.
747 if (!context_->network_task_runner()->BelongsToCurrentThread()) {
748 context_->network_task_runner()->PostTask(FROM_HERE, base::Bind(
749 &HostProcess::OnPolicyUpdate, this, base::Passed(&policies)));
750 return;
753 bool restart_required = false;
754 bool bool_value;
755 std::string string_value;
756 if (policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName,
757 &string_value)) {
758 restart_required |= OnHostDomainPolicyUpdate(string_value);
760 bool curtain_required = false;
761 if (policies->GetBoolean(
762 policy_hack::PolicyWatcher::kHostRequireCurtainPolicyName,
763 &curtain_required)) {
764 OnCurtainPolicyUpdate(curtain_required);
766 if (policies->GetBoolean(
767 policy_hack::PolicyWatcher::kHostMatchUsernamePolicyName,
768 &bool_value)) {
769 restart_required |= OnUsernamePolicyUpdate(curtain_required, bool_value);
771 if (policies->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName,
772 &bool_value)) {
773 restart_required |= OnNatPolicyUpdate(bool_value);
775 if (policies->GetString(
776 policy_hack::PolicyWatcher::kHostTalkGadgetPrefixPolicyName,
777 &string_value)) {
778 restart_required |= OnHostTalkGadgetPrefixPolicyUpdate(string_value);
780 std::string token_url_string, token_validation_url_string;
781 if (policies->GetString(
782 policy_hack::PolicyWatcher::kHostTokenUrlPolicyName,
783 &token_url_string) &&
784 policies->GetString(
785 policy_hack::PolicyWatcher::kHostTokenValidationUrlPolicyName,
786 &token_validation_url_string)) {
787 restart_required |= OnHostTokenUrlPolicyUpdate(
788 GURL(token_url_string), GURL(token_validation_url_string));
790 if (policies->GetBoolean(
791 policy_hack::PolicyWatcher::kHostAllowClientPairing,
792 &bool_value)) {
793 restart_required |= OnPairingPolicyUpdate(bool_value);
796 if (state_ == HOST_INITIALIZING) {
797 StartHost();
798 } else if (state_ == HOST_STARTED && restart_required) {
799 RestartHost();
803 bool HostProcess::OnHostDomainPolicyUpdate(const std::string& host_domain) {
804 // Returns true if the host has to be restarted after this policy update.
805 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
807 LOG(INFO) << "Policy sets host domain: " << host_domain;
809 if (!host_domain.empty() &&
810 !EndsWith(host_owner_, std::string("@") + host_domain, false)) {
811 ShutdownHost(kInvalidHostDomainExitCode);
813 return false;
816 bool HostProcess::OnUsernamePolicyUpdate(bool curtain_required,
817 bool host_username_match_required) {
818 // Returns false: never restart the host after this policy update.
819 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
821 if (host_username_match_required) {
822 LOG(INFO) << "Policy requires host username match.";
823 std::string username = GetUsername();
824 bool shutdown = username.empty() ||
825 !StartsWithASCII(host_owner_, username + std::string("@"),
826 false);
828 #if defined(OS_MACOSX)
829 // On Mac, we run as root at the login screen, so the username won't match.
830 // However, there's no need to enforce the policy at the login screen, as
831 // the client will have to reconnect if a login occurs.
832 if (shutdown && getuid() == 0) {
833 shutdown = false;
835 #endif
837 // Curtain-mode on Windows presents the standard OS login prompt to the user
838 // for each connection, removing the need for an explicit user-name matching
839 // check.
840 #if defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
841 if (curtain_required)
842 return false;
843 #endif // defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
845 // Shutdown the host if the username does not match.
846 if (shutdown) {
847 LOG(ERROR) << "The host username does not match.";
848 ShutdownHost(kUsernameMismatchExitCode);
850 } else {
851 LOG(INFO) << "Policy does not require host username match.";
854 return false;
857 bool HostProcess::OnNatPolicyUpdate(bool nat_traversal_enabled) {
858 // Returns true if the host has to be restarted after this policy update.
859 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
861 if (allow_nat_traversal_ != nat_traversal_enabled) {
862 if (nat_traversal_enabled)
863 LOG(INFO) << "Policy enables NAT traversal.";
864 else
865 LOG(INFO) << "Policy disables NAT traversal.";
866 allow_nat_traversal_ = nat_traversal_enabled;
867 return true;
869 return false;
872 void HostProcess::OnCurtainPolicyUpdate(bool curtain_required) {
873 // Returns true if the host has to be restarted after this policy update.
874 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
876 #if defined(OS_MACOSX)
877 if (curtain_required) {
878 // When curtain mode is in effect on Mac, the host process runs in the
879 // user's switched-out session, but launchd will also run an instance at
880 // the console login screen. Even if no user is currently logged-on, we
881 // can't support remote-access to the login screen because the current host
882 // process model disconnects the client during login, which would leave
883 // the logged in session un-curtained on the console until they reconnect.
885 // TODO(jamiewalch): Fix this once we have implemented the multi-process
886 // daemon architecture (crbug.com/134894)
887 if (getuid() == 0) {
888 LOG(ERROR) << "Running the host in the console login session is yet not "
889 "supported.";
890 ShutdownHost(kLoginScreenNotSupportedExitCode);
891 return;
894 #endif
896 if (curtain_required_ != curtain_required) {
897 if (curtain_required)
898 LOG(INFO) << "Policy requires curtain-mode.";
899 else
900 LOG(INFO) << "Policy does not require curtain-mode.";
901 curtain_required_ = curtain_required;
902 if (host_)
903 host_->SetEnableCurtaining(curtain_required_);
907 bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate(
908 const std::string& talkgadget_prefix) {
909 // Returns true if the host has to be restarted after this policy update.
910 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
912 if (talkgadget_prefix != talkgadget_prefix_) {
913 LOG(INFO) << "Policy sets talkgadget prefix: " << talkgadget_prefix;
914 talkgadget_prefix_ = talkgadget_prefix;
915 return true;
917 return false;
920 bool HostProcess::OnHostTokenUrlPolicyUpdate(
921 const GURL& token_url,
922 const GURL& token_validation_url) {
923 // Returns true if the host has to be restarted after this policy update.
924 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
926 if (token_url_ != token_url ||
927 token_validation_url_ != token_validation_url) {
928 LOG(INFO) << "Policy sets third-party token URLs: "
929 << "TokenUrl: " << token_url << ", "
930 << "TokenValidationUrl: " << token_validation_url;
932 token_url_ = token_url;
933 token_validation_url_ = token_validation_url;
934 return true;
937 return false;
940 bool HostProcess::OnPairingPolicyUpdate(bool allow_pairing) {
941 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
943 if (allow_pairing_ == allow_pairing)
944 return false;
946 if (allow_pairing)
947 LOG(INFO) << "Policy enables client pairing.";
948 else
949 LOG(INFO) << "Policy disables client pairing.";
950 allow_pairing_ = allow_pairing;
951 return true;
954 void HostProcess::StartHost() {
955 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
956 DCHECK(!host_);
957 DCHECK(!signal_strategy_.get());
958 DCHECK(state_ == HOST_INITIALIZING || state_ == HOST_STOPPING_TO_RESTART ||
959 state_ == HOST_STOPPED) << state_;
960 state_ = HOST_STARTED;
962 signal_strategy_.reset(
963 new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
964 context_->url_request_context_getter(),
965 xmpp_server_config_));
967 scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker(
968 new DnsBlackholeChecker(context_->url_request_context_getter(),
969 talkgadget_prefix_));
971 // Create a NetworkChangeNotifier for use by the signaling connector.
972 network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
974 signaling_connector_.reset(new SignalingConnector(
975 signal_strategy_.get(),
976 context_->url_request_context_getter(),
977 dns_blackhole_checker.Pass(),
978 base::Bind(&HostProcess::OnAuthFailed, this)));
980 if (!oauth_refresh_token_.empty()) {
981 scoped_ptr<SignalingConnector::OAuthCredentials> oauth_credentials(
982 new SignalingConnector::OAuthCredentials(
983 xmpp_server_config_.username, oauth_refresh_token_,
984 use_service_account_));
985 signaling_connector_->EnableOAuth(oauth_credentials.Pass());
988 NetworkSettings network_settings(
989 allow_nat_traversal_ ?
990 NetworkSettings::NAT_TRAVERSAL_ENABLED :
991 NetworkSettings::NAT_TRAVERSAL_DISABLED);
992 if (!allow_nat_traversal_) {
993 network_settings.min_port = NetworkSettings::kDefaultMinPort;
994 network_settings.max_port = NetworkSettings::kDefaultMaxPort;
997 host_.reset(new ChromotingHost(
998 signal_strategy_.get(),
999 desktop_environment_factory_.get(),
1000 CreateHostSessionManager(network_settings,
1001 context_->url_request_context_getter()),
1002 context_->audio_task_runner(),
1003 context_->input_task_runner(),
1004 context_->video_capture_task_runner(),
1005 context_->video_encode_task_runner(),
1006 context_->network_task_runner(),
1007 context_->ui_task_runner()));
1009 // TODO(simonmorris): Get the maximum session duration from a policy.
1010 #if defined(OS_LINUX)
1011 host_->SetMaximumSessionDuration(base::TimeDelta::FromHours(20));
1012 #endif
1014 heartbeat_sender_.reset(new HeartbeatSender(
1015 this, host_id_, signal_strategy_.get(), key_pair_,
1016 directory_bot_jid_));
1018 host_status_sender_.reset(new HostStatusSender(
1019 host_id_, signal_strategy_.get(), key_pair_, directory_bot_jid_));
1021 host_change_notification_listener_.reset(new HostChangeNotificationListener(
1022 this, host_id_, signal_strategy_.get(), directory_bot_jid_));
1024 log_to_server_.reset(
1025 new LogToServer(host_->AsWeakPtr(), ServerLogEntry::ME2ME,
1026 signal_strategy_.get(), directory_bot_jid_));
1028 // Set up repoting the host status notifications.
1029 #if defined(REMOTING_MULTI_PROCESS)
1030 host_event_logger_.reset(
1031 new IpcHostEventLogger(host_->AsWeakPtr(), daemon_channel_.get()));
1032 #else // !defined(REMOTING_MULTI_PROCESS)
1033 host_event_logger_ =
1034 HostEventLogger::Create(host_->AsWeakPtr(), kApplicationName);
1035 #endif // !defined(REMOTING_MULTI_PROCESS)
1037 host_->SetEnableCurtaining(curtain_required_);
1038 host_->Start(host_owner_);
1040 CreateAuthenticatorFactory();
1043 void HostProcess::OnAuthFailed() {
1044 ShutdownHost(kInvalidOauthCredentialsExitCode);
1047 void HostProcess::RestartHost() {
1048 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1049 DCHECK_EQ(state_, HOST_STARTED);
1051 state_ = HOST_STOPPING_TO_RESTART;
1052 ShutdownOnNetworkThread();
1055 void HostProcess::ShutdownHost(HostExitCodes exit_code) {
1056 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1058 *exit_code_out_ = exit_code;
1060 switch (state_) {
1061 case HOST_INITIALIZING:
1062 state_ = HOST_STOPPING;
1063 ShutdownOnNetworkThread();
1064 break;
1066 case HOST_STARTED:
1067 state_ = HOST_STOPPING;
1068 host_status_sender_->SendOfflineStatus(exit_code);
1069 ScheduleHostShutdown();
1070 break;
1072 case HOST_STOPPING_TO_RESTART:
1073 state_ = HOST_STOPPING;
1074 break;
1076 case HOST_STOPPING:
1077 case HOST_STOPPED:
1078 // Host is already stopped or being stopped. No action is required.
1079 break;
1083 // TODO(weitaosu): shut down the host once we get an ACK for the offline status
1084 // XMPP message.
1085 void HostProcess::ScheduleHostShutdown() {
1086 // Delay the shutdown by 2 second to allow SendOfflineStatus to complete.
1087 context_->network_task_runner()->PostDelayedTask(
1088 FROM_HERE,
1089 base::Bind(&HostProcess::ShutdownOnNetworkThread, base::Unretained(this)),
1090 base::TimeDelta::FromSeconds(2));
1093 void HostProcess::ShutdownOnNetworkThread() {
1094 DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
1096 host_.reset();
1097 host_event_logger_.reset();
1098 log_to_server_.reset();
1099 heartbeat_sender_.reset();
1100 host_status_sender_.reset();
1101 host_change_notification_listener_.reset();
1102 signaling_connector_.reset();
1103 signal_strategy_.reset();
1104 network_change_notifier_.reset();
1106 if (state_ == HOST_STOPPING_TO_RESTART) {
1107 StartHost();
1108 } else if (state_ == HOST_STOPPING) {
1109 state_ = HOST_STOPPED;
1111 if (policy_watcher_.get()) {
1112 base::WaitableEvent done_event(true, false);
1113 policy_watcher_->StopWatching(&done_event);
1114 done_event.Wait();
1115 policy_watcher_.reset();
1118 config_watcher_.reset();
1120 // Complete the rest of shutdown on the main thread.
1121 context_->ui_task_runner()->PostTask(
1122 FROM_HERE,
1123 base::Bind(&HostProcess::ShutdownOnUiThread, this));
1124 } else {
1125 // This method is only called in STOPPING_TO_RESTART and STOPPING states.
1126 NOTREACHED();
1130 void HostProcess::OnCrash(const std::string& function_name,
1131 const std::string& file_name,
1132 const int& line_number) {
1133 char message[1024];
1134 base::snprintf(message, sizeof(message),
1135 "Requested by %s at %s, line %d.",
1136 function_name.c_str(), file_name.c_str(), line_number);
1137 base::debug::Alias(message);
1139 // The daemon requested us to crash the process.
1140 CHECK(false) << message;
1143 int HostProcessMain() {
1144 #if defined(TOOLKIT_GTK)
1145 // Required for any calls into GTK functions, such as the Disconnect and
1146 // Continue windows, though these should not be used for the Me2Me case
1147 // (crbug.com/104377).
1148 gfx::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
1149 #endif // TOOLKIT_GTK
1151 // Enable support for SSL server sockets, which must be done while still
1152 // single-threaded.
1153 net::EnableSSLServerSockets();
1155 // Ensures runtime specific CPU features are initialized.
1156 media::InitializeCPUSpecificMediaFeatures();
1158 // Create the main message loop and start helper threads.
1159 base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
1160 scoped_ptr<ChromotingHostContext> context =
1161 ChromotingHostContext::Create(new AutoThreadTaskRunner(
1162 message_loop.message_loop_proxy(), base::MessageLoop::QuitClosure()));
1163 if (!context)
1164 return kInitializationFailed;
1166 // Create & start the HostProcess using these threads.
1167 // TODO(wez): The HostProcess holds a reference to itself until Shutdown().
1168 // Remove this hack as part of the multi-process refactoring.
1169 int exit_code = kSuccessExitCode;
1170 new HostProcess(context.Pass(), &exit_code);
1172 // Run the main (also UI) message loop until the host no longer needs it.
1173 message_loop.Run();
1175 return exit_code;
1178 } // namespace remoting
1180 #if !defined(OS_WIN)
1181 int main(int argc, char** argv) {
1182 return remoting::HostMain(argc, argv);
1184 #endif // !defined(OS_WIN)