| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/curtain_mode_mac.h" | 5 #include "remoting/host/curtain_mode_mac.h" |
| 6 | 6 |
| 7 #include <ApplicationServices/ApplicationServices.h> | 7 #include <ApplicationServices/ApplicationServices.h> |
| 8 #include <Security/Security.h> | 8 #include <Security/Security.h> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/mac/scoped_cftyperef.h" | 11 #include "base/mac/scoped_cftyperef.h" |
| 12 | 12 |
| 13 namespace { | 13 namespace { |
| 14 const char* kCGSessionPath = | 14 const char* kCGSessionPath = |
| 15 "/System/Library/CoreServices/Menu Extras/User.menu/Contents/Resources/" | 15 "/System/Library/CoreServices/Menu Extras/User.menu/Contents/Resources/" |
| 16 "CGSession"; | 16 "CGSession"; |
| 17 } | 17 } |
| 18 | 18 |
| 19 namespace remoting { | 19 namespace remoting { |
| 20 | 20 |
| 21 CurtainMode::CurtainMode() : event_handler_(NULL) { | 21 CurtainMode::CurtainMode(const base::Closure& on_session_activate, |
| 22 const base::Closure& on_error) |
| 23 : on_session_activate_(on_session_activate), |
| 24 on_error_(on_error), |
| 25 connection_active_(false), |
| 26 event_handler_(NULL) { |
| 22 } | 27 } |
| 23 | 28 |
| 24 CurtainMode::~CurtainMode() { | 29 CurtainMode::~CurtainMode() { |
| 25 if (event_handler_) { | 30 SetEnabled(false); |
| 26 RemoveEventHandler(event_handler_); | 31 } |
| 32 |
| 33 void CurtainMode::SetEnabled(bool enabled) { |
| 34 if (enabled) { |
| 35 if (connection_active_) { |
| 36 if (!ActivateCurtain()) { |
| 37 on_error_.Run(); |
| 38 } |
| 39 } |
| 40 } else { |
| 41 RemoveEventHandler(); |
| 27 } | 42 } |
| 28 } | 43 } |
| 29 | 44 |
| 30 bool CurtainMode::Init(const base::Closure& on_session_activate) { | 45 bool CurtainMode::ActivateCurtain() { |
| 31 DCHECK(on_session_activate_.is_null()); | 46 // Try to install the switch-in handler. Do this before switching out the |
| 32 on_session_activate_ = on_session_activate; | 47 // current session so that the console session is not affected if it fails. |
| 33 EventTypeSpec event; | 48 if (!InstallEventHandler()) { |
| 34 event.eventClass = kEventClassSystem; | 49 return false; |
| 35 event.eventKind = kEventSystemUserSessionActivated; | 50 } |
| 36 OSStatus result = InstallApplicationEventHandler( | |
| 37 NewEventHandlerUPP(SessionActivateHandler), 1, &event, this, | |
| 38 &event_handler_); | |
| 39 return result == noErr; | |
| 40 } | |
| 41 | 51 |
| 42 void CurtainMode::OnClientAuthenticated(const std::string& jid) { | |
| 43 // If the current session is attached to the console and is not showing | |
| 44 // the logon screen then switch it out to ensure privacy. | |
| 45 base::mac::ScopedCFTypeRef<CFDictionaryRef> session( | 52 base::mac::ScopedCFTypeRef<CFDictionaryRef> session( |
| 46 CGSessionCopyCurrentDictionary()); | 53 CGSessionCopyCurrentDictionary()); |
| 47 const void* on_console = CFDictionaryGetValue(session, | 54 const void* on_console = CFDictionaryGetValue(session, |
| 48 kCGSessionOnConsoleKey); | 55 kCGSessionOnConsoleKey); |
| 49 const void* logged_in = CFDictionaryGetValue(session, kCGSessionLoginDoneKey); | 56 const void* logged_in = CFDictionaryGetValue(session, kCGSessionLoginDoneKey); |
| 50 if (logged_in == kCFBooleanTrue && on_console == kCFBooleanTrue) { | 57 if (logged_in == kCFBooleanTrue && on_console == kCFBooleanTrue) { |
| 51 pid_t child = fork(); | 58 pid_t child = fork(); |
| 52 if (child == 0) { | 59 if (child == 0) { |
| 53 execl(kCGSessionPath, kCGSessionPath, "-suspend", NULL); | 60 execl(kCGSessionPath, kCGSessionPath, "-suspend", NULL); |
| 54 _exit(1); | 61 _exit(1); |
| 55 } else if (child > 0) { | 62 } else if (child > 0) { |
| 56 int status = 0; | 63 int status = 0; |
| 57 waitpid(child, &status, 0); | 64 waitpid(child, &status, 0); |
| 65 if (status != 0) { |
| 66 LOG(ERROR) << kCGSessionPath << " failed."; |
| 67 return false; |
| 68 } |
| 69 } else { |
| 70 LOG(ERROR) << "fork() failed."; |
| 71 return false; |
| 58 } | 72 } |
| 59 } | 73 } |
| 74 return true; |
| 75 } |
| 76 |
| 77 // TODO(jamiewalch): This code assumes at most one client connection at a time. |
| 78 // Add OnFirstClientConnected and OnLastClientDisconnected optional callbacks |
| 79 // to the HostStatusObserver interface to address this. |
| 80 void CurtainMode::OnClientAuthenticated(const std::string& jid) { |
| 81 connection_active_ = true; |
| 82 SetEnabled(true); |
| 83 } |
| 84 |
| 85 void CurtainMode::OnClientDisconnected(const std::string& jid) { |
| 86 SetEnabled(false); |
| 87 connection_active_ = false; |
| 60 } | 88 } |
| 61 | 89 |
| 62 OSStatus CurtainMode::SessionActivateHandler(EventHandlerCallRef handler, | 90 OSStatus CurtainMode::SessionActivateHandler(EventHandlerCallRef handler, |
| 63 EventRef event, | 91 EventRef event, |
| 64 void* user_data) { | 92 void* user_data) { |
| 65 CurtainMode* self = static_cast<CurtainMode*>(user_data); | 93 CurtainMode* self = static_cast<CurtainMode*>(user_data); |
| 66 self->OnSessionActivate(); | 94 self->OnSessionActivate(); |
| 67 return noErr; | 95 return noErr; |
| 68 } | 96 } |
| 69 | 97 |
| 70 void CurtainMode::OnSessionActivate() { | 98 void CurtainMode::OnSessionActivate() { |
| 71 if (!on_session_activate_.is_null()) { | 99 on_session_activate_.Run(); |
| 72 on_session_activate_.Run(); | 100 } |
| 101 |
| 102 bool CurtainMode::InstallEventHandler() { |
| 103 OSStatus result = noErr; |
| 104 if (!event_handler_) { |
| 105 EventTypeSpec event; |
| 106 event.eventClass = kEventClassSystem; |
| 107 event.eventKind = kEventSystemUserSessionActivated; |
| 108 result = ::InstallApplicationEventHandler( |
| 109 NewEventHandlerUPP(SessionActivateHandler), 1, &event, this, |
| 110 &event_handler_); |
| 73 } | 111 } |
| 112 return result == noErr; |
| 113 } |
| 114 |
| 115 bool CurtainMode::RemoveEventHandler() { |
| 116 OSStatus result = noErr; |
| 117 if (event_handler_) { |
| 118 result = ::RemoveEventHandler(event_handler_); |
| 119 } |
| 120 return result == noErr; |
| 74 } | 121 } |
| 75 | 122 |
| 76 } // namespace remoting | 123 } // namespace remoting |
| OLD | NEW |