]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/DynamicDLDBList.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / DynamicDLDBList.cpp
1 /*
2 * Copyright (c) 2004,2011,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
25 /*
26 DynamicDLDBList.cpp
27 */
28
29 #include "DynamicDLDBList.h"
30
31 #include "Globals.h"
32
33 #include <security_utilities/debugging.h>
34 #include <security_cdsa_utilities/cssmbridge.h> // For Required()
35 #include <security_cdsa_client/mdsclient.h>
36 #include <security_cdsa_client/mds_standard.h>
37 #include "KCEventNotifier.h"
38
39 using namespace KeychainCore;
40
41 //
42 // DynamicDLDBList
43 //
44 DynamicDLDBList::DynamicDLDBList()
45 : mMutex(Mutex::recursive), mSearchListSet(false)
46 {
47 }
48
49 DynamicDLDBList::~DynamicDLDBList()
50 {
51 }
52
53 CSSM_RETURN
54 DynamicDLDBList::appNotifyCallback(const CSSM_GUID *guid, void *context,
55 uint32 subserviceId, CSSM_SERVICE_TYPE subserviceType, CSSM_MODULE_EVENT eventType)
56 {
57 CSSM_RETURN status = 0;
58 try
59 {
60 reinterpret_cast<DynamicDLDBList *>(context)->callback(Guid::required(guid),
61 subserviceId, subserviceType, eventType);
62 }
63 catch (const CommonError &error)
64 {
65 status = error.osStatus();
66 }
67 catch (...)
68 {
69 }
70
71 return status;
72 }
73
74 /* Assume mLock is locked already. Add all databases for this module. */
75 bool
76 DynamicDLDBList::_add(const Guid &guid, uint32 subserviceID, CSSM_SERVICE_TYPE subserviceType)
77 {
78 return _add(dlDbIdentifier(guid, subserviceID, subserviceType));
79 }
80
81 /* Assume mLock is locked already. Add a single database to the searchlist. */
82 bool
83 DynamicDLDBList::_add(const DLDbIdentifier &dlDbIdentifier)
84 {
85 StLock<Mutex>_(mMutex);
86
87 if (find(mSearchList.begin(), mSearchList.end(), dlDbIdentifier) == mSearchList.end())
88 {
89 mSearchList.push_back(dlDbIdentifier);
90 return true;
91 }
92
93 return false;
94 }
95
96 /* Assume mLock is locked already. Remove all databases for this module. */
97 bool
98 DynamicDLDBList::_remove(const Guid &guid, uint32 subserviceID, CSSM_SERVICE_TYPE subserviceType)
99 {
100 return _remove(dlDbIdentifier(guid, subserviceID, subserviceType));
101 }
102
103 /* Assume mLock is locked already. Remove a single database from the
104 searchlist. */
105 bool
106 DynamicDLDBList::_remove(const DLDbIdentifier &dlDbIdentifier)
107 {
108 StLock<Mutex>_(mMutex);
109
110 // search for subserviceUid but ignore the dbName, which is dynamic
111 for (SearchList::iterator it = mSearchList.begin(); it != mSearchList.end(); it++)
112 if (it->ssuid() == dlDbIdentifier.ssuid())
113 {
114 mSearchList.erase(it);
115
116 // Remove from the storageManager cache if it was there.
117 globals().storageManager.didRemoveKeychain(dlDbIdentifier);
118 return true;
119 }
120 // not found
121 return false;
122 }
123
124 bool
125 DynamicDLDBList::_load()
126 {
127 StLock<Mutex>_(mMutex);
128
129 bool list_changed = false;
130 MDSClient::Directory &mds = MDSClient::mds();
131 MDSClient::Table<MDSClient::Common> common(mds);
132 MDSClient::Table<MDSClient::DL> dl(mds);
133 MDSClient::Table<MDSClient::CSP> csp(mds);
134
135 for (MDSClient::Table<MDSClient::Common>::iterator commonIt =
136 common.find(MDSClient::Attribute("DynamicFlag") != false);
137 commonIt != common.end(); ++commonIt)
138 {
139 CSSM_SERVICE_MASK serviceMask = (*commonIt)->serviceMask();
140 if (serviceMask & CSSM_SERVICE_DL)
141 {
142 string moduleID = (*commonIt)->moduleID();
143 secdebug("dynamic", "Loading dynamic %sDL module: %s",
144 (serviceMask & CSSM_SERVICE_CSP) ? "CSP/" : "", moduleID.c_str());
145
146 /* Register module for callbacks and load it. */
147 Guid moduleGuid(moduleID);
148 CssmClient::Module module(moduleGuid);
149 module->appNotifyCallback(appNotifyCallback, this);
150 module->load();
151 mModules.push_back(module);
152
153 /* Now that we have registered for notifications, Find all already
154 registered dl subsevices for this module. */
155 for (MDSClient::Table<MDSClient::DL>::iterator dlIt =
156 dl.find(MDSClient::Attribute("ModuleID") == moduleID);
157 dlIt!= dl.end(); ++dlIt)
158 {
159 uint32 subserviceID = (*dlIt)->subserviceID();
160 bool hasCSP = csp.find(MDSClient::Attribute("ModuleID") == moduleID
161 && MDSClient::Attribute("SSID") == subserviceID) != csp.end();
162
163 secdebug("dynamic", "Adding databases from %sDL SSID %lu module: %s",
164 hasCSP ? "CSP/" : "", (unsigned long)subserviceID, moduleID.c_str());
165 list_changed |= _add(moduleGuid, subserviceID,
166 hasCSP ? CSSM_SERVICE_CSP | CSSM_SERVICE_DL : CSSM_SERVICE_DL);
167 }
168 }
169 }
170
171 return list_changed;
172 }
173
174 const vector<DLDbIdentifier> &
175 DynamicDLDBList::searchList()
176 {
177 StLock<Mutex>_(mMutex);
178 if (!mSearchListSet)
179 {
180 // Load all dynamic DL's so we start receiving notifications.
181 _load();
182
183 mSearchListSet = true;
184 }
185
186 return mSearchList;
187 }
188
189 void
190 DynamicDLDBList::callback(const Guid &guid, uint32 subserviceID,
191 CSSM_SERVICE_TYPE subserviceType, CSSM_MODULE_EVENT eventType)
192 {
193 secdebug("event", "Received callback from guid: %s ssid: %lu type: %lu event: %lu",
194 guid.toString().c_str(), (unsigned long)subserviceID, (unsigned long)subserviceType, (unsigned long)eventType);
195
196 StLock<Mutex>_(mMutex);
197
198 bool list_changed = false;
199
200 if (subserviceType & CSSM_SERVICE_DL)
201 {
202 if (eventType == CSSM_NOTIFY_INSERT)
203 {
204 /* A DL or CSP/DL was inserted. */
205 secdebug("dynamic", "%sDL module: %s SSID: %lu inserted",
206 (subserviceType & CSSM_SERVICE_CSP) ? "CSP/" : "", guid.toString().c_str(), (unsigned long)subserviceID);
207 list_changed = _add(guid, subserviceID, subserviceType);
208 }
209 else if (eventType == CSSM_NOTIFY_REMOVE)
210 {
211 /* A DL or CSP/DL was removed. */
212 secdebug("dynamic", "%sDL module: %s SSID: %lu removed",
213 (subserviceType & CSSM_SERVICE_CSP) ? "CSP/" : "", guid.toString().c_str(), (unsigned long)subserviceID);
214 list_changed = _remove(guid, subserviceID, subserviceType);
215 }
216 }
217
218 if (list_changed)
219 {
220 // Make sure we are not holding mLock nor the StorageManager mLock when we post these events.
221 // @@@ Rather than posting we should simulate a receive since each client will receive this
222 // cssm level notification.
223 KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent);
224 }
225 }
226
227 DLDbIdentifier DynamicDLDBList::dlDbIdentifier(const Guid &guid,
228 uint32 subserviceID, CSSM_SERVICE_TYPE subserviceType)
229 {
230 CSSM_VERSION theVersion={};
231 CssmSubserviceUid ssuid(guid, &theVersion, subserviceID, subserviceType);
232 CssmNetAddress *dbLocation=NULL;
233
234 return DLDbIdentifier(ssuid, NULL, dbLocation);
235 }