]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_keychain/lib/DynamicDLDBList.cpp
Security-58286.70.7.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / DynamicDLDBList.cpp
CommitLineData
b1ab9ed8 1/*
d8f41ccd 2 * Copyright (c) 2004,2011,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
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
39using namespace KeychainCore;
40
41//
42// DynamicDLDBList
43//
44DynamicDLDBList::DynamicDLDBList()
45 : mMutex(Mutex::recursive), mSearchListSet(false)
46{
47}
48
49DynamicDLDBList::~DynamicDLDBList()
50{
51}
52
53CSSM_RETURN
54DynamicDLDBList::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. */
75bool
76DynamicDLDBList::_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. */
82bool
83DynamicDLDBList::_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. */
97bool
98DynamicDLDBList::_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. */
105bool
106DynamicDLDBList::_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
124bool
125DynamicDLDBList::_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();
fa7225c8 143 secinfo("dynamic", "Loading dynamic %sDL module: %s",
b1ab9ed8
A
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
fa7225c8 163 secinfo("dynamic", "Adding databases from %sDL SSID %lu module: %s",
b1ab9ed8
A
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
174const vector<DLDbIdentifier> &
175DynamicDLDBList::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
189void
190DynamicDLDBList::callback(const Guid &guid, uint32 subserviceID,
191 CSSM_SERVICE_TYPE subserviceType, CSSM_MODULE_EVENT eventType)
192{
fa7225c8 193 secinfo("event", "Received callback from guid: %s ssid: %lu type: %lu event: %lu",
b1ab9ed8
A
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. */
fa7225c8 205 secinfo("dynamic", "%sDL module: %s SSID: %lu inserted",
b1ab9ed8
A
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. */
fa7225c8 212 secinfo("dynamic", "%sDL module: %s SSID: %lu removed",
b1ab9ed8
A
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
227DLDbIdentifier 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}