]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurityd/lib/eventlistener.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurityd / lib / eventlistener.cpp
CommitLineData
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>
32
33using namespace MachPlusPlus;
34
35
36namespace Security {
37namespace SecurityServer {
38
39typedef RefPointer<EventListener> EventPointer;
40typedef std::list<EventPointer> EventListenerList;
41
42static const char* GetNotificationName ()
43{
44 // the name we give the client depends on the value of the environment variable "SECURITYSERVER"
45 const char* name = getenv (SECURITYSERVER_BOOTSTRAP_ENV);
46 if (name == NULL)
47 {
48 name = SECURITY_MESSAGES_NAME;
49 }
50
51 return name;
52}
53
54
55
56class SharedMemoryClientMaker
57{
58private:
59 SharedMemoryClient mClient;
60
61public:
62 SharedMemoryClientMaker ();
63 SharedMemoryClient* Client ();
64};
65
66
67
68SharedMemoryClientMaker::SharedMemoryClientMaker () : mClient (GetNotificationName (), kSharedMemoryPoolSize)
69{
70}
71
72
73
74SharedMemoryClient* SharedMemoryClientMaker::Client ()
75{
76 return &mClient;
77}
78
79
80
81ModuleNexus<EventListenerList> gEventListeners;
82ModuleNexus<Mutex> gNotificationLock;
83ModuleNexus<SharedMemoryClientMaker> gMemoryClient;
84
85class NotificationPort : public MachPlusPlus::CFAutoPort
86{
87protected:
88 SharedMemoryClient *mClient;
89
90 void ReceiveImplementation(u_int8_t* buffer, SegmentOffsetType length, UnavailableReason ur);
91 static void HandleRunLoopTimer(CFRunLoopTimerRef timer, void* info);
92
93public:
94 NotificationPort (mach_port_t port);
95 virtual ~NotificationPort ();
96 virtual void receive(const MachPlusPlus::Message &msg);
97};
98
99NotificationPort::NotificationPort (mach_port_t mp) : CFAutoPort (mp)
100{
101 mClient = gMemoryClient ().Client ();
102}
103
104
105
106NotificationPort::~NotificationPort ()
107{
108}
109
110
111
112void NotificationPort::ReceiveImplementation(u_int8_t* buffer, SegmentOffsetType length, UnavailableReason ur)
113{
114 EventListenerList& eventList = gEventListeners();
115
116 // route the message to its destination
117 u_int32_t* ptr = (u_int32_t*) buffer;
118
119 // we have a message, do the semantics...
120 SecurityServer::NotificationDomain domain = (SecurityServer::NotificationDomain) OSSwapBigToHostInt32 (*ptr++);
121 SecurityServer::NotificationEvent event = (SecurityServer::NotificationEvent) OSSwapBigToHostInt32 (*ptr++);
122 CssmData data ((u_int8_t*) ptr, buffer + length - (u_int8_t*) ptr);
123
124 EventListenerList::iterator it = eventList.begin ();
125 while (it != eventList.end ())
126 {
127 try
128 {
129 EventPointer ep = *it++;
130 if (ep->GetDomain () == domain &&
131 (ep->GetMask () & (1 << event)) != 0)
132 {
133 ep->consume (domain, event, data);
134 }
135 }
136 catch (CssmError &e)
137 {
138 if (e.error != CSSM_ERRCODE_INTERNAL_ERROR)
139 {
140 throw;
141 }
142 }
143 }
144}
145
146
147
148typedef void (^NotificationBlock)();
149
150
151
152void NotificationPort::HandleRunLoopTimer(CFRunLoopTimerRef timer, void* info)
153{
154 // reconstruct our context and call it
155 NotificationBlock nb = (NotificationBlock) info;
156 nb();
157
158 // clean up
159 Block_release(nb);
160 CFRunLoopTimerInvalidate(timer);
161 CFRelease(timer);
162}
163
164
165
166void NotificationPort::receive (const MachPlusPlus::Message &msg)
167{
168 /*
169 Read each notification received and post a timer for each with an expiration of
170 zero. I'd prefer to use a notification here, but I can't because, according to
171 the documentation, each application may only have one notification center and
172 the main application should have the right to pick the one it needs.
173 */
174
175 SegmentOffsetType length;
176 UnavailableReason ur;
177
178 bool result;
179
180 while (true)
181 {
182 u_int8_t *buffer = new u_int8_t[kSharedMemoryPoolSize];
183
184 {
185 StLock<Mutex> lock (gNotificationLock ());
186 result = mClient->ReadMessage(buffer, length, ur);
187 if (!result)
188 {
189 delete [] buffer;
190 return;
191 }
192 }
193
194 // make a block that contains our data
195 NotificationBlock nb =
196 ^{
197 ReceiveImplementation(buffer, length, ur);
198 delete [] buffer;
199 };
200
201 // keep it in scope
202 nb = Block_copy(nb);
203
204 // set up to run the next time the run loop fires
205 CFRunLoopTimerContext ctx;
206 memset(&ctx, 0, sizeof(ctx));
207 ctx.info = nb;
208
209 // make a run loop timer
210 CFRunLoopTimerRef timerRef =
211 CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(), 0,
212 0, 0, NotificationPort::HandleRunLoopTimer, &ctx);
213
214 // install it to be run.
215 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timerRef, kCFRunLoopDefaultMode);
216 }
217}
218
219
220
221class ThreadNotifier
222{
223protected:
224 NotificationPort *mNotificationPort;
225 int mNotifyToken;
226
227public:
228 ThreadNotifier();
229 ~ThreadNotifier();
230};
231
232
233
234ThreadNotifier::ThreadNotifier()
235 : mNotificationPort(NULL)
236{
237 mach_port_t mp;
238 if (notify_register_mach_port (GetNotificationName (), &mp, 0, &mNotifyToken) == NOTIFY_STATUS_OK) {
239 mNotificationPort = new NotificationPort (mp);
240 mNotificationPort->enable ();
241 }
242}
243
244
245
246ThreadNotifier::~ThreadNotifier()
247{
248 if (mNotificationPort) {
249 notify_cancel (mNotifyToken);
250 delete mNotificationPort;
251 }
252}
253
254
255
256ModuleNexus<ThreadNexus<ThreadNotifier> > threadInfo;
257
258
259
260static void InitializeNotifications ()
261{
262 threadInfo()(); // cause the notifier for this thread to initialize
263}
264
265
266
267EventListener::EventListener (NotificationDomain domain, NotificationMask eventMask)
268 : mDomain (domain), mMask (eventMask)
269{
270 // make sure that notifications are turned on.
271 InitializeNotifications ();
272}
273
274
275//
276// StopNotification() is needed on destruction; everyone else cleans up after themselves.
277//
278EventListener::~EventListener ()
279{
280 StLock<Mutex> lock (gNotificationLock ());
281
282 // find the listener in the list and remove it
283 EventListenerList::iterator it = std::find (gEventListeners ().begin (),
284 gEventListeners ().end (),
285 this);
286 if (it != gEventListeners ().end ())
287 {
288 gEventListeners ().erase (it);
289 }
290}
291
292
293
294// get rid of the pure virtual
295void EventListener::consume(NotificationDomain, NotificationEvent, const Security::CssmData&)
296{
297}
298
299
300
301void EventListener::FinishedInitialization(EventListener *eventListener)
302{
303 StLock<Mutex> lock (gNotificationLock ());
304 gEventListeners().push_back (eventListener);
305}
306
307
308
309} // end namespace SecurityServer
310} // end namespace Security