]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurityd/lib/eventlistener.cpp
Security-59754.80.3.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>
fa7225c8 32#include <Security/SecBasePriv.h>
b1ab9ed8
A
33
34using namespace MachPlusPlus;
35
36
37namespace Security {
38namespace SecurityServer {
39
40typedef RefPointer<EventListener> EventPointer;
41typedef std::list<EventPointer> EventListenerList;
42
43static const char* GetNotificationName ()
44{
ee5f17c7 45 return SharedMemoryCommon::kDefaultSecurityMessagesName;
b1ab9ed8
A
46}
47
48
49
50class SharedMemoryClientMaker
51{
52private:
53 SharedMemoryClient mClient;
54
55public:
56 SharedMemoryClientMaker ();
57 SharedMemoryClient* Client ();
58};
59
60
61
6b200bc3 62SharedMemoryClientMaker::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
69SharedMemoryClient* SharedMemoryClientMaker::Client ()
70{
71 return &mClient;
72}
73
74
75
76ModuleNexus<EventListenerList> gEventListeners;
77ModuleNexus<Mutex> gNotificationLock;
78ModuleNexus<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
83static 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 198EventListener::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
208EventListener::~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
224void EventListener::consume(NotificationDomain, NotificationEvent, const Security::CssmData&)
225{
226}
227
228
229
6b200bc3
A
230void 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
237dispatch_once_t EventListener::queueOnceToken = 0;
238dispatch_queue_t EventListener::notificationQueue = NULL;
239
240dispatch_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