]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2003-2004,2006,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | #include <list> | |
25 | #include <security_utilities/globalizer.h> | |
26 | #include <security_utilities/threading.h> | |
27 | #include "eventlistener.h" | |
28 | #include "SharedMemoryClient.h" | |
29 | #include <notify.h> | |
30 | #include "sscommon.h" | |
31 | #include <sys/syslog.h> | |
fa7225c8 | 32 | #include <Security/SecBasePriv.h> |
b1ab9ed8 A |
33 | |
34 | using namespace MachPlusPlus; | |
35 | ||
36 | ||
37 | namespace Security { | |
38 | namespace SecurityServer { | |
39 | ||
40 | typedef RefPointer<EventListener> EventPointer; | |
41 | typedef std::list<EventPointer> EventListenerList; | |
42 | ||
43 | static const char* GetNotificationName () | |
44 | { | |
ee5f17c7 | 45 | return SharedMemoryCommon::kDefaultSecurityMessagesName; |
b1ab9ed8 A |
46 | } |
47 | ||
48 | ||
49 | ||
50 | class SharedMemoryClientMaker | |
51 | { | |
52 | private: | |
53 | SharedMemoryClient mClient; | |
54 | ||
55 | public: | |
56 | SharedMemoryClientMaker (); | |
57 | SharedMemoryClient* Client (); | |
58 | }; | |
59 | ||
60 | ||
61 | ||
6b200bc3 | 62 | SharedMemoryClientMaker::SharedMemoryClientMaker () : mClient (GetNotificationName (), kSharedMemoryPoolSize, SharedMemoryCommon::fixUID(getuid())) |
b1ab9ed8 | 63 | { |
6b200bc3 | 64 | secdebug("MDSPRIVACY","[%03d] SharedMemoryClientMaker uid: %d, euid: %d, name: %s", mClient.getUID(), getuid(), geteuid(), GetNotificationName ()); |
b1ab9ed8 A |
65 | } |
66 | ||
67 | ||
68 | ||
69 | SharedMemoryClient* SharedMemoryClientMaker::Client () | |
70 | { | |
71 | return &mClient; | |
72 | } | |
73 | ||
74 | ||
75 | ||
76 | ModuleNexus<EventListenerList> gEventListeners; | |
77 | ModuleNexus<Mutex> gNotificationLock; | |
78 | ModuleNexus<SharedMemoryClientMaker> gMemoryClient; | |
79 | ||
fa7225c8 A |
80 | // |
81 | // Note that once we start notifications, we want receive them forever. Don't have a cancel option. | |
82 | // | |
6b200bc3 A |
83 | static bool InitializeNotifications () { |
84 | bool initializationComplete = false; | |
fa7225c8 | 85 | static dispatch_queue_t notification_queue = EventListener::getNotificationQueue(); |
b1ab9ed8 | 86 | |
6b200bc3 | 87 | secdebug("MDSPRIVACY","EventListener Init: uid: %d, euid: %d, name: %s", getuid(), geteuid(), GetNotificationName ()); |
fa7225c8 A |
88 | // Initialize the memory client |
89 | gMemoryClient(); | |
b1ab9ed8 | 90 | |
6b200bc3 A |
91 | if (gMemoryClient().Client()->uninitialized()) { |
92 | secdebug("MDSPRIVACY","[%03d] FATAL: InitializeNotifications EventListener uninitialized; process will never get keychain notifications", getuid()); | |
93 | return initializationComplete; | |
94 | } | |
fa7225c8 | 95 | int out_token; |
b1ab9ed8 | 96 | |
fa7225c8 A |
97 | notify_handler_t receive = ^(int token){ |
98 | try { | |
99 | SegmentOffsetType length; | |
100 | UnavailableReason ur; | |
b1ab9ed8 | 101 | |
fa7225c8 | 102 | bool result; |
b1ab9ed8 | 103 | |
fa7225c8 A |
104 | // Trust the memory client to break our loop here |
105 | while (true) | |
b1ab9ed8 | 106 | { |
fa7225c8 A |
107 | u_int8_t *buffer = new u_int8_t[kSharedMemoryPoolSize]; |
108 | { | |
109 | StLock<Mutex> lock (gNotificationLock ()); | |
110 | result = gMemoryClient().Client()->ReadMessage(buffer, length, ur); | |
111 | if (!result) | |
112 | { | |
6b200bc3 | 113 | secdebug("MDSPRIVACY","[%03d] notify_handler ReadMessage ur: %d", getuid(), ur); |
fa7225c8 A |
114 | delete [] buffer; |
115 | return; | |
116 | } | |
117 | } | |
118 | ||
119 | // Send this event off to the listeners | |
120 | { | |
914fc88e | 121 | StLock<Mutex> lock (gNotificationLock ()); |
fa7225c8 | 122 | EventListenerList& eventList = gEventListeners(); |
866f8763 | 123 | std::set<EventPointer *> processedListeners; |
fa7225c8 A |
124 | |
125 | // route the message to its destination | |
126 | u_int32_t* ptr = (u_int32_t*) buffer; | |
127 | ||
128 | // we have a message, do the semantics... | |
129 | SecurityServer::NotificationDomain domain = (SecurityServer::NotificationDomain) OSSwapBigToHostInt32 (*ptr++); | |
130 | SecurityServer::NotificationEvent event = (SecurityServer::NotificationEvent) OSSwapBigToHostInt32 (*ptr++); | |
131 | CssmData data ((u_int8_t*) ptr, buffer + length - (u_int8_t*) ptr); | |
132 | ||
6b200bc3 A |
133 | string descrip = SharedMemoryCommon::notificationDescription(domain, event); |
134 | secdebug("MDSPRIVACY","[%03d] notify_handler: %s", getuid(), descrip.c_str()); | |
fa7225c8 A |
135 | EventListenerList::iterator it = eventList.begin (); |
136 | while (it != eventList.end ()) | |
137 | { | |
866f8763 A |
138 | EventPointer ep = *it++; |
139 | /* | |
140 | * We can't hold the global event lock when processing callback handers | |
141 | * so remember what items we have processes and don't process them again. | |
142 | * and when we have done a callback we loop back and try again. | |
143 | */ | |
144 | if (processedListeners.find(&ep) != processedListeners.end()) { | |
145 | continue; | |
fa7225c8 | 146 | } |
866f8763 A |
147 | processedListeners.insert(&ep); |
148 | ||
149 | /* is this event for this Event handler */ | |
150 | if (ep->GetDomain() != domain || (ep->GetMask() & (1 << event)) == 0) | |
151 | continue; | |
152 | ||
153 | lock.unlock(); | |
154 | ||
155 | try { | |
156 | ep->consume (domain, event, data); | |
157 | } catch (CssmError &e) { | |
fa7225c8 | 158 | // If we throw, libnotify will abort the process. Log these... |
6b200bc3 | 159 | secerror("caught CssmError while processing notification: %d %s", e.error, cssmErrorString(e.error)); |
fa7225c8 | 160 | } |
866f8763 A |
161 | lock.lock(); |
162 | /* | |
163 | * If we have to grab the lock again, start over iteration | |
164 | */ | |
165 | it = eventList.begin (); | |
fa7225c8 A |
166 | } |
167 | } | |
b1ab9ed8 | 168 | |
b1ab9ed8 | 169 | delete [] buffer; |
b1ab9ed8 A |
170 | } |
171 | } | |
fa7225c8 A |
172 | // If these exceptions propagate, we crash our enclosing app. That's bad. Worse than silently swallowing the error. |
173 | catch(CssmError &cssme) { | |
174 | secerror("caught CssmError during notification: %d %s", (int) cssme.error, cssmErrorString(cssme.error)); | |
175 | } | |
176 | catch(UnixError &ue) { | |
177 | secerror("caught UnixError during notification: %d %s", ue.unixError(), ue.what()); | |
178 | } | |
179 | catch (MacOSError mose) { | |
180 | secerror("caught MacOSError during notification: %d %s", (int) mose.osStatus(), mose.what()); | |
181 | } | |
182 | catch (...) { | |
6b200bc3 | 183 | secerror("caught unknown error during notification"); |
fa7225c8 A |
184 | } |
185 | }; | |
b1ab9ed8 | 186 | |
fa7225c8 | 187 | uint32_t status = notify_register_dispatch(GetNotificationName(), &out_token, notification_queue, receive); |
6b200bc3 | 188 | if (status) { |
fa7225c8 A |
189 | secerror("notify_register_dispatch failed: %d", status); |
190 | syslog(LOG_ERR, "notify_register_dispatch failed: %d", status); | |
6b200bc3 A |
191 | } else { |
192 | initializationComplete = true; | |
b1ab9ed8 | 193 | } |
6b200bc3 | 194 | return initializationComplete; |
b1ab9ed8 A |
195 | } |
196 | ||
197 | ||
b1ab9ed8 | 198 | EventListener::EventListener (NotificationDomain domain, NotificationMask eventMask) |
6b200bc3 | 199 | : mInitialized(false), mDomain (domain), mMask (eventMask) |
b1ab9ed8 A |
200 | { |
201 | // make sure that notifications are turned on. | |
6b200bc3 | 202 | mInitialized = InitializeNotifications(); |
b1ab9ed8 A |
203 | } |
204 | ||
b1ab9ed8 A |
205 | // |
206 | // StopNotification() is needed on destruction; everyone else cleans up after themselves. | |
207 | // | |
6b200bc3 A |
208 | EventListener::~EventListener () { |
209 | if (initialized()) { | |
210 | StLock<Mutex> lock (gNotificationLock ()); | |
211 | ||
212 | // find the listener in the list and remove it | |
213 | EventListenerList::iterator it = std::find (gEventListeners ().begin (), | |
214 | gEventListeners ().end (), | |
215 | this); | |
216 | if (it != gEventListeners ().end ()) | |
217 | { | |
218 | gEventListeners ().erase (it); | |
219 | } | |
220 | } | |
b1ab9ed8 A |
221 | } |
222 | ||
b1ab9ed8 A |
223 | // get rid of the pure virtual |
224 | void EventListener::consume(NotificationDomain, NotificationEvent, const Security::CssmData&) | |
225 | { | |
226 | } | |
227 | ||
228 | ||
229 | ||
6b200bc3 A |
230 | void EventListener::FinishedInitialization(EventListener *eventListener) { |
231 | if (eventListener->initialized()) { | |
232 | StLock<Mutex> lock (gNotificationLock ()); | |
233 | gEventListeners().push_back (eventListener); | |
234 | } | |
b1ab9ed8 A |
235 | } |
236 | ||
fa7225c8 A |
237 | dispatch_once_t EventListener::queueOnceToken = 0; |
238 | dispatch_queue_t EventListener::notificationQueue = NULL; | |
239 | ||
240 | dispatch_queue_t EventListener::getNotificationQueue() { | |
241 | dispatch_once(&queueOnceToken, ^{ | |
242 | notificationQueue = dispatch_queue_create("com.apple.security.keychain-notification-queue", DISPATCH_QUEUE_SERIAL); | |
243 | }); | |
244 | ||
245 | return notificationQueue; | |
246 | } | |
b1ab9ed8 A |
247 | |
248 | ||
249 | } // end namespace SecurityServer | |
250 | } // end namespace Security |