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 |