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/file_path.h"
14 #include "base/file_util.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop.h"
17 #include "base/scoped_native_library.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/string_number_conversions.h"
20 #include "base/string_util.h"
21 #include "base/stringize_macros.h"
22 #include "base/synchronization/waitable_event.h"
23 #include "base/threading/thread.h"
24 #include "base/utf_string_conversions.h"
25 #include "base/win/windows_version.h"
26 #include "build/build_config.h"
27 #include "crypto/nss_util.h"
28 #include "ipc/ipc_channel.h"
29 #include "ipc/ipc_channel_proxy.h"
30 #include "ipc/ipc_listener.h"
31 #include "media/video/capture/screen/screen_capturer.h"
32 #include "net/base/network_change_notifier.h"
33 #include "net/socket/ssl_server_socket.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/host/basic_desktop_environment.h"
38 #include "remoting/host/branding.h"
39 #include "remoting/host/chromoting_host.h"
40 #include "remoting/host/chromoting_host_context.h"
41 #include "remoting/host/chromoting_messages.h"
42 #include "remoting/host/config_file_watcher.h"
43 #include "remoting/host/curtain_mode.h"
44 #include "remoting/host/curtaining_host_observer.h"
45 #include "remoting/host/desktop_environment.h"
46 #include "remoting/host/desktop_resizer.h"
47 #include "remoting/host/desktop_session_connector.h"
48 #include "remoting/host/dns_blackhole_checker.h"
49 #include "remoting/host/event_executor.h"
50 #include "remoting/host/heartbeat_sender.h"
51 #include "remoting/host/host_config.h"
52 #include "remoting/host/host_event_logger.h"
53 #include "remoting/host/host_exit_codes.h"
54 #include "remoting/host/host_user_interface.h"
55 #include "remoting/host/ipc_constants.h"
56 #include "remoting/host/ipc_desktop_environment.h"
57 #include "remoting/host/json_host_config.h"
58 #include "remoting/host/log_to_server.h"
59 #include "remoting/host/logging.h"
60 #include "remoting/host/network_settings.h"
61 #include "remoting/host/policy_hack/policy_watcher.h"
62 #include "remoting/host/resizing_host_observer.h"
63 #include "remoting/host/session_manager_factory.h"
64 #include "remoting/host/signaling_connector.h"
65 #include "remoting/host/ui_strings.h"
66 #include "remoting/host/usage_stats_consent.h"
67 #include "remoting/jingle_glue/xmpp_signal_strategy.h"
68 #include "remoting/protocol/me2me_host_authenticator_factory.h"
73 #include "base/file_descriptor_posix.h"
74 #include "remoting/host/pam_authorization_factory_posix.h"
75 #include "remoting/host/posix/signal_handler.h"
76 #endif // defined(OS_POSIX)
78 #if defined(OS_MACOSX)
79 #include "base/mac/scoped_cftyperef.h"
80 #include "base/mac/scoped_nsautorelease_pool.h"
81 #endif // defined(OS_MACOSX)
84 #include "remoting/host/audio_capturer_linux.h"
85 #endif // defined(OS_LINUX)
89 #include "base/win/scoped_handle.h"
90 #include "remoting/host/win/session_desktop_environment.h"
91 #endif // defined(OS_WIN)
93 #if defined(TOOLKIT_GTK)
94 #include "ui/gfx/gtk_util.h"
95 #endif // defined(TOOLKIT_GTK)
99 // This is used for tagging system event logs.
100 const char kApplicationName
[] = "chromoting";
102 // The command line switch used to get version of the daemon.
103 const char kVersionSwitchName
[] = "version";
105 // The command line switch used to pass name of the pipe to capture audio on
107 const char kAudioPipeSwitchName
[] = "audio-pipe-name";
109 void QuitMessageLoop(MessageLoop
* message_loop
) {
110 message_loop
->PostTask(FROM_HERE
, MessageLoop::QuitClosure());
113 // Returns true if GetUsername() is implemented on this platform.
114 bool CanGetUsername() {
115 #if defined(OS_POSIX)
117 #else // !defined(OS_POSIX)
119 #endif // defined(OS_POSIX)
122 // Returns the username associated with this process, or the empty string on
124 std::string
GetUsername() {
125 #if defined(OS_POSIX)
126 long buf_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
129 scoped_array
<char> buf(new char[buf_size
]);
130 struct passwd passwd
;
131 struct passwd
* passwd_result
= NULL
;
132 getpwuid_r(getuid(), &passwd
, buf
.get(), buf_size
, &passwd_result
);
135 return std::string(passwd_result
->pw_name
);
136 #else // !defined(OS_POSIX)
139 #endif // defined(OS_POSIX)
147 : public ConfigFileWatcher::Delegate
,
148 public HeartbeatSender::Listener
,
149 public IPC::Listener
,
150 public base::RefCountedThreadSafe
<HostProcess
> {
152 HostProcess(scoped_ptr
<ChromotingHostContext
> context
,
155 // ConfigFileWatcher::Delegate interface.
156 virtual void OnConfigUpdated(const std::string
& serialized_config
) OVERRIDE
;
157 virtual void OnConfigWatcherError() OVERRIDE
;
159 // IPC::Listener implementation.
160 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
;
161 virtual void OnChannelError() OVERRIDE
;
163 // HeartbeatSender::Listener overrides.
164 virtual void OnUnknownHostIdError() OVERRIDE
;
168 // Host process has just been started. Waiting for config and policies to be
169 // read from the disk.
172 // Host is started and running.
175 // Host is being stopped and will need to be started again.
176 HOST_STOPPING_TO_RESTART
,
178 // Host is being stopped.
181 // Host has been stopped.
184 // Allowed state transitions:
185 // INITIALIZING->STARTED
186 // INITIALIZING->STOPPED
187 // STARTED->STOPPING_TO_RESTART
189 // STOPPING_TO_RESTART->STARTED
190 // STOPPING_TO_RESTART->STOPPING
194 // |host_| must be NULL in INITIALIZING and STOPPED states and not-NULL in
198 friend class base::RefCountedThreadSafe
<HostProcess
>;
199 virtual ~HostProcess();
201 void StartOnNetworkThread();
203 #if defined(OS_POSIX)
204 // Callback passed to RegisterSignalHandler() to handle SIGTERM events.
205 void SigTermHandler(int signal_number
);
208 // Called to initialize resources on the UI thread.
209 void StartOnUiThread();
211 // Initializes IPC control channel and config file path from |cmd_line|.
212 // Called on the UI thread.
213 bool InitWithCommandLine(const CommandLine
* cmd_line
);
215 // Called on the UI thread to start monitoring the configuration file.
216 void StartWatchingConfigChanges();
218 // Called on the network thread to set the host's Authenticator factory.
219 void CreateAuthenticatorFactory();
221 // Asks the daemon to inject Secure Attention Sequence to the console.
222 void SendSasToConsole();
224 // Tear down resources that run on the UI thread.
225 void ShutdownOnUiThread();
227 // Applies the host config, returning true if successful.
228 bool ApplyConfig(scoped_ptr
<JsonHostConfig
> config
);
230 void OnPolicyUpdate(scoped_ptr
<base::DictionaryValue
> policies
);
231 bool OnHostDomainPolicyUpdate(const std::string
& host_domain
);
232 bool OnUsernamePolicyUpdate(bool username_match_required
);
233 bool OnNatPolicyUpdate(bool nat_traversal_enabled
);
234 bool OnCurtainPolicyUpdate(bool curtain_required
);
235 bool OnHostTalkGadgetPrefixPolicyUpdate(const std::string
& talkgadget_prefix
);
241 void OnCurtainModeFailed();
243 void OnRemoteSessionSwitchedToConsole();
245 // Invoked when the user uses the Disconnect windows to terminate
246 // the sessions, or when the local session is activated in curtain mode.
247 void OnDisconnectRequested();
251 // Stops the host and shuts down the process with the specified |exit_code|.
252 void ShutdownHost(int exit_code
);
254 void ShutdownOnNetworkThread();
256 // Crashes the process in response to a daemon's request. The daemon passes
257 // the location of the code that detected the fatal error resulted in this
259 void OnCrash(const std::string
& function_name
,
260 const std::string
& file_name
,
261 const int& line_number
);
263 scoped_ptr
<ChromotingHostContext
> context_
;
265 // Created on the UI thread but used from the network thread.
266 scoped_ptr
<net::NetworkChangeNotifier
> network_change_notifier_
;
268 // Accessed on the UI thread.
269 scoped_ptr
<IPC::ChannelProxy
> daemon_channel_
;
270 FilePath host_config_path_
;
271 scoped_ptr
<DesktopEnvironmentFactory
> desktop_environment_factory_
;
273 // Accessed on the network thread.
276 scoped_ptr
<ConfigFileWatcher
> config_watcher_
;
278 std::string host_id_
;
279 protocol::SharedSecretHash host_secret_hash_
;
280 HostKeyPair key_pair_
;
281 std::string oauth_refresh_token_
;
282 std::string serialized_config_
;
283 std::string xmpp_login_
;
284 std::string xmpp_auth_token_
;
285 std::string xmpp_auth_service_
;
287 scoped_ptr
<policy_hack::PolicyWatcher
> policy_watcher_
;
288 bool allow_nat_traversal_
;
289 std::string talkgadget_prefix_
;
291 scoped_ptr
<CurtainMode
> curtain_
;
292 scoped_ptr
<CurtainingHostObserver
> curtaining_host_observer_
;
293 bool curtain_required_
;
295 scoped_ptr
<DesktopResizer
> desktop_resizer_
;
296 scoped_ptr
<ResizingHostObserver
> resizing_host_observer_
;
297 scoped_ptr
<XmppSignalStrategy
> signal_strategy_
;
298 scoped_ptr
<SignalingConnector
> signaling_connector_
;
299 scoped_ptr
<HeartbeatSender
> heartbeat_sender_
;
300 scoped_ptr
<LogToServer
> log_to_server_
;
301 scoped_ptr
<HostEventLogger
> host_event_logger_
;
303 // Created on the UI thread and used on the network thread.
304 scoped_ptr
<HostUserInterface
> host_user_interface_
;
306 scoped_refptr
<ChromotingHost
> host_
;
308 // Used to keep this HostProcess alive until it is shutdown.
309 scoped_refptr
<HostProcess
> self_
;
311 #if defined(REMOTING_MULTI_PROCESS)
312 DesktopSessionConnector
* desktop_session_connector_
;
313 #endif // defined(REMOTING_MULTI_PROCESS)
318 HostProcess::HostProcess(scoped_ptr
<ChromotingHostContext
> context
,
320 : context_(context
.Pass()),
321 state_(HOST_INITIALIZING
),
322 allow_nat_traversal_(true),
323 curtain_required_(false),
324 desktop_resizer_(DesktopResizer::Create()),
325 #if defined(REMOTING_MULTI_PROCESS)
326 desktop_session_connector_(NULL
),
327 #endif // defined(REMOTING_MULTI_PROCESS)
328 ALLOW_THIS_IN_INITIALIZER_LIST(self_(this)),
329 exit_code_out_(exit_code_out
) {
330 // Create a NetworkChangeNotifier for use by the signalling connector.
331 network_change_notifier_
.reset(net::NetworkChangeNotifier::Create());
333 // Create the platform-specific curtain-mode implementation.
334 // TODO(wez): Create this on the network thread?
335 curtain_
= CurtainMode::Create(
336 base::Bind(&HostProcess::OnRemoteSessionSwitchedToConsole
,
337 base::Unretained(this)),
338 base::Bind(&HostProcess::OnCurtainModeFailed
,
339 base::Unretained(this)));
344 HostProcess::~HostProcess() {
345 // Verify that UI components have been torn down.
346 DCHECK(!config_watcher_
);
347 DCHECK(!daemon_channel_
);
348 DCHECK(!desktop_environment_factory_
);
349 DCHECK(!host_user_interface_
);
351 // We might be getting deleted on one of the threads the |host_context| owns,
352 // so we need to post it back to the caller thread to safely join & delete the
353 // threads it contains. This will go away when we move to AutoThread.
354 // |context_release()| will null |context_| before the method is invoked, so
355 // we need to pull out the task-runner on which to call DeleteSoon first.
356 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
=
357 context_
->ui_task_runner();
358 task_runner
->DeleteSoon(FROM_HERE
, context_
.release());
361 bool HostProcess::InitWithCommandLine(const CommandLine
* cmd_line
) {
362 #if defined(REMOTING_MULTI_PROCESS)
363 // Parse the handle value and convert it to a handle/file descriptor.
364 std::string channel_name
=
365 cmd_line
->GetSwitchValueASCII(kDaemonPipeSwitchName
);
368 if (channel_name
.empty() ||
369 !base::StringToInt(channel_name
, &pipe_handle
)) {
370 LOG(ERROR
) << "Invalid '" << kDaemonPipeSwitchName
371 << "' value: " << channel_name
;
376 base::win::ScopedHandle
pipe(reinterpret_cast<HANDLE
>(pipe_handle
));
377 IPC::ChannelHandle
channel_handle(pipe
);
378 #elif defined(OS_POSIX)
379 base::FileDescriptor
pipe(pipe_handle
, true);
380 IPC::ChannelHandle
channel_handle(channel_name
, pipe
);
381 #endif // defined(OS_POSIX)
383 // Connect to the daemon process.
384 daemon_channel_
.reset(new IPC::ChannelProxy(
386 IPC::Channel::MODE_CLIENT
,
388 context_
->network_task_runner()));
389 #else // !defined(REMOTING_MULTI_PROCESS)
390 // Connect to the daemon process.
391 std::string channel_name
=
392 cmd_line
->GetSwitchValueASCII(kDaemonPipeSwitchName
);
393 if (!channel_name
.empty()) {
394 daemon_channel_
.reset(new IPC::ChannelProxy(
395 channel_name
, IPC::Channel::MODE_CLIENT
, this,
396 context_
->network_task_runner()));
399 FilePath default_config_dir
= remoting::GetConfigDir();
400 host_config_path_
= default_config_dir
.Append(kDefaultHostConfigFile
);
401 if (cmd_line
->HasSwitch(kHostConfigSwitchName
)) {
402 host_config_path_
= cmd_line
->GetSwitchValuePath(kHostConfigSwitchName
);
404 #endif // !defined(REMOTING_MULTI_PROCESS)
409 void HostProcess::OnConfigUpdated(
410 const std::string
& serialized_config
) {
411 if (!context_
->network_task_runner()->BelongsToCurrentThread()) {
412 context_
->network_task_runner()->PostTask(FROM_HERE
,
413 base::Bind(&HostProcess::OnConfigUpdated
, this, serialized_config
));
417 // Filter out duplicates.
418 if (serialized_config_
== serialized_config
)
421 LOG(INFO
) << "Processing new host configuration.";
423 serialized_config_
= serialized_config
;
424 scoped_ptr
<JsonHostConfig
> config(new JsonHostConfig(FilePath()));
425 if (!config
->SetSerializedData(serialized_config
)) {
426 LOG(ERROR
) << "Invalid configuration.";
427 ShutdownHost(kInvalidHostConfigurationExitCode
);
431 if (!ApplyConfig(config
.Pass())) {
432 LOG(ERROR
) << "Failed to apply the configuration.";
433 ShutdownHost(kInvalidHostConfigurationExitCode
);
437 if (state_
== HOST_INITIALIZING
) {
438 // TODO(sergeyu): Currently OnPolicyUpdate() assumes that host config is
439 // already loaded so PolicyWatcher has to be started here. Separate policy
440 // loading from policy verifications and move |policy_watcher_|
441 // initialization to StartOnNetworkThread().
442 policy_watcher_
.reset(
443 policy_hack::PolicyWatcher::Create(context_
->file_task_runner()));
444 policy_watcher_
->StartWatching(
445 base::Bind(&HostProcess::OnPolicyUpdate
, base::Unretained(this)));
446 } else if (state_
== HOST_STARTED
) {
447 // TODO(sergeyu): Here we assume that PIN is the only part of the config
448 // that may change while the service is running. Change ApplyConfig() to
449 // detect other changes in the config and restart host if necessary here.
450 CreateAuthenticatorFactory();
454 void HostProcess::OnConfigWatcherError() {
455 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
456 ShutdownHost(kInvalidHostConfigurationExitCode
);
459 void HostProcess::StartOnNetworkThread() {
460 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
462 #if !defined(REMOTING_MULTI_PROCESS)
463 // Start watching the host configuration file.
464 config_watcher_
.reset(new ConfigFileWatcher(context_
->network_task_runner(),
465 context_
->file_task_runner(),
467 config_watcher_
->Watch(host_config_path_
);
468 #endif // !defined(REMOTING_MULTI_PROCESS)
470 #if defined(OS_POSIX)
471 remoting::RegisterSignalHandler(
473 base::Bind(&HostProcess::SigTermHandler
, base::Unretained(this)));
474 #endif // defined(OS_POSIX)
477 #if defined(OS_POSIX)
478 void HostProcess::SigTermHandler(int signal_number
) {
479 DCHECK(signal_number
== SIGTERM
);
480 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
481 LOG(INFO
) << "Caught SIGTERM: Shutting down...";
482 ShutdownHost(kSuccessExitCode
);
486 void HostProcess::CreateAuthenticatorFactory() {
487 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
489 if (state_
!= HOST_STARTED
)
492 std::string local_certificate
= key_pair_
.GenerateCertificate();
493 if (local_certificate
.empty()) {
494 LOG(ERROR
) << "Failed to generate host certificate.";
495 ShutdownHost(kInitializationFailed
);
499 scoped_ptr
<protocol::AuthenticatorFactory
> factory(
500 new protocol::Me2MeHostAuthenticatorFactory(
501 local_certificate
, *key_pair_
.private_key(), host_secret_hash_
));
502 #if defined(OS_POSIX)
503 // On Linux and Mac, perform a PAM authorization step after authentication.
504 factory
.reset(new PamAuthorizationFactory(factory
.Pass()));
506 host_
->SetAuthenticatorFactory(factory
.Pass());
509 // IPC::Listener implementation.
510 bool HostProcess::OnMessageReceived(const IPC::Message
& message
) {
511 DCHECK(context_
->ui_task_runner()->BelongsToCurrentThread());
513 #if defined(REMOTING_MULTI_PROCESS)
515 IPC_BEGIN_MESSAGE_MAP(HostProcess
, message
)
516 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Crash
,
518 IPC_MESSAGE_HANDLER(ChromotingDaemonNetworkMsg_Configuration
,
521 ChromotingDaemonNetworkMsg_DesktopAttached
,
522 desktop_session_connector_
,
523 DesktopSessionConnector::OnDesktopSessionAgentAttached
)
524 IPC_MESSAGE_FORWARD(ChromotingDaemonNetworkMsg_TerminalDisconnected
,
525 desktop_session_connector_
,
526 DesktopSessionConnector::OnTerminalDisconnected
)
527 IPC_MESSAGE_UNHANDLED(handled
= false)
528 IPC_END_MESSAGE_MAP()
530 #else // !defined(REMOTING_MULTI_PROCESS)
532 #endif // !defined(REMOTING_MULTI_PROCESS)
535 void HostProcess::OnChannelError() {
536 DCHECK(context_
->ui_task_runner()->BelongsToCurrentThread());
538 // Shutdown the host if the daemon process disconnects the IPC channel.
539 context_
->network_task_runner()->PostTask(
541 base::Bind(&HostProcess::ShutdownHost
, this, kSuccessExitCode
));
544 void HostProcess::StartOnUiThread() {
545 DCHECK(context_
->ui_task_runner()->BelongsToCurrentThread());
547 if (!InitWithCommandLine(CommandLine::ForCurrentProcess())) {
548 OnConfigWatcherError();
552 #if defined(OS_LINUX)
553 // TODO(sergeyu): Pass configuration parameters to the Linux-specific version
554 // of DesktopEnvironmentFactory when we have it.
555 media::ScreenCapturer::EnableXDamage(true);
557 // If an audio pipe is specific on the command-line then initialize
558 // AudioCapturerLinux to capture from it.
559 FilePath audio_pipe_name
= CommandLine::ForCurrentProcess()->
560 GetSwitchValuePath(kAudioPipeSwitchName
);
561 if (!audio_pipe_name
.empty()) {
562 remoting::AudioCapturerLinux::InitializePipeReader(
563 context_
->audio_task_runner(), audio_pipe_name
);
565 #endif // defined(OS_LINUX)
567 // Create a desktop environment factory appropriate to the build type &
571 #if defined(REMOTING_MULTI_PROCESS)
572 IpcDesktopEnvironmentFactory
* desktop_environment_factory
=
573 new IpcDesktopEnvironmentFactory(
574 context_
->network_task_runner(),
575 daemon_channel_
.get());
576 desktop_session_connector_
= desktop_environment_factory
;
577 #else // !defined(REMOTING_MULTI_PROCESS)
578 DesktopEnvironmentFactory
* desktop_environment_factory
=
579 new SessionDesktopEnvironmentFactory(
580 base::Bind(&HostProcess::SendSasToConsole
, this));
581 #endif // !defined(REMOTING_MULTI_PROCESS)
583 #else // !defined(OS_WIN)
584 DesktopEnvironmentFactory
* desktop_environment_factory
=
585 new BasicDesktopEnvironmentFactory();
586 #endif // !defined(OS_WIN)
588 desktop_environment_factory_
.reset(desktop_environment_factory
);
590 // The host UI should be created on the UI thread.
591 bool want_user_interface
= true;
592 #if defined(OS_LINUX) || defined(REMOTING_MULTI_PROCESS)
593 want_user_interface
= false;
594 #elif defined(OS_MACOSX)
595 // Don't try to display any UI on top of the system's login screen as this
596 // is rejected by the Window Server on OS X 10.7.4, and prevents the
597 // capturer from working (http://crbug.com/140984).
599 // TODO(lambroslambrou): Use a better technique of detecting whether we're
600 // running in the LoginWindow context, and refactor this into a separate
601 // function to be used here and in CurtainMode::ActivateCurtain().
602 want_user_interface
= getuid() != 0;
605 if (want_user_interface
) {
606 UiStrings ui_strings
;
607 host_user_interface_
.reset(
608 new HostUserInterface(context_
->network_task_runner(),
609 context_
->ui_task_runner(), ui_strings
));
610 host_user_interface_
->Init();
613 context_
->network_task_runner()->PostTask(
615 base::Bind(&HostProcess::StartOnNetworkThread
, this));
618 void HostProcess::SendSasToConsole() {
619 DCHECK(context_
->ui_task_runner()->BelongsToCurrentThread());
622 daemon_channel_
->Send(new ChromotingNetworkDaemonMsg_SendSasToConsole());
625 void HostProcess::ShutdownOnUiThread() {
626 DCHECK(context_
->ui_task_runner()->BelongsToCurrentThread());
628 // Tear down resources that need to be torn down on the UI thread.
629 network_change_notifier_
.reset();
630 daemon_channel_
.reset();
631 desktop_environment_factory_
.reset();
632 host_user_interface_
.reset();
634 // It is now safe for the HostProcess to be deleted.
637 #if defined(OS_LINUX)
638 // Cause the global AudioPipeReader to be freed, otherwise the audio
639 // thread will remain in-use and prevent the process from exiting.
640 // TODO(wez): DesktopEnvironmentFactory should own the pipe reader.
641 // See crbug.com/161373 and crbug.com/104544.
642 AudioCapturerLinux::InitializePipeReader(NULL
, FilePath());
646 // Overridden from HeartbeatSender::Listener
647 void HostProcess::OnUnknownHostIdError() {
648 LOG(ERROR
) << "Host ID not found.";
649 ShutdownHost(kInvalidHostIdExitCode
);
652 // Applies the host config, returning true if successful.
653 bool HostProcess::ApplyConfig(scoped_ptr
<JsonHostConfig
> config
) {
654 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
656 if (!config
->GetString(kHostIdConfigPath
, &host_id_
)) {
657 LOG(ERROR
) << "host_id is not defined in the config.";
661 if (!key_pair_
.Load(*config
)) {
665 std::string host_secret_hash_string
;
666 if (!config
->GetString(kHostSecretHashConfigPath
,
667 &host_secret_hash_string
)) {
668 host_secret_hash_string
= "plain:";
671 if (!host_secret_hash_
.Parse(host_secret_hash_string
)) {
672 LOG(ERROR
) << "Invalid host_secret_hash.";
676 // Use an XMPP connection to the Talk network for session signalling.
677 if (!config
->GetString(kXmppLoginConfigPath
, &xmpp_login_
) ||
678 !(config
->GetString(kXmppAuthTokenConfigPath
, &xmpp_auth_token_
) ||
679 config
->GetString(kOAuthRefreshTokenConfigPath
,
680 &oauth_refresh_token_
))) {
681 LOG(ERROR
) << "XMPP credentials are not defined in the config.";
685 if (!oauth_refresh_token_
.empty()) {
686 xmpp_auth_token_
= ""; // This will be set to the access token later.
687 xmpp_auth_service_
= "oauth2";
688 } else if (!config
->GetString(kXmppAuthServiceConfigPath
,
689 &xmpp_auth_service_
)) {
690 // For the me2me host, we default to ClientLogin token for chromiumsync
691 // because earlier versions of the host had no HTTP stack with which to
692 // request an OAuth2 access token.
693 xmpp_auth_service_
= kChromotingTokenDefaultServiceName
;
698 void HostProcess::OnPolicyUpdate(scoped_ptr
<base::DictionaryValue
> policies
) {
699 // TODO(rmsousa): Consolidate all On*PolicyUpdate methods into this one.
700 // TODO(sergeyu): Currently polices are verified only when they are loaded.
701 // Separate policy loading from policy verifications - this will allow to
702 // check policies again later, e.g. when host config changes.
704 if (!context_
->network_task_runner()->BelongsToCurrentThread()) {
705 context_
->network_task_runner()->PostTask(FROM_HERE
, base::Bind(
706 &HostProcess::OnPolicyUpdate
, this, base::Passed(&policies
)));
710 bool restart_required
= false;
712 std::string string_value
;
713 if (policies
->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName
,
715 restart_required
|= OnHostDomainPolicyUpdate(string_value
);
717 if (policies
->GetBoolean(
718 policy_hack::PolicyWatcher::kHostMatchUsernamePolicyName
,
720 restart_required
|= OnUsernamePolicyUpdate(bool_value
);
722 if (policies
->GetBoolean(policy_hack::PolicyWatcher::kNatPolicyName
,
724 restart_required
|= OnNatPolicyUpdate(bool_value
);
726 if (policies
->GetString(
727 policy_hack::PolicyWatcher::kHostTalkGadgetPrefixPolicyName
,
729 restart_required
|= OnHostTalkGadgetPrefixPolicyUpdate(string_value
);
731 if (policies
->GetBoolean(
732 policy_hack::PolicyWatcher::kHostRequireCurtainPolicyName
,
734 restart_required
|= OnCurtainPolicyUpdate(bool_value
);
737 if (state_
== HOST_INITIALIZING
) {
739 } else if (state_
== HOST_STARTED
&& restart_required
) {
744 bool HostProcess::OnHostDomainPolicyUpdate(const std::string
& host_domain
) {
745 // Returns true if the host has to be restarted after this policy update.
746 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
748 LOG(INFO
) << "Policy sets host domain: " << host_domain
;
750 if (!host_domain
.empty() &&
751 !EndsWith(xmpp_login_
, std::string("@") + host_domain
, false)) {
752 ShutdownHost(kInvalidHostDomainExitCode
);
757 bool HostProcess::OnUsernamePolicyUpdate(bool host_username_match_required
) {
758 // Returns false: never restart the host after this policy update.
759 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
761 if (host_username_match_required
) {
762 LOG(INFO
) << "Policy requires host username match.";
763 bool shutdown
= !CanGetUsername() ||
764 !StartsWithASCII(xmpp_login_
, GetUsername() + std::string("@"),
767 #if defined(OS_MACOSX)
768 // On Mac, we run as root at the login screen, so the username won't match.
769 // However, there's no need to enforce the policy at the login screen, as
770 // the client will have to reconnect if a login occurs.
771 if (shutdown
&& getuid() == 0) {
777 ShutdownHost(kUsernameMismatchExitCode
);
780 LOG(INFO
) << "Policy does not require host username match.";
786 bool HostProcess::OnNatPolicyUpdate(bool nat_traversal_enabled
) {
787 // Returns true if the host has to be restarted after this policy update.
788 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
790 if (allow_nat_traversal_
!= nat_traversal_enabled
) {
791 if (nat_traversal_enabled
)
792 LOG(INFO
) << "Policy enables NAT traversal.";
794 LOG(INFO
) << "Policy disables NAT traversal.";
795 allow_nat_traversal_
= nat_traversal_enabled
;
801 bool HostProcess::OnCurtainPolicyUpdate(bool curtain_required
) {
802 // Returns true if the host has to be restarted after this policy update.
803 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
805 #if defined(OS_MACOSX)
806 if (curtain_required
) {
807 // When curtain mode is in effect on Mac, the host process runs in the
808 // user's switched-out session, but launchd will also run an instance at
809 // the console login screen. Even if no user is currently logged-on, we
810 // can't support remote-access to the login screen because the current host
811 // process model disconnects the client during login, which would leave
812 // the logged in session un-curtained on the console until they reconnect.
814 // TODO(jamiewalch): Fix this once we have implemented the multi-process
815 // daemon architecture (crbug.com/134894)
817 ShutdownHost(kLoginScreenNotSupportedExitCode
);
823 if (curtain_required_
!= curtain_required
) {
824 if (curtain_required
)
825 LOG(ERROR
) << "Policy requires curtain-mode.";
827 LOG(ERROR
) << "Policy does not require curtain-mode.";
828 curtain_required_
= curtain_required
;
829 if (curtaining_host_observer_
)
830 curtaining_host_observer_
->SetEnableCurtaining(curtain_required_
);
836 bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate(
837 const std::string
& talkgadget_prefix
) {
838 // Returns true if the host has to be restarted after this policy update.
839 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
841 if (talkgadget_prefix
!= talkgadget_prefix_
) {
842 LOG(INFO
) << "Policy sets talkgadget prefix: " << talkgadget_prefix
;
843 talkgadget_prefix_
= talkgadget_prefix
;
849 void HostProcess::StartHost() {
850 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
852 DCHECK(!signal_strategy_
.get());
853 DCHECK(state_
== HOST_INITIALIZING
|| state_
== HOST_STOPPING_TO_RESTART
||
854 state_
== HOST_STOPPED
) << state_
;
855 state_
= HOST_STARTED
;
857 signal_strategy_
.reset(
858 new XmppSignalStrategy(context_
->url_request_context_getter(),
859 xmpp_login_
, xmpp_auth_token_
,
860 xmpp_auth_service_
));
862 scoped_ptr
<DnsBlackholeChecker
> dns_blackhole_checker(
863 new DnsBlackholeChecker(context_
->url_request_context_getter(),
864 talkgadget_prefix_
));
866 signaling_connector_
.reset(new SignalingConnector(
867 signal_strategy_
.get(),
868 context_
->url_request_context_getter(),
869 dns_blackhole_checker
.Pass(),
870 base::Bind(&HostProcess::OnAuthFailed
, this)));
872 if (!oauth_refresh_token_
.empty()) {
873 scoped_ptr
<SignalingConnector::OAuthCredentials
> oauth_credentials(
874 new SignalingConnector::OAuthCredentials(
875 xmpp_login_
, oauth_refresh_token_
));
876 signaling_connector_
->EnableOAuth(oauth_credentials
.Pass());
879 NetworkSettings
network_settings(
880 allow_nat_traversal_
?
881 NetworkSettings::NAT_TRAVERSAL_ENABLED
:
882 NetworkSettings::NAT_TRAVERSAL_DISABLED
);
883 if (!allow_nat_traversal_
) {
884 network_settings
.min_port
= NetworkSettings::kDefaultMinPort
;
885 network_settings
.max_port
= NetworkSettings::kDefaultMaxPort
;
888 host_
= new ChromotingHost(
889 signal_strategy_
.get(),
890 desktop_environment_factory_
.get(),
891 CreateHostSessionManager(network_settings
,
892 context_
->url_request_context_getter()),
893 context_
->audio_task_runner(),
894 context_
->input_task_runner(),
895 context_
->video_capture_task_runner(),
896 context_
->video_encode_task_runner(),
897 context_
->network_task_runner(),
898 context_
->ui_task_runner());
900 // TODO(simonmorris): Get the maximum session duration from a policy.
901 #if defined(OS_LINUX)
902 host_
->SetMaximumSessionDuration(base::TimeDelta::FromHours(20));
905 heartbeat_sender_
.reset(new HeartbeatSender(
906 this, host_id_
, signal_strategy_
.get(), &key_pair_
));
908 log_to_server_
.reset(
909 new LogToServer(host_
, ServerLogEntry::ME2ME
, signal_strategy_
.get()));
910 host_event_logger_
= HostEventLogger::Create(host_
, kApplicationName
);
912 resizing_host_observer_
.reset(
913 new ResizingHostObserver(desktop_resizer_
.get(), host_
));
915 // Create a host observer to enable/disable curtain mode as clients connect
917 curtaining_host_observer_
.reset(new CurtainingHostObserver(
918 curtain_
.get(), host_
));
919 curtaining_host_observer_
->SetEnableCurtaining(curtain_required_
);
921 if (host_user_interface_
.get()) {
922 host_user_interface_
->Start(
923 host_
, base::Bind(&HostProcess::OnDisconnectRequested
, this));
926 host_
->Start(xmpp_login_
);
928 CreateAuthenticatorFactory();
931 void HostProcess::OnAuthFailed() {
932 ShutdownHost(kInvalidOauthCredentialsExitCode
);
935 void HostProcess::OnCurtainModeFailed() {
936 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
938 LOG(ERROR
) << "Curtain mode failed to activate. Closing connection.";
939 host_
->RejectAuthenticatingClient();
942 void HostProcess::OnRemoteSessionSwitchedToConsole() {
943 LOG(INFO
) << "The remote session switched was to the console."
944 " Closing connection.";
945 OnDisconnectRequested();
948 // Invoked when the user uses the Disconnect windows to terminate
949 // the sessions, or when the local session is activated in curtain mode.
950 void HostProcess::OnDisconnectRequested() {
951 if (!context_
->network_task_runner()->BelongsToCurrentThread()) {
952 context_
->network_task_runner()->PostTask(FROM_HERE
,
953 base::Bind(&HostProcess::OnDisconnectRequested
, this));
957 host_
->DisconnectAllClients();
961 void HostProcess::RestartHost() {
962 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
963 DCHECK_EQ(state_
, HOST_STARTED
);
965 state_
= HOST_STOPPING_TO_RESTART
;
966 host_
->Shutdown(base::Bind(&HostProcess::ShutdownOnNetworkThread
, this));
969 void HostProcess::ShutdownHost(int exit_code
) {
970 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
972 *exit_code_out_
= exit_code
;
975 case HOST_INITIALIZING
:
976 state_
= HOST_STOPPING
;
977 ShutdownOnNetworkThread();
981 state_
= HOST_STOPPING
;
982 host_
->Shutdown(base::Bind(&HostProcess::ShutdownOnNetworkThread
, this));
985 case HOST_STOPPING_TO_RESTART
:
986 state_
= HOST_STOPPING
;
991 // Host is already stopped or being stopped. No action is required.
996 void HostProcess::ShutdownOnNetworkThread() {
997 DCHECK(context_
->network_task_runner()->BelongsToCurrentThread());
1000 curtaining_host_observer_
.reset();
1001 host_event_logger_
.reset();
1002 log_to_server_
.reset();
1003 heartbeat_sender_
.reset();
1004 signaling_connector_
.reset();
1005 signal_strategy_
.reset();
1006 resizing_host_observer_
.reset();
1008 if (state_
== HOST_STOPPING_TO_RESTART
) {
1010 } else if (state_
== HOST_STOPPING
) {
1011 state_
= HOST_STOPPED
;
1013 if (policy_watcher_
.get()) {
1014 base::WaitableEvent
done_event(true, false);
1015 policy_watcher_
->StopWatching(&done_event
);
1017 policy_watcher_
.reset();
1020 config_watcher_
.reset();
1022 // Complete the rest of shutdown on the main thread.
1023 context_
->ui_task_runner()->PostTask(
1025 base::Bind(&HostProcess::ShutdownOnUiThread
, this));
1027 // This method is used as a callback for ChromotingHost::Shutdown() which is
1028 // called only in STOPPING_TO_RESTART and STOPPING states.
1033 void HostProcess::OnCrash(const std::string
& function_name
,
1034 const std::string
& file_name
,
1035 const int& line_number
) {
1039 } // namespace remoting
1041 int main(int argc
, char** argv
) {
1042 #if defined(OS_MACOSX)
1043 // Needed so we don't leak objects when threads are created.
1044 base::mac::ScopedNSAutoreleasePool pool
;
1047 CommandLine::Init(argc
, argv
);
1049 // Initialize Breakpad as early as possible. On Windows, this happens in
1050 // WinMain(), so it shouldn't also be done here. The command-line needs to be
1051 // initialized first, so that the preference for crash-reporting can be looked
1052 // up in the config file.
1053 #if defined(MAC_BREAKPAD)
1054 if (remoting::IsUsageStatsAllowed()) {
1055 remoting::InitializeCrashReporting();
1057 #endif // MAC_BREAKPAD
1059 // This object instance is required by Chrome code (for example,
1060 // LazyInstance, MessageLoop).
1061 base::AtExitManager exit_manager
;
1063 if (CommandLine::ForCurrentProcess()->HasSwitch(kVersionSwitchName
)) {
1064 printf("%s\n", STRINGIZE(VERSION
));
1068 remoting::InitHostLogging();
1070 #if defined(TOOLKIT_GTK)
1071 // Required for any calls into GTK functions, such as the Disconnect and
1072 // Continue windows, though these should not be used for the Me2Me case
1073 // (crbug.com/104377).
1074 const CommandLine
* cmd_line
= CommandLine::ForCurrentProcess();
1075 gfx::GtkInitFromCommandLine(*cmd_line
);
1076 #endif // TOOLKIT_GTK
1078 // Enable support for SSL server sockets, which must be done while still
1080 net::EnableSSLServerSockets();
1082 // Create the main message loop and start helper threads.
1083 MessageLoop
message_loop(MessageLoop::TYPE_UI
);
1084 scoped_ptr
<remoting::ChromotingHostContext
> context
=
1085 remoting::ChromotingHostContext::Create(
1086 new remoting::AutoThreadTaskRunner(message_loop
.message_loop_proxy(),
1087 MessageLoop::QuitClosure()));
1089 return remoting::kInitializationFailed
;
1091 // Create & start the HostProcess using these threads.
1092 // TODO(wez): The HostProcess holds a reference to itself until Shutdown().
1093 // Remove this hack as part of the multi-process refactoring.
1094 int exit_code
= remoting::kSuccessExitCode
;
1095 new remoting::HostProcess(context
.Pass(), &exit_code
);
1097 // Run the main (also UI) message loop until the host no longer needs it.
1104 HMODULE g_hModule
= NULL
;
1106 int CALLBACK
WinMain(HINSTANCE instance
,
1107 HINSTANCE previous_instance
,
1110 #if defined(OFFICIAL_BUILD)
1111 if (remoting::IsUsageStatsAllowed()) {
1112 remoting::InitializeCrashReporting();
1114 #endif // OFFICIAL_BUILD
1116 g_hModule
= instance
;
1118 // Register and initialize common controls.
1119 INITCOMMONCONTROLSEX info
;
1120 info
.dwSize
= sizeof(info
);
1121 info
.dwICC
= ICC_STANDARD_CLASSES
;
1122 InitCommonControlsEx(&info
);
1124 // Mark the process as DPI-aware, so Windows won't scale coordinates in APIs.
1125 // N.B. This API exists on Vista and above.
1126 if (base::win::GetVersion() >= base::win::VERSION_VISTA
) {
1127 FilePath
path(base::GetNativeLibraryName(UTF8ToUTF16("user32")));
1128 base::ScopedNativeLibrary
user32(path
);
1129 CHECK(user32
.is_valid());
1131 typedef BOOL (WINAPI
* SetProcessDPIAwareFn
)();
1132 SetProcessDPIAwareFn set_process_dpi_aware
=
1133 static_cast<SetProcessDPIAwareFn
>(
1134 user32
.GetFunctionPointer("SetProcessDPIAware"));
1135 set_process_dpi_aware();
1138 // CommandLine::Init() ignores the passed |argc| and |argv| on Windows getting
1139 // the command line from GetCommandLineW(), so we can safely pass NULL here.
1140 return main(0, NULL
);
1143 #endif // defined(OS_WIN)