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/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"
76 #include <sys/types.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)
88 #include "remoting/host/audio_capturer_linux.h"
89 #endif // defined(OS_LINUX)
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
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
116 const char kStdinConfigPath
[] = "-";
121 : public ConfigFileWatcher::Delegate
,
122 public HeartbeatSender::Listener
,
123 public HostChangeNotificationListener::Listener
,
124 public IPC::Listener
,
125 public base::RefCountedThreadSafe
<HostProcess
> {
127 HostProcess(scoped_ptr
<ChromotingHostContext
> context
,
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
;
147 // Host process has just been started. Waiting for config and policies to be
148 // read from the disk.
151 // Host is started and running.
154 // Host is being stopped and will need to be started again.
155 HOST_STOPPING_TO_RESTART
,
157 // Host is being stopped.
160 // Host has been stopped.
163 // Allowed state transitions:
164 // INITIALIZING->STARTED
165 // INITIALIZING->STOPPED
166 // STARTED->STOPPING_TO_RESTART
168 // STOPPING_TO_RESTART->STARTED
169 // STOPPING_TO_RESTART->STOPPING
173 // |host_| must be NULL in INITIALIZING and STOPPED states and not-NULL in
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
);
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
);
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
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.
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_
;
271 bool curtain_required_
;
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)
296 HostProcess::HostProcess(scoped_ptr
<ChromotingHostContext
> context
,
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)
308 exit_code_out_(exit_code_out
),
309 signal_parent_(false) {
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
);
336 if (channel_name
.empty() ||
337 !base::StringToInt(channel_name
, &pipe_handle
)) {
338 LOG(ERROR
) << "Invalid '" << kDaemonPipeSwitchName
339 << "' value: " << channel_name
;
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(
354 IPC::Channel::MODE_CLIENT
,
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
,
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
)) {
376 while ((len
= fread(buf
, 1, sizeof(buf
), stdin
)) > 0) {
377 host_config_
.append(buf
, len
);
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();
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();
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
);
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
));
422 // Filter out duplicates.
423 if (serialized_config_
== serialized_config
)
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
);
436 if (!ApplyConfig(config
.Pass())) {
437 LOG(ERROR
) << "Failed to apply the configuration.";
438 ShutdownHost(kInvalidHostConfigurationExitCode
);
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_
);
472 // Start watching the host configuration file.
473 config_watcher_
.reset(new ConfigFileWatcher(context_
->network_task_runner(),
474 context_
->file_task_runner(),
476 config_watcher_
->Watch(host_config_path_
);
478 #endif // !defined(REMOTING_MULTI_PROCESS)
480 #if defined(OS_POSIX)
481 remoting::RegisterSignalHandler(
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
);
496 void HostProcess::CreateAuthenticatorFactory() {
497 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
499 if (state_
!= HOST_STARTED
)
502 std::string local_certificate
= key_pair_
->GenerateCertificate();
503 if (local_certificate
.empty()) {
504 LOG(ERROR
) << "Failed to generate host certificate.";
505 ShutdownHost(kInitializationFailed
);
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_
,
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());
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()));
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)
556 IPC_BEGIN_MESSAGE_MAP(HostProcess
, message
)
557 IPC_MESSAGE_HANDLER(ChromotingDaemonMsg_Crash
, OnCrash
)
558 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Configuration
,
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();
573 #else // !defined(REMOTING_MULTI_PROCESS)
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(
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,
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 &
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(
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.
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());
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;
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.";
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.";
691 key_pair_
= RsaKeyPair::FromString(key_base64
);
692 if (!key_pair_
.get()) {
693 LOG(ERROR
) << "Invalid private key in the config file.";
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.";
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.";
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;
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;
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
)));
753 bool restart_required
= false;
755 std::string string_value
;
756 if (policies
->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName
,
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
,
769 restart_required
|= OnUsernamePolicyUpdate(curtain_required
, bool_value
);
771 if (policies
->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName
,
773 restart_required
|= OnNatPolicyUpdate(bool_value
);
775 if (policies
->GetString(
776 policy_hack::PolicyWatcher::kHostTalkGadgetPrefixPolicyName
,
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
) &&
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
,
793 restart_required
|= OnPairingPolicyUpdate(bool_value
);
796 if (state_
== HOST_INITIALIZING
) {
798 } else if (state_
== HOST_STARTED
&& restart_required
) {
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
);
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("@"),
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) {
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
840 #if defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
841 if (curtain_required
)
843 #endif // defined(OS_WIN) && defined(REMOTING_RDP_SESSION)
845 // Shutdown the host if the username does not match.
847 LOG(ERROR
) << "The host username does not match.";
848 ShutdownHost(kUsernameMismatchExitCode
);
851 LOG(INFO
) << "Policy does not require host username match.";
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.";
865 LOG(INFO
) << "Policy disables NAT traversal.";
866 allow_nat_traversal_
= nat_traversal_enabled
;
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)
888 LOG(ERROR
) << "Running the host in the console login session is yet not "
890 ShutdownHost(kLoginScreenNotSupportedExitCode
);
896 if (curtain_required_
!= curtain_required
) {
897 if (curtain_required
)
898 LOG(INFO
) << "Policy requires curtain-mode.";
900 LOG(INFO
) << "Policy does not require curtain-mode.";
901 curtain_required_
= curtain_required
;
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
;
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
;
940 bool HostProcess::OnPairingPolicyUpdate(bool allow_pairing
) {
941 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
943 if (allow_pairing_
== allow_pairing
)
947 LOG(INFO
) << "Policy enables client pairing.";
949 LOG(INFO
) << "Policy disables client pairing.";
950 allow_pairing_
= allow_pairing
;
954 void HostProcess::StartHost() {
955 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
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));
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
;
1061 case HOST_INITIALIZING
:
1062 state_
= HOST_STOPPING
;
1063 ShutdownOnNetworkThread();
1067 state_
= HOST_STOPPING
;
1068 host_status_sender_
->SendOfflineStatus(exit_code
);
1069 ScheduleHostShutdown();
1072 case HOST_STOPPING_TO_RESTART
:
1073 state_
= HOST_STOPPING
;
1078 // Host is already stopped or being stopped. No action is required.
1083 // TODO(weitaosu): shut down the host once we get an ACK for the offline status
1085 void HostProcess::ScheduleHostShutdown() {
1086 // Delay the shutdown by 2 second to allow SendOfflineStatus to complete.
1087 context_
->network_task_runner()->PostDelayedTask(
1089 base::Bind(&HostProcess::ShutdownOnNetworkThread
, base::Unretained(this)),
1090 base::TimeDelta::FromSeconds(2));
1093 void HostProcess::ShutdownOnNetworkThread() {
1094 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
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
) {
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
);
1115 policy_watcher_
.reset();
1118 config_watcher_
.reset();
1120 // Complete the rest of shutdown on the main thread.
1121 context_
->ui_task_runner()->PostTask(
1123 base::Bind(&HostProcess::ShutdownOnUiThread
, this));
1125 // This method is only called in STOPPING_TO_RESTART and STOPPING states.
1130 void HostProcess::OnCrash(const std::string
& function_name
,
1131 const std::string
& file_name
,
1132 const int& line_number
) {
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
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()));
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.
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)