]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurityd/lib/eventlistener.cpp
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / libsecurityd / lib / eventlistener.cpp
1 /*
2 * Copyright (c) 2003-2004,2006,2011-2012,2014 Apple Inc. All Rights Reserved.
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 #include <Security/SecBasePriv.h>
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 {
45 // the name we give the client depends on the value of the environment variable "SECURITYSERVER"
46 const char* name = getenv (SECURITYSERVER_BOOTSTRAP_ENV);
47 if (name == NULL)
48 {
49 name = SECURITY_MESSAGES_NAME;
50 }
51
52 return name;
53 }
54
55
56
57 class SharedMemoryClientMaker
58 {
59 private:
60 SharedMemoryClient mClient;
61
62 public:
63 SharedMemoryClientMaker ();
64 SharedMemoryClient* Client ();
65 };
66
67
68
69 SharedMemoryClientMaker::SharedMemoryClientMaker () : mClient (GetNotificationName (), kSharedMemoryPoolSize)
70 {
71 }
72
73
74
75 SharedMemoryClient* SharedMemoryClientMaker::Client ()
76 {
77 return &mClient;
78 }
79
80
81
82 ModuleNexus<EventListenerList> gEventListeners;
83 ModuleNexus<Mutex> gNotificationLock;
84 ModuleNexus<SharedMemoryClientMaker> gMemoryClient;
85
86 //
87 // Note that once we start notifications, we want receive them forever. Don't have a cancel option.
88 //
89 static void InitializeNotifications () {
90 static dispatch_queue_t notification_queue = EventListener::getNotificationQueue();
91
92 // Initialize the memory client
93 gMemoryClient();
94
95 int out_token;
96
97 notify_handler_t receive = ^(int token){
98 try {
99 SegmentOffsetType length;
100 UnavailableReason ur;
101
102 bool result;
103
104 // Trust the memory client to break our loop here
105 while (true)
106 {
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 {
113 delete [] buffer;
114 return;
115 }
116 }
117
118 // Send this event off to the listeners
119 {
120 EventListenerList& eventList = gEventListeners();
121
122 // route the message to its destination
123 u_int32_t* ptr = (u_int32_t*) buffer;
124
125 // we have a message, do the semantics...
126 SecurityServer::NotificationDomain domain = (SecurityServer::NotificationDomain) OSSwapBigToHostInt32 (*ptr++);
127 SecurityServer::NotificationEvent event = (SecurityServer::NotificationEvent) OSSwapBigToHostInt32 (*ptr++);
128 CssmData data ((u_int8_t*) ptr, buffer + length - (u_int8_t*) ptr);
129
130 EventListenerList::iterator it = eventList.begin ();
131 while (it != eventList.end ())
132 {
133 try
134 {
135 EventPointer ep = *it++;
136 if (ep->GetDomain () == domain &&
137 (ep->GetMask () & (1 << event)) != 0)
138 {
139 ep->consume (domain, event, data);
140 }
141 }
142 catch (CssmError &e)
143 {
144 // If we throw, libnotify will abort the process. Log these...
145 secerror("Caught CssmError while processing notification: %d %s", e.error, cssmErrorString(e.error));
146 }
147 }
148 }
149
150 delete [] buffer;
151 }
152 }
153 // If these exceptions propagate, we crash our enclosing app. That's bad. Worse than silently swallowing the error.
154 catch(CssmError &cssme) {
155 secerror("caught CssmError during notification: %d %s", (int) cssme.error, cssmErrorString(cssme.error));
156 }
157 catch(UnixError &ue) {
158 secerror("caught UnixError during notification: %d %s", ue.unixError(), ue.what());
159 }
160 catch (MacOSError mose) {
161 secerror("caught MacOSError during notification: %d %s", (int) mose.osStatus(), mose.what());
162 }
163 catch (...) {
164 secerror("cauth unknknown error during notification");
165 }
166 };
167
168 uint32_t status = notify_register_dispatch(GetNotificationName(), &out_token, notification_queue, receive);
169 if(status) {
170 secerror("notify_register_dispatch failed: %d", status);
171 syslog(LOG_ERR, "notify_register_dispatch failed: %d", status);
172 }
173 }
174
175
176 EventListener::EventListener (NotificationDomain domain, NotificationMask eventMask)
177 : mDomain (domain), mMask (eventMask)
178 {
179 // make sure that notifications are turned on.
180 InitializeNotifications ();
181 }
182
183 //
184 // StopNotification() is needed on destruction; everyone else cleans up after themselves.
185 //
186 EventListener::~EventListener ()
187 {
188 StLock<Mutex> lock (gNotificationLock ());
189
190 // find the listener in the list and remove it
191 EventListenerList::iterator it = std::find (gEventListeners ().begin (),
192 gEventListeners ().end (),
193 this);
194 if (it != gEventListeners ().end ())
195 {
196 gEventListeners ().erase (it);
197 }
198 }
199
200
201
202 // get rid of the pure virtual
203 void EventListener::consume(NotificationDomain, NotificationEvent, const Security::CssmData&)
204 {
205 }
206
207
208
209 void EventListener::FinishedInitialization(EventListener *eventListener)
210 {
211 StLock<Mutex> lock (gNotificationLock ());
212 gEventListeners().push_back (eventListener);
213 }
214
215 dispatch_once_t EventListener::queueOnceToken = 0;
216 dispatch_queue_t EventListener::notificationQueue = NULL;
217
218 dispatch_queue_t EventListener::getNotificationQueue() {
219 dispatch_once(&queueOnceToken, ^{
220 notificationQueue = dispatch_queue_create("com.apple.security.keychain-notification-queue", DISPATCH_QUEUE_SERIAL);
221 });
222
223 return notificationQueue;
224 }
225
226
227 } // end namespace SecurityServer
228 } // end namespace Security