Commit e59e30dc authored by jamiewalch@google.com's avatar jamiewalch@google.com

Make curtain-mode controllable by policy.

BUG=110111

Review URL: https://chromiumcodereview.appspot.com/10829306

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151714 0039d316-1c4b-4281-b951-d872f2087c98
parent f0417774
...@@ -29,11 +29,12 @@ enum HostExitCodes { ...@@ -29,11 +29,12 @@ enum HostExitCodes {
kInvalidHostIdExitCode = 3, kInvalidHostIdExitCode = 3,
kInvalidOauthCredentialsExitCode = 4, kInvalidOauthCredentialsExitCode = 4,
kInvalidHostDomainExitCode = 5, kInvalidHostDomainExitCode = 5,
kLoginScreenNotSupportedExitCode = 6,
// The range of the exit codes that should be interpreted as a permanent error // The range of the exit codes that should be interpreted as a permanent error
// condition. // condition.
kMinPermanentErrorExitCode = kInvalidHostConfigurationExitCode, kMinPermanentErrorExitCode = kInvalidHostConfigurationExitCode,
kMaxPermanentErrorExitCode = kInvalidHostDomainExitCode kMaxPermanentErrorExitCode = kLoginScreenNotSupportedExitCode
}; };
#if defined(OS_WIN) #if defined(OS_WIN)
......
...@@ -18,30 +18,37 @@ const char* kCGSessionPath = ...@@ -18,30 +18,37 @@ const char* kCGSessionPath =
namespace remoting { namespace remoting {
CurtainMode::CurtainMode() : event_handler_(NULL) { CurtainMode::CurtainMode(const base::Closure& on_session_activate,
const base::Closure& on_error)
: on_session_activate_(on_session_activate),
on_error_(on_error),
connection_active_(false),
event_handler_(NULL) {
} }
CurtainMode::~CurtainMode() { CurtainMode::~CurtainMode() {
if (event_handler_) { SetEnabled(false);
RemoveEventHandler(event_handler_);
}
} }
bool CurtainMode::Init(const base::Closure& on_session_activate) { void CurtainMode::SetEnabled(bool enabled) {
DCHECK(on_session_activate_.is_null()); if (enabled) {
on_session_activate_ = on_session_activate; if (connection_active_) {
EventTypeSpec event; if (!ActivateCurtain()) {
event.eventClass = kEventClassSystem; on_error_.Run();
event.eventKind = kEventSystemUserSessionActivated; }
OSStatus result = InstallApplicationEventHandler( }
NewEventHandlerUPP(SessionActivateHandler), 1, &event, this, } else {
&event_handler_); RemoveEventHandler();
return result == noErr; }
} }
void CurtainMode::OnClientAuthenticated(const std::string& jid) { bool CurtainMode::ActivateCurtain() {
// If the current session is attached to the console and is not showing // Try to install the switch-in handler. Do this before switching out the
// the logon screen then switch it out to ensure privacy. // current session so that the console session is not affected if it fails.
if (!InstallEventHandler()) {
return false;
}
base::mac::ScopedCFTypeRef<CFDictionaryRef> session( base::mac::ScopedCFTypeRef<CFDictionaryRef> session(
CGSessionCopyCurrentDictionary()); CGSessionCopyCurrentDictionary());
const void* on_console = CFDictionaryGetValue(session, const void* on_console = CFDictionaryGetValue(session,
...@@ -55,8 +62,29 @@ void CurtainMode::OnClientAuthenticated(const std::string& jid) { ...@@ -55,8 +62,29 @@ void CurtainMode::OnClientAuthenticated(const std::string& jid) {
} else if (child > 0) { } else if (child > 0) {
int status = 0; int status = 0;
waitpid(child, &status, 0); waitpid(child, &status, 0);
if (status != 0) {
LOG(ERROR) << kCGSessionPath << " failed.";
return false;
}
} else {
LOG(ERROR) << "fork() failed.";
return false;
} }
} }
return true;
}
// TODO(jamiewalch): This code assumes at most one client connection at a time.
// Add OnFirstClientConnected and OnLastClientDisconnected optional callbacks
// to the HostStatusObserver interface to address this.
void CurtainMode::OnClientAuthenticated(const std::string& jid) {
connection_active_ = true;
SetEnabled(true);
}
void CurtainMode::OnClientDisconnected(const std::string& jid) {
SetEnabled(false);
connection_active_ = false;
} }
OSStatus CurtainMode::SessionActivateHandler(EventHandlerCallRef handler, OSStatus CurtainMode::SessionActivateHandler(EventHandlerCallRef handler,
...@@ -68,9 +96,28 @@ OSStatus CurtainMode::SessionActivateHandler(EventHandlerCallRef handler, ...@@ -68,9 +96,28 @@ OSStatus CurtainMode::SessionActivateHandler(EventHandlerCallRef handler,
} }
void CurtainMode::OnSessionActivate() { void CurtainMode::OnSessionActivate() {
if (!on_session_activate_.is_null()) {
on_session_activate_.Run(); on_session_activate_.Run();
}
bool CurtainMode::InstallEventHandler() {
OSStatus result = noErr;
if (!event_handler_) {
EventTypeSpec event;
event.eventClass = kEventClassSystem;
event.eventKind = kEventSystemUserSessionActivated;
result = ::InstallApplicationEventHandler(
NewEventHandlerUPP(SessionActivateHandler), 1, &event, this,
&event_handler_);
}
return result == noErr;
}
bool CurtainMode::RemoveEventHandler() {
OSStatus result = noErr;
if (event_handler_) {
result = ::RemoveEventHandler(event_handler_);
} }
return result == noErr;
} }
} // namespace remoting } // namespace remoting
...@@ -17,27 +17,46 @@ namespace remoting { ...@@ -17,27 +17,46 @@ namespace remoting {
class CurtainMode : public HostStatusObserver { class CurtainMode : public HostStatusObserver {
public: public:
CurtainMode(); // Set callbacks to be invoked when the switched-out session is switched back
// to the console, or in case of errors activating curtain-mode. Typically,
// remote clients should be disconnected in both cases: for errors, because
// the privacy guarantee of curtain-mode cannot be honoured; for switch-in,
// to ensure that only one connection (console or remote) exists to a session.
// Note that only the session's owner (or someone who knows the password) can
// attach it to the console, so this is safe.
CurtainMode(const base::Closure& on_session_activate,
const base::Closure& on_error);
virtual ~CurtainMode(); virtual ~CurtainMode();
// Set the callback to be invoked when the switched-out remote session is // Enable or disable curtain-mode. Note that disabling curtain-mode does not
// switched back to the console. Typically, remote connections should be // deactivate the curtain, but it does remove the switch-in handler, meaning
// closed in this event to make sure that only one connection (console or // that on_session_activate will not be invoked if curtain-mode is disabled.
// remote) exists to a session at any time to ensure privacy. Note that // Conversely, enabling curtain-mode *does* activate the curtain if there is
// only the session's owner (or someone who knows the owner's password) // a connected client at the time.
// can attach it to the console, so this is safe. void SetEnabled(bool enabled);
bool Init(const base::Closure& on_session_activate);
// Overridden from HostStatusObserver // Overridden from HostStatusObserver
virtual void OnClientAuthenticated(const std::string& jid) OVERRIDE; virtual void OnClientAuthenticated(const std::string& jid) OVERRIDE;
virtual void OnClientDisconnected(const std::string& jid) OVERRIDE;
private: private:
// If the current session is attached to the console and is not showing
// the logon screen then switch it out to ensure privacy.
bool ActivateCurtain();
// Add or remove the switch-in event handler.
bool InstallEventHandler();
bool RemoveEventHandler();
// Handlers for the switch-in event.
static OSStatus SessionActivateHandler(EventHandlerCallRef handler, static OSStatus SessionActivateHandler(EventHandlerCallRef handler,
EventRef event, EventRef event,
void* user_data); void* user_data);
void OnSessionActivate(); void OnSessionActivate();
base::Closure on_session_activate_; base::Closure on_session_activate_;
base::Closure on_error_;
bool connection_active_;
EventHandlerRef event_handler_; EventHandlerRef event_handler_;
}; };
......
...@@ -21,7 +21,7 @@ SIGTERM_EXIT_CODE=143 ...@@ -21,7 +21,7 @@ SIGTERM_EXIT_CODE=143
# has occurred and that the host should not be restarted. Please, keep these # has occurred and that the host should not be restarted. Please, keep these
# constants in sync with remoting/host/constants.h. # constants in sync with remoting/host/constants.h.
MIN_PERMANENT_ERROR_EXIT_CODE=2 MIN_PERMANENT_ERROR_EXIT_CODE=2
MAX_PERMANENT_ERROR_EXIT_CODE=5 MAX_PERMANENT_ERROR_EXIT_CODE=6
HOST_PID=0 HOST_PID=0
SIGNAL_WAS_TRAPPED=0 SIGNAL_WAS_TRAPPED=0
......
...@@ -123,7 +123,8 @@ const char PolicyWatcher::kHostRequireCurtainPolicyName[] = ...@@ -123,7 +123,8 @@ const char PolicyWatcher::kHostRequireCurtainPolicyName[] =
const char* const PolicyWatcher::kBooleanPolicyNames[] = const char* const PolicyWatcher::kBooleanPolicyNames[] =
{ PolicyWatcher::kNatPolicyName, { PolicyWatcher::kNatPolicyName,
PolicyWatcher::kHostRequireTwoFactorPolicyName PolicyWatcher::kHostRequireTwoFactorPolicyName,
PolicyWatcher::kHostRequireCurtainPolicyName
}; };
const int PolicyWatcher::kBooleanPolicyNamesNum = const int PolicyWatcher::kBooleanPolicyNamesNum =
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include "remoting/protocol/me2me_host_authenticator_factory.h" #include "remoting/protocol/me2me_host_authenticator_factory.h"
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsautorelease_pool.h" #include "base/mac/scoped_nsautorelease_pool.h"
#include "remoting/host/curtain_mode_mac.h" #include "remoting/host/curtain_mode_mac.h"
#include "remoting/host/sighup_listener_mac.h" #include "remoting/host/sighup_listener_mac.h"
...@@ -103,7 +104,14 @@ class HostProcess ...@@ -103,7 +104,14 @@ class HostProcess
allow_nat_traversal_(true), allow_nat_traversal_(true),
restarting_(false), restarting_(false),
shutting_down_(false), shutting_down_(false),
exit_code_(kSuccessExitCode) { exit_code_(kSuccessExitCode)
#if defined(OS_MACOSX)
, curtain_(base::Bind(&HostProcess::OnDisconnectRequested,
base::Unretained(this)),
base::Bind(&HostProcess::OnDisconnectRequested,
base::Unretained(this)))
#endif
{
context_.reset( context_.reset(
new ChromotingHostContext(message_loop_.message_loop_proxy())); new ChromotingHostContext(message_loop_.message_loop_proxy()));
context_->Start(); context_->Start();
...@@ -319,6 +327,10 @@ class HostProcess ...@@ -319,6 +327,10 @@ class HostProcess
return; return;
} }
if (!host_) {
StartHost();
}
bool bool_value; bool bool_value;
std::string string_value; std::string string_value;
if (policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName, if (policies->GetString(policy_hack::PolicyWatcher::kHostDomainPolicyName,
...@@ -329,6 +341,11 @@ class HostProcess ...@@ -329,6 +341,11 @@ class HostProcess
&bool_value)) { &bool_value)) {
OnNatPolicyUpdate(bool_value); OnNatPolicyUpdate(bool_value);
} }
if (policies->GetBoolean(
policy_hack::PolicyWatcher::kHostRequireCurtainPolicyName,
&bool_value)) {
OnCurtainPolicyUpdate(bool_value);
}
} }
void OnHostDomainPolicyUpdate(const std::string& host_domain) { void OnHostDomainPolicyUpdate(const std::string& host_domain) {
...@@ -356,15 +373,44 @@ class HostProcess ...@@ -356,15 +373,44 @@ class HostProcess
bool policy_changed = allow_nat_traversal_ != nat_traversal_enabled; bool policy_changed = allow_nat_traversal_ != nat_traversal_enabled;
allow_nat_traversal_ = nat_traversal_enabled; allow_nat_traversal_ = nat_traversal_enabled;
if (host_) { if (policy_changed) {
// Restart the host if the policy has changed while the host was
// online.
if (policy_changed)
RestartHost(); RestartHost();
}
}
void OnCurtainPolicyUpdate(bool curtain_required) {
#if defined(OS_MACOSX)
if (!context_->network_task_runner()->BelongsToCurrentThread()) {
context_->network_task_runner()->PostTask(FROM_HERE, base::Bind(
&HostProcess::OnCurtainPolicyUpdate, base::Unretained(this),
curtain_required));
return;
}
if (curtain_required) {
// If curtain mode is required, then we can't currently support remoting
// the login screen. This is because we don't curtain the login screen
// and the current daemon architecture means that the connction is closed
// immediately after login, leaving the host system uncurtained.
//
// TODO(jamiewalch): Fix this once we have implemented the multi-process
// daemon architecture (crbug.com/134894)
base::mac::ScopedCFTypeRef<CFDictionaryRef> session(
CGSessionCopyCurrentDictionary());
const void* logged_in = CFDictionaryGetValue(session,
kCGSessionLoginDoneKey);
if (logged_in != kCFBooleanTrue) {
Shutdown(kLoginScreenNotSupportedExitCode);
return;
}
host_->AddStatusObserver(&curtain_);
curtain_.SetEnabled(true);
} else { } else {
// Just start the host otherwise. curtain_.SetEnabled(false);
StartHost(); host_->RemoveStatusObserver(&curtain_);
} }
#endif
} }
void StartHost() { void StartHost() {
...@@ -447,12 +493,6 @@ class HostProcess ...@@ -447,12 +493,6 @@ class HostProcess
base::Unretained(this))); base::Unretained(this)));
#endif #endif
#if defined(OS_MACOSX)
curtain_.Init(base::Bind(&HostProcess::OnDisconnectRequested,
base::Unretained(this)));
host_->AddStatusObserver(&curtain_);
#endif
host_->Start(); host_->Start();
CreateAuthenticatorFactory(); CreateAuthenticatorFactory();
......
...@@ -916,6 +916,7 @@ def main(): ...@@ -916,6 +916,7 @@ def main():
logging.info("Host domain is blocked by policy - exiting.") logging.info("Host domain is blocked by policy - exiting.")
os.remove(host.config_file) os.remove(host.config_file)
return 0 return 0
# Nothing to do for Mac-only status 6 (login screen unsupported)
if __name__ == "__main__": if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment