]> git.saurik.com Git - apple/security.git/blob - Keychain/CCallbackMgr.cp
Security-54.1.7.tar.gz
[apple/security.git] / Keychain / CCallbackMgr.cp
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 File: CCallbackMgr.cp
21
22 Contains: Code that communicates with processes that install a callback
23 with the Keychain Manager to receive keychain events.
24
25 */
26
27 #include "CCallbackMgr.h"
28
29 #include <algorithm>
30 #include <list>
31
32 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
33 #include "Globals.h"
34 #include <Security/DLDBListCFPref.h>
35 #include <Security/SecCFTypes.h>
36 //#include <Security/Keychain.h>
37
38 using namespace KeychainCore;
39 using namespace CssmClient;
40
41 #pragma mark ÑÑÑÑ CallbackInfo ÑÑÑÑ
42
43 CallbackInfo::CallbackInfo() : mCallback(NULL),mEventMask(0),mContext(NULL)
44 {
45 }
46
47 CallbackInfo::CallbackInfo(SecKeychainCallback inCallbackFunction,
48 SecKeychainEventMask inEventMask, void *inContext)
49 : mCallback(inCallbackFunction), mEventMask(inEventMask), mContext(inContext)
50 {
51 }
52
53 CallbackInfo::~CallbackInfo()
54 {
55 }
56
57 bool CallbackInfo::operator==(const CallbackInfo& other) const
58 {
59 return mCallback==other.mCallback;
60 }
61
62 bool CallbackInfo::operator!=(const CallbackInfo& other) const
63 {
64 return !(*this==other);
65 }
66
67
68 #pragma mark ÑÑÑÑ CCallbackMgr ÑÑÑÑ
69
70 CCallbackMgr *CCallbackMgr::mCCallbackMgr;
71
72 CCallbackMgr::CCallbackMgr() :
73 // register for receiving Keychain events via CF
74 Observer(kSecEventNotificationName, NULL, CFNotificationSuspensionBehaviorDeliverImmediately)
75 {
76 }
77
78 CCallbackMgr::~CCallbackMgr()
79 {
80 }
81
82 CCallbackMgr& CCallbackMgr::Instance()
83 {
84 if (!mCCallbackMgr)
85 mCCallbackMgr = new CCallbackMgr();
86
87 return *mCCallbackMgr;
88 }
89
90 void CCallbackMgr::AddCallback( SecKeychainCallback inCallbackFunction,
91 SecKeychainEventMask inEventMask,
92 void* inContext)
93
94 {
95 CallbackInfo info( inCallbackFunction, inEventMask, inContext );
96 CallbackInfo existingInfo;
97
98
99 CallbackInfoListIterator ix = find( CCallbackMgr::Instance().mEventCallbacks.begin(),
100 CCallbackMgr::Instance().mEventCallbacks.end(), info );
101
102 // make sure it is not already there
103 if ( ix!=CCallbackMgr::Instance().mEventCallbacks.end() )
104 {
105 // It's already there. This could mean that the old process died unexpectedly,
106 // so we need to validate the process ID of the existing callback.
107 // On Mac OS X this list is per process so this is always a duplicate
108 MacOSError::throwMe(errSecDuplicateCallback);
109 }
110
111 CCallbackMgr::Instance().mEventCallbacks.push_back(info);
112 }
113
114
115 class Predicate
116 {
117 SecKeychainCallback mCallbackFunction;
118 public:
119 Predicate(SecKeychainCallback inCallbackFunction) : mCallbackFunction(inCallbackFunction) {}
120 bool operator()(const CallbackInfo &cbInfo) { return cbInfo.mCallback == mCallbackFunction; }
121 };
122
123 void CCallbackMgr::RemoveCallback(SecKeychainCallback inCallbackFunction)
124 {
125 size_t oldSize = CCallbackMgr::Instance().mEventCallbacks.size();
126 Predicate predicate(inCallbackFunction);
127 CCallbackMgr::Instance().mEventCallbacks.remove_if(predicate);
128
129 if (oldSize == CCallbackMgr::Instance().mEventCallbacks.size())
130 MacOSError::throwMe(errSecInvalidCallback);
131 }
132
133 void CCallbackMgr::AlertClients(SecKeychainEvent inEvent,
134 pid_t inPid,
135 const Keychain &inKeychain,
136 const Item &inItem)
137 {
138 debug("kcnotify", "dispatch event %d pid %d keychain %p item %p",
139 inEvent, inPid, &inKeychain, !!inItem ? &*inItem : NULL);
140
141 // Deal with events that we care about ourselves first.
142 if (inEvent == kSecDefaultChangedEvent)
143 globals().defaultKeychain.reload(true);
144 else if (inEvent == kSecKeychainListChangedEvent)
145 globals().storageManager.reload(true);
146 else if (inEvent == kSecDeleteEvent && inKeychain.get() && inItem.get())
147 inKeychain->didDeleteItem(inItem.get());
148
149 // Iterate through callbacks, looking for those registered for inEvent
150 const SecKeychainEventMask theMask = 1U << inEvent;
151
152 for ( CallbackInfoListIterator ix = CCallbackMgr::Instance().mEventCallbacks.begin();
153 ix != CCallbackMgr::Instance().mEventCallbacks.end(); ++ix )
154 {
155 if (!(ix->mEventMask & theMask))
156 continue;
157
158 SecKeychainCallbackInfo cbInfo;
159 cbInfo.version = 0; // @@@ kKeychainAPIVersion;
160 cbInfo.item = inItem ? gTypes().item.handle(*inItem) : 0;
161 cbInfo.keychain = inKeychain ? gTypes().keychain.handle(*inKeychain) : 0;
162 cbInfo.pid = inPid;
163
164 ix->mCallback(inEvent, &cbInfo, ix->mContext);
165 }
166 }
167
168 /***********************************************************************************
169 * Event() - Overriden function of the KCEventObserver object.
170 * Each instance of KeychainCore will receive events from CF
171 * that was initiated by another KeychainCore instance that
172 * triggered the event.
173 *
174 * We <could> care about which KeychainCore posted the event:
175 * Example (KCDeleteItem event):
176 * If it was 'us', we don't do anything; we already processed the event.
177 * If it wasn't 'us', we should remove our cached reference to the item that was deleted.
178 *
179 ***********************************************************************************/
180 void CCallbackMgr::Event(CFNotificationCenterRef center,
181 CFStringRef name,
182 const void *object,
183 CFDictionaryRef userInfo)
184 {
185 // Decode from userInfo the event type, 'keychain' CFDict, and 'item' CFDict
186 CCFValue event(CFDictionaryGetValue( userInfo, kSecEventTypeKey ));
187 SecKeychainEvent thisEvent = 0;
188 if (!event.hasValue())
189 return;
190
191 thisEvent = sint32( event );
192
193 CFNumberRef pid = reinterpret_cast<CFNumberRef>
194 (CFDictionaryGetValue(userInfo, kSecEventPidKey));
195 pid_t thisPid;
196 if (!pid || !CFNumberGetValue(pid, kCFNumberSInt32Type, &thisPid))
197 {
198 thisPid = 0;
199 }
200
201 CFDictionaryRef kc = reinterpret_cast<CFDictionaryRef>
202 (CFDictionaryGetValue(userInfo, kSecEventKeychainKey));
203 Keychain thisKeychain;
204 if (kc)
205 {
206 thisKeychain = globals().storageManager.keychain
207 (DLDbListCFPref::cfDictionaryRefToDLDbIdentifier(kc));
208 }
209
210 CFDataRef item = reinterpret_cast<CFDataRef>
211 (CFDictionaryGetValue(userInfo, kSecEventItemKey));
212 Item thisItem;
213 if (item && thisKeychain)
214 {
215 const CssmData pkData(const_cast<UInt8*>(CFDataGetBytePtr(item)), CFDataGetLength(item));
216 PrimaryKey pk(pkData);
217 thisItem = thisKeychain->item(pk);
218 }
219
220 // Notify our process of this event.
221 CCallbackMgr::AlertClients(thisEvent, thisPid, thisKeychain, thisItem);
222 }